Skip to content

Commit

Permalink
uncompressed: wip on generic compression
Browse files Browse the repository at this point in the history
  • Loading branch information
bradh committed Jun 28, 2024
1 parent 0a63293 commit 889d0b5
Show file tree
Hide file tree
Showing 17 changed files with 446 additions and 36 deletions.
11 changes: 10 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -379,9 +379,18 @@ endif()
if (LIBSHARPYUV_FOUND)
list(APPEND REQUIRES_PRIVATE "libsharpyuv")
endif()
if (WITH_DEFLATE_HEADER_COMPRESSION)
if (WITH_DEFLATE_HEADER_COMPRESSION OR WITH_UNCOMPRESSED_CODEC)
list(APPEND REQUIRES_PRIVATE "zlib")
endif()
if (WITH_UNCOMPRESSED_CODEC)
find_package(Brotli)
if (Brotli_FOUND)
message("Brotli found")
list(APPEND REQUIRES_PRIVATE "libbrotli")
else()
message("Brotli not found")
endif()
endif()

list(JOIN REQUIRES_PRIVATE " " REQUIRES_PRIVATE)

Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,8 @@ The placeholder `{codec}` can have these values: `LIBDE265`, `X265`, `AOM_DECODE

Further options are:

* `WITH_UNCOMPRESSED_CODEC`: enable support for uncompressed images according to ISO/IEC 23001-17:2023. This is *experimental*
and not available as a dynamic plugin.
* `WITH_UNCOMPRESSED_CODEC`: enable support for uncompressed images according to ISO/IEC 23001-17:2024. This is *experimental*
and not available as a dynamic plugin. When enabled, it adds a dependency to `zlib`, and optionally will use `brotli`.
* `WITH_DEFLATE_HEADER_COMPRESSION`: enables support for compressed metadata. When enabled, it adds a dependency to `zlib`.
Note that header compression is not widely supported yet.
* `WITH_LIBSHARPYUV`: enables high-quality YCbCr/RGB color space conversion algorithms (requires `libsharpyuv`,
Expand All @@ -170,7 +170,7 @@ Further options are:
* `PLUGIN_DIRECTORY`: the directory where libheif will search for dynamic plugins when the environment
variable `LIBHEIF_PLUGIN_PATH` is not set.
* `WITH_REDUCED_VISIBILITY`: only export those symbols into the library that are public API.
Has to be turned off for running the tests.
Has to be turned off for running some tests.

### macOS

Expand Down Expand Up @@ -377,5 +377,5 @@ The sample applications are distributed under the terms of the MIT License.
See COPYING for more details.
Copyright (c) 2017-2020 Struktur AG</br>
Copyright (c) 2017-2023 Dirk Farin</br>
Copyright (c) 2017-2024 Dirk Farin</br>
Contact: Dirk Farin <[email protected]>
26 changes: 26 additions & 0 deletions cmake/modules/FindBrotli.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
include(FindPackageHandleStandardArgs)

find_path(BROTLI_DEC_INCLUDE_DIR "brotli/decode.h")
find_path(BROTLI_ENC_INCLUDE_DIR "brotli/encode.h")

find_library(BROTLI_COMMON_LIB NAMES brotlicommon)
find_library(BROTLI_DEC_LIB NAMES brotlidec)
find_library(BROTLI_ENC_LIB NAMES brotlienc)

find_package_handle_standard_args(Brotli
FOUND_VAR
Brotli_FOUND
REQUIRED_VARS
BROTLI_COMMON_LIB
BROTLI_DEC_INCLUDE_DIR
BROTLI_DEC_LIB
BROTLI_ENC_INCLUDE_DIR
BROTLI_ENC_LIB
FAIL_MESSAGE
"Did not find Brotli"
)


set(HAVE_BROTLI ${Brotli_FOUND})
set(BROTLI_INCLUDE_DIRS ${BROTLI_DEC_INCLUDE_DIR} ${BROTLI_ENC_INCLUDE_DIR})
set(BROTLI_LIBS "${BROTLICOMMON_LIBRARY}" "${BROTLI_DEC_LIB}" "${BROTLI_ENC_LIB}")
6 changes: 6 additions & 0 deletions go/heif/heif.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,13 +269,17 @@ const (

SuberrorCameraExtrinsicMatrixUndefined = C.heif_suberror_Camera_extrinsic_matrix_undefined

SuberrorDecompressionInvalidData = C.heif_suberror_Decompression_invalid_data

// --- Memory_allocation_error ---

// A security limit preventing unreasonable memory allocations was exceeded by the input file.
// Please check whether the file is valid. If it is, contact us so that we could increase the
// security limits further.
SuberrorSecurityLimitExceeded = C.heif_suberror_Security_limit_exceeded

CompressionInitialisationError = C.heif_suberror_Compression_initialisation_error

// --- Usage_error ---

// An item ID was used that is not present in the file.
Expand Down Expand Up @@ -331,6 +335,8 @@ const (

SuberrorUnsupportedDataVersion = C.heif_suberror_Unsupported_data_version

SuberrorUnsupportedGenericCompressionMethod = C.heif_suberror_Unsupported_generic_compression_method

// The conversion of the source image to the requested chroma / colorspace is not supported.
SuberrorUnsupportedColorConversion = C.heif_suberror_Unsupported_color_conversion

Expand Down
17 changes: 14 additions & 3 deletions libheif/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@ set(libheif_sources
init.h
logging.h
logging.cc
metadata_compression.cc
metadata_compression.h
compression.h
compression_brotli.cc
compression_zlib.cc
common_utils.cc
common_utils.h
region.cc
Expand Down Expand Up @@ -133,11 +134,21 @@ else ()
message("Not compiling 'libsharpyuv'")
endif ()

if (WITH_DEFLATE_HEADER_COMPRESSION)
if (WITH_DEFLATE_HEADER_COMPRESSION OR WITH_UNCOMPRESSED_CODEC)
find_package(ZLIB REQUIRED)
target_link_libraries(heif PRIVATE ZLIB::ZLIB)
target_compile_definitions(heif PRIVATE WITH_ZLIB_COMPRESSION=1)
endif ()

if (WITH_DEFLATE_HEADER_COMPRESSION)
target_compile_definitions(heif PRIVATE WITH_DEFLATE_HEADER_COMPRESSION=1)
endif ()

if (HAVE_BROTLI)
target_compile_definitions(heif PUBLIC HAVE_BROTLI=1)
target_include_directories(heif PRIVATE ${BROTLI_INCLUDE_DIRS})
target_link_libraries(heif PRIVATE ${BROTLI_LIBS})
endif()

if (ENABLE_MULTITHREADING_SUPPORT)
find_package(Threads)
Expand Down
7 changes: 7 additions & 0 deletions libheif/api/libheif/heif.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,8 @@ enum heif_suberror_code

heif_suberror_No_vvcC_box = 141,

// Decompressing generic compression or header compression data failed (e.g. bitstream corruption)
heif_suberror_Decompression_invalid_data = 150,

// --- Memory_allocation_error ---

Expand All @@ -249,6 +251,9 @@ enum heif_suberror_code
// security limits further.
heif_suberror_Security_limit_exceeded = 1000,

// There was an error from the underlying compression / decompression library.
// One possibility is lack of resources (e.g. memory).
heif_suberror_Compression_initialisation_error = 1001,

// --- Usage_error ---

Expand Down Expand Up @@ -297,6 +302,8 @@ enum heif_suberror_code

heif_suberror_Unsupported_header_compression_method = 3005,

// Generically compressed data used an unsupported compression method
heif_suberror_Unsupported_generic_compression_method = 3006,

// --- Encoder_plugin_error ---

Expand Down
3 changes: 3 additions & 0 deletions libheif/api/libheif/heif_emscripten.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ EMSCRIPTEN_BINDINGS(libheif) {
emscripten::enum_<heif_suberror_code>("heif_suberror_code")
.value("heif_suberror_Unspecified", heif_suberror_Unspecified)
.value("heif_suberror_Cannot_write_output_data", heif_suberror_Cannot_write_output_data)
.value("heif_suberror_Compression_initialisation_error", heif_suberror_Compression_initialisation_error)
.value("heif_suberror_Decompression_invalid_data", heif_suberror_Decompression_invalid_data)
.value("heif_suberror_Encoder_initialization", heif_suberror_Encoder_initialization)
.value("heif_suberror_Encoder_encoding", heif_suberror_Encoder_encoding)
.value("heif_suberror_Encoder_cleanup", heif_suberror_Encoder_cleanup)
Expand Down Expand Up @@ -358,6 +360,7 @@ EMSCRIPTEN_BINDINGS(libheif) {
.value("heif_suberror_Unsupported_codec", heif_suberror_Unsupported_codec)
.value("heif_suberror_Unsupported_image_type", heif_suberror_Unsupported_image_type)
.value("heif_suberror_Unsupported_data_version", heif_suberror_Unsupported_data_version)
.value("heif_suberror_Unsupported_generic_compression_method", heif_suberror_Unsupported_generic_compression_method)
.value("heif_suberror_Unsupported_color_conversion", heif_suberror_Unsupported_color_conversion)
.value("heif_suberror_Unsupported_item_construction_method", heif_suberror_Unsupported_item_construction_method)
.value("heif_suberror_Unsupported_header_compression_method", heif_suberror_Unsupported_header_compression_method)
Expand Down
85 changes: 85 additions & 0 deletions libheif/codecs/uncompressed_box.cc
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@ std::string Box_uncC::dump(Indent& indent) const
return sstr.str();
}


Error Box_uncC::write(StreamWriter& writer) const
{
size_t box_start = reserve_box_header_space(writer);
Expand Down Expand Up @@ -350,3 +351,87 @@ Error Box_uncC::write(StreamWriter& writer) const

return Error::Ok;
}


Error Box_cmpC::parse(BitstreamRange& range)
{
parse_full_box_header(range);
compression_type = range.read32();
uint8_t v = range.read8();
can_decompress_contiguous_ranges = ((v & 0x80) == 0x80);
compressed_range_type = (v & 0x7f);
return range.get_error();
}


std::string Box_cmpC::dump(Indent& indent) const
{
std::ostringstream sstr;
sstr << Box::dump(indent);
sstr << indent << "compression_type: " << to_fourcc(compression_type) << "\n";
sstr << indent << "can_compress_contiguous_ranges: " << can_decompress_contiguous_ranges << "\n";
sstr << indent << "compressed_range_type: " << (int)compressed_range_type << "\n";
return sstr.str();
}

Error Box_cmpC::write(StreamWriter& writer) const
{
size_t box_start = reserve_box_header_space(writer);

writer.write32(compression_type);
uint8_t v = can_decompress_contiguous_ranges ? 0x80 : 0x00;
v |= (compressed_range_type & 0x7F);
writer.write8(v);

prepend_header(writer, box_start);

return Error::Ok;
}


Error Box_icbr::parse(BitstreamRange& range)
{
parse_full_box_header(range);
uint32_t num_ranges = range.read32();
for (uint32_t r = 0; r < num_ranges; r++) {
struct ByteRange byteRange;
if (get_version() == 1) {
// TODO
} else if (get_version() == 0) {
byteRange.range_offset = range.read32();
byteRange.range_size = range.read32();
}
m_ranges.push_back(byteRange);
}
return range.get_error();
}


std::string Box_icbr::dump(Indent& indent) const
{
std::ostringstream sstr;
sstr << Box::dump(indent);
sstr << indent << "num_ranges: " << m_ranges.size() << "\n";
for (ByteRange range: m_ranges) {
sstr << indent << "range_offset: " << range.range_offset << ", range_size: " << range.range_size << "\n";
}
return sstr.str();
}

Error Box_icbr::write(StreamWriter& writer) const
{
size_t box_start = reserve_box_header_space(writer);

writer.write32((uint32_t)m_ranges.size());
for (ByteRange range: m_ranges) {
if (get_version() == 1) {
// TODO
} else if (get_version() == 0) {
writer.write32((uint32_t)range.range_offset);
writer.write32((uint32_t)range.range_size);
}
}
prepend_header(writer, box_start);

return Error::Ok;
}
79 changes: 78 additions & 1 deletion libheif/codecs/uncompressed_box.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,22 @@ class Box_cmpd : public Box
class Box_uncC : public FullBox
{
public:
Box_uncC() {
Box_uncC() :
m_profile(0),
m_sampling_type(sampling_mode_no_subsampling),
m_interleave_type(interleave_mode_component),
m_block_size(0),
m_components_little_endian(false),
m_block_pad_lsb(false),
m_block_little_endian(false),
m_block_reversed(false),
m_pad_unknown(false),
m_pixel_size(0),
m_row_align_size(0),
m_tile_align_size(0),
m_num_tile_cols(1),
m_num_tile_rows(1)
{
set_short_type(fourcc("uncC"));
}

Expand Down Expand Up @@ -220,4 +235,66 @@ class Box_uncC : public FullBox
uint32_t m_num_tile_rows = 1;
};

/**
* Generic compression box (cmpC).
*
* This is from ISO/IEC 23001-17 Amd 2.
*/
class Box_cmpC : public FullBox
{
public:
Box_cmpC()
{
set_short_type(fourcc("cmpC"));
}

std::string dump(Indent&) const override;

uint32_t get_compression_type() const { return compression_type; }
Error write(StreamWriter& writer) const override;

protected:
Error parse(BitstreamRange& range) override;

uint32_t compression_type;
bool can_decompress_contiguous_ranges;
uint8_t compressed_range_type;
};

/**
* Item compressed byte range info (icbr).
*
* This is from ISO/IEC 23001-17 Amd 2.
*/
class Box_icbr : public FullBox
{
public:
Box_icbr()
{
set_short_type(fourcc("icbr"));
}

struct ByteRange
{
uint64_t range_offset;
uint64_t range_size;
};

const std::vector<ByteRange>& get_ranges() const { return m_ranges; }

void add_component(const ByteRange& range)
{
m_ranges.push_back(range);
}

std::string dump(Indent&) const override;

Error write(StreamWriter& writer) const override;

protected:
Error parse(BitstreamRange& range) override;

std::vector<ByteRange> m_ranges;
};

#endif //LIBHEIF_UNCOMPRESSED_BOX_H
Loading

0 comments on commit 889d0b5

Please sign in to comment.