libheif/box.h (1,168 lines of code) (raw):

/* * HEIF codec. * Copyright (c) 2017 Dirk Farin <dirk.farin@gmail.com> * * This file is part of libheif. * * libheif is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of * the License, or (at your option) any later version. * * libheif is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with libheif. If not, see <http://www.gnu.org/licenses/>. */ #ifndef LIBHEIF_BOX_H #define LIBHEIF_BOX_H #include <cstdint> #include "common_utils.h" #include "libheif/heif.h" #include "libheif/heif_properties.h" #include <cinttypes> #include <cstddef> #include <vector> #include <string> #include <memory> #include <limits> #include <istream> #include <bitset> #include <utility> #include "error.h" #include "logging.h" #include "bitstream.h" #if !defined(__EMSCRIPTEN__) && !defined(_MSC_VER) // std::array<bool> is not supported on some older compilers. #define HAS_BOOL_ARRAY 1 #endif // abbreviation constexpr inline uint32_t fourcc(const char* id) { return fourcc_to_uint32(id); } std::string to_fourcc(uint32_t code); /* constexpr uint32_t fourcc(const char* string) { return ((string[0]<<24) | (string[1]<<16) | (string[2]<< 8) | (string[3])); } */ struct sampleofchunk { uint32_t m_first_chunk; uint32_t m_samples_per_chunk; uint32_t m_sample_description_index; }; class Fraction { public: Fraction() = default; Fraction(int32_t num, int32_t den); // may only use values up to int32_t maximum Fraction(uint32_t num, uint32_t den); // Values will be reduced until they fit into int32_t. Fraction(int64_t num, int64_t den); Fraction operator+(const Fraction&) const; Fraction operator-(const Fraction&) const; Fraction operator+(int) const; Fraction operator-(int) const; Fraction operator/(int) const; int32_t round_down() const; int32_t round_up() const; int32_t round() const; bool is_valid() const; double to_double() const { return numerator / (double)denominator; } int32_t numerator = 0; int32_t denominator = 1; }; inline std::ostream& operator<<(std::ostream& str, const Fraction& f) { str << f.numerator << "/" << f.denominator; return str; } class BoxHeader { public: BoxHeader(); virtual ~BoxHeader() = default; constexpr static uint64_t size_until_end_of_file = 0; uint64_t get_box_size() const { return m_size; } bool has_fixed_box_size() const { return m_size != 0; } uint32_t get_header_size() const { return m_header_size; } uint32_t get_short_type() const { return m_type; } std::vector<uint8_t> get_type() const; std::string get_type_string() const; void set_short_type(uint32_t type) { m_type = type; } // should only be called if get_short_type == fourcc("uuid") std::vector<uint8_t> get_uuid_type() const; void set_uuid_type(const std::vector<uint8_t>&); Error parse_header(BitstreamRange& range); virtual std::string dump(Indent&) const; virtual bool is_full_box_header() const { return false; } private: uint64_t m_size = 0; uint32_t m_type = 0; std::vector<uint8_t> m_uuid_type; protected: uint32_t m_header_size = 0; }; class Box : public BoxHeader { public: Box() = default; void set_short_header(const BoxHeader& hdr) { *(BoxHeader*) this = hdr; } // header size without the FullBox fields (if applicable) int calculate_header_size(bool data64bit) const; static Error read(BitstreamRange& range, std::shared_ptr<Box>* box); virtual Error write(StreamWriter& writer) const; // check, which box version is required and set this in the (full) box header virtual void derive_box_version() {} void derive_box_version_recursive(); std::string dump(Indent&) const override; std::shared_ptr<Box> get_child_box(uint32_t short_type) const; std::vector<std::shared_ptr<Box>> get_child_boxes(uint32_t short_type) const; template<typename T> std::vector<std::shared_ptr<T>> get_typed_child_boxes(uint32_t short_type) const { auto boxes = get_child_boxes(short_type); std::vector<std::shared_ptr<T>> typedBoxes; for (const auto& box : boxes) { typedBoxes.push_back(std::dynamic_pointer_cast<T>(box)); } return typedBoxes; } const std::vector<std::shared_ptr<Box>>& get_all_child_boxes() const { return m_children; } int append_child_box(const std::shared_ptr<Box>& box) { m_children.push_back(box); return (int) m_children.size() - 1; } virtual bool operator==(const Box& other) const; static bool equal(const std::shared_ptr<Box>& box1, const std::shared_ptr<Box>& box2); protected: virtual Error parse(BitstreamRange& range); std::vector<std::shared_ptr<Box>> m_children; const static int READ_CHILDREN_ALL = -1; Error read_children(BitstreamRange& range, int number = READ_CHILDREN_ALL); Error write_children(StreamWriter& writer) const; std::string dump_children(Indent&) const; // --- writing virtual size_t reserve_box_header_space(StreamWriter& writer, bool data64bit = false) const; Error prepend_header(StreamWriter&, size_t box_start, bool data64bit = false) const; virtual Error write_header(StreamWriter&, size_t total_box_size, bool data64bit = false) const; }; class FullBox : public Box { public: bool is_full_box_header() const override { return true; } std::string dump(Indent& indent) const override; void derive_box_version() override { set_version(0); } Error parse_full_box_header(BitstreamRange& range); uint8_t get_version() const { return m_version; } void set_version(uint8_t version) { m_version = version; } uint32_t get_flags() const { return m_flags; } void set_flags(uint32_t flags) { m_flags = flags; } protected: // --- writing size_t reserve_box_header_space(StreamWriter& writer, bool data64bit = false) const override; Error write_header(StreamWriter&, size_t total_size, bool data64bit = false) const override; Error unsupported_version_error(const char* box) const; private: uint8_t m_version = 0; uint32_t m_flags = 0; }; class Box_other : public Box { public: Box_other(uint32_t short_type) { set_short_type(short_type); } const std::vector<uint8_t>& get_raw_data() const { return m_data; } void set_raw_data(const std::vector<uint8_t>& data) { m_data = data; } Error write(StreamWriter& writer) const override; std::string dump(Indent&) const override; protected: Error parse(BitstreamRange& range) override; std::vector<uint8_t> m_data; }; class Box_ftyp : public Box { public: Box_ftyp() { set_short_type(fourcc("ftyp")); } std::string dump(Indent&) const override; bool has_compatible_brand(uint32_t brand) const; std::vector<uint32_t> list_brands() const { return m_compatible_brands; } void set_major_brand(heif_brand2 major_brand) { m_major_brand = major_brand; } void set_minor_version(uint32_t minor_version) { m_minor_version = minor_version; } void clear_compatible_brands() { m_compatible_brands.clear(); } void add_compatible_brand(heif_brand2 brand); Error write(StreamWriter& writer) const override; bool get_compatiable_bands_avaliable() {return compatiable_bands_avaliable;} void set_compatiable_bands_avaliable(bool avaliable) {compatiable_bands_avaliable = avaliable;} protected: Error parse(BitstreamRange& range) override; private: bool compatiable_bands_avaliable = false; uint32_t m_major_brand = 0; uint32_t m_minor_version = 0; std::vector<heif_brand2> m_compatible_brands; }; class Box_meta : public FullBox { public: Box_meta() { set_short_type(fourcc("meta")); } std::string dump(Indent&) const override; protected: Error parse(BitstreamRange& range) override; }; class Box_moov : public Box { public: Box_moov() { set_short_type(fourcc("moov")); } std::string dump(Indent&) const override; protected: Error parse(BitstreamRange& range) override; }; class Box_mvhd : public FullBox { public: Box_mvhd() { set_short_type(fourcc("mvhd")); } void derive_box_version() override; void set_mvhd_data(uint64_t creation_time, uint64_t modification_time, uint32_t timescale, uint64_t duration, uint32_t next_track_ID) { m_creation_time = creation_time; m_modification_time = modification_time; m_timescale = timescale; m_duration = duration; m_next_track_ID = next_track_ID; } uint32_t get_timescale() { return m_timescale; }; uint64_t get_duration() { return m_duration; }; std::string dump(Indent&) const override; Error write(StreamWriter& writer) const override; protected: Error parse(BitstreamRange& range) override; private: uint64_t m_creation_time; uint64_t m_modification_time; uint32_t m_timescale; uint64_t m_duration; uint32_t m_matrix[9] = {0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000}; uint32_t m_next_track_ID; uint32_t m_rate; uint16_t m_volume; uint16_t m_reserved0 = 0; uint32_t m_reserved1[2] = {0,}; uint32_t pre_defined[6] = {0,}; }; class Box_trak : public Box { public: Box_trak() { set_short_type(fourcc("trak")); } std::string dump(Indent&) const override; protected: Error parse(BitstreamRange& range) override; }; class Box_tkhd : public FullBox { public: Box_tkhd() { set_short_type(fourcc("tkhd")); } void derive_box_version() override; void set_tkhd_data(uint64_t creation_time, uint64_t modification_time, uint32_t track_ID, uint64_t duration, uint32_t width, uint32_t height) { m_creation_time = creation_time; m_modification_time = modification_time; m_track_ID = track_ID; m_duration = duration; m_width = width; m_height = height; } std::string dump(Indent&) const override; uint32_t get_width() {return m_width;} uint32_t get_height() {return m_height;} Error write(StreamWriter& writer) const override; protected: Error parse(BitstreamRange& range) override; private: uint64_t m_creation_time; uint64_t m_modification_time; uint32_t m_track_ID; uint32_t m_reserved0 = 0; uint64_t m_duration; uint32_t m_reserved1[2] = {0,}; uint16_t m_layer = 0; uint16_t m_alternate_group = 0; uint16_t m_volume = 0; uint16_t m_reserved2 = 0; uint32_t m_matrix[9] = {0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000}; uint32_t m_width; uint32_t m_height; }; class Box_mdia : public Box { public: Box_mdia() { set_short_type(fourcc("mdia")); } std::string dump(Indent&) const override; protected: Error parse(BitstreamRange& range) override; }; class Box_mdhd : public FullBox { public: Box_mdhd() { set_short_type(fourcc("mdhd")); } void derive_box_version() override; void set_mdhd_data(uint64_t creation_time, uint64_t modification_time, uint32_t timescale, uint64_t duration, uint16_t language) { m_creation_time = creation_time; m_modification_time = modification_time; m_timescale = timescale; m_duration = duration; m_language = language; } std::string dump(Indent&) const override; Error write(StreamWriter& writer) const override; protected: Error parse(BitstreamRange& range) override; private: uint64_t m_creation_time; uint64_t m_modification_time; uint32_t m_timescale; uint64_t m_duration; uint16_t m_language; uint16_t m_pre_defined = 0; }; class Box_minf : public Box { public: Box_minf() { set_short_type(fourcc("minf")); } std::string dump(Indent&) const override; protected: Error parse(BitstreamRange& range) override; }; class Box_vmhd : public FullBox { public: Box_vmhd() { set_short_type(fourcc("vmhd")); } void derive_box_version() override; std::string dump(Indent&) const override; Error write(StreamWriter& writer) const override; protected: Error parse(BitstreamRange& range) override; private: uint16_t m_graphicsmode; uint16_t m_opcolor[3]; }; class Box_stbl : public Box { public: Box_stbl() { set_short_type(fourcc("stbl")); } std::string dump(Indent&) const override; protected: Error parse(BitstreamRange& range) override; }; class Box_stsd : public FullBox { public: Box_stsd() { set_short_type(fourcc("stsd")); } void derive_box_version() override; std::string dump(Indent&) const override; Error write(StreamWriter& writer) const override; protected: Error parse(BitstreamRange& range) override; private: uint32_t m_entry_count = 1; }; class Box_hvc1 : public Box { public: Box_hvc1() { set_short_type(fourcc("hvc1")); } void set_hvc1_data(uint16_t img_src_width, uint16_t img_src_height, uint16_t frame_count); std::string dump(Indent&) const override; Error write(StreamWriter& writer) const override; protected: Error parse(BitstreamRange& range) override; private: uint8_t m_reserved0[6] = {0,}; uint16_t m_data_reference_index = 1; uint16_t m_pre_defined0 = 0; uint16_t m_reserved1 = 0; uint32_t m_pre_defined1[3] = {0,}; uint16_t m_width; uint16_t m_height; uint32_t m_horizresolution = 0x00480000; uint32_t m_vertresolution = 0x00480000; uint32_t m_reserved2 = 0; uint16_t m_frame_count = 1; std::string m_compressorname; //= "\013HEVC Coding"; uint16_t m_depth = 0x0018; uint16_t m_pre_defined2 = (uint16_t)0xffff; }; class Box_ccst : public FullBox { public: // typedef union // { // struct { // unsigned m_all_ref_pics_intra : 1; // unsigned intra_pred_used : 1; // unsigned max_ref_per_pic : 4; // unsigned rsvd : 2; // }bits; // uint8_t val; // }ccst_data; Box_ccst() { set_short_type(fourcc("ccst")); } void derive_box_version() override; std::string dump(Indent&) const override; Error write(StreamWriter& writer) const override; protected: Error parse(BitstreamRange& range) override; private: uint8_t m_ccst_data = 0; uint8_t m_reserved[3] = {0,}; }; class Box_stsz : public FullBox { public: Box_stsz() { set_short_type(fourcc("stsz")); } void derive_box_version() override; void add_entry_size(uint32_t entry_size) { entry_sizes.push_back(entry_size); } uint32_t get_sample_offset(uint32_t ID); uint32_t get_sample_size(uint32_t ID); std::string dump(Indent&) const override; Error write(StreamWriter& writer) const override; protected: Error parse(BitstreamRange& range) override; private: uint32_t m_sample_size = 0; std::vector<uint32_t> entry_sizes; }; class Box_stts : public FullBox { public: struct sample_info { uint32_t m_sample_count; uint32_t m_sample_delta; }; Box_stts() { set_short_type(fourcc("stts")); } void set_frame_durationinTimeScale(uint64_t duration){ frame_durationinTimeScales.push_back(duration); } void derive_box_version() override; void calc_stts_data(); std::string dump(Indent&) const override; Error write(StreamWriter& writer) const override; protected: Error parse(BitstreamRange& range) override; private: uint32_t m_entry_count = 0; std::vector<sample_info> m_samples; std::vector<uint64_t> frame_durationinTimeScales; }; class Box_stsc : public FullBox { public: Box_stsc() { set_short_type(fourcc("stsc")); } void add_chunk_sample(){ m_samples_per_chunk++; } void derive_box_version() override; std::string dump(Indent&) const override; Error write(StreamWriter& writer) const override; uint32_t get_entry_count() {return m_entry_count;} struct sampleofchunk get_chunk_samples(int i) {return m_chunk_samples[i];}; protected: Error parse(BitstreamRange& range) override; private: uint32_t m_entry_count = 1; std::vector<sampleofchunk> m_chunk_samples; uint32_t m_first_chunk = 1; uint32_t m_samples_per_chunk = 0; uint32_t m_sample_description_index = 1; }; class Box_stco : public FullBox { public: Box_stco() { set_short_type(fourcc("stco")); } void derive_box_version() override; uint32_t get_base_offset() {return m_stco_mdat_offset;} std::string dump(Indent&) const override; Error write(StreamWriter& writer) const override; void patch_iloc_header(StreamWriter& writer, uint64_t mdate_offset); protected: Error parse(BitstreamRange& range) override; private: mutable size_t m_stco_box_start = 0; uint32_t m_entry_count = 1; uint32_t m_stco_mdat_offset = 0; }; class Box_stss : public FullBox { public: Box_stss() { set_short_type(fourcc("stss")); } void derive_box_version() override; std::string dump(Indent&) const override; Error write(StreamWriter& writer) const override; void record_sync_data(uint8_t nal_type); void set_stss_data(); protected: Error parse(BitstreamRange& range) override; private: std::vector<bool> m_sync_flags; uint32_t m_entry_count = 0; std::vector<uint32_t> m_sample_number; }; class Box_hdlr : public FullBox { public: Box_hdlr() { set_short_type(fourcc("hdlr")); } std::string dump(Indent&) const override; uint32_t get_handler_type() const { return m_handler_type; } void set_handler_type(uint32_t handler) { m_handler_type = handler; } Error write(StreamWriter& writer) const override; void set_name(std::string name) { m_name = std::move(name); } protected: Error parse(BitstreamRange& range) override; private: uint32_t m_pre_defined = 0; uint32_t m_handler_type = fourcc("pict"); uint32_t m_reserved[3] = {0,}; std::string m_name; }; class Box_pitm : public FullBox { public: Box_pitm() { set_short_type(fourcc("pitm")); } std::string dump(Indent&) const override; heif_item_id get_item_ID() const { return m_item_ID; } void set_item_ID(heif_item_id id) { m_item_ID = id; } void derive_box_version() override; Error write(StreamWriter& writer) const override; protected: Error parse(BitstreamRange& range) override; private: heif_item_id m_item_ID = 0; }; class Box_iloc : public FullBox { public: Box_iloc() { set_short_type(fourcc("iloc")); } std::string dump(Indent&) const override; struct Extent { uint64_t index = 0; uint64_t offset = 0; uint64_t length = 0; std::vector<uint8_t> data; // only used when writing data }; struct Item { heif_item_id item_ID = 0; uint8_t construction_method = 0; // >= version 1 uint16_t data_reference_index = 0; uint64_t base_offset = 0; std::vector<Extent> extents; }; const std::vector<Item>& get_items() const { return m_items; } Error read_data(const Item& item, const std::shared_ptr<StreamReader>& istr, const std::shared_ptr<class Box_idat>&, std::vector<uint8_t>* dest) const; void set_min_version(uint8_t min_version) { m_user_defined_min_version = min_version; } // append bitstream data that will be written later (after iloc box) Error append_data(heif_item_id item_ID, const std::vector<uint8_t>& data, uint8_t construction_method = 0); // append bitstream data that already has been written (before iloc box) // Error write_mdat_before_iloc(heif_image_id item_ID, // std::vector<uint8_t>& data) // reserve data entry that will be written later // Error reserve_mdat_item(heif_image_id item_ID, // uint8_t construction_method, // uint32_t* slot_ID); // void patch_mdat_slot(uint32_t slot_ID, size_t start, size_t length); void derive_box_version() override; Error write(StreamWriter& writer) const override; Error write_mdat_after_iloc(StreamWriter& writer); void set_moov_flag(bool flag) {moov_flag = flag;} protected: Error parse(BitstreamRange& range) override; private: bool moov_flag = false; std::vector<Item> m_items; mutable size_t m_iloc_box_start = 0; uint8_t m_user_defined_min_version = 0; uint8_t m_offset_size = 0; uint8_t m_length_size = 0; uint8_t m_base_offset_size = 0; uint8_t m_index_size = 0; void patch_iloc_header(StreamWriter& writer) const; int m_idat_offset = 0; // only for writing: offset of next data array }; class Box_infe : public FullBox { public: Box_infe() { set_short_type(fourcc("infe")); } std::string dump(Indent&) const override; bool is_hidden_item() const { return m_hidden_item; } void set_hidden_item(bool hidden); heif_item_id get_item_ID() const { return m_item_ID; } void set_item_ID(heif_item_id id) { m_item_ID = id; } const std::string& get_item_type() const { return m_item_type; } void set_item_type(const std::string& type) { m_item_type = type; } void set_item_name(const std::string& name) { m_item_name = name; } const std::string& get_item_name() const { return m_item_name; } const std::string& get_content_type() const { return m_content_type; } const std::string& get_content_encoding() const { return m_content_encoding; } void set_content_type(const std::string& content_type) { m_content_type = content_type; } void set_content_encoding(const std::string& content_encoding) { m_content_encoding = content_encoding; } void derive_box_version() override; Error write(StreamWriter& writer) const override; const std::string& get_item_uri_type() const { return m_item_uri_type; } void set_item_uri_type(const std::string& uritype) { m_item_uri_type = uritype; } protected: Error parse(BitstreamRange& range) override; private: heif_item_id m_item_ID = 0; uint16_t m_item_protection_index = 0; std::string m_item_type; std::string m_item_name; std::string m_content_type; std::string m_content_encoding; std::string m_item_uri_type; // if set, this item should not be part of the presentation (i.e. hidden) bool m_hidden_item = false; }; class Box_iinf : public FullBox { public: Box_iinf() { set_short_type(fourcc("iinf")); } std::string dump(Indent&) const override; void derive_box_version() override; Error write(StreamWriter& writer) const override; protected: Error parse(BitstreamRange& range) override; private: //std::vector< std::shared_ptr<Box_infe> > m_iteminfos; }; class Box_iprp : public Box { public: Box_iprp() { set_short_type(fourcc("iprp")); } std::string dump(Indent&) const override; protected: Error parse(BitstreamRange& range) override; }; class Box_ipco : public Box { public: Box_ipco() { set_short_type(fourcc("ipco")); } int find_or_append_child_box(const std::shared_ptr<Box>& box); Error get_properties_for_item_ID(heif_item_id itemID, const std::shared_ptr<class Box_ipma>&, std::vector<std::shared_ptr<Box>>& out_properties) const; std::shared_ptr<Box> get_property_for_item_ID(heif_item_id itemID, const std::shared_ptr<class Box_ipma>&, uint32_t property_box_type) const; bool is_property_essential_for_item(heif_item_id itemId, const std::shared_ptr<const class Box>& property, const std::shared_ptr<class Box_ipma>&) const; std::string dump(Indent&) const override; protected: Error parse(BitstreamRange& range) override; }; class Box_ispe : public FullBox { public: Box_ispe() { set_short_type(fourcc("ispe")); } uint32_t get_width() const { return m_image_width; } uint32_t get_height() const { return m_image_height; } void set_size(uint32_t width, uint32_t height) { m_image_width = width; m_image_height = height; } std::string dump(Indent&) const override; Error write(StreamWriter& writer) const override; bool operator==(const Box& other) const override; protected: Error parse(BitstreamRange& range) override; private: uint32_t m_image_width = 0; uint32_t m_image_height = 0; }; class Box_ipma : public FullBox { public: Box_ipma() { set_short_type(fourcc("ipma")); } std::string dump(Indent&) const override; struct PropertyAssociation { bool essential; uint16_t property_index; }; const std::vector<PropertyAssociation>* get_properties_for_item_ID(heif_item_id itemID) const; bool is_property_essential_for_item(heif_item_id itemId, int propertyIndex) const; void add_property_for_item_ID(heif_item_id itemID, PropertyAssociation assoc); void derive_box_version() override; Error write(StreamWriter& writer) const override; void insert_entries_from_other_ipma_box(const Box_ipma& b); protected: Error parse(BitstreamRange& range) override; struct Entry { heif_item_id item_ID; std::vector<PropertyAssociation> associations; }; std::vector<Entry> m_entries; }; class Box_auxC : public FullBox { public: Box_auxC() { set_short_type(fourcc("auxC")); } const std::string& get_aux_type() const { return m_aux_type; } void set_aux_type(const std::string& type) { m_aux_type = type; } const std::vector<uint8_t>& get_subtypes() const { return m_aux_subtypes; } std::string dump(Indent&) const override; protected: Error parse(BitstreamRange& range) override; Error write(StreamWriter& writer) const override; private: std::string m_aux_type; std::vector<uint8_t> m_aux_subtypes; }; class Box_irot : public Box { public: Box_irot() { set_short_type(fourcc("irot")); } std::string dump(Indent&) const override; int get_rotation() const { return m_rotation; } // Only these multiples of 90 are allowed: 0, 90, 180, 270. void set_rotation_ccw(int rot) { m_rotation = rot; } protected: Error parse(BitstreamRange& range) override; Error write(StreamWriter& writer) const override; private: int m_rotation = 0; // in degrees (CCW) }; class Box_imir : public Box { public: Box_imir() { set_short_type(fourcc("imir")); } heif_transform_mirror_direction get_mirror_direction() const { return m_axis; } void set_mirror_direction(heif_transform_mirror_direction dir) { m_axis = dir; } std::string dump(Indent&) const override; protected: Error parse(BitstreamRange& range) override; Error write(StreamWriter& writer) const override; private: heif_transform_mirror_direction m_axis = heif_transform_mirror_direction_vertical; }; class Box_clap : public Box { public: Box_clap() { set_short_type(fourcc("clap")); } std::string dump(Indent&) const override; int left_rounded(int image_width) const; // first column int right_rounded(int image_width) const; // last column that is part of the cropped image int top_rounded(int image_height) const; // first row int bottom_rounded(int image_height) const; // last row included in the cropped image double left(int image_width) const; double top(int image_height) const; int get_width_rounded() const; int get_height_rounded() const; void set(uint32_t clap_width, uint32_t clap_height, uint32_t image_width, uint32_t image_height); protected: Error parse(BitstreamRange& range) override; Error write(StreamWriter& writer) const override; private: Fraction m_clean_aperture_width; Fraction m_clean_aperture_height; Fraction m_horizontal_offset; Fraction m_vertical_offset; }; class Box_iref : public FullBox { public: Box_iref() { set_short_type(fourcc("iref")); } struct Reference { BoxHeader header; heif_item_id from_item_ID; std::vector<heif_item_id> to_item_ID; }; std::string dump(Indent&) const override; bool has_references(heif_item_id itemID) const; std::vector<heif_item_id> get_references(heif_item_id itemID, uint32_t ref_type) const; std::vector<Reference> get_references_from(heif_item_id itemID) const; void add_references(heif_item_id from_id, uint32_t type, const std::vector<heif_item_id>& to_ids); protected: Error parse(BitstreamRange& range) override; Error write(StreamWriter& writer) const override; void derive_box_version() override; private: std::vector<Reference> m_references; }; // class Box_hvcC : public Box // { // public: // Box_hvcC() // { // set_short_type(fourcc("hvcC")); // set_is_full_box(false); // } // Box_hvcC(const BoxHeader& hdr) : Box(hdr) // {} // struct configuration // { // uint8_t configuration_version; // uint8_t general_profile_space; // bool general_tier_flag; // uint8_t general_profile_idc; // uint32_t general_profile_compatibility_flags; // static const int NUM_CONSTRAINT_INDICATOR_FLAGS = 48; // std::bitset<NUM_CONSTRAINT_INDICATOR_FLAGS> general_constraint_indicator_flags; // uint8_t general_level_idc; // uint16_t min_spatial_segmentation_idc; // uint8_t parallelism_type; // uint8_t chroma_format; // uint8_t bit_depth_luma; // uint8_t bit_depth_chroma; // uint16_t avg_frame_rate; // uint8_t constant_frame_rate; // uint8_t num_temporal_layers; // uint8_t temporal_id_nested; // }; // std::string dump(Indent&) const override; // bool get_headers(std::vector<uint8_t>* dest) const; // void set_configuration(const configuration& config) // { m_configuration = config; } // const configuration& get_configuration() const // { return m_configuration; } // void append_nal_data(const std::vector<uint8_t>& nal); // void append_nal_data(const uint8_t* data, size_t size); // void append_nal_data_for_movie(const uint8_t* data, size_t size); // bool get_header(uint32_t id, std::vector<uint8_t>* dest) const; // Error write(StreamWriter& writer) const override; // protected: // Error parse(BitstreamRange& range) override; // private: // struct NalArray // { // uint8_t m_array_completeness; // uint8_t m_NAL_unit_type; // std::vector<std::vector<uint8_t> > m_nal_units; // }; // configuration m_configuration; // uint8_t m_length_size = 4; // default: 4 bytes for NAL unit lengths // std::vector<NalArray> m_nal_array; // }; // class Box_av1C : public Box // { // public: // Box_av1C() // { // set_short_type(fourcc("av1C")); // set_is_full_box(false); // } // Box_av1C(const BoxHeader& hdr) : Box(hdr) // {} // struct configuration // { // //unsigned int (1) marker = 1; // uint8_t version = 1; // uint8_t seq_profile = 0; // uint8_t seq_level_idx_0 = 0; // uint8_t seq_tier_0 = 0; // uint8_t high_bitdepth = 0; // uint8_t twelve_bit = 0; // uint8_t monochrome = 0; // uint8_t chroma_subsampling_x = 0; // uint8_t chroma_subsampling_y = 0; // uint8_t chroma_sample_position = 0; // //uint8_t reserved = 0; // uint8_t initial_presentation_delay_present = 0; // uint8_t initial_presentation_delay_minus_one = 0; // //unsigned int (8)[] configOBUs; // }; // std::string dump(Indent&) const override; // bool get_headers(std::vector<uint8_t>* dest) const // { // *dest = m_config_OBUs; // return true; // } // void set_configuration(const configuration& config) // { m_configuration = config; } // const configuration& get_configuration() const // { return m_configuration; } // //void append_nal_data(const std::vector<uint8_t>& nal); // //void append_nal_data(const uint8_t* data, size_t size); // Error write(StreamWriter& writer) const override; // protected: // Error parse(BitstreamRange& range) override; // private: // configuration m_configuration; // std::vector<uint8_t> m_config_OBUs; // }; class Box_idat : public Box { public: std::string dump(Indent&) const override; Error read_data(const std::shared_ptr<StreamReader>& istr, uint64_t start, uint64_t length, std::vector<uint8_t>& out_data) const; int append_data(const std::vector<uint8_t>& data) { auto pos = m_data_for_writing.size(); m_data_for_writing.insert(m_data_for_writing.end(), data.begin(), data.end()); return (int) pos; } Error write(StreamWriter& writer) const override; protected: Error parse(BitstreamRange& range) override; std::streampos m_data_start_pos; std::vector<uint8_t> m_data_for_writing; }; class Box_grpl : public Box { public: std::string dump(Indent&) const override; protected: Error parse(BitstreamRange& range) override; }; class Box_EntityToGroup : public FullBox { public: std::string dump(Indent&) const override; protected: uint32_t group_id; std::vector<heif_item_id> entity_ids; Error parse(BitstreamRange& range) override; }; class Box_ster : public Box_EntityToGroup { public: std::string dump(Indent&) const override; heif_item_id get_left_image() const { return entity_ids[0]; } heif_item_id get_right_image() const { return entity_ids[1]; } protected: Error parse(BitstreamRange& range) override; }; class Box_pymd : public Box_EntityToGroup { public: std::string dump(Indent&) const override; protected: uint16_t tile_size_x; uint16_t tile_size_y; struct LayerInfo { uint16_t layer_binning; uint16_t tiles_in_layer_row_minus1; uint16_t tiles_in_layer_column_minus1; }; std::vector<LayerInfo> m_layer_infos; Error parse(BitstreamRange& range) override; }; class Box_dinf : public Box { public: Box_dinf() { set_short_type(fourcc("dinf")); } std::string dump(Indent&) const override; protected: Error parse(BitstreamRange& range) override; }; class Box_dref : public FullBox { public: Box_dref() { set_short_type(fourcc("dref")); } Error write(StreamWriter& writer) const override; std::string dump(Indent&) const override; protected: Error parse(BitstreamRange& range) override; }; class Box_url : public FullBox { public: Box_url() { set_short_type(fourcc("url ")); } void derive_box_version() override; std::string dump(Indent&) const override; protected: Error parse(BitstreamRange& range) override; std::string m_location; }; class Box_pixi : public FullBox { public: Box_pixi() { set_short_type(fourcc("pixi")); } int get_num_channels() const { return (int) m_bits_per_channel.size(); } int get_bits_per_channel(int channel) const { return m_bits_per_channel[channel]; } void add_channel_bits(uint8_t c) { m_bits_per_channel.push_back(c); } std::string dump(Indent&) const override; Error write(StreamWriter& writer) const override; protected: Error parse(BitstreamRange& range) override; private: std::vector<uint8_t> m_bits_per_channel; }; class Box_pasp : public Box { public: Box_pasp() { set_short_type(fourcc("pasp")); } uint32_t hSpacing = 1; uint32_t vSpacing = 1; std::string dump(Indent&) const override; Error write(StreamWriter& writer) const override; protected: Error parse(BitstreamRange& range) override; }; class Box_lsel : public Box { public: Box_lsel() { set_short_type(fourcc("lsel")); } uint16_t layer_id = 0; std::string dump(Indent&) const override; Error write(StreamWriter& writer) const override; protected: Error parse(BitstreamRange& range) override; }; class Box_clli : public Box { public: Box_clli() { set_short_type(fourcc("clli")); clli.max_content_light_level = 0; clli.max_pic_average_light_level = 0; } heif_content_light_level clli; std::string dump(Indent&) const override; Error write(StreamWriter& writer) const override; protected: Error parse(BitstreamRange& range) override; }; class Box_mdcv : public Box { public: Box_mdcv(); heif_mastering_display_colour_volume mdcv; std::string dump(Indent&) const override; Error write(StreamWriter& writer) const override; protected: Error parse(BitstreamRange& range) override; }; class Box_cmin : public FullBox { public: Box_cmin() { set_short_type(fourcc("cmin")); } struct AbsoluteIntrinsicMatrix; struct RelativeIntrinsicMatrix { double focal_length_x = 0; double principal_point_x = 0; double principal_point_y = 0; bool is_anisotropic = false; double focal_length_y = 0; double skew = 0; void compute_focal_length(int image_width, int image_height, double& out_focal_length_x, double& out_focal_length_y) const; void compute_principal_point(int image_width, int image_height, double& out_principal_point_x, double& out_principal_point_y) const; struct AbsoluteIntrinsicMatrix to_absolute(int image_width, int image_height) const; }; struct AbsoluteIntrinsicMatrix { double focal_length_x; double focal_length_y; double principal_point_x; double principal_point_y; double skew = 0; void apply_clap(const Box_clap* clap, int image_width, int image_height) { principal_point_x -= clap->left(image_width); principal_point_y -= clap->top(image_height); } void apply_imir(const Box_imir* imir, int image_width, int image_height) { switch (imir->get_mirror_direction()) { case heif_transform_mirror_direction_horizontal: focal_length_x *= -1; skew *= -1; principal_point_x = image_width - 1 - principal_point_x; break; case heif_transform_mirror_direction_vertical: focal_length_y *= -1; principal_point_y = image_height - 1 - principal_point_y; break; case heif_transform_mirror_direction_invalid: break; } } }; std::string dump(Indent&) const override; RelativeIntrinsicMatrix get_intrinsic_matrix() const { return m_matrix; } void set_intrinsic_matrix(RelativeIntrinsicMatrix matrix); protected: Error parse(BitstreamRange& range) override; Error write(StreamWriter& writer) const override; private: RelativeIntrinsicMatrix m_matrix; uint32_t m_denominatorShift = 0; uint32_t m_skewDenominatorShift = 0; }; class Box_cmex : public FullBox { public: Box_cmex() { set_short_type(fourcc("cmex")); } struct ExtrinsicMatrix { // in micrometers (um) int32_t pos_x = 0; int32_t pos_y = 0; int32_t pos_z = 0; bool rotation_as_quaternions = true; bool orientation_is_32bit = false; double quaternion_x = 0; double quaternion_y = 0; double quaternion_z = 0; double quaternion_w = 1.0; // rotation angle in degrees double rotation_yaw = 0; // [-180 ; 180) double rotation_pitch = 0; // [-90 ; 90] double rotation_roll = 0; // [-180 ; 180) uint32_t world_coordinate_system_id = 0; // Returns rotation matrix in row-major order. std::array<double,9> calculate_rotation_matrix() const; }; std::string dump(Indent&) const override; ExtrinsicMatrix get_extrinsic_matrix() const { return m_matrix; } Error set_extrinsic_matrix(ExtrinsicMatrix matrix); protected: Error parse(BitstreamRange& range) override; Error write(StreamWriter& writer) const override; private: ExtrinsicMatrix m_matrix; bool m_has_pos_x = false; bool m_has_pos_y = false; bool m_has_pos_z = false; bool m_has_orientation = false; bool m_has_world_coordinate_system_id = false; enum Flags { pos_x_present = 0x01, pos_y_present = 0x02, pos_z_present = 0x04, orientation_present = 0x08, rot_large_field_size = 0x10, id_present = 0x20 }; }; /** * User Description property. * * Permits the association of items or entity groups with a user-defined name, description and tags; * there may be multiple udes properties, each with a different language code. * * See ISO/IEC 23008-12:2022(E) Section 6.5.20. */ class Box_udes : public FullBox { public: Box_udes() { set_short_type(fourcc("udes")); } std::string dump(Indent&) const override; Error write(StreamWriter& writer) const override; /** * Language tag. * * An RFC 5646 compliant language identifier for the language of the text contained in the other properties. * Examples: "en-AU", "de-DE", or "zh-CN“. * When is empty, the language is unknown or not undefined. */ std::string get_lang() const { return m_lang; } /** * Set the language tag. * * An RFC 5646 compliant language identifier for the language of the text contained in the other properties. * Examples: "en-AU", "de-DE", or "zh-CN“. */ void set_lang(const std::string lang) { m_lang = lang; } /** * Name. * * Human readable name for the item or group being described. * May be empty, indicating no name is applicable. */ std::string get_name() const { return m_name; } /** * Set the name. * * Human readable name for the item or group being described. */ void set_name(const std::string name) { m_name = name; } /** * Description. * * Human readable description for the item or group. * May be empty, indicating no description has been provided. */ std::string get_description() const { return m_description; } /** * Set the description. * * Human readable description for the item or group. */ void set_description(const std::string description) { m_description = description; } /** * Tags. * * Comma separated user defined tags applicable to the item or group. * May be empty, indicating no tags have been assigned. */ std::string get_tags() const { return m_tags; } /** * Set the tags. * * Comma separated user defined tags applicable to the item or group. */ void set_tags(const std::string tags) { m_tags = tags; } protected: Error parse(BitstreamRange& range) override; private: std::string m_lang; std::string m_name; std::string m_description; std::string m_tags; }; #endif