Skip to content

Commit

Permalink
change 'grid' encoding API to match other grid image types
Browse files Browse the repository at this point in the history
  • Loading branch information
farindk committed Oct 13, 2024
1 parent 96a150e commit bbbd67b
Show file tree
Hide file tree
Showing 11 changed files with 170 additions and 115 deletions.
85 changes: 23 additions & 62 deletions examples/heif_enc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ const char* encoderId = nullptr;
std::string chroma_downsampling;
int tiled_image_width = 0;
int tiled_image_height = 0;
std::string tiling_method;
std::string tiling_method = "grid";
heif_metadata_compression unci_compression = heif_metadata_compression_brotli;

uint16_t nclx_colour_primaries = 1;
Expand Down Expand Up @@ -747,80 +747,38 @@ std::optional<input_tiles_generator> determine_input_images_tiling(const std::st
}


heif_image_handle* encode_tiled_grid(heif_context* ctx, heif_encoder* encoder, heif_encoding_options* options,
int output_bit_depth,
const input_tiles_generator& tile_generator,
const heif_image_tiling& tiling)
{
std::vector<heif_item_id> image_ids;

std::cout << "encoding tiled image, tile size: " << tiling.tile_width << "x" << tiling.tile_height
<< " image size: " << tiling.image_width << "x" << tiling.image_height << "\n";

for (uint32_t ty = 0; ty < tile_generator.nRows(); ty++)
for (uint32_t tx = 0; tx < tile_generator.nColumns(); tx++) {
std::string input_filename = tile_generator.filename(tx,ty);

InputImage input_image = load_image(input_filename, output_bit_depth);

std::cout << "encoding tile " << ty+1 << " " << tx+1
<< " (of " << tile_generator.nRows() << "x" << tile_generator.nColumns() << ") \r";
std::cout.flush();

heif_image_handle* handle;
heif_error error = heif_context_encode_image(ctx,
input_image.image.get(),
encoder,
options,
&handle);
if (error.code != 0) {
std::cerr << "Could not encode HEIF/AVIF file: " << error.message << "\n";
return nullptr;
}

image_ids.push_back(heif_image_handle_get_item_id(handle));
heif_image_handle_release(handle);
}

std::cout << "\n";

heif_image_handle* grid_image;
heif_error error = heif_context_add_grid_image(ctx, tiling.image_width, tiling.image_height,
tiling.num_columns, tiling.num_rows, image_ids.data(), &grid_image);
if (error.code != 0) {
std::cerr << "Could not generate grid image: " << error.message << "\n";
return nullptr;
}

return grid_image;
}


heif_image_handle* encode_tiled(heif_context* ctx, heif_encoder* encoder, heif_encoding_options* options,
int output_bit_depth,
const input_tiles_generator& tile_generator,
const heif_image_tiling& tiling)
{
if (tiling_method == "grid") {
return encode_tiled_grid(ctx, encoder, options, output_bit_depth, tile_generator, tiling);
}
heif_image_handle* tiled_image;


heif_image_handle* tiled_image;
heif_error error;
if (tiling_method == "tili") {
// --- create the main grid image

if (tiling_method == "grid") {
heif_error error = heif_context_add_grid_image(ctx, tiling.image_width, tiling.image_height,
tiling.num_columns, tiling.num_rows,
options,
&tiled_image);
if (error.code != 0) {
std::cerr << "Could not generate grid image: " << error.message << "\n";
return nullptr;
}
}
else if (tiling_method == "tili") {
heif_tiled_image_parameters tiled_params{};
tiled_params.version = 1;
tiled_params.image_width = tiling.image_width;
tiled_params.image_height = tiling.image_height;
tiled_params.tile_width = tiling.tile_width;
tiled_params.tile_height = tiling.tile_height;
// tiled_params.compression_format_fourcc = heif_fourcc('a', 'v', '0', '1'); // TODO HACK
tiled_params.offset_field_length = 32;
tiled_params.size_field_length = 24;
tiled_params.tiles_are_sequential = 1;

error = heif_context_add_tiled_image(ctx, &tiled_params, options, encoder, &tiled_image);
heif_error error = heif_context_add_tiled_image(ctx, &tiled_params, options, encoder, &tiled_image);
if (error.code != 0) {
std::cerr << "Could not generate tili image: " << error.message << "\n";
return nullptr;
Expand All @@ -835,10 +793,10 @@ heif_image_handle* encode_tiled(heif_context* ctx, heif_encoder* encoder, heif_e
params.tile_height = tiling.tile_height;
params.compression = unci_compression;

std::string input_filename = tile_generator.filename(0,0);
std::string input_filename = tile_generator.filename(0, 0);
InputImage prototype_image = load_image(input_filename, output_bit_depth);

error = heif_context_add_unci_image(ctx, &params, options, prototype_image.image.get(), &tiled_image);
heif_error error = heif_context_add_unci_image(ctx, &params, options, prototype_image.image.get(), &tiled_image);
if (error.code != 0) {
std::cerr << "Could not generate unci image: " << error.message << "\n";
return nullptr;
Expand All @@ -849,6 +807,9 @@ heif_image_handle* encode_tiled(heif_context* ctx, heif_encoder* encoder, heif_e
exit(10);
}


// --- add all the image tiles

std::cout << "encoding tiled image, tile size: " << tiling.tile_width << "x" << tiling.tile_height
<< " image size: " << tiling.image_width << "x" << tiling.image_height << "\n";

Expand All @@ -863,8 +824,8 @@ heif_image_handle* encode_tiled(heif_context* ctx, heif_encoder* encoder, heif_e
std::cout.flush();

heif_error error = heif_context_add_image_tile(ctx, tiled_image, tx, ty,
input_image.image.get(),
encoder);
input_image.image.get(),
encoder);
if (error.code != 0) {
std::cerr << "Could not encode HEIF/AVIF file: " << error.message << "\n";
return nullptr;
Expand Down
23 changes: 9 additions & 14 deletions libheif/api/libheif/heif.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3429,14 +3429,10 @@ struct heif_error heif_context_add_grid_image(struct heif_context* ctx,
uint32_t image_height,
uint32_t tile_columns,
uint32_t tile_rows,
const heif_item_id* image_ids,
const struct heif_encoding_options* encoding_options,
struct heif_image_handle** out_grid_image_handle)
{
if (!image_ids) {
return Error(heif_error_Usage_error,
heif_suberror_Null_pointer_argument).error_struct(ctx->context.get());
}
else if (tile_rows == 0 || tile_columns == 0) {
if (tile_rows == 0 || tile_columns == 0) {
return Error(heif_error_Usage_error,
heif_suberror_Invalid_parameter_value).error_struct(ctx->context.get());
}
Expand All @@ -3446,16 +3442,11 @@ struct heif_error heif_context_add_grid_image(struct heif_context* ctx,
"Number of tile rows/columns may not exceed 65535"};
}


std::vector<heif_item_id> tiles(tile_rows * tile_columns);
for (uint64_t i = 0; i < tile_rows * tile_columns; i++) {
tiles[i] = image_ids[i];
}

std::shared_ptr<ImageItem> gridimage;
Error error = ctx->context->add_grid_item(tiles, image_width, image_height,
std::shared_ptr<ImageItem_Grid> gridimage;
Error error = ctx->context->add_grid_item(image_width, image_height,
static_cast<uint16_t>(tile_rows),
static_cast<uint16_t>(tile_columns),
encoding_options,
gridimage);

if (error != Error::Ok) {
Expand Down Expand Up @@ -3565,6 +3556,10 @@ struct heif_error heif_context_add_image_tile(struct heif_context* ctx,
return err.error_struct(ctx->context.get());
}
#endif
else if (tiled_image->image->get_infe_type() == fourcc("grid")) {
Error err = ctx->context->add_grid_image_tile(tiled_image->image->get_id(), tile_x, tile_y, image->image, encoder);
return err.error_struct(ctx->context.get());
}
else {
return {
heif_error_Usage_error,
Expand Down
2 changes: 1 addition & 1 deletion libheif/api/libheif/heif.h
Original file line number Diff line number Diff line change
Expand Up @@ -2369,7 +2369,7 @@ struct heif_error heif_context_add_grid_image(struct heif_context* ctx,
uint32_t image_height,
uint32_t tile_columns,
uint32_t tile_rows,
const heif_item_id* image_ids,
const struct heif_encoding_options* encoding_options,
struct heif_image_handle** out_grid_image_handle);

LIBHEIF_API
Expand Down
63 changes: 50 additions & 13 deletions libheif/box.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2766,6 +2766,15 @@ void Box_ipma::add_property_for_item_ID(heif_item_id itemID,
m_entries.push_back(entry);
}

// If the property is already associated with the item, skip.
for (auto const& a : m_entries[idx].associations) {
if (a.property_index == assoc.property_index) {
return;
}

// TODO: should we check that the essential flag matches and return an internal error if not?
}

// add the property association
m_entries[idx].associations.push_back(assoc);
}
Expand Down Expand Up @@ -3209,18 +3218,8 @@ Error Box_iref::parse(BitstreamRange& range, const heif_security_limits* limits)

// --- check for duplicate references

for (const auto& ref : m_references) {
std::set<heif_item_id> to_ids;
for (const auto to_id : ref.to_item_ID) {
if (to_ids.find(to_id) == to_ids.end()) {
to_ids.insert(to_id);
}
else {
return Error(heif_error_Invalid_input,
heif_suberror_Unspecified,
"'iref' has double references");
}
}
if (auto error = check_for_double_references()) {
return error;
}


Expand Down Expand Up @@ -3279,6 +3278,26 @@ Error Box_iref::parse(BitstreamRange& range, const heif_security_limits* limits)
}


Error Box_iref::check_for_double_references() const
{
for (const auto& ref : m_references) {
std::set<heif_item_id> to_ids;
for (const auto to_id : ref.to_item_ID) {
if (to_ids.find(to_id) == to_ids.end()) {
to_ids.insert(to_id);
}
else {
return {heif_error_Invalid_input,
heif_suberror_Unspecified,
"'iref' has double references"};
}
}
}

return Error::Ok;
}


void Box_iref::derive_box_version()
{
uint8_t version = 0;
Expand All @@ -3303,6 +3322,10 @@ void Box_iref::derive_box_version()

Error Box_iref::write(StreamWriter& writer) const
{
if (auto error = check_for_double_references()) {
return error;
}

size_t box_start = reserve_box_header_space(writer);

int id_size = ((get_version() == 0) ? 2 : 4);
Expand All @@ -3322,7 +3345,6 @@ Error Box_iref::write(StreamWriter& writer) const
}
}


prepend_header(writer, box_start);

return Error::Ok;
Expand Down Expand Up @@ -3400,6 +3422,21 @@ void Box_iref::add_references(heif_item_id from_id, uint32_t type, const std::ve
}


void Box_iref::overwrite_reference(heif_item_id from_id, uint32_t type, uint32_t reference_idx, heif_item_id to_item)
{
for (auto& ref : m_references) {
if (ref.from_item_ID == from_id && ref.header.get_short_type() == type) {
assert(reference_idx >= 0 && reference_idx < ref.to_item_ID.size());

ref.to_item_ID[reference_idx] = to_item;
return;
}
}

assert(false); // reference was not found
}


Error Box_idat::parse(BitstreamRange& range, const heif_security_limits* limits)
{
//parse_full_box_header(range);
Expand Down
4 changes: 4 additions & 0 deletions libheif/box.h
Original file line number Diff line number Diff line change
Expand Up @@ -932,13 +932,17 @@ class Box_iref : public FullBox

void add_references(heif_item_id from_id, uint32_t type, const std::vector<heif_item_id>& to_ids);

void overwrite_reference(heif_item_id from_id, uint32_t type, uint32_t reference_idx, heif_item_id to_item);

protected:
Error parse(BitstreamRange& range, const heif_security_limits*) override;

Error write(StreamWriter& writer) const override;

void derive_box_version() override;

Error check_for_double_references() const;

private:
std::vector<Reference> m_references;
};
Expand Down
Loading

0 comments on commit bbbd67b

Please sign in to comment.