diff --git a/libheif/CMakeLists.txt b/libheif/CMakeLists.txt index 07c068d50c..2b9ca52f79 100644 --- a/libheif/CMakeLists.txt +++ b/libheif/CMakeLists.txt @@ -187,7 +187,9 @@ if (WITH_UNCOMPRESSED_CODEC) codecs/uncompressed/unc_boxes.h codecs/uncompressed/unc_boxes.cc codecs/uncompressed/unc_image.h - codecs/uncompressed/unc_image.cc) + codecs/uncompressed/unc_image.cc + codecs/uncompressed/unc_dec.h + codecs/uncompressed/unc_dec.cc) endif () write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake COMPATIBILITY ExactVersion) diff --git a/libheif/codecs/image_item.cc b/libheif/codecs/image_item.cc index f1c449f267..3b314e1144 100644 --- a/libheif/codecs/image_item.cc +++ b/libheif/codecs/image_item.cc @@ -436,6 +436,7 @@ Error ImageItem::get_coded_image_colorspace(heif_colorspace* out_colorspace, hei return err; } + // TODO: should we use this or maybe use this just as an additional check that pixi and coded colorspace match? auto pixi = m_heif_context->get_heif_file()->get_property(id); if (pixi && pixi->get_num_channels() == 1) { *out_colorspace = heif_colorspace_monochrome; @@ -453,53 +454,6 @@ Error ImageItem::get_coded_image_colorspace(heif_colorspace* out_colorspace, hei auto decoder = get_decoder(); assert(decoder); return decoder->get_coded_image_colorspace(out_colorspace, out_chroma); - - // TODO: this should be codec specific. JPEG 2000, for example, can use RGB internally. - - *out_colorspace = heif_colorspace_YCbCr; - *out_chroma = heif_chroma_undefined; - - if (auto hvcC = m_heif_context->get_heif_file()->get_property(id)) { - *out_chroma = (heif_chroma) (hvcC->get_configuration().chroma_format); - } - else if (auto vvcC = m_heif_context->get_heif_file()->get_property(id)) { - *out_chroma = (heif_chroma) (vvcC->get_configuration().chroma_format_idc); - } - else if (auto av1C = m_heif_context->get_heif_file()->get_property(id)) { - *out_chroma = (heif_chroma) (av1C->get_configuration().get_heif_chroma()); - } - else if (auto j2kH = m_heif_context->get_heif_file()->get_property(id)) { - Result> dataResult = get_compressed_image_data(); - if (dataResult.error) { - return dataResult.error; - } - - JPEG2000MainHeader jpeg2000Header; - err = jpeg2000Header.parseHeader(*dataResult); - if (err) { - return err; - } - *out_chroma = jpeg2000Header.get_chroma_format(); - } -#if WITH_UNCOMPRESSED_CODEC - else if (auto uncC = m_heif_context->get_heif_file()->get_property(id)) { - if (uncC->get_version() == 1) { - // This is the shortform case, no cmpd box, and always some kind of RGB - *out_colorspace = heif_colorspace_RGB; - if (uncC->get_profile() == fourcc("rgb3")) { - *out_chroma = heif_chroma_interleaved_RGB; - } - else if ((uncC->get_profile() == fourcc("rgba")) || (uncC->get_profile() == fourcc("abgr"))) { - *out_chroma = heif_chroma_interleaved_RGBA; - } - } - if (auto cmpd = m_heif_context->get_heif_file()->get_property(id)) { - UncompressedImageCodec::get_heif_chroma_uncompressed(uncC, cmpd, out_chroma, out_colorspace); - } - } -#endif - - return err; } diff --git a/libheif/codecs/uncompressed/unc_dec.cc b/libheif/codecs/uncompressed/unc_dec.cc new file mode 100644 index 0000000000..1ee0018566 --- /dev/null +++ b/libheif/codecs/uncompressed/unc_dec.cc @@ -0,0 +1,148 @@ +/* + * HEIF codec. + * Copyright (c) 2024 Dirk Farin + * + * 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 . + */ + +#include "codecs/uncompressed/unc_dec.h" +#include "codecs/uncompressed/unc_image.h" +#include "error.h" +#include "context.h" + +#include + + +Result> Decoder_uncompressed::read_bitstream_configuration_data() const +{ + return std::vector{}; +} + + +int Decoder_uncompressed::get_luma_bits_per_pixel() const +{ + assert(m_uncC); + + if (!m_cmpd) { + if (isKnownUncompressedFrameConfigurationBoxProfile(m_uncC)) { + return 8; + } + else { + return -1; + } + } + + int luma_bits = 0; + int alternate_channel_bits = 0; + for (Box_uncC::Component component : m_uncC->get_components()) { + uint16_t component_index = component.component_index; + if (component_index >= m_cmpd->get_components().size()) { + return -1; + } + auto component_type = m_cmpd->get_components()[component_index].component_type; + switch (component_type) { + case component_type_monochrome: + case component_type_red: + case component_type_green: + case component_type_blue: + alternate_channel_bits = std::max(alternate_channel_bits, (int) component.component_bit_depth); + break; + case component_type_Y: + luma_bits = std::max(luma_bits, (int) component.component_bit_depth); + break; + // TODO: there are other things we'll need to handle eventually, like palette. + } + } + if (luma_bits > 0) { + return luma_bits; + } + else if (alternate_channel_bits > 0) { + return alternate_channel_bits; + } + else { + return 8; + } +} + +int Decoder_uncompressed::get_chroma_bits_per_pixel() const +{ + if (m_uncC && m_uncC->get_version() == 1) { + // All of the version 1 cases are 8 bit + return 8; + } + + if (!m_uncC || !m_cmpd) { + return -1; + } + + int chroma_bits = 0; + int alternate_channel_bits = 0; + for (Box_uncC::Component component : m_uncC->get_components()) { + uint16_t component_index = component.component_index; + if (component_index >= m_cmpd->get_components().size()) { + return -1; + } + auto component_type = m_cmpd->get_components()[component_index].component_type; + switch (component_type) { + case component_type_monochrome: + case component_type_red: + case component_type_green: + case component_type_blue: + alternate_channel_bits = std::max(alternate_channel_bits, (int) component.component_bit_depth); + break; + case component_type_Cb: + case component_type_Cr: + chroma_bits = std::max(chroma_bits, (int) component.component_bit_depth); + break; + // TODO: there are other things we'll need to handle eventually, like palette. + } + } + if (chroma_bits > 0) { + return chroma_bits; + } + else if (alternate_channel_bits > 0) { + return alternate_channel_bits; + } + else { + return 8; + } +} + + +Error Decoder_uncompressed::get_coded_image_colorspace(heif_colorspace* out_colorspace, heif_chroma* out_chroma) const +{ + if (m_uncC->get_version() == 1) { + // This is the shortform case, no cmpd box, and always some kind of RGB + *out_colorspace = heif_colorspace_RGB; + if (m_uncC->get_profile() == fourcc("rgb3")) { + *out_chroma = heif_chroma_interleaved_RGB; + } + else if ((m_uncC->get_profile() == fourcc("rgba")) || (m_uncC->get_profile() == fourcc("abgr"))) { + *out_chroma = heif_chroma_interleaved_RGBA; + } + + return Error::Ok; + } + else if (m_cmpd) { + UncompressedImageCodec::get_heif_chroma_uncompressed(m_uncC, m_cmpd, out_chroma, out_colorspace); + return Error::Ok; + } + else { + return {heif_error_Invalid_input, + heif_suberror_Unspecified, + "Missing 'cmpd' box."}; + } +} diff --git a/libheif/codecs/uncompressed/unc_dec.h b/libheif/codecs/uncompressed/unc_dec.h new file mode 100644 index 0000000000..2521df1493 --- /dev/null +++ b/libheif/codecs/uncompressed/unc_dec.h @@ -0,0 +1,57 @@ +/* + * HEIF codec. + * Copyright (c) 2024 Dirk Farin + * + * 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 . + */ + +#ifndef HEIF_UNC_DEC_H +#define HEIF_UNC_DEC_H + +#include "libheif/heif.h" +#include "box.h" +#include "error.h" + +#include +#include +#include "codecs/decoder.h" + +class Box_uncC; +class Box_cmpd; + + +class Decoder_uncompressed : public Decoder +{ +public: + explicit Decoder_uncompressed(const std::shared_ptr& uncC, + const std::shared_ptr& cmpd) : m_uncC(uncC), m_cmpd(cmpd) {} + + heif_compression_format get_compression_format() const override { return heif_compression_uncompressed; } + + int get_luma_bits_per_pixel() const override; + + int get_chroma_bits_per_pixel() const override; + + Error get_coded_image_colorspace(heif_colorspace*, heif_chroma*) const override; + + Result> read_bitstream_configuration_data() const override; + +private: + const std::shared_ptr m_uncC; + const std::shared_ptr m_cmpd; +}; + +#endif diff --git a/libheif/codecs/uncompressed/unc_image.cc b/libheif/codecs/uncompressed/unc_image.cc index 316ff8f073..919d08e79e 100644 --- a/libheif/codecs/uncompressed/unc_image.cc +++ b/libheif/codecs/uncompressed/unc_image.cc @@ -34,9 +34,11 @@ #include "unc_types.h" #include "unc_boxes.h" #include "unc_image.h" +#include "unc_dec.h" #include "codecs/image_item.h" -static bool isKnownUncompressedFrameConfigurationBoxProfile(const std::shared_ptr& uncC) + +bool isKnownUncompressedFrameConfigurationBoxProfile(const std::shared_ptr& uncC) { return ((uncC != nullptr) && (uncC->get_version() == 1) && ((uncC->get_profile() == fourcc("rgb3")) || (uncC->get_profile() == fourcc("rgba")) || (uncC->get_profile() == fourcc("abgr")))); } @@ -307,103 +309,6 @@ Error UncompressedImageCodec::get_heif_chroma_uncompressed(const std::shared_ptr } } - -int UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci(const HeifFile& heif_file, heif_item_id imageID) -{ - std::shared_ptr uncC_box = heif_file.get_property(imageID); - std::shared_ptr cmpd_box = heif_file.get_property(imageID); - - if (!uncC_box) { - return -1; - } - - if (!cmpd_box) { - if (isKnownUncompressedFrameConfigurationBoxProfile(uncC_box)) { - return 8; - } else { - return -1; - } - } - - int luma_bits = 0; - int alternate_channel_bits = 0; - for (Box_uncC::Component component : uncC_box->get_components()) { - uint16_t component_index = component.component_index; - if (component_index >= cmpd_box->get_components().size()) { - return -1; - } - auto component_type = cmpd_box->get_components()[component_index].component_type; - switch (component_type) { - case component_type_monochrome: - case component_type_red: - case component_type_green: - case component_type_blue: - alternate_channel_bits = std::max(alternate_channel_bits, (int)component.component_bit_depth); - break; - case component_type_Y: - luma_bits = std::max(luma_bits, (int)component.component_bit_depth); - break; - // TODO: there are other things we'll need to handle eventually, like palette. - } - } - if (luma_bits > 0) { - return luma_bits; - } - else if (alternate_channel_bits > 0) { - return alternate_channel_bits; - } - else { - return 8; - } -} - -int UncompressedImageCodec::get_chroma_bits_per_pixel_from_configuration_unci(const HeifFile& heif_file, heif_item_id imageID) -{ - std::shared_ptr uncC_box = heif_file.get_property(imageID); - std::shared_ptr cmpd_box = heif_file.get_property(imageID); - - if (uncC_box && uncC_box->get_version() == 1) { - // All of the version 1 cases are 8 bit - return 8; - } - - if (!uncC_box || !cmpd_box) { - return -1; - } - - int chroma_bits = 0; - int alternate_channel_bits = 0; - for (Box_uncC::Component component : uncC_box->get_components()) { - uint16_t component_index = component.component_index; - if (component_index >= cmpd_box->get_components().size()) { - return -1; - } - auto component_type = cmpd_box->get_components()[component_index].component_type; - switch (component_type) { - case component_type_monochrome: - case component_type_red: - case component_type_green: - case component_type_blue: - alternate_channel_bits = std::max(alternate_channel_bits, (int)component.component_bit_depth); - break; - case component_type_Cb: - case component_type_Cr: - chroma_bits = std::max(chroma_bits, (int)component.component_bit_depth); - break; - // TODO: there are other things we'll need to handle eventually, like palette. - } - } - if (chroma_bits > 0) { - return chroma_bits; - } - else if (alternate_channel_bits > 0) { - return alternate_channel_bits; - } - else { - return 8; - } -} - static bool map_uncompressed_component_to_channel(const std::shared_ptr &cmpd, const std::shared_ptr &uncC, Box_uncC::Component component, @@ -2178,20 +2083,6 @@ Error ImageItem_uncompressed::add_image_tile(uint32_t tile_x, uint32_t tile_y, c } -int ImageItem_uncompressed::get_luma_bits_per_pixel() const -{ - int bpp = UncompressedImageCodec::get_luma_bits_per_pixel_from_configuration_unci(*get_file(), get_id()); - return bpp; -} - - -int ImageItem_uncompressed::get_chroma_bits_per_pixel() const -{ - int bpp = UncompressedImageCodec::get_chroma_bits_per_pixel_from_configuration_unci(*get_file(), get_id()); - return bpp; -} - - void ImageItem_uncompressed::get_tile_size(uint32_t& w, uint32_t& h) const { auto ispe = get_file()->get_property(get_id()); @@ -2226,3 +2117,29 @@ heif_image_tiling ImageItem_uncompressed::get_heif_image_tiling() const return tiling; } + +std::shared_ptr ImageItem_uncompressed::get_decoder() const +{ + return m_decoder; +} + +Error ImageItem_uncompressed::on_load_file() +{ + std::shared_ptr cmpd = get_file()->get_property(get_id()); + std::shared_ptr uncC = get_file()->get_property(get_id()); + + if (!uncC) { + return Error{heif_error_Invalid_input, + heif_suberror_Unspecified, + "No 'uncC' box found."}; + } + + m_decoder = std::make_shared(uncC, cmpd); + + DataExtent extent; + extent.set_from_image_item(get_context()->get_heif_file(), get_id()); + + m_decoder->set_data_extent(extent); + + return Error::Ok; +} diff --git a/libheif/codecs/uncompressed/unc_image.h b/libheif/codecs/uncompressed/unc_image.h index 13cc3bd962..5b8a42647a 100644 --- a/libheif/codecs/uncompressed/unc_image.h +++ b/libheif/codecs/uncompressed/unc_image.h @@ -33,6 +33,10 @@ class HeifContext; + +bool isKnownUncompressedFrameConfigurationBoxProfile(const std::shared_ptr& uncC); + + class UncompressedImageCodec { public: @@ -82,10 +86,6 @@ class ImageItem_uncompressed : public ImageItem bool is_ispe_essential() const override { return true; } - int get_luma_bits_per_pixel() const override; - - int get_chroma_bits_per_pixel() const override; - void get_tile_size(uint32_t& w, uint32_t& h) const override; // Code from encode_uncompressed_image() has been moved to here. @@ -95,6 +95,10 @@ class ImageItem_uncompressed : public ImageItem heif_image_tiling get_heif_image_tiling() const; + Error on_load_file() override; + +public: + // --- encoding Result encode(const std::shared_ptr& image, @@ -109,7 +113,11 @@ class ImageItem_uncompressed : public ImageItem Error add_image_tile(uint32_t tile_x, uint32_t tile_y, const std::shared_ptr& image); +protected: + std::shared_ptr get_decoder() const override; + private: + std::shared_ptr m_decoder; /* Result generate_headers(const std::shared_ptr& src_image, const heif_unci_image_parameters* parameters,