From 6ef2c54ffa6b406ef02fccfc9e4e0ee5b13a399f Mon Sep 17 00:00:00 2001 From: Dirk Farin Date: Mon, 4 Nov 2024 21:00:40 +0100 Subject: [PATCH] move expansion of mini boxes into the Box_mini class (#1351) --- libheif/box.cc | 13 ++ libheif/box.h | 13 ++ libheif/codecs/avif_boxes.h | 2 +- libheif/codecs/hevc_boxes.h | 2 +- libheif/file.cc | 333 ++++++------------------------------ libheif/file.h | 16 ++ libheif/mini.cc | 293 +++++++++++++++++++++++++++++++ libheif/mini.h | 2 + 8 files changed, 389 insertions(+), 285 deletions(-) diff --git a/libheif/box.cc b/libheif/box.cc index cbe94eb586..e5446cf9c9 100644 --- a/libheif/box.cc +++ b/libheif/box.cc @@ -858,6 +858,19 @@ bool Box::operator==(const Box& other) const } +bool Box::remove_child_box(const std::shared_ptr& box) +{ + for (int i=0; i<(int)m_children.size(); i++) { + if (m_children[i].get() == box.get()) { + m_children.erase(m_children.begin() + i); + return true; + } + } + + return false; +} + + bool Box::equal(const std::shared_ptr& box1, const std::shared_ptr& box2) { if (!box1 || !box2) { diff --git a/libheif/box.h b/libheif/box.h index b784d227b1..551d749716 100644 --- a/libheif/box.h +++ b/libheif/box.h @@ -208,7 +208,18 @@ class Box : public BoxHeader return nullptr; } + template bool replace_child_box(const std::shared_ptr& box) + { + for (auto & b : m_children) { + if (std::dynamic_pointer_cast(b) != nullptr) { + b = box; + return true; + } + } + append_child_box(box); + return false; + } template std::vector> get_child_boxes() const @@ -233,6 +244,8 @@ class Box : public BoxHeader bool has_child_boxes() const { return !m_children.empty(); } + bool remove_child_box(const std::shared_ptr& box); + virtual bool operator==(const Box& other) const; static bool equal(const std::shared_ptr& box1, const std::shared_ptr& box2); diff --git a/libheif/codecs/avif_boxes.h b/libheif/codecs/avif_boxes.h index 8b678e511a..d1e5c6e7a3 100644 --- a/libheif/codecs/avif_boxes.h +++ b/libheif/codecs/avif_boxes.h @@ -37,7 +37,7 @@ class Box_av1C : public Box { // allow access to protected parse() method -friend class HeifFile; +friend class Box_mini; public: Box_av1C() diff --git a/libheif/codecs/hevc_boxes.h b/libheif/codecs/hevc_boxes.h index 9ade3c697d..575a1ff9ca 100644 --- a/libheif/codecs/hevc_boxes.h +++ b/libheif/codecs/hevc_boxes.h @@ -35,7 +35,7 @@ class Box_hvcC : public Box { // allow access to protected parse() method -friend class HeifFile; +friend class Box_mini; public: Box_hvcC() diff --git a/libheif/file.cc b/libheif/file.cc index e4a5794b9d..2ddaa82fd1 100644 --- a/libheif/file.cc +++ b/libheif/file.cc @@ -294,19 +294,6 @@ std::string HeifFile::debug_dump_boxes() const return sstr.str(); } -#if ENABLE_EXPERIMENTAL_MINI_FORMAT -static uint32_t get_item_type_for_brand(const heif_brand2 brand) -{ - switch(brand) { - case heif_brand2_avif: - return fourcc("av01"); - case heif_brand2_heic: - return fourcc("hvc1"); - default: - return 0; - } -} -#endif Error HeifFile::parse_heif_file() { @@ -348,16 +335,7 @@ Error HeifFile::parse_heif_file() #endif m_ftyp_box = m_file_layout->get_ftyp_box(); - m_meta_box = m_file_layout->get_meta_box(); - m_top_level_boxes.push_back(m_ftyp_box); - m_top_level_boxes.push_back(m_meta_box); - // TODO: we are missing 'mdat' top level boxes - -#if ENABLE_EXPERIMENTAL_MINI_FORMAT - m_mini_box = m_file_layout->get_mini_box(); - m_top_level_boxes.push_back(m_mini_box); -#endif // --- check whether this is a HEIF file and its structural format @@ -384,272 +362,21 @@ Error HeifFile::parse_heif_file() } #if ENABLE_EXPERIMENTAL_MINI_FORMAT - if (m_mini_box) { - m_hdlr_box = std::make_shared(); - m_hdlr_box->set_handler_type(fourcc("pict")); - - m_pitm_box = std::make_shared(); - m_pitm_box->set_item_ID(1); - - std::shared_ptr primary_infe_box = std::make_shared(); - primary_infe_box->set_version(2); - primary_infe_box->set_item_ID(1); - // TODO: check explicit codec flag - uint32_t minor_version = m_ftyp_box->get_minor_version(); - heif_brand2 mini_brand = minor_version; - uint32_t infe_type = get_item_type_for_brand(mini_brand); - if (infe_type == 0) { - // not found - std::stringstream sstr; - sstr << "Minimised file requires brand " << fourcc_to_string(mini_brand) << " but this is not yet supported."; - return Error(heif_error_Unsupported_filetype, - heif_suberror_Unspecified, - sstr.str()); - } - primary_infe_box->set_item_type_4cc(infe_type); - m_infe_boxes.insert(std::make_pair(1, primary_infe_box)); - - if (m_mini_box->get_alpha_item_data_size() != 0) { - std::shared_ptr alpha_infe_box = std::make_shared(); - alpha_infe_box->set_version(2); - alpha_infe_box->set_flags(1); - alpha_infe_box->set_item_ID(2); - alpha_infe_box->set_item_type_4cc(infe_type); - m_infe_boxes.insert(std::make_pair(2, alpha_infe_box)); - } - - if (m_mini_box->get_exif_flag()) { - std::shared_ptr exif_infe_box = std::make_shared(); - exif_infe_box->set_version(2); - exif_infe_box->set_flags(1); - exif_infe_box->set_item_ID(6); - exif_infe_box->set_item_type_4cc(fourcc("Exif")); - m_infe_boxes.insert(std::make_pair(6, exif_infe_box)); - } - - if (m_mini_box->get_xmp_flag()) { - std::shared_ptr xmp_infe_box = std::make_shared(); - xmp_infe_box->set_version(2); - xmp_infe_box->set_flags(1); - xmp_infe_box->set_item_ID(7); - xmp_infe_box->set_item_type_4cc(fourcc("mime")); - xmp_infe_box->set_content_type("application/rdf+xml"); - m_infe_boxes.insert(std::make_pair(7, xmp_infe_box)); - } - - m_ipco_box = std::make_shared(); - - if (m_mini_box->get_main_item_codec_config().size() != 0) { - std::shared_ptr istr = std::make_shared( - m_mini_box->get_main_item_codec_config().data(), - m_mini_box->get_main_item_codec_config().size(), - false - ); - BitstreamRange codec_range(istr, m_mini_box->get_main_item_codec_config().size(), nullptr); - - std::shared_ptr main_item_codec_prop; - if (infe_type == fourcc("av01")) { - std::shared_ptr codec_prop = std::make_shared(); - codec_prop->parse(codec_range, heif_get_global_security_limits()); - main_item_codec_prop = std::move(codec_prop); - } else if (infe_type == fourcc("hvc1")) { - std::shared_ptr codec_prop = std::make_shared(); - codec_prop->parse(codec_range, heif_get_global_security_limits()); - main_item_codec_prop = std::move(codec_prop); - } else { - // not found - std::stringstream sstr; - sstr << "Minimised file requires infe support for " << fourcc_to_string(infe_type) << " but this is not yet supported."; - return Error(heif_error_Unsupported_filetype, - heif_suberror_Unspecified, - sstr.str()); - } - m_ipco_box->append_child_box(main_item_codec_prop); // entry 1 - } else { - m_ipco_box->append_child_box(std::make_shared()); // placeholder for entry 1 - } - - std::shared_ptr ispe = std::make_shared(); - ispe->set_size(m_mini_box->get_width(), m_mini_box->get_height()); - m_ipco_box->append_child_box(ispe); // entry 2 - - std::shared_ptr pixi = std::make_shared(); - pixi->set_version(0); - // pixi->set_version(1); // TODO: when we support version 1 - // TODO: there is more when we do version 1, and anything other than RGB - pixi->add_channel_bits(m_mini_box->get_bit_depth()); - pixi->add_channel_bits(m_mini_box->get_bit_depth()); - pixi->add_channel_bits(m_mini_box->get_bit_depth()); - m_ipco_box->append_child_box(pixi); // entry 3 - - std::shared_ptr colr = std::make_shared(); - std::shared_ptr nclx = std::make_shared(); - nclx->set_colour_primaries(m_mini_box->get_colour_primaries()); - nclx->set_transfer_characteristics(m_mini_box->get_transfer_characteristics()); - nclx->set_matrix_coefficients(m_mini_box->get_matrix_coefficients()); - nclx->set_full_range_flag(m_mini_box->get_full_range_flag()); - colr->set_color_profile(nclx); - m_ipco_box->append_child_box(colr); // entry 4 - - if (m_mini_box->get_icc_flag()) { - std::shared_ptr colr_icc = std::make_shared(); - std::shared_ptr icc = std::make_shared(fourcc("prof"), m_mini_box->get_icc_data()); - colr_icc->set_color_profile(icc); - m_ipco_box->append_child_box(colr_icc); // entry 5 - } else { - m_ipco_box->append_child_box(std::make_shared()); // placeholder for entry 5 - } - - if (m_mini_box->get_alpha_item_codec_config().size() != 0) { - std::shared_ptr istr = std::make_shared( - m_mini_box->get_alpha_item_codec_config().data(), - m_mini_box->get_alpha_item_codec_config().size(), - false - ); - BitstreamRange alpha_codec_range(istr, m_mini_box->get_alpha_item_codec_config().size(), nullptr); - std::shared_ptr alpha_item_codec_prop; - if (infe_type == fourcc("av01")) { - std::shared_ptr codec_prop = std::make_shared(); - codec_prop->parse(alpha_codec_range, heif_get_global_security_limits()); - alpha_item_codec_prop = std::move(codec_prop); - } else if (infe_type == fourcc("hvc1")) { - std::shared_ptr codec_prop = std::make_shared(); - codec_prop->parse(alpha_codec_range, heif_get_global_security_limits()); - alpha_item_codec_prop = std::move(codec_prop); - } else { - // not found - std::stringstream sstr; - sstr << "Minimised file requires infe support for " << fourcc_to_string(infe_type) << " but this is not yet supported."; - return Error(heif_error_Unsupported_filetype, - heif_suberror_Unspecified, - sstr.str()); - } - m_ipco_box->append_child_box(alpha_item_codec_prop); // entry 6 - } else { - m_ipco_box->append_child_box(std::make_shared()); // placeholder for entry 6 - } - - if (m_mini_box->get_alpha_item_data_size() != 0) { - std::shared_ptr aux_type = std::make_shared(); - aux_type->set_aux_type("urn:mpeg:mpegB:cicp:systems:auxiliary:alpha"); - m_ipco_box->append_child_box(aux_type); // entry 7 - } else { - m_ipco_box->append_child_box(std::make_shared()); // placeholder for entry 7 - } - - // TODO: replace this placeholder with pixi box version 1 once that is supported - m_ipco_box->append_child_box(std::make_shared()); // placeholder for entry 8 - - if (m_mini_box->get_orientation() == 2) { - std::shared_ptr irot = std::make_shared(); - irot->set_rotation_ccw(2 * 90); - m_ipco_box->append_child_box(irot); // entry 9 - } else if ((m_mini_box->get_orientation() == 4) || (m_mini_box->get_orientation() == 6) || (m_mini_box->get_orientation() == 7)) { - std::shared_ptr irot = std::make_shared(); - irot->set_rotation_ccw(1 * 90); - m_ipco_box->append_child_box(irot); // entry 9 - } else if (m_mini_box->get_orientation() == 5) { - std::shared_ptr irot = std::make_shared(); - irot->set_rotation_ccw(3 * 90); - m_ipco_box->append_child_box(irot); // entry 9 - } else { - m_ipco_box->append_child_box(std::make_shared()); // placeholder for entry 9 - } - - if ((m_mini_box->get_orientation() == 1) || (m_mini_box->get_orientation() == 6)) { - std::shared_ptr imir = std::make_shared(); - imir->set_mirror_direction(heif_transform_mirror_direction_horizontal); - m_ipco_box->append_child_box(imir); // entry 10 - } else if ((m_mini_box->get_orientation() == 3) || (m_mini_box->get_orientation() == 4)) { - std::shared_ptr imir = std::make_shared(); - imir->set_mirror_direction(heif_transform_mirror_direction_vertical); - m_ipco_box->append_child_box(imir); // entry 10 - } else { - m_ipco_box->append_child_box(std::make_shared()); // placeholder for entry 10 - } - - m_ipma_box = std::make_shared(); - m_ipma_box->add_property_for_item_ID(1, Box_ipma::PropertyAssociation{true, uint16_t(1)}); - m_ipma_box->add_property_for_item_ID(1, Box_ipma::PropertyAssociation{false, uint16_t(2)}); - m_ipma_box->add_property_for_item_ID(1, Box_ipma::PropertyAssociation{false, uint16_t(3)}); - m_ipma_box->add_property_for_item_ID(1, Box_ipma::PropertyAssociation{true, uint16_t(4)}); - m_ipma_box->add_property_for_item_ID(1, Box_ipma::PropertyAssociation{true, uint16_t(5)}); - m_ipma_box->add_property_for_item_ID(1, Box_ipma::PropertyAssociation{true, uint16_t(9)}); - m_ipma_box->add_property_for_item_ID(1, Box_ipma::PropertyAssociation{true, uint16_t(10)}); - - if (m_mini_box->get_alpha_item_data_size() != 0) { - m_ipma_box->add_property_for_item_ID(2, Box_ipma::PropertyAssociation{true, uint16_t(6)}); - m_ipma_box->add_property_for_item_ID(2, Box_ipma::PropertyAssociation{false, uint16_t(2)}); - m_ipma_box->add_property_for_item_ID(2, Box_ipma::PropertyAssociation{true, uint16_t(7)}); - m_ipma_box->add_property_for_item_ID(2, Box_ipma::PropertyAssociation{false, uint16_t(8)}); - m_ipma_box->add_property_for_item_ID(2, Box_ipma::PropertyAssociation{true, uint16_t(9)}); - m_ipma_box->add_property_for_item_ID(2, Box_ipma::PropertyAssociation{true, uint16_t(10)}); - } - // TODO: will need more once we support HDR / gainmap representation - - m_iloc_box = std::make_shared(); - Box_iloc::Item main_item; - main_item.item_ID = 1; - main_item.construction_method = 0; - main_item.base_offset = 0; - main_item.data_reference_index = 0; - Box_iloc::Extent main_item_extent; - main_item_extent.offset = m_mini_box->get_main_item_data_offset(); - main_item_extent.length = m_mini_box->get_main_item_data_size(); - main_item.extents.push_back(main_item_extent); - m_iloc_box->append_item(main_item); - - if (m_mini_box->get_alpha_item_data_size() != 0) { - Box_iloc::Item alpha_item; - alpha_item.item_ID = 2; - alpha_item.base_offset = 0; - alpha_item.data_reference_index = 0; - Box_iloc::Extent alpha_item_extent; - alpha_item_extent.offset = m_mini_box->get_alpha_item_data_offset(); - alpha_item_extent.length = m_mini_box->get_alpha_item_data_size(); - alpha_item.extents.push_back(alpha_item_extent); - m_iloc_box->append_item(alpha_item); - } - if (m_mini_box->get_exif_flag()) { - Box_iloc::Item exif_item; - exif_item.item_ID = 6; - exif_item.base_offset = 0; - exif_item.data_reference_index = 0; - Box_iloc::Extent exif_item_extent; - exif_item_extent.offset = m_mini_box->get_exif_item_data_offset(); - exif_item_extent.length = m_mini_box->get_exif_item_data_size(); - exif_item.extents.push_back(exif_item_extent); - m_iloc_box->append_item(exif_item); - } - if (m_mini_box->get_xmp_flag()) { - Box_iloc::Item xmp_item; - xmp_item.item_ID = 7; - xmp_item.base_offset = 0; - xmp_item.data_reference_index = 0; - Box_iloc::Extent xmp_item_extent; - xmp_item_extent.offset = m_mini_box->get_xmp_item_data_offset(); - xmp_item_extent.length = m_mini_box->get_xmp_item_data_size(); - xmp_item.extents.push_back(xmp_item_extent); - m_iloc_box->append_item(xmp_item); - } + m_mini_box = m_file_layout->get_mini_box(); + m_top_level_boxes.push_back(m_mini_box); - m_iref_box = std::make_shared(); - std::vector to_items = {1}; - if (m_mini_box->get_alpha_item_data_size() != 0) { - m_iref_box->add_references(2, fourcc("auxl"), to_items); - } - // TODO: if alpha prem - // TODO: if gainmap flag && item 4 - // TODO: if gainmap flag && !item 4 - if (m_mini_box->get_exif_flag()) { - m_iref_box->add_references(6, fourcc("cdsc"), to_items); - } - if (m_mini_box->get_xmp_flag()) { - m_iref_box->add_references(7, fourcc("cdsc"), to_items); + if (m_mini_box) { + Error err = m_mini_box->create_expanded_boxes(this); + if (err) { + return err; } return Error::Ok; } + m_meta_box = m_file_layout->get_meta_box(); + m_top_level_boxes.push_back(m_meta_box); + // TODO: we are missing 'mdat' top level boxes + // if we didn't find the mini box, meta is required #endif if (!m_meta_box) { @@ -1194,6 +921,12 @@ Result HeifFile::add_infe(uint32_t item_type, const uint8_t* data, } +void HeifFile::add_infe_box(heif_item_id id, std::shared_ptr infe) +{ + m_infe_boxes.insert(std::make_pair(id, std::move(infe))); +} + + Result HeifFile::add_infe_mime(const char* content_type, heif_metadata_compression content_encoding, const uint8_t* data, size_t size) { Result result; @@ -1338,9 +1071,43 @@ void HeifFile::replace_iloc_data(heif_item_id id, uint64_t offset, const std::ve void HeifFile::set_primary_item_id(heif_item_id id) { + if (!m_pitm_box) { + m_pitm_box = std::make_shared(); + m_meta_box->replace_child_box(m_pitm_box); + } + m_pitm_box->set_item_ID(id); } + +void HeifFile::set_ipco_box(std::shared_ptr ipco) +{ + m_ipco_box = ipco; + m_meta_box->replace_child_box(ipco); +} + + +void HeifFile::set_ipma_box(std::shared_ptr ipma) +{ + m_ipma_box = ipma; + m_meta_box->replace_child_box(ipma); +} + + +void HeifFile::set_iloc_box(std::shared_ptr iloc) +{ + m_iloc_box = iloc; + m_meta_box->replace_child_box(iloc); +} + + +void HeifFile::set_iref_box(std::shared_ptr iref) +{ + m_iref_box = iref; + m_meta_box->replace_child_box(iref); +} + + void HeifFile::add_iref_reference(heif_item_id from, uint32_t type, const std::vector& to) { diff --git a/libheif/file.h b/libheif/file.h index fbe2ef38c8..84ea8f21d0 100644 --- a/libheif/file.h +++ b/libheif/file.h @@ -72,6 +72,8 @@ class HeifFile void set_brand(heif_compression_format format, bool miaf_compatible); + void set_hdlr_box(std::shared_ptr box) { m_hdlr_box = std::move(box); } + void write(StreamWriter& writer); int get_num_images() const { return static_cast(m_infe_boxes.size()); } @@ -104,18 +106,26 @@ class HeifFile std::shared_ptr get_ftyp_box() { return m_ftyp_box; } + void init_meta_box() { m_meta_box = std::make_shared(); } + std::shared_ptr get_infe_box(heif_item_id imageID) const; std::shared_ptr get_infe_box(heif_item_id imageID); + void set_iref_box(std::shared_ptr); + std::shared_ptr get_iref_box() { return m_iref_box; } std::shared_ptr get_iref_box() const { return m_iref_box; } std::shared_ptr get_ipco_box() { return m_ipco_box; } + void set_ipco_box(std::shared_ptr); + std::shared_ptr get_ipco_box() const { return m_ipco_box; } + void set_ipma_box(std::shared_ptr); + std::shared_ptr get_ipma_box() { return m_ipma_box; } std::shared_ptr get_ipma_box() const { return m_ipma_box; } @@ -168,6 +178,8 @@ class HeifFile Result add_infe(uint32_t item_type, const uint8_t* data, size_t size); + void add_infe_box(heif_item_id, std::shared_ptr infe); + Result add_infe_mime(const char* content_type, heif_metadata_compression content_encoding, const uint8_t* data, size_t size); Result add_precompressed_infe_mime(const char* content_type, std::string content_encoding, const uint8_t* data, size_t size); @@ -182,6 +194,10 @@ class HeifFile void replace_iloc_data(heif_item_id id, uint64_t offset, const std::vector& data, uint8_t construction_method = 0); + void set_iloc_box(std::shared_ptr); + + std::shared_ptr get_iloc_box() { return m_iloc_box; } + void set_primary_item_id(heif_item_id id); void add_iref_reference(heif_item_id from, uint32_t type, diff --git a/libheif/mini.cc b/libheif/mini.cc index cf49843503..99643dc6e8 100644 --- a/libheif/mini.cc +++ b/libheif/mini.cc @@ -19,6 +19,9 @@ */ #include "mini.h" +#include "file.h" +#include "codecs/avif_boxes.h" +#include "codecs/hevc_boxes.h" #include #include @@ -26,6 +29,7 @@ #include #include + Error Box_mini::parse(BitstreamRange &range, const heif_security_limits *limits) { uint64_t start_offset = range.get_istream()->get_position(); @@ -736,3 +740,292 @@ std::string Box_mini::dump(Indent &indent) const } return sstr.str(); } + + +static uint32_t get_item_type_for_brand(const heif_brand2 brand) +{ + switch(brand) { + case heif_brand2_avif: + return fourcc("av01"); + case heif_brand2_heic: + return fourcc("hvc1"); + default: + return 0; + } +} + + +Error Box_mini::create_expanded_boxes(class HeifFile* file) +{ + file->init_meta_box(); + + auto hdlr_box = std::make_shared(); + hdlr_box->set_handler_type(fourcc("pict")); + file->set_hdlr_box(hdlr_box); + + file->set_primary_item_id(1); + + std::shared_ptr primary_infe_box = std::make_shared(); + primary_infe_box->set_version(2); + primary_infe_box->set_item_ID(1); + + // TODO: check explicit codec flag + uint32_t minor_version = file->get_ftyp_box()->get_minor_version(); + heif_brand2 mini_brand = minor_version; + uint32_t infe_type = get_item_type_for_brand(mini_brand); + if (infe_type == 0) { + // not found + std::stringstream sstr; + sstr << "Minimised file requires brand " << fourcc_to_string(mini_brand) << " but this is not yet supported."; + return Error(heif_error_Unsupported_filetype, + heif_suberror_Unspecified, + sstr.str()); + } + primary_infe_box->set_item_type_4cc(infe_type); + file->add_infe_box(1, primary_infe_box); + + if (get_alpha_item_data_size() != 0) { + std::shared_ptr alpha_infe_box = std::make_shared(); + alpha_infe_box->set_version(2); + alpha_infe_box->set_flags(1); + alpha_infe_box->set_item_ID(2); + alpha_infe_box->set_item_type_4cc(infe_type); + file->add_infe_box(2, alpha_infe_box); + } + + if (get_exif_flag()) { + std::shared_ptr exif_infe_box = std::make_shared(); + exif_infe_box->set_version(2); + exif_infe_box->set_flags(1); + exif_infe_box->set_item_ID(6); + exif_infe_box->set_item_type_4cc(fourcc("Exif")); + file->add_infe_box(6, exif_infe_box); + } + + if (get_xmp_flag()) { + std::shared_ptr xmp_infe_box = std::make_shared(); + xmp_infe_box->set_version(2); + xmp_infe_box->set_flags(1); + xmp_infe_box->set_item_ID(7); + xmp_infe_box->set_item_type_4cc(fourcc("mime")); + xmp_infe_box->set_content_type("application/rdf+xml"); + file->add_infe_box(7, xmp_infe_box); + } + + auto ipco_box = std::make_shared(); + file->set_ipco_box(ipco_box); + + if (get_main_item_codec_config().size() != 0) { + std::shared_ptr istr = std::make_shared( + get_main_item_codec_config().data(), + get_main_item_codec_config().size(), + false + ); + BitstreamRange codec_range(istr, get_main_item_codec_config().size(), nullptr); + + std::shared_ptr main_item_codec_prop; + if (infe_type == fourcc("av01")) { + std::shared_ptr codec_prop = std::make_shared(); + codec_prop->parse(codec_range, heif_get_global_security_limits()); + main_item_codec_prop = std::move(codec_prop); + } else if (infe_type == fourcc("hvc1")) { + std::shared_ptr codec_prop = std::make_shared(); + codec_prop->parse(codec_range, heif_get_global_security_limits()); + main_item_codec_prop = std::move(codec_prop); + } else { + // not found + std::stringstream sstr; + sstr << "Minimised file requires infe support for " << fourcc_to_string(infe_type) << " but this is not yet supported."; + return Error(heif_error_Unsupported_filetype, + heif_suberror_Unspecified, + sstr.str()); + } + ipco_box->append_child_box(main_item_codec_prop); // entry 1 + } else { + ipco_box->append_child_box(std::make_shared()); // placeholder for entry 1 + } + + std::shared_ptr ispe = std::make_shared(); + ispe->set_size(get_width(), get_height()); + ipco_box->append_child_box(ispe); // entry 2 + + std::shared_ptr pixi = std::make_shared(); + pixi->set_version(0); + // pixi->set_version(1); // TODO: when we support version 1 + // TODO: there is more when we do version 1, and anything other than RGB + pixi->add_channel_bits(get_bit_depth()); + pixi->add_channel_bits(get_bit_depth()); + pixi->add_channel_bits(get_bit_depth()); + ipco_box->append_child_box(pixi); // entry 3 + + std::shared_ptr colr = std::make_shared(); + std::shared_ptr nclx = std::make_shared(); + nclx->set_colour_primaries(get_colour_primaries()); + nclx->set_transfer_characteristics(get_transfer_characteristics()); + nclx->set_matrix_coefficients(get_matrix_coefficients()); + nclx->set_full_range_flag(get_full_range_flag()); + colr->set_color_profile(nclx); + ipco_box->append_child_box(colr); // entry 4 + + if (get_icc_flag()) { + std::shared_ptr colr_icc = std::make_shared(); + std::shared_ptr icc = std::make_shared(fourcc("prof"), get_icc_data()); + colr_icc->set_color_profile(icc); + ipco_box->append_child_box(colr_icc); // entry 5 + } else { + ipco_box->append_child_box(std::make_shared()); // placeholder for entry 5 + } + + if (get_alpha_item_codec_config().size() != 0) { + std::shared_ptr istr = std::make_shared( + get_alpha_item_codec_config().data(), + get_alpha_item_codec_config().size(), + false + ); + BitstreamRange alpha_codec_range(istr, get_alpha_item_codec_config().size(), nullptr); + std::shared_ptr alpha_item_codec_prop; + if (infe_type == fourcc("av01")) { + std::shared_ptr codec_prop = std::make_shared(); + codec_prop->parse(alpha_codec_range, heif_get_global_security_limits()); + alpha_item_codec_prop = std::move(codec_prop); + } else if (infe_type == fourcc("hvc1")) { + std::shared_ptr codec_prop = std::make_shared(); + codec_prop->parse(alpha_codec_range, heif_get_global_security_limits()); + alpha_item_codec_prop = std::move(codec_prop); + } else { + // not found + std::stringstream sstr; + sstr << "Minimised file requires infe support for " << fourcc_to_string(infe_type) << " but this is not yet supported."; + return Error(heif_error_Unsupported_filetype, + heif_suberror_Unspecified, + sstr.str()); + } + ipco_box->append_child_box(alpha_item_codec_prop); // entry 6 + } else { + ipco_box->append_child_box(std::make_shared()); // placeholder for entry 6 + } + + if (get_alpha_item_data_size() != 0) { + std::shared_ptr aux_type = std::make_shared(); + aux_type->set_aux_type("urn:mpeg:mpegB:cicp:systems:auxiliary:alpha"); + ipco_box->append_child_box(aux_type); // entry 7 + } else { + ipco_box->append_child_box(std::make_shared()); // placeholder for entry 7 + } + + // TODO: replace this placeholder with pixi box version 1 once that is supported + ipco_box->append_child_box(std::make_shared()); // placeholder for entry 8 + + if (get_orientation() == 2) { + std::shared_ptr irot = std::make_shared(); + irot->set_rotation_ccw(2 * 90); + ipco_box->append_child_box(irot); // entry 9 + } else if ((get_orientation() == 4) || (get_orientation() == 6) || (get_orientation() == 7)) { + std::shared_ptr irot = std::make_shared(); + irot->set_rotation_ccw(1 * 90); + ipco_box->append_child_box(irot); // entry 9 + } else if (get_orientation() == 5) { + std::shared_ptr irot = std::make_shared(); + irot->set_rotation_ccw(3 * 90); + ipco_box->append_child_box(irot); // entry 9 + } else { + ipco_box->append_child_box(std::make_shared()); // placeholder for entry 9 + } + + if ((get_orientation() == 1) || (get_orientation() == 6)) { + std::shared_ptr imir = std::make_shared(); + imir->set_mirror_direction(heif_transform_mirror_direction_horizontal); + ipco_box->append_child_box(imir); // entry 10 + } else if ((get_orientation() == 3) || (get_orientation() == 4)) { + std::shared_ptr imir = std::make_shared(); + imir->set_mirror_direction(heif_transform_mirror_direction_vertical); + ipco_box->append_child_box(imir); // entry 10 + } else { + ipco_box->append_child_box(std::make_shared()); // placeholder for entry 10 + } + + auto ipma_box = std::make_shared(); + file->set_ipma_box(ipma_box); + ipma_box->add_property_for_item_ID(1, Box_ipma::PropertyAssociation{true, uint16_t(1)}); + ipma_box->add_property_for_item_ID(1, Box_ipma::PropertyAssociation{false, uint16_t(2)}); + ipma_box->add_property_for_item_ID(1, Box_ipma::PropertyAssociation{false, uint16_t(3)}); + ipma_box->add_property_for_item_ID(1, Box_ipma::PropertyAssociation{true, uint16_t(4)}); + ipma_box->add_property_for_item_ID(1, Box_ipma::PropertyAssociation{true, uint16_t(5)}); + ipma_box->add_property_for_item_ID(1, Box_ipma::PropertyAssociation{true, uint16_t(9)}); + ipma_box->add_property_for_item_ID(1, Box_ipma::PropertyAssociation{true, uint16_t(10)}); + + if (get_alpha_item_data_size() != 0) { + ipma_box->add_property_for_item_ID(2, Box_ipma::PropertyAssociation{true, uint16_t(6)}); + ipma_box->add_property_for_item_ID(2, Box_ipma::PropertyAssociation{false, uint16_t(2)}); + ipma_box->add_property_for_item_ID(2, Box_ipma::PropertyAssociation{true, uint16_t(7)}); + ipma_box->add_property_for_item_ID(2, Box_ipma::PropertyAssociation{false, uint16_t(8)}); + ipma_box->add_property_for_item_ID(2, Box_ipma::PropertyAssociation{true, uint16_t(9)}); + ipma_box->add_property_for_item_ID(2, Box_ipma::PropertyAssociation{true, uint16_t(10)}); + } + // TODO: will need more once we support HDR / gainmap representation + + auto iloc_box = std::make_shared(); + file->set_iloc_box(iloc_box); + Box_iloc::Item main_item; + main_item.item_ID = 1; + main_item.construction_method = 0; + main_item.base_offset = 0; + main_item.data_reference_index = 0; + Box_iloc::Extent main_item_extent; + main_item_extent.offset = get_main_item_data_offset(); + main_item_extent.length = get_main_item_data_size(); + main_item.extents.push_back(main_item_extent); + iloc_box->append_item(main_item); + + if (get_alpha_item_data_size() != 0) { + Box_iloc::Item alpha_item; + alpha_item.item_ID = 2; + alpha_item.base_offset = 0; + alpha_item.data_reference_index = 0; + Box_iloc::Extent alpha_item_extent; + alpha_item_extent.offset = get_alpha_item_data_offset(); + alpha_item_extent.length = get_alpha_item_data_size(); + alpha_item.extents.push_back(alpha_item_extent); + iloc_box->append_item(alpha_item); + } + if (get_exif_flag()) { + Box_iloc::Item exif_item; + exif_item.item_ID = 6; + exif_item.base_offset = 0; + exif_item.data_reference_index = 0; + Box_iloc::Extent exif_item_extent; + exif_item_extent.offset = get_exif_item_data_offset(); + exif_item_extent.length = get_exif_item_data_size(); + exif_item.extents.push_back(exif_item_extent); + iloc_box->append_item(exif_item); + } + if (get_xmp_flag()) { + Box_iloc::Item xmp_item; + xmp_item.item_ID = 7; + xmp_item.base_offset = 0; + xmp_item.data_reference_index = 0; + Box_iloc::Extent xmp_item_extent; + xmp_item_extent.offset = get_xmp_item_data_offset(); + xmp_item_extent.length = get_xmp_item_data_size(); + xmp_item.extents.push_back(xmp_item_extent); + iloc_box->append_item(xmp_item); + } + + auto iref_box = std::make_shared(); + file->set_iref_box(iref_box); + std::vector to_items = {1}; + if (get_alpha_item_data_size() != 0) { + iref_box->add_references(2, fourcc("auxl"), to_items); + } + // TODO: if alpha prem + // TODO: if gainmap flag && item 4 + // TODO: if gainmap flag && !item 4 + if (get_exif_flag()) { + iref_box->add_references(6, fourcc("cdsc"), to_items); + } + if (get_xmp_flag()) { + iref_box->add_references(7, fourcc("cdsc"), to_items); + } + + return Error::Ok; +} diff --git a/libheif/mini.h b/libheif/mini.h index 0f6f38ddf3..2358246a23 100644 --- a/libheif/mini.h +++ b/libheif/mini.h @@ -36,6 +36,8 @@ class Box_mini : public Box set_short_type(fourcc("mini")); } + Error create_expanded_boxes(class HeifFile* file); + bool get_icc_flag() const { return m_icc_flag; } bool get_exif_flag() const { return m_exif_flag; } bool get_xmp_flag() const { return m_xmp_flag; }