#ifndef LIBHEIF_BOX_H
#define LIBHEIF_BOX_H
#if defined(HAVE_CONFIG_H)
#include "config.h"
#endif
#if defined(HAVE_INTTYPES_H)
#include <inttypes.h>
#endif
#if defined(HAVE_STDDEF_H)
#include <stddef.h>
#endif
#include <vector>
#include <string>
#include <memory>
#include <limits>
#include <istream>
#include <bitset>
#include "error.h"
#include "heif.h"
#include "logging.h"
#include "bitstream.h"
#if !defined(__EMSCRIPTEN__) && !defined(_MSC_VER)
#define HAS_BOOL_ARRAY 1
#endif
namespace heif {
#define fourcc(id) (((uint32_t)(id[0])<<24) | (id[1]<<16) | (id[2]<<8) | (id[3]))
class Fraction {
public:
Fraction() { }
Fraction(int num,int den) : numerator(num), denominator(den) { }
Fraction operator+(const Fraction&) const;
Fraction operator-(const Fraction&) const;
Fraction operator-(int) const;
Fraction operator/(int) const;
int round_down() const;
int round_up() const;
int round() const;
int numerator, denominator;
};
class BoxHeader {
public:
BoxHeader();
~BoxHeader() { }
constexpr static uint64_t size_until_end_of_file = 0;
uint64_t get_box_size() const { return m_size; }
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; }
Error parse(BitstreamRange& range);
virtual std::string dump(Indent&) const;
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; }
void set_is_full_box(bool flag=true) { m_is_full_box=flag; }
bool is_full_box_header() const { return m_is_full_box; }
size_t reserve_box_header_space(StreamWriter& writer) const;
Error prepend_header(StreamWriter&, size_t box_start) const;
private:
uint64_t m_size = 0;
uint32_t m_header_size = 0;
uint32_t m_type = 0;
std::vector<uint8_t> m_uuid_type;
bool m_is_full_box = false;
uint8_t m_version = 0;
uint32_t m_flags = 0;
};
class Box : public BoxHeader {
public:
Box() { }
Box(const BoxHeader& hdr) : BoxHeader(hdr) { }
virtual ~Box() { }
static Error read(BitstreamRange& range, std::shared_ptr<heif::Box>* box);
virtual Error write(StreamWriter& writer) const;
virtual void derive_box_version() { set_version(0); }
void derive_box_version_recursive();
virtual std::string dump(Indent&) const;
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;
const std::vector<std::shared_ptr<Box>>& get_all_child_boxes() const { return m_children; }
int append_child_box(std::shared_ptr<Box> box) {
m_children.push_back(box);
return (int)m_children.size()-1;
}
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;
};
class Box_ftyp : public Box {
public:
Box_ftyp() { set_short_type(fourcc("ftyp")); set_is_full_box(false); }
Box_ftyp(const BoxHeader& hdr) : Box(hdr) { }
std::string dump(Indent&) const override;
bool has_compatible_brand(uint32_t brand) const;
void set_major_brand(uint32_t 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(uint32_t brand);
Error write(StreamWriter& writer) const override;
protected:
Error parse(BitstreamRange& range) override;
private:
uint32_t m_major_brand;
uint32_t m_minor_version;
std::vector<uint32_t> m_compatible_brands;
};
class Box_meta : public Box {
public:
Box_meta() { set_short_type(fourcc("meta")); set_is_full_box(true); }
Box_meta(const BoxHeader& hdr) : Box(hdr) { }
std::string dump(Indent&) const override;
protected:
Error parse(BitstreamRange& range) override;
};
class Box_hdlr : public Box {
public:
Box_hdlr() { set_short_type(fourcc("hdlr")); set_is_full_box(true); }
Box_hdlr(const BoxHeader& hdr) : Box(hdr) { }
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;
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];
std::string m_name;
};
class Box_pitm : public Box {
public:
Box_pitm() { set_short_type(fourcc("pitm")); set_is_full_box(true); }
Box_pitm(const BoxHeader& hdr) : Box(hdr) { }
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;
};
class Box_iloc : public Box {
public:
Box_iloc() { set_short_type(fourcc("iloc")); set_is_full_box(true); }
Box_iloc(const BoxHeader& hdr) : Box(hdr) { }
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;
};
struct Item {
heif_item_id item_ID;
uint8_t construction_method = 0;
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,
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; }
Error append_data(heif_item_id item_ID,
const std::vector<uint8_t>& data,
uint8_t construction_method=0);
void derive_box_version() override;
Error write(StreamWriter& writer) const override;
Error write_mdat_after_iloc(StreamWriter& writer);
protected:
Error parse(BitstreamRange& range) override;
private:
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;
};
class Box_infe : public Box {
public:
Box_infe() { set_short_type(fourcc("infe")); set_is_full_box(true); }
Box_infe(const BoxHeader& hdr) : Box(hdr) { }
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; }
std::string get_item_type() const { return m_item_type; }
void set_item_type(std::string type) { m_item_type = type; }
void set_item_name(std::string name) { m_item_name = name; }
std::string get_content_type() const { return m_content_type; }
void set_content_type(std::string content_type) { m_content_type = content_type; }
void derive_box_version() override;
Error write(StreamWriter& writer) const override;
protected:
Error parse(BitstreamRange& range) override;
private:
heif_item_id m_item_ID;
uint16_t m_item_protection_index;
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;
bool m_hidden_item = false;
};
class Box_iinf : public Box {
public:
Box_iinf() { set_short_type(fourcc("iinf")); set_is_full_box(true); }
Box_iinf(const BoxHeader& hdr) : Box(hdr) { }
std::string dump(Indent&) const override;
void derive_box_version() override;
Error write(StreamWriter& writer) const override;
protected:
Error parse(BitstreamRange& range) override;
private:
};
class Box_iprp : public Box {
public:
Box_iprp() { set_short_type(fourcc("iprp")); set_is_full_box(false); }
Box_iprp(const BoxHeader& hdr) : Box(hdr) { }
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")); set_is_full_box(false); }
Box_ipco(const BoxHeader& hdr) : Box(hdr) { }
struct Property {
bool essential;
std::shared_ptr<Box> property;
};
Error get_properties_for_item_ID(heif_item_id itemID,
const std::shared_ptr<class Box_ipma>&,
std::vector<Property>& 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;
std::string dump(Indent&) const override;
protected:
Error parse(BitstreamRange& range) override;
};
class Box_ispe : public Box {
public:
Box_ispe() { set_short_type(fourcc("ispe")); set_is_full_box(true); }
Box_ispe(const BoxHeader& hdr) : Box(hdr) { }
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;
protected:
Error parse(BitstreamRange& range) override;
private:
uint32_t m_image_width;
uint32_t m_image_height;
};
class Box_ipma : public Box {
public:
Box_ipma() { set_short_type(fourcc("ipma")); set_is_full_box(true); }
Box_ipma(const BoxHeader& hdr) : Box(hdr) { }
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;
void add_property_for_item_ID(heif_item_id itemID,
PropertyAssociation assoc);
void derive_box_version() override;
Error write(StreamWriter& writer) const override;
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 Box {
public:
Box_auxC() { set_short_type(fourcc("auxC")); set_is_full_box(true); }
Box_auxC(const BoxHeader& hdr) : Box(hdr) { }
std::string get_aux_type() const { return m_aux_type; }
void set_aux_type(std::string type) { m_aux_type = type; }
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(const BoxHeader& hdr) : Box(hdr) { }
std::string dump(Indent&) const override;
int get_rotation() const { return m_rotation; }
protected:
Error parse(BitstreamRange& range) override;
private:
int m_rotation;
};
class Box_imir : public Box {
public:
Box_imir(const BoxHeader& hdr) : Box(hdr) { }
enum class MirrorAxis : uint8_t {
Vertical = 0,
Horizontal = 1
};
MirrorAxis get_mirror_axis() const { return m_axis; }
std::string dump(Indent&) const override;
protected:
Error parse(BitstreamRange& range) override;
private:
MirrorAxis m_axis;
};
class Box_clap : public Box {
public:
Box_clap(const BoxHeader& hdr) : Box(hdr) { }
std::string dump(Indent&) const override;
int left_rounded(int image_width) const;
int right_rounded(int image_width) const;
int top_rounded(int image_height) const;
int bottom_rounded(int image_height) const;
int get_width_rounded() const;
int get_height_rounded() const;
protected:
Error parse(BitstreamRange& range) override;
private:
Fraction m_clean_aperture_width;
Fraction m_clean_aperture_height;
Fraction m_horizontal_offset;
Fraction m_vertical_offset;
};
class Box_iref : public Box {
public:
Box_iref() { set_short_type(fourcc("iref")); set_is_full_box(true); }
Box_iref(const BoxHeader& hdr) : Box(hdr) { }
std::string dump(Indent&) const override;
bool has_references(heif_item_id itemID) const;
uint32_t get_reference_type(heif_item_id itemID) const;
std::vector<heif_item_id> get_references(heif_item_id itemID) const;
void add_reference(heif_item_id from_id, uint32_t type, 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:
struct Reference {
BoxHeader header;
heif_item_id from_item_ID;
std::vector<heif_item_id> to_item_ID;
};
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; }
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:
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;
std::vector<NalArray> m_nal_array;
};
class Box_idat : public Box {
public:
Box_idat(const BoxHeader& hdr) : Box(hdr) { }
std::string dump(Indent&) const override;
Error read_data(std::shared_ptr<StreamReader> istr,
uint64_t start, uint64_t length,
std::vector<uint8_t>& out_data) const;
protected:
Error parse(BitstreamRange& range) override;
std::streampos m_data_start_pos;
};
class Box_grpl : public Box {
public:
Box_grpl(const BoxHeader& hdr) : Box(hdr) { }
std::string dump(Indent&) const override;
protected:
Error parse(BitstreamRange& range) override;
struct EntityGroup {
BoxHeader header;
uint32_t group_id;
std::vector<heif_item_id> entity_ids;
};
std::vector<EntityGroup> m_entity_groups;
};
class Box_dinf : public Box {
public:
Box_dinf(const BoxHeader& hdr) : Box(hdr) { }
std::string dump(Indent&) const override;
protected:
Error parse(BitstreamRange& range) override;
};
class Box_dref : public Box {
public:
Box_dref(const BoxHeader& hdr) : Box(hdr) { }
std::string dump(Indent&) const override;
protected:
Error parse(BitstreamRange& range) override;
};
class Box_url : public Box {
public:
Box_url(const BoxHeader& hdr) : Box(hdr) { }
std::string dump(Indent&) const override;
protected:
Error parse(BitstreamRange& range) override;
std::string m_location;
};
}
#endif