Coverage Report

Created: 2026-04-01 07:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libheif/libheif/codecs/uncompressed/unc_boxes.h
Line
Count
Source
1
/*
2
 * HEIF codec.
3
 * Copyright (c) 2023 Dirk Farin <dirk.farin@gmail.com>
4
 *
5
 * This file is part of libheif.
6
 *
7
 * libheif is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Lesser General Public License as
9
 * published by the Free Software Foundation, either version 3 of
10
 * the License, or (at your option) any later version.
11
 *
12
 * libheif is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public License
18
 * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
22
#ifndef LIBHEIF_UNC_BOXES_H
23
#define LIBHEIF_UNC_BOXES_H
24
25
#include "box.h"
26
#include "bitstream.h"
27
#include "pixelimage.h"
28
#include "unc_types.h"
29
#include "sequences/seq_boxes.h"
30
31
#include <cstdint>
32
#include <string>
33
#include <vector>
34
#include <memory>
35
#include <utility>
36
37
38
/**
39
 * Component definition (cmpd) box.
40
 */
41
class Box_cmpd : public Box
42
{
43
public:
44
  Box_cmpd()
45
0
  {
46
0
    set_short_type(fourcc("cmpd"));
47
0
  }
48
49
  std::string dump(Indent&) const override;
50
51
  Error write(StreamWriter& writer) const override;
52
53
0
  bool is_essential() const override { return true; }
54
55
  struct Component
56
  {
57
    uint16_t component_type;
58
    std::string component_type_uri;
59
60
0
    std::string get_component_type_name() const { return get_component_type_name(component_type); }
61
62
    static std::string get_component_type_name(uint16_t type);
63
  };
64
65
0
  const std::vector<Component>& get_components() const { return m_components; }
66
67
  bool has_component(heif_uncompressed_component_type) const;
68
69
  uint16_t add_component(const Component& component)
70
0
  {
71
0
    auto index = static_cast<uint16_t>(m_components.size());
72
0
    m_components.push_back(component);
73
0
    return index;
74
0
  }
75
76
  void set_components(const std::vector<uint16_t>&);
77
78
protected:
79
  Error parse(BitstreamRange& range, const heif_security_limits* limits) override;
80
81
  std::vector<Component> m_components;
82
};
83
84
/**
85
 * Uncompressed Frame Configuration Box
86
*/
87
class Box_uncC : public FullBox
88
{
89
public:
90
0
  Box_uncC() {
91
0
    set_short_type(fourcc("uncC"));
92
0
  }
93
94
0
  bool is_essential() const override { return true; }
95
96
  bool is_minimized() const
97
0
  {
98
0
    return m_profile != 0 && m_num_tile_cols==1 && m_num_tile_rows==1;
99
0
  }
100
101
  void derive_box_version() override
102
0
  {
103
0
    set_version(is_minimized() ? 1 : 0);
104
0
  }
105
106
  std::string dump(Indent&) const override;
107
108
  Error write(StreamWriter& writer) const override;
109
110
  struct Component
111
  {
112
    uint32_t component_index;
113
    uint16_t component_bit_depth; // range [1..256]
114
    uint8_t component_format;
115
    uint8_t component_align_size;
116
  };
117
118
0
  const std::vector<Component>& get_components() const { return m_components; }
119
120
  void add_component(Component component)
121
0
  {
122
0
    m_components.push_back(component);
123
0
  }
124
125
0
  uint32_t get_profile() const { return m_profile; }
126
127
  void set_profile(const uint32_t profile)
128
0
  {
129
0
    m_profile = profile;
130
0
  }
131
132
0
  uint8_t get_sampling_type() const { return m_sampling_type; }
133
134
  void set_sampling_type(const uint8_t sampling_type)
135
0
  {
136
0
    m_sampling_type = sampling_type;
137
0
  }
138
139
0
  uint8_t get_interleave_type() const { return m_interleave_type; }
140
141
  void set_interleave_type(const uint8_t interleave_type)
142
0
  {
143
0
    m_interleave_type = interleave_type;
144
0
  }
145
146
0
  uint8_t get_block_size() const { return m_block_size; }
147
148
  void set_block_size(const uint8_t block_size)
149
0
  {
150
0
    m_block_size = block_size;
151
0
  }
152
153
0
  bool is_components_little_endian() const { return m_components_little_endian; }
154
155
  void set_components_little_endian (const bool components_little_endian)
156
0
  {
157
0
    m_components_little_endian = components_little_endian;
158
0
  }
159
160
0
  bool is_block_pad_lsb() const { return m_block_pad_lsb; }
161
162
  void set_block_pad_lsb(const bool block_pad_lsb)
163
0
  {
164
0
    m_block_pad_lsb = block_pad_lsb;
165
0
  }
166
167
0
  bool is_block_little_endian() const { return m_block_little_endian; }
168
169
  void set_block_little_endian(const bool block_little_endian)
170
0
  {
171
0
    m_block_little_endian = block_little_endian;
172
0
  }
173
174
0
  bool is_block_reversed() const { return m_block_reversed; }
175
176
  void set_block_reversed(const bool block_reversed)
177
0
  {
178
0
    m_block_reversed = block_reversed;
179
0
  }
180
181
0
  bool is_pad_unknown() const { return m_pad_unknown; }
182
183
  void set_pad_unknown(const bool pad_unknown)
184
0
  {
185
0
    m_pad_unknown = pad_unknown;
186
0
  }
187
188
0
  uint32_t get_pixel_size() const { return m_pixel_size; }
189
190
  void set_pixel_size(const uint32_t pixel_size)
191
0
  {
192
0
    m_pixel_size = pixel_size;
193
0
  }
194
195
0
  uint32_t get_row_align_size() const { return m_row_align_size; }
196
197
  void set_row_align_size(const uint32_t row_align_size)
198
0
  {
199
0
    m_row_align_size = row_align_size;
200
0
  }
201
202
0
  uint32_t get_tile_align_size() const { return m_tile_align_size; }
203
204
  void set_tile_align_size(const uint32_t tile_align_size)
205
0
  {
206
0
    m_tile_align_size = tile_align_size;
207
0
  }
208
209
0
  uint32_t get_number_of_tile_columns() const { return m_num_tile_cols; }
210
211
  void set_number_of_tile_columns(const uint32_t num_tile_cols)
212
0
  {
213
0
    m_num_tile_cols = num_tile_cols;
214
0
  }
215
216
0
  uint32_t get_number_of_tile_rows() const { return m_num_tile_rows; }
217
218
  void set_number_of_tile_rows(const uint32_t num_tile_rows)
219
0
  {
220
0
    m_num_tile_rows = num_tile_rows;
221
0
  }
222
223
0
  uint32_t get_number_of_tiles() const { return m_num_tile_rows * m_num_tile_rows; }
224
225
0
  std::shared_ptr<Box_cmpd> get_synthetic_cmpd() const { return m_synthetic_cmpd; }
226
227
0
  void set_synthetic_cmpd(std::shared_ptr<Box_cmpd> cmpd) { m_synthetic_cmpd = std::move(cmpd); }
228
229
protected:
230
  Error parse(BitstreamRange& range, const heif_security_limits* limits) override;
231
232
  uint32_t m_profile = 0; // 0 = not compliant to any profile
233
234
  std::vector<Component> m_components;
235
  uint8_t m_sampling_type = sampling_mode_no_subsampling; // no subsampling
236
  uint8_t m_interleave_type = interleave_mode_pixel; // component interleaving
237
  uint8_t m_block_size = 0;
238
  bool m_components_little_endian = false;
239
  bool m_block_pad_lsb = false;
240
  bool m_block_little_endian = false;
241
  bool m_block_reversed = false;
242
  bool m_pad_unknown = false;
243
  uint32_t m_pixel_size = 0;
244
  uint32_t m_row_align_size = 0;
245
  uint32_t m_tile_align_size = 0;
246
  uint32_t m_num_tile_cols = 1;
247
  uint32_t m_num_tile_rows = 1;
248
249
  std::shared_ptr<Box_cmpd> m_synthetic_cmpd;
250
};
251
252
253
enum heif_cmpC_compressed_unit_type {
254
  heif_cmpC_compressed_unit_type_full_item = 0,
255
  heif_cmpC_compressed_unit_type_image = 1,
256
  heif_cmpC_compressed_unit_type_image_tile = 2,
257
  heif_cmpC_compressed_unit_type_image_row = 3,
258
  heif_cmpC_compressed_unit_type_image_pixel = 4
259
};
260
261
/**
262
 * Generic compression configuration box (cmpC).
263
 *
264
 * This is from ISO/IEC 23001-17 Amd 2.
265
 */
266
class Box_cmpC : public FullBox
267
{
268
public:
269
  Box_cmpC()
270
0
  {
271
0
    set_short_type(fourcc("cmpC"));
272
0
  }
273
274
  std::string dump(Indent&) const override;
275
276
0
  uint32_t get_compression_type() const { return m_compression_type; }
277
278
0
  heif_cmpC_compressed_unit_type get_compressed_unit_type() const { return m_compressed_unit_type; }
279
280
0
  void set_compression_type(uint32_t type) { m_compression_type = type; }
281
282
0
  void set_compressed_unit_type(heif_cmpC_compressed_unit_type type) { m_compressed_unit_type = type; }
283
284
  Error write(StreamWriter& writer) const override;
285
286
protected:
287
  Error parse(BitstreamRange& range, const heif_security_limits* limits) override;
288
289
  uint32_t m_compression_type = 0;
290
  heif_cmpC_compressed_unit_type m_compressed_unit_type = heif_cmpC_compressed_unit_type_full_item;
291
};
292
293
/**
294
 * Generically compressed units item info (icef).
295
 *
296
 * This describes the units of compressed data for an item.
297
 *
298
 * The box is from ISO/IEC 23001-17 Amd 2.
299
 */
300
class Box_icef : public FullBox
301
{
302
public:
303
  Box_icef()
304
0
  {
305
0
    set_short_type(fourcc("icef"));
306
0
  }
307
308
  struct CompressedUnitInfo
309
  {
310
    uint64_t unit_offset = 0;
311
    uint64_t unit_size = 0;
312
  };
313
314
0
  const std::vector<CompressedUnitInfo>& get_units() const { return m_unit_infos; }
315
316
  void add_component(const CompressedUnitInfo& unit_info)
317
0
  {
318
0
    m_unit_infos.push_back(unit_info);
319
0
  }
320
321
  void set_component(uint32_t tile_idx, const CompressedUnitInfo& unit_info)
322
0
  {
323
0
    if (tile_idx >= m_unit_infos.size()) {
324
0
      m_unit_infos.resize(tile_idx+1);
325
0
    }
326
0
327
0
    m_unit_infos[tile_idx] = unit_info;
328
0
  }
329
330
  std::string dump(Indent&) const override;
331
332
  Error write(StreamWriter& writer) const override;
333
334
protected:
335
  Error parse(BitstreamRange& range, const heif_security_limits* limits) override;
336
337
  std::vector<CompressedUnitInfo> m_unit_infos;
338
339
private:
340
  const uint8_t get_required_offset_code(uint64_t offset) const;
341
  const uint8_t get_required_size_code(uint64_t size) const;
342
};
343
344
345
/**
346
 * Component pattern definition box (cpat).
347
 *
348
 * The component pattern is used when representing filter array
349
 * data, such as Bayer. It defines the filter mask in the raw
350
 * data.
351
 *
352
 * This is from ISO/IEC 23001-17 Section 6.1.3.
353
 */
354
class Box_cpat : public FullBox
355
{
356
public:
357
  Box_cpat()
358
0
  {
359
0
    set_short_type(fourcc("cpat"));
360
0
  }
361
362
0
  uint16_t get_pattern_width() const { return m_pattern.pattern_width; }
363
364
0
  uint16_t get_pattern_height() const { return m_pattern.pattern_height; }
365
366
0
  const BayerPattern& get_pattern() const { return m_pattern; }
367
368
0
  void set_pattern(const BayerPattern& pattern) { m_pattern = pattern; }
369
370
  std::string dump(Indent&) const override;
371
372
  Error write(StreamWriter& writer) const override;
373
374
protected:
375
  Error parse(BitstreamRange& range, const heif_security_limits* limits) override;
376
377
  BayerPattern m_pattern;
378
};
379
380
381
/**
382
 * Polarization pattern definition box (splz).
383
 *
384
 * Describes the polarization filter array pattern on an image sensor.
385
 * Multiple splz boxes can exist (one per set of components with
386
 * different polarization filters).
387
 *
388
 * This is from ISO/IEC 23001-17 Section 6.1.5.
389
 */
390
class Box_splz : public FullBox
391
{
392
public:
393
0
  Box_splz() { set_short_type(fourcc("splz")); }
394
395
0
  const PolarizationPattern& get_pattern() const { return m_pattern; }
396
397
0
  void set_pattern(const PolarizationPattern& pattern) { m_pattern = pattern; }
398
399
  std::string dump(Indent&) const override;
400
401
  Error write(StreamWriter& writer) const override;
402
403
protected:
404
  Error parse(BitstreamRange& range, const heif_security_limits* limits) override;
405
406
  PolarizationPattern m_pattern;
407
};
408
409
410
/**
411
 * Sensor bad pixels map box (sbpm).
412
 *
413
 * Identifies bad pixels on a sensor for which at least one component
414
 * value is corrupted. Supports bad rows, bad columns, and individual
415
 * bad pixel coordinates.
416
 *
417
 * This is from ISO/IEC 23001-17 Section 6.1.7.
418
 */
419
class Box_sbpm : public FullBox
420
{
421
public:
422
0
  Box_sbpm() { set_short_type(fourcc("sbpm")); }
423
424
0
  const SensorBadPixelsMap& get_bad_pixels_map() const { return m_map; }
425
0
  void set_bad_pixels_map(const SensorBadPixelsMap& map) { m_map = map; }
426
427
  std::string dump(Indent&) const override;
428
  Error write(StreamWriter& writer) const override;
429
430
protected:
431
  Error parse(BitstreamRange& range, const heif_security_limits* limits) override;
432
433
  SensorBadPixelsMap m_map;
434
};
435
436
437
/**
438
 * Sensor non-uniformity correction box (snuc).
439
 *
440
 * Provides per-pixel gain and offset tables for sensor non-uniformity
441
 * correction. The correction equation is: y = nuc_gain * x + nuc_offset.
442
 *
443
 * This is from ISO/IEC 23001-17 Section 6.1.6.
444
 */
445
class Box_snuc : public FullBox
446
{
447
public:
448
0
  Box_snuc() { set_short_type(fourcc("snuc")); }
449
450
0
  const SensorNonUniformityCorrection& get_nuc() const { return m_nuc; }
451
0
  void set_nuc(const SensorNonUniformityCorrection& nuc) { m_nuc = nuc; }
452
453
  std::string dump(Indent&) const override;
454
  Error write(StreamWriter& writer) const override;
455
456
protected:
457
  Error parse(BitstreamRange& range, const heif_security_limits* limits) override;
458
459
  MemoryHandle m_memory_handle;
460
  SensorNonUniformityCorrection m_nuc;
461
};
462
463
464
/**
465
 * Chroma location box (cloc).
466
 *
467
 * Signals the chroma sample position for subsampled images.
468
 *
469
 * This is from ISO/IEC 23001-17 Section 6.1.4.
470
 */
471
class Box_cloc : public FullBox
472
{
473
public:
474
0
  Box_cloc() { set_short_type(fourcc("cloc")); }
475
476
0
  uint8_t get_chroma_location() const { return m_chroma_location; }
477
0
  void set_chroma_location(uint8_t loc) { m_chroma_location = loc; }
478
479
  std::string dump(Indent&) const override;
480
  Error write(StreamWriter& writer) const override;
481
482
protected:
483
  Error parse(BitstreamRange& range, const heif_security_limits* limits) override;
484
485
  uint8_t m_chroma_location = 0;
486
};
487
488
489
void fill_uncC_and_cmpd_from_profile(const std::shared_ptr<Box_uncC>& uncC,
490
                                     std::shared_ptr<Box_cmpd>& cmpd);
491
492
493
class Box_uncv : public Box_VisualSampleEntry
494
{
495
public:
496
  Box_uncv()
497
0
  {
498
0
    set_short_type(fourcc("uncv"));
499
0
  }
500
};
501
502
503
/**
504
 * GIMI ItemComponentContentIDProperty.
505
 *
506
 * A UUID-type item property that assigns a unique Content ID string
507
 * to each cmpd component of an image item.
508
 *
509
 * UUID: 9db9dd6e-373c-5a4e-8110-21fc83a911fd
510
 */
511
class Box_gimi_component_content_ids : public Box
512
{
513
public:
514
  Box_gimi_component_content_ids()
515
0
  {
516
0
    set_uuid_type(std::vector<uint8_t>{0x9d, 0xb9, 0xdd, 0x6e, 0x37, 0x3c, 0x5a, 0x4e,
517
0
                                       0x81, 0x10, 0x21, 0xfc, 0x83, 0xa9, 0x11, 0xfd});
518
0
  }
519
520
0
  bool is_essential() const override { return false; }
521
522
0
  bool is_transformative_property() const override { return false; }
523
524
  std::string dump(Indent&) const override;
525
526
0
  const char* debug_box_name() const override { return "GIMI Component Content IDs"; }
527
528
0
  const std::vector<std::string>& get_content_ids() const { return m_content_ids; }
529
530
0
  void set_content_ids(const std::vector<std::string>& ids) { m_content_ids = ids; }
531
532
0
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::ignorable; }
533
534
protected:
535
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
536
537
  Error write(StreamWriter& writer) const override;
538
539
private:
540
  std::vector<std::string> m_content_ids;
541
};
542
543
544
#endif //LIBHEIF_UNC_BOXES_H