Skip to content

Commit

Permalink
heif-enc: option to switch tiling method
Browse files Browse the repository at this point in the history
  • Loading branch information
farindk committed Oct 12, 2024
1 parent 1918cfd commit 8361c6a
Show file tree
Hide file tree
Showing 9 changed files with 134 additions and 18 deletions.
87 changes: 83 additions & 4 deletions examples/heif_enc.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@

#include "benchmark.h"
#include "common.h"
#include "libheif/heif_experimental.h"

int master_alpha = 1;
int thumb_alpha = 1;
Expand All @@ -62,6 +63,7 @@ const char* encoderId = nullptr;
std::string chroma_downsampling;
int tiled_image_width = 0;
int tiled_image_height = 0;
std::string tiling_method;

uint16_t nclx_colour_primaries = 1;
uint16_t nclx_transfer_characteristic = 13;
Expand Down Expand Up @@ -100,6 +102,7 @@ const int OPTION_USE_HTJ2K_COMPRESSION = 1009;
const int OPTION_USE_VVC_COMPRESSION = 1010;
const int OPTION_TILED_IMAGE_WIDTH = 1011;
const int OPTION_TILED_IMAGE_HEIGHT = 1012;
const int OPTION_TILING_METHOD = 1013;


static struct option long_options[] = {
Expand Down Expand Up @@ -140,6 +143,7 @@ static struct option long_options[] = {
{(char* const) "tiled-image-width", required_argument, nullptr, OPTION_TILED_IMAGE_WIDTH},
{(char* const) "tiled-image-height", required_argument, nullptr, OPTION_TILED_IMAGE_HEIGHT},
{(char* const) "tiled-input-x-y", no_argument, &tiled_input_x_y, 1},
{(char* const) "tiling-method", required_argument, nullptr, OPTION_TILING_METHOD},
{0, 0, 0, 0},
};

Expand Down Expand Up @@ -202,6 +206,7 @@ void show_help(const char* argv0)
<< " --tiled-image-height # override image height of tiled image\n"
<< " --tiled-input-x-y usually, the first number in the input tile filename should be the y position.\n"
<< " With this option, this can be swapped so that the first number is x, the second number y.\n"
<< " --tiling-method METHOD choose one of these methods: grid, tili, unci. The default is 'grid'.\n"
;
}

Expand Down Expand Up @@ -738,10 +743,10 @@ std::optional<input_tiles_generator> determine_input_images_tiling(const std::st
}


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)
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;

Expand Down Expand Up @@ -787,6 +792,71 @@ heif_image_handle* encode_tiled(heif_context* ctx, heif_encoder* encoder, heif_e
}


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_error error;
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);
if (error.code != 0) {
std::cerr << "Could not generate grid image: " << error.message << "\n";
return nullptr;
}
}
else if (tiling_method == "unci") {
// TODO
}
else {
assert(false);
}

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_error error = heif_context_add_image_tile(ctx, tiled_image, tx, ty,
input_image.image.get(),
encoder);
if (error.code != 0) {
std::cerr << "Could not encode HEIF/AVIF file: " << error.message << "\n";
return nullptr;
}
}

std::cout << "\n";

return tiled_image;
}


class LibHeifInitializer
{
public:
Expand Down Expand Up @@ -918,6 +988,15 @@ int main(int argc, char** argv)
case OPTION_TILED_IMAGE_HEIGHT:
tiled_image_height = (int) strtol(optarg, nullptr, 0);
break;
case OPTION_TILING_METHOD:
tiling_method = optarg;
if (tiling_method != "grid" &&
tiling_method != "tili" &&
tiling_method != "unci") {
std::cerr << "Invalid tiling method '" << tiling_method << "'\n";
exit(5);
}
break;
case 'C':
chroma_downsampling = optarg;
if (chroma_downsampling != "nn" &&
Expand Down
3 changes: 2 additions & 1 deletion libheif/api/libheif/heif.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3529,10 +3529,11 @@ struct heif_error heif_context_add_overlay_image(struct heif_context* ctx,
struct heif_error heif_context_add_tiled_image(struct heif_context* ctx,
const struct heif_tiled_image_parameters* parameters,
const struct heif_encoding_options* options, // TODO: do we need this?
const struct heif_encoder* encoder,
struct heif_image_handle** out_grid_image_handle)
{
Result<std::shared_ptr<ImageItem_Tiled>> gridImageResult;
gridImageResult = ctx->context->add_tiled_item(parameters);
gridImageResult = ctx->context->add_tiled_item(parameters, encoder);

if (gridImageResult.error != Error::Ok) {
return gridImageResult.error.error_struct(ctx->context.get());
Expand Down
3 changes: 2 additions & 1 deletion libheif/api/libheif/heif_experimental.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ struct heif_tiled_image_parameters {
uint32_t tile_width;
uint32_t tile_height;

uint32_t compression_type_fourcc; // TODO: can this be set automatically ?
uint32_t compression_format_fourcc; // will be set automatically when calling heif_context_add_tiled_image()

uint8_t offset_field_length; // one of: 32, 40, 48, 64
uint8_t size_field_length; // one of: 0, 24, 32, 64
Expand All @@ -140,6 +140,7 @@ LIBHEIF_API
struct heif_error heif_context_add_tiled_image(struct heif_context* ctx,
const struct heif_tiled_image_parameters* parameters,
const struct heif_encoding_options* options, // TODO: do we need this?
const struct heif_encoder* encoder,
struct heif_image_handle** out_tiled_image_handle);


Expand Down
7 changes: 4 additions & 3 deletions libheif/context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1342,9 +1342,10 @@ Result<std::shared_ptr<ImageItem_Overlay>> HeifContext::add_iovl_item(const Imag
}


Result<std::shared_ptr<ImageItem_Tiled>> HeifContext::add_tiled_item(const heif_tiled_image_parameters* parameters)
Result<std::shared_ptr<ImageItem_Tiled>> HeifContext::add_tiled_item(const heif_tiled_image_parameters* parameters,
const struct heif_encoder* encoder)
{
return ImageItem_Tiled::add_new_tiled_item(this, parameters);
return ImageItem_Tiled::add_new_tiled_item(this, parameters, encoder);
}


Expand All @@ -1354,7 +1355,7 @@ Error HeifContext::add_tiled_image_tile(heif_item_id tild_id, uint32_t tile_x, u
{
auto item = ImageItem::alloc_for_compression_format(this, encoder->plugin->compression_format);

heif_encoding_options* options = heif_encoding_options_alloc();
heif_encoding_options* options = heif_encoding_options_alloc(); // TODO: should this be taken from heif_context_add_tiled_image() ?

Result<std::shared_ptr<HeifPixelImage>> colorConversionResult = item->convert_colorspace_for_encoding(image, encoder, *options);
if (colorConversionResult.error) {
Expand Down
3 changes: 2 additions & 1 deletion libheif/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ class HeifContext : public ErrorBuffer

Result<std::shared_ptr<ImageItem_Overlay>> add_iovl_item(const ImageOverlay& overlayspec);

Result<std::shared_ptr<ImageItem_Tiled>> add_tiled_item(const heif_tiled_image_parameters* parameters);
Result<std::shared_ptr<ImageItem_Tiled>> add_tiled_item(const heif_tiled_image_parameters* parameters,
const struct heif_encoder* encoder);

Error add_tiled_image_tile(heif_item_id tili_id, uint32_t tile_x, uint32_t tile_y,
const std::shared_ptr<HeifPixelImage>& image,
Expand Down
22 changes: 22 additions & 0 deletions libheif/image-items/image_item.cc
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,28 @@ heif_compression_format ImageItem::compression_format_from_fourcc_infe_type(uint
}
}

uint32_t ImageItem::compression_format_to_fourcc_infe_type(heif_compression_format format)
{
switch (format) {
case heif_compression_JPEG:
return fourcc("jpeg");
case heif_compression_HEVC:
return fourcc("hvc1");
case heif_compression_AV1:
return fourcc("av01");
case heif_compression_VVC:
return fourcc("vvc1");
case heif_compression_JPEG2000:
return fourcc("j2k1");
case heif_compression_uncompressed:
return fourcc("unci");
case heif_compression_mask:
return fourcc("mski");
default:
return 0;
}
}


std::shared_ptr<ImageItem> ImageItem::alloc_for_infe_box(HeifContext* ctx, const std::shared_ptr<Box_infe>& infe)
{
Expand Down
2 changes: 2 additions & 0 deletions libheif/image-items/image_item.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ class ImageItem : public ErrorBuffer

static heif_compression_format compression_format_from_fourcc_infe_type(uint32_t type);

static uint32_t compression_format_to_fourcc_infe_type(heif_compression_format);

Result<std::shared_ptr<HeifPixelImage>> convert_colorspace_for_encoding(const std::shared_ptr<HeifPixelImage>& image,
struct heif_encoder* encoder,
const struct heif_encoding_options& options);
Expand Down
18 changes: 11 additions & 7 deletions libheif/image-items/tiled.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include <algorithm>
#include "security_limits.h"
#include "codecs/hevc_dec.h"
#include "libheif/api_structs.h"


static uint64_t readvec(const std::vector<uint8_t>& data, size_t& ptr, int len)
Expand Down Expand Up @@ -127,7 +128,7 @@ Error Box_tilC::write(StreamWriter& writer) const

writer.write32(m_parameters.tile_width);
writer.write32(m_parameters.tile_height);
writer.write32(m_parameters.compression_type_fourcc);
writer.write32(m_parameters.compression_format_fourcc);

writer.write8(m_parameters.number_of_extra_dimensions);

Expand All @@ -150,7 +151,7 @@ std::string Box_tilC::dump(Indent& indent) const
sstr << indent << "version: " << ((int) get_version()) << "\n"
//<< indent << "image size: " << m_parameters.image_width << "x" << m_parameters.image_height << "\n"
<< indent << "tile size: " << m_parameters.tile_width << "x" << m_parameters.tile_height << "\n"
<< indent << "compression: " << fourcc_to_string(m_parameters.compression_type_fourcc) << "\n"
<< indent << "compression: " << fourcc_to_string(m_parameters.compression_format_fourcc) << "\n"
<< indent << "tiles are sequential: " << (m_parameters.tiles_are_sequential ? "yes" : "no") << "\n"
<< indent << "offset field length: " << ((int) m_parameters.offset_field_length) << " bits\n"
<< indent << "size field length: " << ((int) m_parameters.size_field_length) << " bits\n"
Expand Down Expand Up @@ -213,7 +214,7 @@ Error Box_tilC::parse(BitstreamRange& range, const heif_security_limits* limits)

m_parameters.tile_width = range.read32();
m_parameters.tile_height = range.read32();
m_parameters.compression_type_fourcc = range.read32();
m_parameters.compression_format_fourcc = range.read32();

if (m_parameters.tile_width == 0 || m_parameters.tile_height == 0) {
return {heif_error_Invalid_input,
Expand Down Expand Up @@ -445,7 +446,7 @@ ImageItem_Tiled::ImageItem_Tiled(HeifContext* ctx, heif_item_id id)

heif_compression_format ImageItem_Tiled::get_compression_format() const
{
return compression_format_from_fourcc_infe_type(m_tild_header.get_parameters().compression_type_fourcc);
return compression_format_from_fourcc_infe_type(m_tild_header.get_parameters().compression_format_fourcc);
}


Expand Down Expand Up @@ -481,7 +482,7 @@ Error ImageItem_Tiled::on_load_file()
return err;
}

m_tile_decoder = Decoder::alloc_for_infe_type(get_context(), get_id(), parameters.compression_type_fourcc);
m_tile_decoder = Decoder::alloc_for_infe_type(get_context(), get_id(), parameters.compression_format_fourcc);
if (!m_tile_decoder) {
return {heif_error_Unsupported_feature,
heif_suberror_Unsupported_codec,
Expand All @@ -499,7 +500,8 @@ Error ImageItem_Tiled::on_load_file()


Result<std::shared_ptr<ImageItem_Tiled>>
ImageItem_Tiled::add_new_tiled_item(HeifContext* ctx, const heif_tiled_image_parameters* parameters)
ImageItem_Tiled::add_new_tiled_item(HeifContext* ctx, const heif_tiled_image_parameters* parameters,
const heif_encoder* encoder)
{
auto max_tild_tiles = ctx->get_security_limits()->max_number_of_tiles;
if (max_tild_tiles && number_of_tiles(*parameters) > max_tild_tiles) {
Expand All @@ -521,12 +523,14 @@ ImageItem_Tiled::add_new_tiled_item(HeifContext* ctx, const heif_tiled_image_par

auto tilC_box = std::make_shared<Box_tilC>();
tilC_box->set_parameters(*parameters);
tilC_box->set_compression_format(encoder->plugin->compression_format);
ctx->get_heif_file()->add_property(tild_id, tilC_box, true);

// Create header + offset table

TildHeader tild_header;
tild_header.set_parameters(*parameters);
tild_header.set_compression_format(encoder->plugin->compression_format);

std::vector<uint8_t> header_data = tild_header.write_offset_table();

Expand Down Expand Up @@ -616,7 +620,7 @@ Result<std::shared_ptr<HeifPixelImage>>
ImageItem_Tiled::decode_grid_tile(const heif_decoding_options& options, uint32_t tx, uint32_t ty) const
{
heif_compression_format format = compression_format_from_fourcc_infe_type(
m_tild_header.get_parameters().compression_type_fourcc);
m_tild_header.get_parameters().compression_format_fourcc);

// --- get compressed data

Expand Down
7 changes: 6 additions & 1 deletion libheif/image-items/tiled.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ class Box_tilC : public FullBox

void set_parameters(const heif_tiled_image_parameters& params) { m_parameters = params; }

void set_compression_format(heif_compression_format format) { m_parameters.compression_format_fourcc = ImageItem::compression_format_to_fourcc_infe_type(format); }

const heif_tiled_image_parameters& get_parameters() const { return m_parameters; }

Error write(StreamWriter& writer) const override;
Expand All @@ -84,6 +86,8 @@ class TildHeader

const heif_tiled_image_parameters& get_parameters() const { return m_parameters; }

void set_compression_format(heif_compression_format format) { m_parameters.compression_format_fourcc = ImageItem::compression_format_to_fourcc_infe_type(format); }

Error read_full_offset_table(const std::shared_ptr<HeifFile>& file, heif_item_id tild_id, const heif_security_limits* limits);

Error read_offset_table_range(const std::shared_ptr<HeifFile>& file, heif_item_id tild_id,
Expand Down Expand Up @@ -140,7 +144,8 @@ class ImageItem_Tiled : public ImageItem

heif_compression_format get_compression_format() const override;

static Result<std::shared_ptr<ImageItem_Tiled>> add_new_tiled_item(HeifContext* ctx, const heif_tiled_image_parameters* parameters);
static Result<std::shared_ptr<ImageItem_Tiled>> add_new_tiled_item(HeifContext* ctx, const heif_tiled_image_parameters* parameters,
const heif_encoder* encoder);

Error on_load_file() override;

Expand Down

0 comments on commit 8361c6a

Please sign in to comment.