Skip to content

Commit

Permalink
uncompressed: implement generic compression decode
Browse files Browse the repository at this point in the history
  • Loading branch information
bradh committed Jul 6, 2024
1 parent 9a8f1e1 commit b20e382
Show file tree
Hide file tree
Showing 32 changed files with 1,189 additions and 193 deletions.
11 changes: 10 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -395,9 +395,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
6 changes: 3 additions & 3 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
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
10 changes: 10 additions & 0 deletions libheif/api/libheif/heif.h
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,11 @@ enum heif_suberror_code

heif_suberror_No_vvcC_box = 141,

// icbr is only needed in some situations, this error is for those cases
heif_suberror_No_icbr_box = 142,

// 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 +254,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 +305,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 @@ -331,6 +331,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 @@ -386,6 +388,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
25 changes: 25 additions & 0 deletions libheif/bitstream.cc
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,31 @@ uint32_t BitstreamRange::read32()
(buf[3]));
}

uint64_t BitstreamRange::read64()
{
if (!prepare_read(8)) {
return 0;
}

uint8_t buf[8];

auto istr = get_istream();
bool success = istr->read((char*) buf, 8);

if (!success) {
set_eof_while_reading();
return 0;
}

return (uint64_t) (((uint64_t)buf[0] << 56) |
((uint64_t)buf[1] << 48) |
((uint64_t)buf[2] << 40) |
((uint64_t)buf[3] << 32) |
(buf[4] << 24) |
(buf[5] << 16) |
(buf[6] << 8) |
(buf[7]));
}

int32_t BitstreamRange::read32s()
{
Expand Down
2 changes: 2 additions & 0 deletions libheif/bitstream.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,8 @@ class BitstreamRange

int32_t read32s();

uint64_t read64();

std::string read_string();

bool read(uint8_t* data, size_t n);
Expand Down
8 changes: 8 additions & 0 deletions libheif/box.cc
Original file line number Diff line number Diff line change
Expand Up @@ -611,6 +611,14 @@ Error Box::read(BitstreamRange& range, std::shared_ptr<Box>* result)
case fourcc("uncC"):
box = std::make_shared<Box_uncC>();
break;

case fourcc("cmpC"):
box = std::make_shared<Box_cmpC>();
break;

case fourcc("icbr"):
box = std::make_shared<Box_icbr>();
break;
#endif

// --- JPEG 2000
Expand Down
87 changes: 87 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,89 @@ 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();
must_decompress_individual_entities = ((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 << "must_decompress_individual_entities: " << must_decompress_individual_entities << "\n";
sstr << indent << "compressed_entity_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 = must_decompress_individual_entities ? 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) {
byteRange.range_offset = range.read64();
byteRange.range_size = range.read64();
} 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) {
writer.write64(range.range_offset);
writer.write64(range.range_size);
} 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;
}
Loading

0 comments on commit b20e382

Please sign in to comment.