Skip to content

Commit 889d0b5

Browse files
committed
uncompressed: wip on generic compression
1 parent 0a63293 commit 889d0b5

17 files changed

+446
-36
lines changed

CMakeLists.txt

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -379,9 +379,18 @@ endif()
379379
if (LIBSHARPYUV_FOUND)
380380
list(APPEND REQUIRES_PRIVATE "libsharpyuv")
381381
endif()
382-
if (WITH_DEFLATE_HEADER_COMPRESSION)
382+
if (WITH_DEFLATE_HEADER_COMPRESSION OR WITH_UNCOMPRESSED_CODEC)
383383
list(APPEND REQUIRES_PRIVATE "zlib")
384384
endif()
385+
if (WITH_UNCOMPRESSED_CODEC)
386+
find_package(Brotli)
387+
if (Brotli_FOUND)
388+
message("Brotli found")
389+
list(APPEND REQUIRES_PRIVATE "libbrotli")
390+
else()
391+
message("Brotli not found")
392+
endif()
393+
endif()
385394

386395
list(JOIN REQUIRES_PRIVATE " " REQUIRES_PRIVATE)
387396

README.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,8 @@ The placeholder `{codec}` can have these values: `LIBDE265`, `X265`, `AOM_DECODE
159159

160160
Further options are:
161161

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

175175
### macOS
176176

@@ -377,5 +377,5 @@ The sample applications are distributed under the terms of the MIT License.
377377
See COPYING for more details.
378378
379379
Copyright (c) 2017-2020 Struktur AG</br>
380-
Copyright (c) 2017-2023 Dirk Farin</br>
380+
Copyright (c) 2017-2024 Dirk Farin</br>
381381
Contact: Dirk Farin <dirk.farin@gmail.com>

cmake/modules/FindBrotli.cmake

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
include(FindPackageHandleStandardArgs)
2+
3+
find_path(BROTLI_DEC_INCLUDE_DIR "brotli/decode.h")
4+
find_path(BROTLI_ENC_INCLUDE_DIR "brotli/encode.h")
5+
6+
find_library(BROTLI_COMMON_LIB NAMES brotlicommon)
7+
find_library(BROTLI_DEC_LIB NAMES brotlidec)
8+
find_library(BROTLI_ENC_LIB NAMES brotlienc)
9+
10+
find_package_handle_standard_args(Brotli
11+
FOUND_VAR
12+
Brotli_FOUND
13+
REQUIRED_VARS
14+
BROTLI_COMMON_LIB
15+
BROTLI_DEC_INCLUDE_DIR
16+
BROTLI_DEC_LIB
17+
BROTLI_ENC_INCLUDE_DIR
18+
BROTLI_ENC_LIB
19+
FAIL_MESSAGE
20+
"Did not find Brotli"
21+
)
22+
23+
24+
set(HAVE_BROTLI ${Brotli_FOUND})
25+
set(BROTLI_INCLUDE_DIRS ${BROTLI_DEC_INCLUDE_DIR} ${BROTLI_ENC_INCLUDE_DIR})
26+
set(BROTLI_LIBS "${BROTLICOMMON_LIBRARY}" "${BROTLI_DEC_LIB}" "${BROTLI_ENC_LIB}")

go/heif/heif.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,13 +269,17 @@ const (
269269

270270
SuberrorCameraExtrinsicMatrixUndefined = C.heif_suberror_Camera_extrinsic_matrix_undefined
271271

272+
SuberrorDecompressionInvalidData = C.heif_suberror_Decompression_invalid_data
273+
272274
// --- Memory_allocation_error ---
273275

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

281+
CompressionInitialisationError = C.heif_suberror_Compression_initialisation_error
282+
279283
// --- Usage_error ---
280284

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

332336
SuberrorUnsupportedDataVersion = C.heif_suberror_Unsupported_data_version
333337

338+
SuberrorUnsupportedGenericCompressionMethod = C.heif_suberror_Unsupported_generic_compression_method
339+
334340
// The conversion of the source image to the requested chroma / colorspace is not supported.
335341
SuberrorUnsupportedColorConversion = C.heif_suberror_Unsupported_color_conversion
336342

libheif/CMakeLists.txt

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,9 @@ set(libheif_sources
3333
init.h
3434
logging.h
3535
logging.cc
36-
metadata_compression.cc
37-
metadata_compression.h
36+
compression.h
37+
compression_brotli.cc
38+
compression_zlib.cc
3839
common_utils.cc
3940
common_utils.h
4041
region.cc
@@ -133,11 +134,21 @@ else ()
133134
message("Not compiling 'libsharpyuv'")
134135
endif ()
135136

136-
if (WITH_DEFLATE_HEADER_COMPRESSION)
137+
if (WITH_DEFLATE_HEADER_COMPRESSION OR WITH_UNCOMPRESSED_CODEC)
137138
find_package(ZLIB REQUIRED)
138139
target_link_libraries(heif PRIVATE ZLIB::ZLIB)
140+
target_compile_definitions(heif PRIVATE WITH_ZLIB_COMPRESSION=1)
141+
endif ()
142+
143+
if (WITH_DEFLATE_HEADER_COMPRESSION)
139144
target_compile_definitions(heif PRIVATE WITH_DEFLATE_HEADER_COMPRESSION=1)
140145
endif ()
146+
147+
if (HAVE_BROTLI)
148+
target_compile_definitions(heif PUBLIC HAVE_BROTLI=1)
149+
target_include_directories(heif PRIVATE ${BROTLI_INCLUDE_DIRS})
150+
target_link_libraries(heif PRIVATE ${BROTLI_LIBS})
151+
endif()
141152

142153
if (ENABLE_MULTITHREADING_SUPPORT)
143154
find_package(Threads)

libheif/api/libheif/heif.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,8 @@ enum heif_suberror_code
241241

242242
heif_suberror_No_vvcC_box = 141,
243243

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

245247
// --- Memory_allocation_error ---
246248

@@ -249,6 +251,9 @@ enum heif_suberror_code
249251
// security limits further.
250252
heif_suberror_Security_limit_exceeded = 1000,
251253

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

253258
// --- Usage_error ---
254259

@@ -297,6 +302,8 @@ enum heif_suberror_code
297302

298303
heif_suberror_Unsupported_header_compression_method = 3005,
299304

305+
// Generically compressed data used an unsupported compression method
306+
heif_suberror_Unsupported_generic_compression_method = 3006,
300307

301308
// --- Encoder_plugin_error ---
302309

libheif/api/libheif/heif_emscripten.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,8 @@ EMSCRIPTEN_BINDINGS(libheif) {
303303
emscripten::enum_<heif_suberror_code>("heif_suberror_code")
304304
.value("heif_suberror_Unspecified", heif_suberror_Unspecified)
305305
.value("heif_suberror_Cannot_write_output_data", heif_suberror_Cannot_write_output_data)
306+
.value("heif_suberror_Compression_initialisation_error", heif_suberror_Compression_initialisation_error)
307+
.value("heif_suberror_Decompression_invalid_data", heif_suberror_Decompression_invalid_data)
306308
.value("heif_suberror_Encoder_initialization", heif_suberror_Encoder_initialization)
307309
.value("heif_suberror_Encoder_encoding", heif_suberror_Encoder_encoding)
308310
.value("heif_suberror_Encoder_cleanup", heif_suberror_Encoder_cleanup)
@@ -358,6 +360,7 @@ EMSCRIPTEN_BINDINGS(libheif) {
358360
.value("heif_suberror_Unsupported_codec", heif_suberror_Unsupported_codec)
359361
.value("heif_suberror_Unsupported_image_type", heif_suberror_Unsupported_image_type)
360362
.value("heif_suberror_Unsupported_data_version", heif_suberror_Unsupported_data_version)
363+
.value("heif_suberror_Unsupported_generic_compression_method", heif_suberror_Unsupported_generic_compression_method)
361364
.value("heif_suberror_Unsupported_color_conversion", heif_suberror_Unsupported_color_conversion)
362365
.value("heif_suberror_Unsupported_item_construction_method", heif_suberror_Unsupported_item_construction_method)
363366
.value("heif_suberror_Unsupported_header_compression_method", heif_suberror_Unsupported_header_compression_method)

libheif/codecs/uncompressed_box.cc

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@ std::string Box_uncC::dump(Indent& indent) const
312312
return sstr.str();
313313
}
314314

315+
315316
Error Box_uncC::write(StreamWriter& writer) const
316317
{
317318
size_t box_start = reserve_box_header_space(writer);
@@ -350,3 +351,87 @@ Error Box_uncC::write(StreamWriter& writer) const
350351

351352
return Error::Ok;
352353
}
354+
355+
356+
Error Box_cmpC::parse(BitstreamRange& range)
357+
{
358+
parse_full_box_header(range);
359+
compression_type = range.read32();
360+
uint8_t v = range.read8();
361+
can_decompress_contiguous_ranges = ((v & 0x80) == 0x80);
362+
compressed_range_type = (v & 0x7f);
363+
return range.get_error();
364+
}
365+
366+
367+
std::string Box_cmpC::dump(Indent& indent) const
368+
{
369+
std::ostringstream sstr;
370+
sstr << Box::dump(indent);
371+
sstr << indent << "compression_type: " << to_fourcc(compression_type) << "\n";
372+
sstr << indent << "can_compress_contiguous_ranges: " << can_decompress_contiguous_ranges << "\n";
373+
sstr << indent << "compressed_range_type: " << (int)compressed_range_type << "\n";
374+
return sstr.str();
375+
}
376+
377+
Error Box_cmpC::write(StreamWriter& writer) const
378+
{
379+
size_t box_start = reserve_box_header_space(writer);
380+
381+
writer.write32(compression_type);
382+
uint8_t v = can_decompress_contiguous_ranges ? 0x80 : 0x00;
383+
v |= (compressed_range_type & 0x7F);
384+
writer.write8(v);
385+
386+
prepend_header(writer, box_start);
387+
388+
return Error::Ok;
389+
}
390+
391+
392+
Error Box_icbr::parse(BitstreamRange& range)
393+
{
394+
parse_full_box_header(range);
395+
uint32_t num_ranges = range.read32();
396+
for (uint32_t r = 0; r < num_ranges; r++) {
397+
struct ByteRange byteRange;
398+
if (get_version() == 1) {
399+
// TODO
400+
} else if (get_version() == 0) {
401+
byteRange.range_offset = range.read32();
402+
byteRange.range_size = range.read32();
403+
}
404+
m_ranges.push_back(byteRange);
405+
}
406+
return range.get_error();
407+
}
408+
409+
410+
std::string Box_icbr::dump(Indent& indent) const
411+
{
412+
std::ostringstream sstr;
413+
sstr << Box::dump(indent);
414+
sstr << indent << "num_ranges: " << m_ranges.size() << "\n";
415+
for (ByteRange range: m_ranges) {
416+
sstr << indent << "range_offset: " << range.range_offset << ", range_size: " << range.range_size << "\n";
417+
}
418+
return sstr.str();
419+
}
420+
421+
Error Box_icbr::write(StreamWriter& writer) const
422+
{
423+
size_t box_start = reserve_box_header_space(writer);
424+
425+
writer.write32((uint32_t)m_ranges.size());
426+
for (ByteRange range: m_ranges) {
427+
if (get_version() == 1) {
428+
// TODO
429+
} else if (get_version() == 0) {
430+
writer.write32((uint32_t)range.range_offset);
431+
writer.write32((uint32_t)range.range_size);
432+
}
433+
}
434+
prepend_header(writer, box_start);
435+
436+
return Error::Ok;
437+
}

libheif/codecs/uncompressed_box.h

Lines changed: 78 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,22 @@ class Box_cmpd : public Box
7676
class Box_uncC : public FullBox
7777
{
7878
public:
79-
Box_uncC() {
79+
Box_uncC() :
80+
m_profile(0),
81+
m_sampling_type(sampling_mode_no_subsampling),
82+
m_interleave_type(interleave_mode_component),
83+
m_block_size(0),
84+
m_components_little_endian(false),
85+
m_block_pad_lsb(false),
86+
m_block_little_endian(false),
87+
m_block_reversed(false),
88+
m_pad_unknown(false),
89+
m_pixel_size(0),
90+
m_row_align_size(0),
91+
m_tile_align_size(0),
92+
m_num_tile_cols(1),
93+
m_num_tile_rows(1)
94+
{
8095
set_short_type(fourcc("uncC"));
8196
}
8297

@@ -220,4 +235,66 @@ class Box_uncC : public FullBox
220235
uint32_t m_num_tile_rows = 1;
221236
};
222237

238+
/**
239+
* Generic compression box (cmpC).
240+
*
241+
* This is from ISO/IEC 23001-17 Amd 2.
242+
*/
243+
class Box_cmpC : public FullBox
244+
{
245+
public:
246+
Box_cmpC()
247+
{
248+
set_short_type(fourcc("cmpC"));
249+
}
250+
251+
std::string dump(Indent&) const override;
252+
253+
uint32_t get_compression_type() const { return compression_type; }
254+
Error write(StreamWriter& writer) const override;
255+
256+
protected:
257+
Error parse(BitstreamRange& range) override;
258+
259+
uint32_t compression_type;
260+
bool can_decompress_contiguous_ranges;
261+
uint8_t compressed_range_type;
262+
};
263+
264+
/**
265+
* Item compressed byte range info (icbr).
266+
*
267+
* This is from ISO/IEC 23001-17 Amd 2.
268+
*/
269+
class Box_icbr : public FullBox
270+
{
271+
public:
272+
Box_icbr()
273+
{
274+
set_short_type(fourcc("icbr"));
275+
}
276+
277+
struct ByteRange
278+
{
279+
uint64_t range_offset;
280+
uint64_t range_size;
281+
};
282+
283+
const std::vector<ByteRange>& get_ranges() const { return m_ranges; }
284+
285+
void add_component(const ByteRange& range)
286+
{
287+
m_ranges.push_back(range);
288+
}
289+
290+
std::string dump(Indent&) const override;
291+
292+
Error write(StreamWriter& writer) const override;
293+
294+
protected:
295+
Error parse(BitstreamRange& range) override;
296+
297+
std::vector<ByteRange> m_ranges;
298+
};
299+
223300
#endif //LIBHEIF_UNCOMPRESSED_BOX_H

0 commit comments

Comments
 (0)