From 0733824fed0d9b6f622ef9b2fbd2a4f71429590a Mon Sep 17 00:00:00 2001 From: Brad Hards Date: Tue, 29 Oct 2024 13:48:55 +1100 Subject: [PATCH] mini: implement HEVC reading --- libheif/box.cc | 27 +++++++ libheif/box.h | 17 +++++ libheif/codecs/hevc_boxes.h | 4 + libheif/file.cc | 129 +++++++++++++++++++++++++-------- libheif/mini.h | 2 + tests/data/lightning_mini.heif | Bin 0 -> 4726 bytes tests/mini_box.cc | 48 ++++++++++++ tests/mini_decode.cc | 51 +++++++++++++ 8 files changed, 248 insertions(+), 30 deletions(-) create mode 100644 tests/data/lightning_mini.heif diff --git a/libheif/box.cc b/libheif/box.cc index f9da5da18d..b9cb0e3353 100644 --- a/libheif/box.cc +++ b/libheif/box.cc @@ -460,6 +460,10 @@ Error Box::read(BitstreamRange& range, std::shared_ptr* result, const heif_ box = std::make_shared(); break; + case fourcc("free"): + box = std::make_shared(); + break; + case fourcc("meta"): box = std::make_shared(); break; @@ -1152,6 +1156,29 @@ Error Box_ftyp::write(StreamWriter& writer) const } +Error Box_free::parse(BitstreamRange& range, const heif_security_limits* limits) +{ + range.skip_to_end_of_box(); + return range.get_error(); +} + + +std::string Box_free::dump(Indent& indent) const +{ + std::ostringstream sstr; + sstr << BoxHeader::dump(indent); + return sstr.str(); +} + + +Error Box_free::write(StreamWriter& writer) const +{ + size_t box_start = reserve_box_header_space(writer); + prepend_header(writer, box_start); + return Error::Ok; +} + + Error Box_meta::parse(BitstreamRange& range, const heif_security_limits* limits) { parse_full_box_header(range); diff --git a/libheif/box.h b/libheif/box.h index 220062563f..b438c13e0a 100644 --- a/libheif/box.h +++ b/libheif/box.h @@ -412,6 +412,23 @@ class Box_ftyp : public Box }; +class Box_free : public Box +{ +public: + Box_free() + { + set_short_type(fourcc("free")); + } + + std::string dump(Indent&) const override; + + Error write(StreamWriter& writer) const override; + +protected: + Error parse(BitstreamRange& range, const heif_security_limits*) override; +}; + + class Box_meta : public FullBox { public: diff --git a/libheif/codecs/hevc_boxes.h b/libheif/codecs/hevc_boxes.h index 9b2a4971e2..9ade3c697d 100644 --- a/libheif/codecs/hevc_boxes.h +++ b/libheif/codecs/hevc_boxes.h @@ -33,6 +33,10 @@ class Box_hvcC : public Box { + +// allow access to protected parse() method +friend class HeifFile; + public: Box_hvcC() { diff --git a/libheif/file.cc b/libheif/file.cc index 2904728bb9..e4a5794b9d 100644 --- a/libheif/file.cc +++ b/libheif/file.cc @@ -27,6 +27,7 @@ #include "image-items/jpeg.h" #include "image-items/vvc.h" #include "codecs/avif_boxes.h" +#include "codecs/hevc_boxes.h" #include "codecs/uncompressed/unc_boxes.h" #include @@ -299,7 +300,8 @@ static uint32_t get_item_type_for_brand(const heif_brand2 brand) switch(brand) { case heif_brand2_avif: return fourcc("av01"); - // TODO: more + case heif_brand2_heic: + return fourcc("hvc1"); default: return 0; } @@ -437,16 +439,35 @@ Error HeifFile::parse_heif_file() m_ipco_box = std::make_shared(); - // TODO: we should look this up based on the infe prop, not assume Box_av1C. - std::shared_ptr main_item_codec_prop = std::make_shared(); - 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); - main_item_codec_prop->parse(codec_range, heif_get_global_security_limits()); - m_ipco_box->append_child_box(main_item_codec_prop); // entry 1 + 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()); @@ -470,53 +491,101 @@ Error HeifFile::parse_heif_file() colr->set_color_profile(nclx); m_ipco_box->append_child_box(colr); // entry 4 - 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 + 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 alpha_item_codec_prop = std::make_shared(); 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); - alpha_item_codec_prop->parse(alpha_codec_range, heif_get_global_security_limits()); + 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 } - // 8 + // 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 + } - // 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 + } - // 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)}); - if (m_mini_box->get_icc_flag()) { - // m_ipma_box->add_property_for_item_ID(1, Box_ipma::PropertyAssociation{true, uint16_t(5)}); - } - if (m_mini_box->get_alpha_item_data_size() > 0) { + 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)}); + 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 - - + // TODO: will need more once we support HDR / gainmap representation m_iloc_box = std::make_shared(); Box_iloc::Item main_item; diff --git a/libheif/mini.h b/libheif/mini.h index 49872b9c7a..0f6f38ddf3 100644 --- a/libheif/mini.h +++ b/libheif/mini.h @@ -45,6 +45,8 @@ class Box_mini : public Box uint8_t get_bit_depth() const { return m_bit_depth; } + uint8_t get_orientation() const { return m_orientation; } + std::vector get_main_item_codec_config() const { return m_main_item_codec_config; } std::vector get_alpha_item_codec_config() const { return m_alpha_item_codec_config; } std::vector get_icc_data() const { return m_icc_data; } diff --git a/tests/data/lightning_mini.heif b/tests/data/lightning_mini.heif new file mode 100644 index 0000000000000000000000000000000000000000..8fc407816621f8a69aa1e5a3e8cc7dd91b65d97e GIT binary patch literal 4726 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 EI9jn2W&i*H literal 0 HcmV?d00001 diff --git a/tests/mini_box.cc b/tests/mini_box.cc index 7b6f361a37..f9f2540e06 100644 --- a/tests/mini_box.cc +++ b/tests/mini_box.cc @@ -224,3 +224,51 @@ TEST_CASE("check mini+exif+xmp version") "exif_data offset: 770, size: 208\n" "xmp_data offset: 978, size: 3426\n"); } + + +TEST_CASE("check heif mini") +{ + auto istr = std::unique_ptr(new std::ifstream(tests_data_directory + "/lightning_mini.heif", std::ios::binary)); + auto reader = std::make_shared(std::move(istr)); + FileLayout file; + Error err = file.read(reader, heif_get_global_security_limits()); + REQUIRE(err.error_code == heif_error_Ok); + + std::shared_ptr mini = file.get_mini_box(); + REQUIRE(mini->get_exif_flag() == false); + REQUIRE(mini->get_xmp_flag() == false); + REQUIRE(mini->get_bit_depth() == 8); + REQUIRE(mini->get_colour_primaries() == 1); + REQUIRE(mini->get_transfer_characteristics() == 13); + REQUIRE(mini->get_matrix_coefficients() == 6); + REQUIRE(mini->get_width() == 128); + REQUIRE(mini->get_height() == 128); + REQUIRE(mini->get_main_item_codec_config().size() == 112); + Indent indent; + std::string dumpResult = mini->dump(indent); + REQUIRE(dumpResult == "Box: mini -----\n" + "size: 4710 (header size: 8)\n" + "version: 0\n" + "explicit_codec_types_flag: 0\n" + "float_flag: 0\n" + "full_range_flag: 1\n" + "alpha_flag: 0\n" + "explicit_cicp_flag: 0\n" + "hdr_flag: 0\n" + "icc_flag: 0\n" + "exif_flag: 0\n" + "xmp_flag: 0\n" + "chroma_subsampling: 1\n" + "orientation: 1\n" + "width: 128\n" + "height: 128\n" + "chroma_is_horizontally_centered: 0\n" + "chroma_is_vertically_centered: 0\n" + "bit_depth: 8\n" + "colour_primaries: 1\n" + "transfer_characteristics: 13\n" + "matrix_coefficients: 6\n" + "main_item_code_config size: 112\n" + "main_item_data offset: 144, size: 4582\n"); +} + diff --git a/tests/mini_decode.cc b/tests/mini_decode.cc index 12112d031d..37951d5dcd 100644 --- a/tests/mini_decode.cc +++ b/tests/mini_decode.cc @@ -56,3 +56,54 @@ TEST_CASE("check image handle size") { heif_context_free(context); } +void check_image_size_heif_mini(struct heif_context *&context) { + heif_image_handle *handle = get_primary_image_handle(context); + heif_image *img = get_primary_image_ycbcr(handle, heif_chroma_444); + + REQUIRE(heif_image_has_channel(img, heif_channel_Y) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_Cb) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_Cr) == 1); + REQUIRE(heif_image_has_channel(img, heif_channel_R) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_G) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_B) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_Alpha) == 0); + REQUIRE(heif_image_has_channel(img, heif_channel_interleaved) == 0); + int width = heif_image_get_primary_width(img); + REQUIRE(width == 128); + int height = heif_image_get_primary_height(img); + REQUIRE(height == 128); + width = heif_image_get_width(img, heif_channel_Y); + REQUIRE(width == 128); + height = heif_image_get_height(img, heif_channel_Y); + REQUIRE(height == 128); + width = heif_image_get_width(img, heif_channel_Cb); + REQUIRE(width == 128); + height = heif_image_get_height(img, heif_channel_Cr); + REQUIRE(height == 128); + width = heif_image_get_width(img, heif_channel_Cr); + REQUIRE(width == 128); + height = heif_image_get_height(img, heif_channel_Cr); + REQUIRE(height == 128); + + int pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Y); + REQUIRE(pixel_depth == 8); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Cb); + REQUIRE(pixel_depth == 8); + pixel_depth = heif_image_get_bits_per_pixel(img, heif_channel_Cr); + REQUIRE(pixel_depth == 8); + int pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Y); + REQUIRE(pixel_range == 8); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Cb); + REQUIRE(pixel_range == 8); + pixel_range = heif_image_get_bits_per_pixel_range(img, heif_channel_Cr); + REQUIRE(pixel_range == 8); + + heif_image_release(img); + heif_image_handle_release(handle); +} + +TEST_CASE("check image size HEIF mini") { + auto context = get_context_for_test_file("lightning_mini.heif"); + check_image_size_heif_mini(context); + heif_context_free(context); +}