libheif/context.h (377 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_CONTEXT_H #define LIBHEIF_CONTEXT_H #include <map> #include <memory> #include <set> #include <string> #include <vector> #include <utility> #include "error.h" #include "libheif/heif.h" #include "libheif/heif_plugin.h" #include "bitstream.h" #include "box.h" // only for color_profile, TODO: maybe move the color_profiles to its own header #include "region.h" class HeifContext; class HeifFile; class HeifPixelImage; class StreamWriter; class ImageMetadata { public: heif_item_id item_id; std::string item_type; // e.g. "Exif" std::string content_type; std::string item_uri_type; std::vector<uint8_t> m_data; }; // This is a higher-level view than HeifFile. // Images are grouped logically into main images and their thumbnails. // The class also handles automatic color-space conversion. class HeifContext : public ErrorBuffer { public: HeifContext(); ~HeifContext(); void set_max_decoding_threads(int max_threads) { m_max_decoding_threads = max_threads; } // Sets the maximum size of both width and height of an image. The total limit // of the image size (width * height) will be "maximum_size * maximum_size". void set_maximum_image_size_limit(int maximum_size) { m_maximum_image_size_limit = int64_t(maximum_size) * maximum_size; } void set_max_decoder_threads(int max_threads) {m_max_decoder_threads = max_threads;} Error read(const std::shared_ptr<StreamReader>& reader); Error read_from_file(const char* input_filename); Error read_params(libheif_parameters* params); int read_grid_params(heif_item_id ID); Error read_from_memory(const void* data, size_t size, bool copy); class Image : public ErrorBuffer { public: Image(HeifContext* file, heif_item_id id); ~Image(); void clear() { m_thumbnails.clear(); m_alpha_channel.reset(); m_depth_channel.reset(); m_aux_images.clear(); } Error check_resolution(uint32_t w, uint32_t h) const { return m_heif_context->check_resolution(w, h); } void set_resolution(int w, int h) { m_width = w; m_height = h; } void set_primary(bool flag = true) { m_is_primary = flag; } heif_item_id get_id() const { return m_id; } //void set_id(heif_item_id id) { m_id=id; } (already set in constructor) int get_width() const { return m_width; } int get_height() const { return m_height; } int get_ispe_width() const; int get_ispe_height() const; int get_luma_bits_per_pixel() const; int get_chroma_bits_per_pixel() const; Error get_preferred_decoding_colorspace(heif_colorspace* out_colorspace, heif_chroma* out_chroma) const; bool is_primary() const { return m_is_primary; } void set_size(int w, int h) { m_width = w; m_height = h; } // -- thumbnails void set_is_thumbnail() { m_is_thumbnail = true; } void add_thumbnail(const std::shared_ptr<Image>& img) { m_thumbnails.push_back(img); } bool is_thumbnail() const { return m_is_thumbnail; } const std::vector<std::shared_ptr<Image>>& get_thumbnails() const { return m_thumbnails; } // --- alpha channel void set_is_alpha_channel() { m_is_alpha_channel = true; } void set_alpha_channel(std::shared_ptr<Image> img) { m_alpha_channel = std::move(img); } bool is_alpha_channel() const { return m_is_alpha_channel; } const std::shared_ptr<Image>& get_alpha_channel() const { return m_alpha_channel; } void set_is_premultiplied_alpha(bool flag) { m_premultiplied_alpha = flag; } bool is_premultiplied_alpha() const { return m_premultiplied_alpha; } // --- depth channel void set_is_depth_channel() { m_is_depth_channel = true; } void set_depth_channel(std::shared_ptr<Image> img) { m_depth_channel = std::move(img); } bool is_depth_channel() const { return m_is_depth_channel; } const std::shared_ptr<Image>& get_depth_channel() const { return m_depth_channel; } void set_depth_representation_info(struct heif_depth_representation_info& info) { m_has_depth_representation_info = true; m_depth_representation_info = info; } bool has_depth_representation_info() const { return m_has_depth_representation_info; } const struct heif_depth_representation_info& get_depth_representation_info() const { return m_depth_representation_info; } // --- generic aux image void set_is_aux_image(const std::string& aux_type) { m_is_aux_image = true; m_aux_image_type = aux_type; } void add_aux_image(std::shared_ptr<Image> img) { m_aux_images.push_back(std::move(img)); } bool is_aux_image() const { return m_is_aux_image; } const std::string& get_aux_type() const { return m_aux_image_type; } std::vector<std::shared_ptr<Image>> get_aux_images(int aux_image_filter = 0) const { if (aux_image_filter == 0) { return m_aux_images; } else { std::vector<std::shared_ptr<Image>> auxImgs; for (const auto& aux : m_aux_images) { if ((aux_image_filter & LIBHEIF_AUX_IMAGE_FILTER_OMIT_ALPHA) && aux->is_alpha_channel()) { continue; } if ((aux_image_filter & LIBHEIF_AUX_IMAGE_FILTER_OMIT_DEPTH) && aux->is_depth_channel()) { continue; } auxImgs.push_back(aux); } return auxImgs; } } // --- metadata void add_metadata(std::shared_ptr<ImageMetadata> metadata) { m_metadata.push_back(std::move(metadata)); } const std::vector<std::shared_ptr<ImageMetadata>>& get_metadata() const { return m_metadata; } // --- miaf void mark_not_miaf_compatible() { m_miaf_compatible = false; } bool is_miaf_compatible() const { return m_miaf_compatible; } // === writing === void set_preencoded_hevc_image(const std::vector<uint8_t>& data); const std::shared_ptr<const color_profile_nclx>& get_color_profile_nclx() const { return m_color_profile_nclx; } const std::shared_ptr<const color_profile_raw>& get_color_profile_icc() const { return m_color_profile_icc; } void set_color_profile(const std::shared_ptr<const color_profile>& profile) { auto icc = std::dynamic_pointer_cast<const color_profile_raw>(profile); if (icc) { m_color_profile_icc = std::move(icc); } auto nclx = std::dynamic_pointer_cast<const color_profile_nclx>(profile); if (nclx) { m_color_profile_nclx = std::move(nclx); } }; void set_intrinsic_matrix(const Box_cmin::RelativeIntrinsicMatrix& cmin) { m_has_intrinsic_matrix = true; m_intrinsic_matrix = cmin.to_absolute(get_ispe_width(), get_ispe_height()); } bool has_intrinsic_matrix() const { return m_has_intrinsic_matrix; } Box_cmin::AbsoluteIntrinsicMatrix& get_intrinsic_matrix() { return m_intrinsic_matrix; } const Box_cmin::AbsoluteIntrinsicMatrix& get_intrinsic_matrix() const { return m_intrinsic_matrix; } void set_extrinsic_matrix(const Box_cmex::ExtrinsicMatrix& cmex) { m_has_extrinsic_matrix = true; m_extrinsic_matrix = cmex; } bool has_extrinsic_matrix() const { return m_has_extrinsic_matrix; } Box_cmex::ExtrinsicMatrix& get_extrinsic_matrix() { return m_extrinsic_matrix; } const Box_cmex::ExtrinsicMatrix& get_extrinsic_matrix() const { return m_extrinsic_matrix; } void add_region_item_id(heif_item_id id) { m_region_item_ids.push_back(id); } const std::vector<heif_item_id>& get_region_item_ids() const { return m_region_item_ids; } private: HeifContext* m_heif_context; heif_item_id m_id = 0; uint32_t m_width = 0, m_height = 0; // after all transformations have been applied bool m_is_primary = false; bool m_is_thumbnail = false; std::vector<std::shared_ptr<Image>> m_thumbnails; bool m_is_alpha_channel = false; bool m_premultiplied_alpha = false; std::shared_ptr<Image> m_alpha_channel; bool m_is_depth_channel = false; std::shared_ptr<Image> m_depth_channel; bool m_has_depth_representation_info = false; struct heif_depth_representation_info m_depth_representation_info; bool m_is_aux_image = false; std::string m_aux_image_type; std::vector<std::shared_ptr<Image>> m_aux_images; std::vector<std::shared_ptr<ImageMetadata>> m_metadata; std::shared_ptr<const color_profile_nclx> m_color_profile_nclx; std::shared_ptr<const color_profile_raw> m_color_profile_icc; bool m_miaf_compatible = true; std::vector<heif_item_id> m_region_item_ids; bool m_has_intrinsic_matrix = false; Box_cmin::AbsoluteIntrinsicMatrix m_intrinsic_matrix{}; bool m_has_extrinsic_matrix = false; Box_cmex::ExtrinsicMatrix m_extrinsic_matrix{}; }; Error check_resolution(uint32_t width, uint32_t height) const; std::shared_ptr<HeifFile> get_heif_file() const { return m_heif_file; } std::vector<std::shared_ptr<Image>> get_top_level_images() { return m_top_level_images; } std::shared_ptr<Image> get_top_level_image(heif_item_id id) { for (auto& img : m_top_level_images) { if (img->get_id() == id) { return img; } } return nullptr; } std::shared_ptr<const Image> get_top_level_image(heif_item_id id) const { return const_cast<HeifContext*>(this)->get_top_level_image(id); } std::shared_ptr<Image> get_image(heif_item_id id) { auto iter = m_all_images.find(id); if (iter == m_all_images.end()) { return nullptr; } else { return iter->second; } } std::shared_ptr<const Image> get_image(heif_item_id id) const { return const_cast<HeifContext*>(this)->get_image(id); } std::shared_ptr<Image> get_primary_image() { return m_primary_image; } bool is_image(heif_item_id ID) const; bool has_alpha(heif_item_id ID) const; Error decode_image_user(heif_item_id ID, std::shared_ptr<HeifPixelImage>& img, heif_colorspace out_colorspace, heif_chroma out_chroma, int32_t out_width, int32_t out_height, bool has_alpha, const struct heif_decoding_options& options) const; Error decode_image_planar(heif_item_id ID, std::shared_ptr<HeifPixelImage>& img, heif_colorspace out_colorspace, heif_chroma out_chroma, const struct heif_decoding_options& options, bool alphaImage) const; Error decode_image_planar_for_moov( heif_item_id ID, std::shared_ptr<HeifPixelImage>& img, heif_colorspace out_colorspace, heif_chroma out_chroma, const struct heif_decoding_options& options, bool alphaImage) const; std::string debug_dump_boxes() const; // === writing === // Create all boxes necessary for an empty HEIF file. // Note that this is no valid HEIF file, since some boxes (e.g. pitm) are generated, but // contain no valid data yet. void reset_to_empty_heif(); Error encode_image(const std::shared_ptr<HeifPixelImage>& image, struct heif_encoder* encoder, const struct heif_encoding_options& options, enum heif_image_input_class input_class, std::shared_ptr<Image>& out_image); Error encode_grid(const std::vector<std::shared_ptr<HeifPixelImage>>& tiles, uint16_t rows, uint16_t columns, struct heif_encoder* encoder, const struct heif_encoding_options& options, std::shared_ptr<Image>& out_image); Error encode_image_as_hevc(const std::shared_ptr<HeifPixelImage>& image, struct heif_encoder* encoder, const struct heif_encoding_options& options, enum heif_image_input_class input_class, std::shared_ptr<Image>& out_image); Error encode_image_as_vvc(const std::shared_ptr<HeifPixelImage>& image, struct heif_encoder* encoder, const struct heif_encoding_options& options, enum heif_image_input_class input_class, std::shared_ptr<Image>& out_image); Error encode_image_as_av1(const std::shared_ptr<HeifPixelImage>& image, struct heif_encoder* encoder, const struct heif_encoding_options& options, enum heif_image_input_class input_class, std::shared_ptr<Image>& out_image); Error encode_image_as_jpeg(const std::shared_ptr<HeifPixelImage>& image, struct heif_encoder* encoder, const struct heif_encoding_options& options, enum heif_image_input_class input_class, std::shared_ptr<Image>& out_image); Error encode_image_as_jpeg2000(const std::shared_ptr<HeifPixelImage>& image, struct heif_encoder* encoder, const struct heif_encoding_options& options, enum heif_image_input_class input_class, std::shared_ptr<Image>& out_image); Error encode_image_as_uncompressed(const std::shared_ptr<HeifPixelImage>& src_image, struct heif_encoder* encoder, const struct heif_encoding_options& options, enum heif_image_input_class input_class, std::shared_ptr<Image>& out_image); Error encode_image_as_mask(const std::shared_ptr<HeifPixelImage>& src_image, struct heif_encoder* encoder, const struct heif_encoding_options& options, enum heif_image_input_class input_class, std::shared_ptr<Image>& out_image); // write PIXI, CLLI, MDVC void write_image_metadata(std::shared_ptr<HeifPixelImage> src_image, int image_id); void set_primary_image(const std::shared_ptr<Image>& image); Error set_primary_item(heif_item_id id); bool is_primary_image_set() const { return m_primary_image != nullptr; } Error assign_thumbnail(const std::shared_ptr<Image>& master_image, const std::shared_ptr<Image>& thumbnail_image); Error encode_thumbnail(const std::shared_ptr<HeifPixelImage>& image, struct heif_encoder* encoder, const struct heif_encoding_options& options, int bbox_size, std::shared_ptr<Image>& out_image_handle); Error add_exif_metadata(const std::shared_ptr<Image>& master_image, const void* data, int size); Error add_XMP_metadata(const std::shared_ptr<Image>& master_image, const void* data, int size, heif_metadata_compression compression); Error add_generic_metadata(const std::shared_ptr<Image>& master_image, const void* data, int size, const char* item_type, const char* content_type, const char* item_uri_type, heif_metadata_compression compression, heif_item_id* out_item_id); heif_property_id add_property(heif_item_id targetItem, std::shared_ptr<Box> property, bool essential); // --- region items void add_region_item(std::shared_ptr<RegionItem> region_item) { m_region_items.push_back(std::move(region_item)); } std::shared_ptr<RegionItem> add_region_item(uint32_t reference_width, uint32_t reference_height); std::shared_ptr<RegionItem> get_region_item(heif_item_id id) const { for (auto& item : m_region_items) { if (item->item_id == id) return item; } return nullptr; } void add_region_referenced_mask_ref(heif_item_id region_item_id, heif_item_id mask_item_id); void write(StreamWriter& writer); void patch_stco_data(StreamWriter& writer); void set_movie_flag(bool movie_flag) {m_movie_flag = movie_flag;} bool get_movie_flag() const {return m_movie_flag;} void set_mvhd_data(uint64_t creation_time, uint64_t modification_time, uint32_t timescale, uint32_t duration, uint32_t next_track_ID); void ctx_set_tkhd_data(uint64_t creat_time, uint64_t modified_time, uint32_t track_id, uint64_t duration, uint32_t img_src_width, uint32_t img_src_height); void ctx_set_mdhd_data(uint64_t creat_time, uint64_t modified_time, uint32_t timescale, uint64_t duration, uint16_t language); void ctx_set_hvc1_data(uint16_t img_src_width, uint16_t img_src_height, uint16_t frame_count); void ctx_calc_stts_data(); void ctx_set_stss_data(); void ctx_add_movie_box(); private: std::map<heif_item_id, std::shared_ptr<Image>> m_all_images; // We store this in a vector because we need stable indices for the C API. // TODO: stable indices are obsolet now... std::vector<std::shared_ptr<Image>> m_top_level_images; std::shared_ptr<Image> m_primary_image; // shortcut to primary image bool m_movie_flag = false; std::shared_ptr<HeifFile> m_heif_file; int m_max_decoding_threads = 0; int m_max_decoder_threads = 0; // Maximum image size in pixels (width * height). uint64_t m_maximum_image_size_limit; std::vector<std::shared_ptr<RegionItem>> m_region_items; Error interpret_heif_file(); Error interpret_heif_file_for_moov(); void remove_top_level_image(const std::shared_ptr<Image>& image); Error decode_full_grid_image(heif_item_id ID, std::shared_ptr<HeifPixelImage>& img, const std::vector<uint8_t>& grid_data, const heif_decoding_options& options) const; Error decode_and_paste_tile_image(heif_item_id tileID, const std::shared_ptr<HeifPixelImage>& out_image, heif_chroma out_chroma, uint32_t x0, uint32_t y0, const heif_decoding_options& options) const; Error decode_derived_image(heif_item_id ID, std::shared_ptr<HeifPixelImage>& img, const heif_decoding_options& options) const; Error decode_overlay_image(heif_item_id ID, std::shared_ptr<HeifPixelImage>& img, const std::vector<uint8_t>& overlay_data, const heif_decoding_options& options) const; Error get_id_of_non_virtual_child_image(heif_item_id in, heif_item_id& out) const; }; #endif