This source file includes following definitions.
- get_item_IDs
- read_from_file
- read_from_memory
- read
- new_empty_file
- write
- debug_dump_boxes
- parse_heif_file
- image_exists
- get_infe
- get_item_type
- get_content_type
- get_properties
- get_compressed_image_data
- get_unused_item_id
- add_new_image
- add_new_infe_box
- add_ispe_property
- add_hvcC_property
- append_hvcC_nal_data
- set_hvcC_configuration
- append_hvcC_nal_data
- append_iloc_data
- append_iloc_data_with_4byte_size
- set_primary_item_id
- add_iref_reference
- set_auxC_property
#include "heif_file.h"
#include "heif_image.h"
#include <fstream>
#include <limits>
#include <sstream>
#include <utility>
#include <string.h>
#include <assert.h>
using namespace heif;
HeifFile::HeifFile()
{
}
HeifFile::~HeifFile()
{
}
std::vector<heif_item_id> HeifFile::get_item_IDs() const
{
std::vector<heif_item_id> IDs;
for (const auto& infe : m_infe_boxes) {
IDs.push_back(infe.second->get_item_ID());
}
return IDs;
}
Error HeifFile::read_from_file(const char* input_filename)
{
auto input_stream_istr = std::unique_ptr<std::istream>(new std::ifstream(input_filename));
auto input_stream = std::make_shared<StreamReader_istream>(std::move(input_stream_istr));
return read(input_stream);
}
Error HeifFile::read_from_memory(const void* data, size_t size, bool copy)
{
auto input_stream = std::make_shared<StreamReader_memory>((const uint8_t*)data, size, copy);
return read(input_stream);
}
Error HeifFile::read(std::shared_ptr<StreamReader> reader)
{
m_input_stream = reader;
uint64_t maxSize = std::numeric_limits<int64_t>::max();
heif::BitstreamRange range(m_input_stream, maxSize);
Error error = parse_heif_file(range);
return error;
}
void HeifFile::new_empty_file()
{
m_input_stream.reset();
m_top_level_boxes.clear();
m_ftyp_box = std::make_shared<Box_ftyp>();
m_hdlr_box = std::make_shared<Box_hdlr>();
m_meta_box = std::make_shared<Box_meta>();
m_ipco_box = std::make_shared<Box_ipco>();
m_ipma_box = std::make_shared<Box_ipma>();
m_iloc_box = std::make_shared<Box_iloc>();
m_iinf_box = std::make_shared<Box_iinf>();
m_iprp_box = std::make_shared<Box_iprp>();
m_pitm_box = std::make_shared<Box_pitm>();
m_meta_box->append_child_box(m_hdlr_box);
m_meta_box->append_child_box(m_pitm_box);
m_meta_box->append_child_box(m_iloc_box);
m_meta_box->append_child_box(m_iinf_box);
m_meta_box->append_child_box(m_iprp_box);
m_iprp_box->append_child_box(m_ipco_box);
m_iprp_box->append_child_box(m_ipma_box);
m_infe_boxes.clear();
m_top_level_boxes.push_back(m_ftyp_box);
m_top_level_boxes.push_back(m_meta_box);
m_ftyp_box->set_major_brand(fourcc("heic"));
m_ftyp_box->set_minor_version(0);
m_ftyp_box->add_compatible_brand(fourcc("mif1"));
m_ftyp_box->add_compatible_brand(fourcc("heic"));
}
void HeifFile::write(StreamWriter& writer)
{
for (auto& box : m_top_level_boxes) {
box->derive_box_version_recursive();
box->write(writer);
}
m_iloc_box->write_mdat_after_iloc(writer);
}
std::string HeifFile::debug_dump_boxes() const
{
std::stringstream sstr;
bool first=true;
for (const auto& box : m_top_level_boxes) {
if (first) {
first = false;
}
else {
sstr << "\n";
}
heif::Indent indent;
sstr << box->dump(indent);
}
return sstr.str();
}
Error HeifFile::parse_heif_file(BitstreamRange& range)
{
for (;;) {
std::shared_ptr<Box> box;
Error error = Box::read(range, &box);
if (error != Error::Ok || range.error() || range.eof()) {
break;
}
m_top_level_boxes.push_back(box);
if (box->get_short_type() == fourcc("meta")) {
m_meta_box = std::dynamic_pointer_cast<Box_meta>(box);
}
if (box->get_short_type() == fourcc("ftyp")) {
m_ftyp_box = std::dynamic_pointer_cast<Box_ftyp>(box);
}
}
if (!m_ftyp_box) {
return Error(heif_error_Invalid_input,
heif_suberror_No_ftyp_box);
}
if (!m_ftyp_box->has_compatible_brand(fourcc("heic"))) {
std::stringstream sstr;
sstr << "File does not support the 'heic' brand.\n";
return Error(heif_error_Unsupported_filetype,
heif_suberror_Unspecified,
sstr.str());
}
if (!m_meta_box) {
return Error(heif_error_Invalid_input,
heif_suberror_No_meta_box);
}
m_hdlr_box = std::dynamic_pointer_cast<Box_hdlr>(m_meta_box->get_child_box(fourcc("hdlr")));
if (!m_hdlr_box) {
return Error(heif_error_Invalid_input,
heif_suberror_No_hdlr_box);
}
if (m_hdlr_box->get_handler_type() != fourcc("pict")) {
return Error(heif_error_Invalid_input,
heif_suberror_No_pict_handler);
}
m_pitm_box = std::dynamic_pointer_cast<Box_pitm>(m_meta_box->get_child_box(fourcc("pitm")));
if (!m_pitm_box) {
return Error(heif_error_Invalid_input,
heif_suberror_No_pitm_box);
}
m_iprp_box = std::dynamic_pointer_cast<Box_iprp>(m_meta_box->get_child_box(fourcc("iprp")));
if (!m_iprp_box) {
return Error(heif_error_Invalid_input,
heif_suberror_No_iprp_box);
}
m_ipco_box = std::dynamic_pointer_cast<Box_ipco>(m_iprp_box->get_child_box(fourcc("ipco")));
if (!m_ipco_box) {
return Error(heif_error_Invalid_input,
heif_suberror_No_ipco_box);
}
m_ipma_box = std::dynamic_pointer_cast<Box_ipma>(m_iprp_box->get_child_box(fourcc("ipma")));
if (!m_ipma_box) {
return Error(heif_error_Invalid_input,
heif_suberror_No_ipma_box);
}
m_iloc_box = std::dynamic_pointer_cast<Box_iloc>(m_meta_box->get_child_box(fourcc("iloc")));
if (!m_iloc_box) {
return Error(heif_error_Invalid_input,
heif_suberror_No_iloc_box);
}
m_idat_box = std::dynamic_pointer_cast<Box_idat>(m_meta_box->get_child_box(fourcc("idat")));
m_iref_box = std::dynamic_pointer_cast<Box_iref>(m_meta_box->get_child_box(fourcc("iref")));
m_iinf_box = std::dynamic_pointer_cast<Box_iinf>(m_meta_box->get_child_box(fourcc("iinf")));
if (!m_iinf_box) {
return Error(heif_error_Invalid_input,
heif_suberror_No_iinf_box);
}
std::vector<std::shared_ptr<Box>> infe_boxes = m_iinf_box->get_child_boxes(fourcc("infe"));
for (auto& box : infe_boxes) {
std::shared_ptr<Box_infe> infe_box = std::dynamic_pointer_cast<Box_infe>(box);
if (!infe_box) {
return Error(heif_error_Invalid_input,
heif_suberror_No_infe_box);
}
m_infe_boxes.insert( std::make_pair(infe_box->get_item_ID(), infe_box) );
}
return Error::Ok;
}
bool HeifFile::image_exists(heif_item_id ID) const
{
auto image_iter = m_infe_boxes.find(ID);
return image_iter != m_infe_boxes.end();
}
std::shared_ptr<Box_infe> HeifFile::get_infe(heif_item_id ID) const
{
auto image_iter = m_infe_boxes.find(ID);
if (image_iter == m_infe_boxes.end()) {
return nullptr;
}
return image_iter->second;
}
std::string HeifFile::get_item_type(heif_item_id ID) const
{
auto infe_box = get_infe(ID);
if (!infe_box) {
return "";
}
return infe_box->get_item_type();
}
std::string HeifFile::get_content_type(heif_item_id ID) const
{
auto infe_box = get_infe(ID);
if (!infe_box) {
return "";
}
return infe_box->get_content_type();
}
Error HeifFile::get_properties(heif_item_id imageID,
std::vector<Box_ipco::Property>& properties) const
{
if (!m_ipco_box) {
return Error(heif_error_Invalid_input,
heif_suberror_No_ipco_box);
} else if (!m_ipma_box) {
return Error(heif_error_Invalid_input,
heif_suberror_No_ipma_box);
}
return m_ipco_box->get_properties_for_item_ID(imageID, m_ipma_box, properties);
}
Error HeifFile::get_compressed_image_data(heif_item_id ID, std::vector<uint8_t>* data) const
{
#if ENABLE_PARALLEL_TILE_DECODING
std::lock_guard<std::mutex> guard(m_read_mutex);
#endif
if (!image_exists(ID)) {
return Error(heif_error_Usage_error,
heif_suberror_Nonexisting_item_referenced);
}
auto infe_box = get_infe(ID);
if (!infe_box) {
return Error(heif_error_Usage_error,
heif_suberror_Nonexisting_item_referenced);
}
std::string item_type = infe_box->get_item_type();
std::string content_type = infe_box->get_content_type();
auto items = m_iloc_box->get_items();
const Box_iloc::Item* item = nullptr;
for (const auto& i : items) {
if (i.item_ID == ID) {
item = &i;
break;
}
}
if (!item) {
std::stringstream sstr;
sstr << "Item with ID " << ID << " has no compressed data";
return Error(heif_error_Invalid_input,
heif_suberror_No_item_data,
sstr.str());
}
Error error = Error(heif_error_Unsupported_feature,
heif_suberror_Unsupported_codec);
if (item_type == "hvc1") {
std::vector<Box_ipco::Property> properties;
Error err = m_ipco_box->get_properties_for_item_ID(ID, m_ipma_box, properties);
if (err) {
return err;
}
std::shared_ptr<Box_hvcC> hvcC_box;
for (auto& prop : properties) {
if (prop.property->get_short_type() == fourcc("hvcC")) {
hvcC_box = std::dynamic_pointer_cast<Box_hvcC>(prop.property);
if (hvcC_box) {
break;
}
}
}
if (!hvcC_box) {
return Error(heif_error_Invalid_input,
heif_suberror_No_hvcC_box);
} else if (!hvcC_box->get_headers(data)) {
return Error(heif_error_Invalid_input,
heif_suberror_No_item_data);
}
error = m_iloc_box->read_data(*item, m_input_stream, m_idat_box, data);
} else if (item_type == "grid" ||
item_type == "iovl" ||
item_type == "Exif" ||
(item_type == "mime" && content_type=="application/rdf+xml")) {
error = m_iloc_box->read_data(*item, m_input_stream, m_idat_box, data);
}
if (error != Error::Ok) {
return error;
}
return Error::Ok;
}
heif_item_id HeifFile::get_unused_item_id() const
{
for (heif_item_id id = 1;
;
id++) {
bool id_exists = false;
for (const auto& infe : m_infe_boxes) {
if (infe.second->get_item_ID() == id) {
id_exists = true;
break;
}
}
if (!id_exists) {
return id;
}
}
assert(false);
return 0;
}
heif_item_id HeifFile::add_new_image(const char* item_type)
{
auto box = add_new_infe_box(item_type);
return box->get_item_ID();
}
std::shared_ptr<Box_infe> HeifFile::add_new_infe_box(const char* item_type)
{
heif_item_id id = get_unused_item_id();
auto infe = std::make_shared<Box_infe>();
infe->set_item_ID(id);
infe->set_hidden_item(false);
infe->set_item_type(item_type);
m_infe_boxes[id] = infe;
m_iinf_box->append_child_box(infe);
return infe;
}
void HeifFile::add_ispe_property(heif_item_id id, uint32_t width, uint32_t height)
{
auto ispe = std::make_shared<Box_ispe>();
ispe->set_size(width,height);
int index = m_ipco_box->append_child_box(ispe);
m_ipma_box->add_property_for_item_ID(id, Box_ipma::PropertyAssociation { false, uint16_t(index+1) });
}
void HeifFile::add_hvcC_property(heif_item_id id)
{
auto hvcC = std::make_shared<Box_hvcC>();
int index = m_ipco_box->append_child_box(hvcC);
m_ipma_box->add_property_for_item_ID(id, Box_ipma::PropertyAssociation { true, uint16_t(index+1) });
}
Error HeifFile::append_hvcC_nal_data(heif_item_id id, const std::vector<uint8_t>& nal_data)
{
auto hvcC = std::dynamic_pointer_cast<Box_hvcC>(m_ipco_box->get_property_for_item_ID(id,
m_ipma_box,
fourcc("hvcC")));
if (hvcC) {
hvcC->append_nal_data(nal_data);
return Error::Ok;
}
else {
return Error(heif_error_Usage_error,
heif_suberror_No_hvcC_box);
}
}
Error HeifFile::set_hvcC_configuration(heif_item_id id, const Box_hvcC::configuration& config)
{
auto hvcC = std::dynamic_pointer_cast<Box_hvcC>(m_ipco_box->get_property_for_item_ID(id,
m_ipma_box,
fourcc("hvcC")));
if (hvcC) {
hvcC->set_configuration(config);
return Error::Ok;
}
else {
return Error(heif_error_Usage_error,
heif_suberror_No_hvcC_box);
}
}
Error HeifFile::append_hvcC_nal_data(heif_item_id id, const uint8_t* data, size_t size)
{
std::vector<Box_ipco::Property> properties;
auto hvcC = std::dynamic_pointer_cast<Box_hvcC>(m_ipco_box->get_property_for_item_ID(id,
m_ipma_box,
fourcc("hvcC")));
if (hvcC) {
hvcC->append_nal_data(data,size);
return Error::Ok;
}
else {
return Error(heif_error_Usage_error,
heif_suberror_No_hvcC_box);
}
}
void HeifFile::append_iloc_data(heif_item_id id, const std::vector<uint8_t>& nal_packets)
{
m_iloc_box->append_data(id, nal_packets);
}
void HeifFile::append_iloc_data_with_4byte_size(heif_item_id id, const uint8_t* data, size_t size)
{
std::vector<uint8_t> nal;
nal.resize(size + 4);
nal[0] = (size>>24) & 0xFF;
nal[1] = (size>>16) & 0xFF;
nal[2] = (size>> 8) & 0xFF;
nal[3] = (size>> 0) & 0xFF;
memcpy(nal.data()+4, data, size);
append_iloc_data(id, nal);
}
void HeifFile::set_primary_item_id(heif_item_id id)
{
m_pitm_box->set_item_ID(id);
}
void HeifFile::add_iref_reference(uint32_t type, heif_item_id from,
std::vector<heif_item_id> to)
{
if (!m_iref_box) {
m_iref_box = std::make_shared<Box_iref>();
m_meta_box->append_child_box(m_iref_box);
}
m_iref_box->add_reference(type,from,to);
}
void HeifFile::set_auxC_property(heif_item_id id, std::string type)
{
auto auxC = std::make_shared<Box_auxC>();
auxC->set_aux_type(type);
int index = m_ipco_box->append_child_box(auxC);
m_ipma_box->add_property_for_item_ID(id, Box_ipma::PropertyAssociation { true, uint16_t(index+1) });
}