Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CMakePresets.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
"WITH_VVDEC_PLUGIN" : "OFF",
"WITH_VVENC" : "ON",
"WITH_VVENC_PLUGIN" : "OFF",
"WITH_EXPERIMENTAL_GAIN_MAP" : "OFF",

"WITH_REDUCED_VISIBILITY" : "OFF",
"WITH_HEADER_COMPRESSION" : "ON",
Expand Down Expand Up @@ -110,6 +111,7 @@
"WITH_VVDEC_PLUGIN" : "ON",
"WITH_VVENC" : "ON",
"WITH_VVENC_PLUGIN" : "ON",
"WITH_EXPERIMENTAL_GAIN_MAP" : "OFF",

"WITH_REDUCED_VISIBILITY" : "ON",
"WITH_HEADER_COMPRESSION" : "ON",
Expand Down Expand Up @@ -148,6 +150,7 @@
"WITH_UVG266" : "OFF",
"WITH_VVDEC" : "OFF",
"WITH_VVENC" : "OFF",
"WITH_EXPERIMENTAL_GAIN_MAP" : "OFF",

"WITH_REDUCED_VISIBILITY" : "ON",
"WITH_HEADER_COMPRESSION" : "OFF",
Expand Down
4 changes: 4 additions & 0 deletions libheif/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,10 @@ if (ENABLE_EXPERIMENTAL_MINI_FORMAT)
mini.cc)
endif ()

if (WITH_EXPERIMENTAL_GAIN_MAP)
target_compile_definitions(heif PUBLIC WITH_EXPERIMENTAL_GAIN_MAP=1)
endif ()

write_basic_package_version_file(${PROJECT_NAME}-config-version.cmake COMPATIBILITY ExactVersion)

install(TARGETS heif EXPORT ${PROJECT_NAME}-config
Expand Down
233 changes: 233 additions & 0 deletions libheif/api/libheif/heif.cc
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,124 @@ struct heif_error heif_context_get_primary_image_ID(struct heif_context* ctx, he
}


#if WITH_EXPERIMENTAL_GAIN_MAP

struct heif_error heif_image_handle_get_gain_map_image_handle(
const struct heif_image_handle* handle, struct heif_image_handle** gain_map_handle) {
if (!gain_map_handle) {
return {heif_error_Usage_error, heif_suberror_Null_pointer_argument,
"NULL gain_map_handle passed to heif_image_handle_get_gain_map_image_handle()"};
}

std::shared_ptr<ImageItem> gain_map_image = handle->image->get_gain_map();
if (!gain_map_image) {
Error err(heif_error_Usage_error, heif_suberror_Nonexisting_item_referenced,
"base image handle is not associated with a gain map image");
return err.error_struct(handle->image.get());
}

*gain_map_handle = new heif_image_handle();
(*gain_map_handle)->image = gain_map_image;
(*gain_map_handle)->context = handle->context;

return Error::Ok.error_struct(handle->image.get());
}

size_t heif_image_handle_get_gain_map_metadata_size(const struct heif_image_handle* handle) {
std::shared_ptr<ImageMetadata> metadata = handle->image->get_gain_map_metadata();

if (metadata) {
// Ignore unsigned int(8) version = 0; field of ToneMapImage syntax
size_t sz = metadata->m_data.size();
return sz > 0 ? (sz - 1) : 0;
}

return 0;
}

struct heif_error heif_image_handle_get_gain_map_metadata(const struct heif_image_handle* handle,
void* out_data) {
if (!out_data) {
return {heif_error_Usage_error, heif_suberror_Null_pointer_argument,
"NULL out_data passed to heif_image_handle_get_gain_map_metadata()"};
}

std::shared_ptr<ImageMetadata> metadata = handle->image->get_gain_map_metadata();
if (!metadata) {
Error err(heif_error_Invalid_input, heif_suberror_No_item_data,
"base image handle is not associated with a gain map image");
return err.error_struct(handle->image.get());
}

uint8_t version = 0xff;
size_t pos = 0;
std::vector<uint8_t>& buffer = metadata->m_data;

if (pos >= buffer.size()) {
Error err(heif_error_Invalid_input, heif_suberror_End_of_data);
return err.error_struct(handle->image.get());
}
version = buffer[pos++];
if (version != 0) {
Error err(heif_error_Invalid_input, heif_suberror_Unsupported_data_version,
"Box[tmap] has unsupported version");
return err.error_struct(handle->image.get());
}

memcpy(out_data, buffer.data() + pos, buffer.size() - pos);

return heif_error_success;
}

struct heif_error heif_image_handle_get_derived_image_nclx_color_profile(
const struct heif_image_handle* handle, struct heif_color_profile_nclx** out_data) {
if (!out_data) {
return {heif_error_Usage_error, heif_suberror_Null_pointer_argument,
"NULL out_data passed to heif_image_handle_get_derived_image_nclx_color_profile()"};
}

auto nclx_profile = handle->image->get_derived_img_color_profile_nclx();
if (!nclx_profile) {
Error err(heif_error_Color_profile_does_not_exist, heif_suberror_Unspecified);
return err.error_struct(handle->image.get());
}

Error err = nclx_profile->get_nclx_color_profile(out_data);

return err.error_struct(handle->image.get());
}

size_t heif_image_handle_get_derived_image_raw_color_profile_size(
const struct heif_image_handle* handle) {
auto profile_icc = handle->image->get_color_profile_icc();
if (profile_icc) {
return profile_icc->get_data().size();
} else {
return 0;
}
}

struct heif_error heif_image_handle_get_derived_image_raw_color_profile(
const struct heif_image_handle* handle, void* out_data) {
if (!out_data) {
return {heif_error_Usage_error, heif_suberror_Null_pointer_argument,
"NULL out_data passed to heif_image_handle_get_derived_image_raw_color_profile()"};
}

auto raw_profile = handle->image->get_derived_img_color_profile_icc();
if (raw_profile) {
memcpy(out_data, raw_profile->get_data().data(), raw_profile->get_data().size());
} else {
Error err(heif_error_Color_profile_does_not_exist, heif_suberror_Unspecified);
return err.error_struct(handle->image.get());
}

return Error::Ok.error_struct(handle->image.get());
}

#endif


int heif_context_is_top_level_image_ID(struct heif_context* ctx, heif_item_id id)
{
const std::vector<std::shared_ptr<ImageItem>> images = ctx->context->get_top_level_images(true);
Expand Down Expand Up @@ -3442,6 +3560,121 @@ struct heif_error heif_context_encode_image(struct heif_context* ctx,
}


#if WITH_EXPERIMENTAL_GAIN_MAP

struct heif_error heif_context_encode_gain_map_image(
struct heif_context* ctx, const struct heif_image_handle* base_image_handle,
struct heif_encoder* encoder, const struct heif_image* gain_map_image,
const struct heif_encoding_options* input_options, const uint8_t* gain_map_metadata,
int gain_map_metadata_len, const struct heif_color_profile_nclx* derived_image_nclx,
struct heif_image_handle** out_image_handle) {
if (!encoder) {
return Error(heif_error_Usage_error, heif_suberror_Null_pointer_argument)
.error_struct(ctx->context.get());
}

if (gain_map_metadata_len <= 0) {
return Error(heif_error_Invalid_input, heif_suberror_Invalid_parameter_value)
.error_struct(ctx->context.get());
}

if (out_image_handle) {
*out_image_handle = nullptr;
}

// --- write tmap item
std::vector<uint8_t> metadata;
metadata.push_back(0); // version = 0
for (int i = 0; i < gain_map_metadata_len; i++) {
metadata.push_back(gain_map_metadata[i]);
}
heif_item_id tmap_item_id = -1;
ctx->context->add_tmap_item(metadata, tmap_item_id);

std::vector<std::shared_ptr<Box>> properties;

// --- write ISPE property for tmap item
std::shared_ptr<Box_ispe> ispe = std::make_shared<Box_ispe>();
ispe->set_size(base_image_handle->image->get_ispe_width(),
base_image_handle->image->get_ispe_height());

properties.push_back(ispe);

// --- write PIXI property for tmap item
// TODO: this assumes the base image is 8 bit and derived image is 10 bit. Have to handle the
// other way where the base image is hdr and derived image is sdr
std::shared_ptr<Box_pixi> pixi = std::make_shared<Box_pixi>();
pixi->add_channel_bits(10);
pixi->add_channel_bits(10);
pixi->add_channel_bits(10);

properties.push_back(pixi);

// --- write COLR property for tmap item
if (derived_image_nclx != nullptr) {
std::shared_ptr<Box_colr> colr = std::make_shared<Box_colr>();
auto derived_img_nclx_profile = std::make_shared<color_profile_nclx>();
derived_img_nclx_profile->set_colour_primaries(derived_image_nclx->color_primaries);
derived_img_nclx_profile->set_transfer_characteristics(
derived_image_nclx->transfer_characteristics);
derived_img_nclx_profile->set_matrix_coefficients(derived_image_nclx->matrix_coefficients);
derived_img_nclx_profile->set_full_range_flag(derived_image_nclx->full_range_flag);
colr->set_color_profile(derived_img_nclx_profile);

properties.push_back(colr);
}
// set tmap item properties
for (auto& propertyBox : properties) {
int index =
ctx->context->get_heif_file()->get_ipco_box()->find_or_append_child_box(propertyBox);
ctx->context->get_heif_file()->get_ipma_box()->add_property_for_item_ID(
tmap_item_id,
Box_ipma::PropertyAssociation{propertyBox->is_essential(), uint16_t(index + 1)});
}

heif_encoding_options options;
set_default_encoding_options(options);
if (input_options != nullptr) {
copy_options(options, *input_options);
}

auto gainmap_encoding_result = ctx->context->encode_image(gain_map_image->image, encoder, options,
heif_image_input_class_gain_map);
if (gainmap_encoding_result.error) {
return gainmap_encoding_result.error.error_struct(ctx->context.get());
}

std::shared_ptr<ImageItem> gain_map_image_item = *gainmap_encoding_result;
Error error =
ctx->context->link_gain_map(base_image_handle->image, gain_map_image_item, tmap_item_id);
if (error != Error::Ok) {
return error.error_struct(ctx->context.get());
}

if (out_image_handle) {
*out_image_handle = new heif_image_handle;
(*out_image_handle)->image = std::move(gain_map_image_item);
(*out_image_handle)->context = ctx->context;
}

// --- generate altr box
auto altr_box = std::make_shared<Box_EntityToGroup>();
altr_box->set_short_type(fourcc("altr"));
altr_box->set_group_id(ctx->context->get_heif_file()->get_unused_item_id());

std::vector<heif_item_id> ids;
ids.push_back(tmap_item_id);
ids.push_back(base_image_handle->image->get_id());

altr_box->set_item_ids(ids);
ctx->context->get_heif_file()->add_entity_group_box(altr_box);

return heif_error_success;
}

#endif


struct heif_error heif_context_encode_grid(struct heif_context* ctx,
struct heif_image** tiles,
uint16_t columns,
Expand Down
59 changes: 59 additions & 0 deletions libheif/api/libheif/heif.h
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,13 @@ typedef uint32_t heif_brand2;
*/
#define heif_brand2_1pic heif_fourcc('1','p','i','c')

/**
* HEIF tone map brand (`tmap`).
*
* This is a compatible brand indicating the file contains a gainmap image.
*/
#define heif_brand2_tmap heif_fourcc('t', 'm', 'a', 'p')

// input data should be at least 12 bytes
LIBHEIF_API
heif_brand2 heif_read_main_brand(const uint8_t* data, int len);
Expand Down Expand Up @@ -1453,6 +1460,42 @@ struct heif_error heif_image_handle_get_auxiliary_image_handle(const struct heif
heif_item_id auxiliary_id,
struct heif_image_handle** out_auxiliary_handle);

#if WITH_EXPERIMENTAL_GAIN_MAP

// ------------------------- gain map images -------------------------

// Get the gain map image associated with the main image. If no gain map image is available, this
// method will return error.
LIBHEIF_API
struct heif_error heif_image_handle_get_gain_map_image_handle(
const struct heif_image_handle* handle, struct heif_image_handle** gain_map_handle);

// Get the gain map metadata size associated with the main image. If no gain map image is available,
// this method will return 0
LIBHEIF_API
size_t heif_image_handle_get_gain_map_metadata_size(const struct heif_image_handle* handle);

// Get the gain map metadata associated with the main image. if no gain map image is available, this
// method will return error
LIBHEIF_API
struct heif_error heif_image_handle_get_gain_map_metadata(const struct heif_image_handle* handle,
void* out_data);

// Get nclx color profile for derived image
LIBHEIF_API
struct heif_error heif_image_handle_get_derived_image_nclx_color_profile(
const struct heif_image_handle* handle, struct heif_color_profile_nclx** out_data);

// Get raw color profile for derived image
LIBHEIF_API
size_t heif_image_handle_get_derived_image_raw_color_profile_size(
const struct heif_image_handle* handle);

LIBHEIF_API
struct heif_error heif_image_handle_get_derived_image_raw_color_profile(
const struct heif_image_handle* handle, void* out_data);

#endif

// ------------------------- metadata (Exif / XMP) -------------------------

Expand Down Expand Up @@ -2621,6 +2664,22 @@ LIBHEIF_API
int heif_encoder_descriptor_supportes_lossless_compression(const struct heif_encoder_descriptor*);



#if WITH_EXPERIMENTAL_GAIN_MAP

// Compress the gain map image and write metadata.
// Returns a handle to the coded image in 'out_image_handle' unless out_image_handle = NULL.
LIBHEIF_API
struct heif_error heif_context_encode_gain_map_image(
struct heif_context* ctx, const struct heif_image_handle* base_image_handle,
struct heif_encoder* encoder, const struct heif_image* gain_map_image,
const struct heif_encoding_options* input_options, const uint8_t* gain_map_metadata,
int gain_map_metadata_len, const struct heif_color_profile_nclx* derived_image_nclx,
struct heif_image_handle** out_image_handle);

#endif


#ifdef __cplusplus
}
#endif
Expand Down
3 changes: 3 additions & 0 deletions libheif/api/libheif/heif_plugin.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ enum heif_image_input_class
heif_image_input_class_alpha = 2,
heif_image_input_class_depth = 3,
heif_image_input_class_thumbnail = 4
#if WITH_EXPERIMENTAL_GAIN_MAP
, heif_image_input_class_gain_map = 5
#endif
};


Expand Down
Loading