Coverage Report

Created: 2025-10-12 06:18

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libheif/libheif/box.h
Line
Count
Source
1
/*
2
 * HEIF codec.
3
 * Copyright (c) 2017 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
#ifndef LIBHEIF_BOX_H
22
#define LIBHEIF_BOX_H
23
24
#include <cstdint>
25
#include "common_utils.h"
26
#include "libheif/heif.h"
27
#include "libheif/heif_experimental.h"
28
#include "libheif/heif_properties.h"
29
#include "libheif/heif_tai_timestamps.h"
30
#include <cinttypes>
31
#include <cstddef>
32
33
#include <utility>
34
#include <vector>
35
#include <string>
36
#include <memory>
37
#include <limits>
38
#include <istream>
39
#include <bitset>
40
#include <utility>
41
#include <optional>
42
43
#include "error.h"
44
#include "logging.h"
45
#include "bitstream.h"
46
47
#if !defined(__EMSCRIPTEN__) && !defined(_MSC_VER)
48
// std::array<bool> is not supported on some older compilers.
49
#define HAS_BOOL_ARRAY 1
50
#endif
51
52
/*
53
  constexpr uint32_t fourcc(const char* string)
54
  {
55
  return ((string[0]<<24) |
56
  (string[1]<<16) |
57
  (string[2]<< 8) |
58
  (string[3]));
59
  }
60
*/
61
62
63
class Fraction
64
{
65
public:
66
88.4k
  Fraction() = default;
67
68
  Fraction(int32_t num, int32_t den);
69
70
  // may only use values up to int32_t maximum
71
  Fraction(uint32_t num, uint32_t den);
72
73
  // Values will be reduced until they fit into int32_t.
74
  Fraction(int64_t num, int64_t den);
75
76
  Fraction operator+(const Fraction&) const;
77
78
  Fraction operator-(const Fraction&) const;
79
80
  Fraction operator+(int) const;
81
82
  Fraction operator-(int) const;
83
84
  Fraction operator/(int) const;
85
86
  int32_t round_down() const;
87
88
  int32_t round_up() const;
89
90
  int32_t round() const;
91
92
  bool is_valid() const;
93
94
0
  double to_double() const {
95
0
    return numerator / (double)denominator;
96
0
  }
97
98
  int32_t numerator = 0;
99
  int32_t denominator = 1;
100
};
101
102
103
inline std::ostream& operator<<(std::ostream& str, const Fraction& f)
104
0
{
105
0
  str << f.numerator << "/" << f.denominator;
106
0
  return str;
107
0
}
108
109
110
class BoxHeader
111
{
112
public:
113
  BoxHeader();
114
115
1.09M
  virtual ~BoxHeader() = default;
116
117
  constexpr static uint64_t size_until_end_of_file = 0;
118
119
2.62M
  uint64_t get_box_size() const { return m_size; }
120
121
1.08M
  bool has_fixed_box_size() const { return m_size != 0; }
122
123
2.11M
  uint32_t get_header_size() const { return m_header_size; }
124
125
808k
  uint32_t get_short_type() const { return m_type; }
126
127
  std::vector<uint8_t> get_type() const;
128
129
  std::string get_type_string() const;
130
131
171k
  virtual const char* debug_box_name() const { return nullptr; }
132
133
483k
  void set_short_type(uint32_t type) { m_type = type; }
134
135
136
  // should only be called if get_short_type == fourcc("uuid")
137
  std::vector<uint8_t> get_uuid_type() const;
138
139
  void set_uuid_type(const std::vector<uint8_t>&);
140
141
142
  Error parse_header(BitstreamRange& range);
143
144
  virtual std::string dump(Indent&) const;
145
146
147
0
  virtual bool is_full_box_header() const { return false; }
148
149
150
private:
151
  uint64_t m_size = 0;
152
153
  uint32_t m_type = 0;
154
  std::vector<uint8_t> m_uuid_type;
155
156
protected:
157
  uint32_t m_header_size = 0;
158
};
159
160
161
enum class BoxStorageMode {
162
  Undefined,
163
  Memory,
164
  Parsed,
165
  File
166
};
167
168
169
// Consequence of a box parse error
170
enum class parse_error_fatality {
171
  fatal,     // failure to parse this box leads to the associated item being unreable
172
  ignorable, // ignoring this box will lead to unexpected output, but may be better than nothing
173
  optional   // the box contains extra information that is not essential for viewing
174
};
175
176
177
class Box : public BoxHeader
178
{
179
public:
180
504k
  Box() = default;
181
182
  void set_short_header(const BoxHeader& hdr)
183
458k
  {
184
458k
    *(BoxHeader*) this = hdr;
185
458k
  }
186
187
  // header size without the FullBox fields (if applicable)
188
  int calculate_header_size(bool data64bit) const;
189
190
  static Error read(BitstreamRange& range, std::shared_ptr<Box>* box, const heif_security_limits*);
191
192
  virtual Error write(StreamWriter& writer) const;
193
194
  // check, which box version is required and set this in the (full) box header
195
0
  virtual void derive_box_version() {}
196
197
  void derive_box_version_recursive();
198
199
0
  virtual void patch_file_pointers(StreamWriter&, size_t offset) {}
200
201
  void patch_file_pointers_recursively(StreamWriter&, size_t offset);
202
203
  std::string dump(Indent&) const override;
204
205
  template<typename T> [[nodiscard]] std::shared_ptr<T> get_child_box() const
206
4.23k
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
20.7k
    for (auto& box : m_children) {
210
20.7k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
3.12k
        return typed_box;
212
3.12k
      }
213
20.7k
    }
214
215
1.11k
    return nullptr;
216
4.23k
  }
Unexecuted instantiation: std::__1::shared_ptr<Box_mvhd> Box::get_child_box<Box_mvhd>() const
std::__1::shared_ptr<Box_hdlr> Box::get_child_box<Box_hdlr>() const
Line
Count
Source
206
479
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
2.31k
    for (auto& box : m_children) {
210
2.31k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
204
        return typed_box;
212
204
      }
213
2.31k
    }
214
215
275
    return nullptr;
216
479
  }
std::__1::shared_ptr<Box_pitm> Box::get_child_box<Box_pitm>() const
Line
Count
Source
206
479
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
1.13k
    for (auto& box : m_children) {
210
1.13k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
476
        return typed_box;
212
476
      }
213
1.13k
    }
214
215
3
    return nullptr;
216
479
  }
std::__1::shared_ptr<Box_iprp> Box::get_child_box<Box_iprp>() const
Line
Count
Source
206
476
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
3.09k
    for (auto& box : m_children) {
210
3.09k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
472
        return typed_box;
212
472
      }
213
3.09k
    }
214
215
4
    return nullptr;
216
476
  }
std::__1::shared_ptr<Box_ipco> Box::get_child_box<Box_ipco>() const
Line
Count
Source
206
472
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
472
    for (auto& box : m_children) {
210
472
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
472
        return typed_box;
212
472
      }
213
472
    }
214
215
0
    return nullptr;
216
472
  }
std::__1::shared_ptr<Box_iloc> Box::get_child_box<Box_iloc>() const
Line
Count
Source
206
472
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
2.10k
    for (auto& box : m_children) {
210
2.10k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
472
        return typed_box;
212
472
      }
213
2.10k
    }
214
215
0
    return nullptr;
216
472
  }
std::__1::shared_ptr<Box_idat> Box::get_child_box<Box_idat>() const
Line
Count
Source
206
472
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
3.47k
    for (auto& box : m_children) {
210
3.47k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
122
        return typed_box;
212
122
      }
213
3.47k
    }
214
215
350
    return nullptr;
216
472
  }
std::__1::shared_ptr<Box_iref> Box::get_child_box<Box_iref>() const
Line
Count
Source
206
472
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
2.82k
    for (auto& box : m_children) {
210
2.82k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
336
        return typed_box;
212
336
      }
213
2.82k
    }
214
215
136
    return nullptr;
216
472
  }
std::__1::shared_ptr<Box_iinf> Box::get_child_box<Box_iinf>() const
Line
Count
Source
206
468
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
2.00k
    for (auto& box : m_children) {
210
2.00k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
445
        return typed_box;
212
445
      }
213
2.00k
    }
214
215
23
    return nullptr;
216
468
  }
std::__1::shared_ptr<Box_grpl> Box::get_child_box<Box_grpl>() const
Line
Count
Source
206
445
  {
207
    // TODO: we could remove the dynamic_cast<> by adding the fourcc type of each Box
208
    //       as a "constexpr uint32_t Box::short_type", compare to that and use static_cast<>
209
3.35k
    for (auto& box : m_children) {
210
3.35k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
211
125
        return typed_box;
212
125
      }
213
3.35k
    }
214
215
320
    return nullptr;
216
445
  }
Unexecuted instantiation: std::__1::shared_ptr<Box_infe> Box::get_child_box<Box_infe>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_tkhd> Box::get_child_box<Box_tkhd>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_edts> Box::get_child_box<Box_edts>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_elst> Box::get_child_box<Box_elst>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_mdia> Box::get_child_box<Box_mdia>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_tref> Box::get_child_box<Box_tref>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_minf> Box::get_child_box<Box_minf>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_mdhd> Box::get_child_box<Box_mdhd>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_stbl> Box::get_child_box<Box_stbl>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_stsd> Box::get_child_box<Box_stsd>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_stsc> Box::get_child_box<Box_stsc>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_stco> Box::get_child_box<Box_stco>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_stsz> Box::get_child_box<Box_stsz>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_stts> Box::get_child_box<Box_stts>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_auxi> Box::get_child_box<Box_auxi>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_taic> Box::get_child_box<Box_taic>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_meta> Box::get_child_box<Box_meta>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_uri const> Box::get_child_box<Box_uri const>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_hvcC> Box::get_child_box<Box_hvcC>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_av1C> Box::get_child_box<Box_av1C>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_vvcC> Box::get_child_box<Box_vvcC>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_avcC> Box::get_child_box<Box_avcC>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_uncC> Box::get_child_box<Box_uncC>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_cmpd> Box::get_child_box<Box_cmpd>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_j2kH> Box::get_child_box<Box_j2kH>() const
Unexecuted instantiation: std::__1::shared_ptr<Box_jpgC> Box::get_child_box<Box_jpgC>() const
217
218
  template<typename T> bool replace_child_box(const std::shared_ptr<T>& box)
219
0
  {
220
0
    for (auto & b : m_children) {
221
0
      if (std::dynamic_pointer_cast<T>(b) != nullptr) {
222
0
        b = box;
223
0
        return true;
224
0
      }
225
0
    }
226
227
0
    append_child_box(box);
228
0
    return false;
229
0
  }
Unexecuted instantiation: bool Box::replace_child_box<Box_pitm>(std::__1::shared_ptr<Box_pitm> const&)
Unexecuted instantiation: bool Box::replace_child_box<Box_ipco>(std::__1::shared_ptr<Box_ipco> const&)
Unexecuted instantiation: bool Box::replace_child_box<Box_ipma>(std::__1::shared_ptr<Box_ipma> const&)
Unexecuted instantiation: bool Box::replace_child_box<Box_iloc>(std::__1::shared_ptr<Box_iloc> const&)
Unexecuted instantiation: bool Box::replace_child_box<Box_iref>(std::__1::shared_ptr<Box_iref> const&)
230
231
  template<typename T>
232
  std::vector<std::shared_ptr<T>> get_child_boxes() const
233
917
  {
234
917
    std::vector<std::shared_ptr<T>> result;
235
12.2k
    for (auto& box : m_children) {
236
12.2k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
237
7.54k
        result.push_back(typed_box);
238
7.54k
      }
239
12.2k
    }
240
241
917
    return result;
242
917
  }
Unexecuted instantiation: std::__1::vector<std::__1::shared_ptr<Box_trak>, std::__1::allocator<std::__1::shared_ptr<Box_trak> > > Box::get_child_boxes<Box_trak>() const
std::__1::vector<std::__1::shared_ptr<Box_ipma>, std::__1::allocator<std::__1::shared_ptr<Box_ipma> > > Box::get_child_boxes<Box_ipma>() const
Line
Count
Source
233
472
  {
234
472
    std::vector<std::shared_ptr<T>> result;
235
1.11k
    for (auto& box : m_children) {
236
1.11k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
237
503
        result.push_back(typed_box);
238
503
      }
239
1.11k
    }
240
241
472
    return result;
242
472
  }
std::__1::vector<std::__1::shared_ptr<Box_infe>, std::__1::allocator<std::__1::shared_ptr<Box_infe> > > Box::get_child_boxes<Box_infe>() const
Line
Count
Source
233
445
  {
234
445
    std::vector<std::shared_ptr<T>> result;
235
11.1k
    for (auto& box : m_children) {
236
11.1k
      if (auto typed_box = std::dynamic_pointer_cast<T>(box)) {
237
7.04k
        result.push_back(typed_box);
238
7.04k
      }
239
11.1k
    }
240
241
445
    return result;
242
445
  }
Unexecuted instantiation: std::__1::vector<std::__1::shared_ptr<Box_saiz>, std::__1::allocator<std::__1::shared_ptr<Box_saiz> > > Box::get_child_boxes<Box_saiz>() const
Unexecuted instantiation: std::__1::vector<std::__1::shared_ptr<Box_saio>, std::__1::allocator<std::__1::shared_ptr<Box_saio> > > Box::get_child_boxes<Box_saio>() const
243
244
5.14k
  const std::vector<std::shared_ptr<Box>>& get_all_child_boxes() const { return m_children; }
245
246
  uint32_t append_child_box(const std::shared_ptr<Box>& box)
247
0
  {
248
0
    m_children.push_back(box);
249
0
    return (int) m_children.size() - 1;
250
0
  }
251
252
3.15k
  bool has_child_boxes() const { return !m_children.empty(); }
253
254
  bool remove_child_box(const std::shared_ptr<const Box>& box);
255
256
  virtual bool operator==(const Box& other) const;
257
258
  static bool equal(const std::shared_ptr<Box>& box1, const std::shared_ptr<Box>& box2);
259
260
0
  BoxStorageMode get_box_storage_mode() const { return m_storage_mode; }
261
262
4.90k
  void set_output_position(uint64_t pos) { m_output_position = pos; }
263
264
2.58k
  virtual parse_error_fatality get_parse_error_fatality() const { return parse_error_fatality::fatal; }
265
266
  // Note: this function may never be called for `ispe` items since it depends
267
  //       on the image item type whether the `ispe` is essential.
268
0
  virtual bool is_essential() const { return m_is_essential; } // only used for properties
269
270
0
  void set_is_essential(bool flag) { m_is_essential = flag; }
271
272
0
  virtual bool is_transformative_property() const { return false; } // only used for properties
273
274
protected:
275
  virtual Error parse(BitstreamRange& range, const heif_security_limits* limits);
276
277
  std::vector<std::shared_ptr<Box>> m_children;
278
279
  BoxStorageMode m_storage_mode = BoxStorageMode::Undefined;
280
281
  const static uint64_t INVALID_POSITION = 0xFFFFFFFFFFFFFFFF;
282
283
  uint64_t m_input_position = INVALID_POSITION;
284
  uint64_t m_output_position = INVALID_POSITION;
285
  std::vector<uint8_t> m_box_data; // including header
286
287
  std::string m_debug_box_type;
288
289
  bool m_is_essential = false;
290
291
  const static uint32_t READ_CHILDREN_ALL = 0xFFFFFFFF;
292
293
  Error read_children(BitstreamRange& range, uint32_t number /* READ_CHILDREN_ALL */, const heif_security_limits* limits);
294
295
  Error write_children(StreamWriter& writer) const;
296
297
  std::string dump_children(Indent&, bool with_index = false) const;
298
299
300
  // --- writing
301
302
  virtual size_t reserve_box_header_space(StreamWriter& writer, bool data64bit = false) const;
303
304
  Error prepend_header(StreamWriter&, size_t box_start, bool data64bit = false) const;
305
306
  virtual Error write_header(StreamWriter&, size_t total_box_size, bool data64bit = false) const;
307
};
308
309
310
class FullBox : public Box
311
{
312
public:
313
0
  bool is_full_box_header() const override { return true; }
314
315
  std::string dump(Indent& indent) const override;
316
317
0
  void derive_box_version() override { set_version(0); }
318
319
320
  Error parse_full_box_header(BitstreamRange& range);
321
322
826k
  uint8_t get_version() const { return m_version; }
323
324
0
  void set_version(uint8_t version) { m_version = version; }
325
326
2.48M
  uint32_t get_flags() const { return m_flags; }
327
328
919
  void set_flags(uint32_t flags) { m_flags = flags; }
329
330
protected:
331
332
  // --- writing
333
334
  size_t reserve_box_header_space(StreamWriter& writer, bool data64bit = false) const override;
335
336
  Error write_header(StreamWriter&, size_t total_size, bool data64bit = false) const override;
337
338
  Error unsupported_version_error(const char* box) const;
339
340
private:
341
  uint8_t m_version = 0;
342
  uint32_t m_flags = 0;
343
};
344
345
346
class Box_other : public Box
347
{
348
public:
349
  Box_other(uint32_t short_type)
350
149k
  {
351
149k
    set_short_type(short_type);
352
149k
  }
353
354
0
  const std::vector<uint8_t>& get_raw_data() const { return m_data; }
355
356
0
  void set_raw_data(const std::vector<uint8_t>& data) { m_data = data; }
357
358
  Error write(StreamWriter& writer) const override;
359
360
  std::string dump(Indent&) const override;
361
362
protected:
363
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
364
365
  std::vector<uint8_t> m_data;
366
};
367
368
369
370
class Box_Error : public Box
371
{
372
public:
373
  Box_Error(uint32_t box4cc, Error err, parse_error_fatality fatality)
374
36.4k
  {
375
36.4k
    set_short_type(fourcc("ERR "));
376
377
36.4k
    m_box_type_with_parse_error = box4cc;
378
36.4k
    m_error = std::move(err);
379
36.4k
    m_fatality = fatality;
380
36.4k
  }
381
382
0
  Error write(StreamWriter& writer) const override { return {heif_error_Usage_error, heif_suberror_Unspecified, "Cannot write dummy error box."}; }
383
384
  std::string dump(Indent&) const override;
385
386
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override;
387
388
351
  [[nodiscard]] Error get_error() const { return m_error; }
389
390
protected:
391
0
  Error parse(BitstreamRange& range, const heif_security_limits*) override { assert(false); return Error::Ok; }
392
393
  uint32_t m_box_type_with_parse_error;
394
  Error m_error;
395
  parse_error_fatality m_fatality;
396
};
397
398
399
400
401
class Box_ftyp : public Box
402
{
403
public:
404
  Box_ftyp()
405
19.3k
  {
406
19.3k
    set_short_type(fourcc("ftyp"));
407
19.3k
  }
408
409
  std::string dump(Indent&) const override;
410
411
8.48k
  const char* debug_box_name() const override { return "File Type"; }
412
413
  bool has_compatible_brand(uint32_t brand) const;
414
415
0
  std::vector<uint32_t> list_brands() const { return m_compatible_brands; }
416
417
0
  uint32_t get_major_brand() const { return m_major_brand; }
418
419
0
  void set_major_brand(heif_brand2 major_brand) { m_major_brand = major_brand; }
420
421
0
  uint32_t get_minor_version() const { return m_minor_version; }
422
423
0
  void set_minor_version(uint32_t minor_version) { m_minor_version = minor_version; }
424
425
0
  void clear_compatible_brands() { m_compatible_brands.clear(); }
426
427
  void add_compatible_brand(heif_brand2 brand);
428
429
  Error write(StreamWriter& writer) const override;
430
431
protected:
432
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
433
434
private:
435
  uint32_t m_major_brand = 0;
436
  uint32_t m_minor_version = 0;
437
  std::vector<heif_brand2> m_compatible_brands;
438
};
439
440
441
class Box_free : public Box
442
{
443
public:
444
  Box_free()
445
751
  {
446
751
    set_short_type(fourcc("free"));
447
751
  }
448
449
  std::string dump(Indent&) const override;
450
451
290
  const char* debug_box_name() const override { return "Free Space"; }
452
453
  Error write(StreamWriter& writer) const override;
454
455
protected:
456
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
457
};
458
459
460
class Box_meta : public FullBox
461
{
462
public:
463
  Box_meta()
464
9.65k
  {
465
9.65k
    set_short_type(fourcc("meta"));
466
9.65k
  }
467
468
  std::string dump(Indent&) const override;
469
470
1.86k
  const char* debug_box_name() const override { return "Metadata"; }
471
472
protected:
473
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
474
};
475
476
477
class Box_hdlr : public FullBox
478
{
479
public:
480
  Box_hdlr()
481
2.69k
  {
482
2.69k
    set_short_type(fourcc("hdlr"));
483
2.69k
  }
484
485
  std::string dump(Indent&) const override;
486
487
2.21k
  const char* debug_box_name() const override { return "Handler Reference"; }
488
489
204
  uint32_t get_handler_type() const { return m_handler_type; }
490
491
0
  void set_handler_type(uint32_t handler) { m_handler_type = handler; }
492
493
  Error write(StreamWriter& writer) const override;
494
495
0
  void set_name(std::string name) { m_name = std::move(name); }
496
497
protected:
498
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
499
500
private:
501
  uint32_t m_pre_defined = 0;
502
  uint32_t m_handler_type = fourcc("pict");
503
  uint32_t m_reserved[3] = {0,};
504
  std::string m_name;
505
};
506
507
508
class Box_pitm : public FullBox
509
{
510
public:
511
  Box_pitm()
512
2.84k
  {
513
2.84k
    set_short_type(fourcc("pitm"));
514
2.84k
  }
515
516
  std::string dump(Indent&) const override;
517
518
1.94k
  const char* debug_box_name() const override { return "Primary Item"; }
519
520
1.61k
  heif_item_id get_item_ID() const { return m_item_ID; }
521
522
0
  void set_item_ID(heif_item_id id) { m_item_ID = id; }
523
524
  void derive_box_version() override;
525
526
  Error write(StreamWriter& writer) const override;
527
528
protected:
529
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
530
531
private:
532
  heif_item_id m_item_ID = 0;
533
};
534
535
536
class Box_iloc : public FullBox
537
{
538
public:
539
  Box_iloc();
540
541
  ~Box_iloc() override;
542
543
  void set_use_tmp_file(bool flag);
544
545
  std::string dump(Indent&) const override;
546
547
800
  const char* debug_box_name() const override { return "Item Location"; }
548
549
  struct Extent
550
  {
551
    uint64_t index = 0;
552
    uint64_t offset = 0;
553
    uint64_t length = 0;
554
555
    std::vector<uint8_t> data; // only used when writing data
556
  };
557
558
  struct Item
559
  {
560
    heif_item_id item_ID = 0;
561
    uint8_t construction_method = 0; // >= version 1
562
    uint16_t data_reference_index = 0;
563
    uint64_t base_offset = 0;
564
565
    std::vector<Extent> extents;
566
  };
567
568
74
  const std::vector<Item>& get_items() const { return m_items; }
569
570
  Error read_data(heif_item_id item,
571
                  const std::shared_ptr<StreamReader>& istr,
572
                  const std::shared_ptr<class Box_idat>&,
573
                  std::vector<uint8_t>* dest,
574
                  const heif_security_limits* limits) const;
575
576
  // Note: size==std::numeric_limits<uint64_t>::max() reads the data until the end
577
  Error read_data(heif_item_id item,
578
                  const std::shared_ptr<StreamReader>& istr,
579
                  const std::shared_ptr<class Box_idat>&,
580
                  std::vector<uint8_t>* dest,
581
                  uint64_t offset, uint64_t size,
582
                  const heif_security_limits* limits) const;
583
584
0
  void set_min_version(uint8_t min_version) { m_user_defined_min_version = min_version; }
585
586
  // append bitstream data that will be written later (after iloc box)
587
  // TODO: use an enum for the construction method
588
  Error append_data(heif_item_id item_ID,
589
                    const std::vector<uint8_t>& data,
590
                    uint8_t construction_method = 0);
591
592
  Error replace_data(heif_item_id item_ID,
593
                     uint64_t output_offset,
594
                     const std::vector<uint8_t>& data,
595
                     uint8_t construction_method);
596
597
  // append bitstream data that already has been written (before iloc box)
598
  // Error write_mdat_before_iloc(heif_image_id item_ID,
599
  //                              std::vector<uint8_t>& data)
600
601
  // reserve data entry that will be written later
602
  // Error reserve_mdat_item(heif_image_id item_ID,
603
  //                         uint8_t construction_method,
604
  //                         uint32_t* slot_ID);
605
  // void patch_mdat_slot(uint32_t slot_ID, size_t start, size_t length);
606
607
  void derive_box_version() override;
608
609
  Error write(StreamWriter& writer) const override;
610
611
  Error write_mdat_after_iloc(StreamWriter& writer);
612
613
0
  void append_item(Item &item) { m_items.push_back(item); }
614
615
protected:
616
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
617
618
private:
619
  std::vector<Item> m_items;
620
621
  mutable size_t m_iloc_box_start = 0;
622
  uint8_t m_user_defined_min_version = 0;
623
  uint8_t m_offset_size = 0;
624
  uint8_t m_length_size = 0;
625
  uint8_t m_base_offset_size = 0;
626
  uint8_t m_index_size = 0;
627
628
  void patch_iloc_header(StreamWriter& writer) const;
629
630
  int m_idat_offset = 0; // only for writing: offset of next data array
631
632
  bool m_use_tmpfile = false;
633
  int m_tmpfile_fd = 0;
634
  char m_tmp_filename[20];
635
};
636
637
638
class Box_infe : public FullBox
639
{
640
public:
641
  Box_infe()
642
11.5k
  {
643
11.5k
    set_short_type(fourcc("infe"));
644
11.5k
  }
645
646
  std::string dump(Indent&) const override;
647
648
3.65k
  const char* debug_box_name() const override { return "Item Info Entry"; }
649
650
2.88k
  bool is_hidden_item() const { return m_hidden_item; }
651
652
  void set_hidden_item(bool hidden);
653
654
20.4k
  heif_item_id get_item_ID() const { return m_item_ID; }
655
656
0
  void set_item_ID(heif_item_id id) { m_item_ID = id; }
657
658
30.7k
  uint32_t get_item_type_4cc() const { return m_item_type_4cc; }
659
660
0
  void set_item_type_4cc(uint32_t type) { m_item_type_4cc = type; }
661
662
0
  void set_item_name(const std::string& name) { m_item_name = name; }
663
664
0
  const std::string& get_item_name() const { return m_item_name; }
665
666
9.55k
  const std::string& get_content_type() const { return m_content_type; }
667
668
14
  const std::string& get_content_encoding() const { return m_content_encoding; }
669
670
0
  void set_content_type(const std::string& content_type) { m_content_type = content_type; }
671
672
0
  void set_content_encoding(const std::string& content_encoding) { m_content_encoding = content_encoding; }
673
674
  void derive_box_version() override;
675
676
  Error write(StreamWriter& writer) const override;
677
678
3.11k
  const std::string& get_item_uri_type() const { return m_item_uri_type; }
679
680
0
  void set_item_uri_type(const std::string& uritype) { m_item_uri_type = uritype; }
681
682
protected:
683
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
684
685
private:
686
  heif_item_id m_item_ID = 0;
687
  uint16_t m_item_protection_index = 0;
688
689
  uint32_t m_item_type_4cc = 0;
690
  std::string m_item_name;
691
  std::string m_content_type;
692
  std::string m_content_encoding;
693
  std::string m_item_uri_type;
694
695
  // if set, this item should not be part of the presentation (i.e. hidden)
696
  bool m_hidden_item = false;
697
};
698
699
700
class Box_iinf : public FullBox
701
{
702
public:
703
  Box_iinf()
704
3.26k
  {
705
3.26k
    set_short_type(fourcc("iinf"));
706
3.26k
  }
707
708
  std::string dump(Indent&) const override;
709
710
2.23k
  const char* debug_box_name() const override { return "Item Information"; }
711
712
  void derive_box_version() override;
713
714
  Error write(StreamWriter& writer) const override;
715
716
protected:
717
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
718
719
private:
720
  //std::vector< std::shared_ptr<Box_infe> > m_iteminfos;
721
};
722
723
724
class Box_iprp : public Box
725
{
726
public:
727
  Box_iprp()
728
23.3k
  {
729
23.3k
    set_short_type(fourcc("iprp"));
730
23.3k
  }
731
732
  std::string dump(Indent&) const override;
733
734
19.1k
  const char* debug_box_name() const override { return "Item Properties"; }
735
736
protected:
737
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
738
};
739
740
741
class Box_ipco : public Box
742
{
743
public:
744
  Box_ipco()
745
8.80k
  {
746
8.80k
    set_short_type(fourcc("ipco"));
747
8.80k
  }
748
749
  uint32_t find_or_append_child_box(const std::shared_ptr<Box>& box);
750
751
  Error get_properties_for_item_ID(heif_item_id itemID,
752
                                   const std::shared_ptr<class Box_ipma>&,
753
                                   std::vector<std::shared_ptr<Box>>& out_properties) const;
754
755
  std::shared_ptr<Box> get_property_for_item_ID(heif_item_id itemID,
756
                                                const std::shared_ptr<class Box_ipma>&,
757
                                                uint32_t property_box_type) const;
758
759
  bool is_property_essential_for_item(heif_item_id itemId,
760
                                      const std::shared_ptr<const class Box>& property,
761
                                      const std::shared_ptr<class Box_ipma>&) const;
762
763
  std::string dump(Indent&) const override;
764
765
7.48k
  const char* debug_box_name() const override { return "Item Property Container"; }
766
767
protected:
768
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
769
};
770
771
772
class Box_ispe : public FullBox
773
{
774
public:
775
  Box_ispe()
776
2.72k
  {
777
2.72k
    set_short_type(fourcc("ispe"));
778
2.72k
  }
779
780
2.11k
  uint32_t get_width() const { return m_image_width; }
781
782
2.11k
  uint32_t get_height() const { return m_image_height; }
783
784
  void set_size(uint32_t width, uint32_t height)
785
0
  {
786
0
    m_image_width = width;
787
0
    m_image_height = height;
788
0
  }
789
790
  std::string dump(Indent&) const override;
791
792
1.46k
  const char* debug_box_name() const override { return "Image Spatial Extents"; }
793
794
  Error write(StreamWriter& writer) const override;
795
796
  bool operator==(const Box& other) const override;
797
798
  // Note: this depends on the image item type. Never call this for an `ispe` property.
799
0
  bool is_essential() const override { assert(false); return false; }
800
801
protected:
802
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
803
804
private:
805
  uint32_t m_image_width = 0;
806
  uint32_t m_image_height = 0;
807
};
808
809
810
class Box_ipma : public FullBox
811
{
812
public:
813
  Box_ipma()
814
2.84k
  {
815
2.84k
    set_short_type(fourcc("ipma"));
816
2.84k
  }
817
818
  std::string dump(Indent&) const override;
819
820
2.05k
  const char* debug_box_name() const override { return "Item Property Association"; }
821
822
  struct PropertyAssociation
823
  {
824
    bool essential;
825
    uint16_t property_index;
826
  };
827
828
  const std::vector<PropertyAssociation>* get_properties_for_item_ID(heif_item_id itemID) const;
829
830
  bool is_property_essential_for_item(heif_item_id itemId, int propertyIndex) const;
831
832
  void add_property_for_item_ID(heif_item_id itemID,
833
                                PropertyAssociation assoc);
834
835
  void derive_box_version() override;
836
837
  Error write(StreamWriter& writer) const override;
838
839
  void insert_entries_from_other_ipma_box(const Box_ipma& b);
840
841
  // sorts properties such that descriptive properties precede the transformative properties
842
  void sort_properties(const std::shared_ptr<Box_ipco>&);
843
844
protected:
845
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
846
847
  struct Entry
848
  {
849
    heif_item_id item_ID;
850
    std::vector<PropertyAssociation> associations;
851
  };
852
853
  std::vector<Entry> m_entries;
854
};
855
856
857
class Box_auxC : public FullBox
858
{
859
public:
860
  Box_auxC()
861
1.07k
  {
862
1.07k
    set_short_type(fourcc("auxC"));
863
1.07k
  }
864
865
215
  const std::string& get_aux_type() const { return m_aux_type; }
866
867
0
  void set_aux_type(const std::string& type) { m_aux_type = type; }
868
869
7
  const std::vector<uint8_t>& get_subtypes() const { return m_aux_subtypes; }
870
871
0
  bool is_essential() const override { return true; }
872
873
  std::string dump(Indent&) const override;
874
875
570
  const char* debug_box_name() const override { return "Image Properties for Auxiliary Images"; }
876
877
protected:
878
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
879
880
  Error write(StreamWriter& writer) const override;
881
882
private:
883
  std::string m_aux_type;
884
  std::vector<uint8_t> m_aux_subtypes;
885
};
886
887
888
class Box_irot : public Box
889
{
890
public:
891
  Box_irot()
892
7.55k
  {
893
7.55k
    set_short_type(fourcc("irot"));
894
7.55k
  }
895
896
0
  bool is_essential() const override { return true; }
897
898
0
  bool is_transformative_property() const override { return true; }
899
900
  std::string dump(Indent&) const override;
901
902
6.34k
  const char* debug_box_name() const override { return "Image Rotation"; }
903
904
360
  int get_rotation_ccw() const { return m_rotation; }
905
906
  // Only these multiples of 90 are allowed: 0, 90, 180, 270.
907
0
  void set_rotation_ccw(int rot) { m_rotation = rot; }
908
909
228
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::ignorable; }
910
911
protected:
912
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
913
914
  Error write(StreamWriter& writer) const override;
915
916
private:
917
  int m_rotation = 0; // in degrees (CCW)
918
};
919
920
921
class Box_imir : public Box
922
{
923
public:
924
  Box_imir()
925
1.88k
  {
926
1.88k
    set_short_type(fourcc("imir"));
927
1.88k
  }
928
929
0
  bool is_essential() const override { return true; }
930
931
0
  bool is_transformative_property() const override { return true; }
932
933
0
  heif_transform_mirror_direction get_mirror_direction() const { return m_axis; }
934
935
0
  void set_mirror_direction(heif_transform_mirror_direction dir) { m_axis = dir; }
936
937
  std::string dump(Indent&) const override;
938
939
1.56k
  const char* debug_box_name() const override { return "Image Mirroring"; }
940
941
63
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::ignorable; }
942
943
protected:
944
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
945
946
  Error write(StreamWriter& writer) const override;
947
948
private:
949
  heif_transform_mirror_direction m_axis = heif_transform_mirror_direction_vertical;
950
};
951
952
953
class Box_clap : public Box
954
{
955
public:
956
  Box_clap()
957
22.1k
  {
958
22.1k
    set_short_type(fourcc("clap"));
959
22.1k
  }
960
961
0
  bool is_essential() const override { return true; }
962
963
0
  bool is_transformative_property() const override { return true; }
964
965
  std::string dump(Indent&) const override;
966
967
419
  const char* debug_box_name() const override { return "Clean Aperture"; }
968
969
  int left_rounded(uint32_t image_width) const;  // first column
970
  int right_rounded(uint32_t image_width) const; // last column that is part of the cropped image
971
  int top_rounded(uint32_t image_height) const;   // first row
972
  int bottom_rounded(uint32_t image_height) const; // last row included in the cropped image
973
974
  double left(int image_width) const;
975
  double top(int image_height) const;
976
977
  int get_width_rounded() const;
978
979
  int get_height_rounded() const;
980
981
  void set(uint32_t clap_width, uint32_t clap_height,
982
           uint32_t image_width, uint32_t image_height);
983
984
21.4k
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::ignorable; }
985
986
protected:
987
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
988
989
  Error write(StreamWriter& writer) const override;
990
991
private:
992
  Fraction m_clean_aperture_width;
993
  Fraction m_clean_aperture_height;
994
  Fraction m_horizontal_offset;
995
  Fraction m_vertical_offset;
996
};
997
998
999
class Box_iref : public FullBox
1000
{
1001
public:
1002
  Box_iref()
1003
15.2k
  {
1004
15.2k
    set_short_type(fourcc("iref"));
1005
15.2k
  }
1006
1007
  struct Reference
1008
  {
1009
    BoxHeader header;
1010
1011
    heif_item_id from_item_ID;
1012
    std::vector<heif_item_id> to_item_ID;
1013
  };
1014
1015
1016
  std::string dump(Indent&) const override;
1017
1018
12.9k
  const char* debug_box_name() const override { return "Item Reference"; }
1019
1020
  bool has_references(heif_item_id itemID) const;
1021
1022
  std::vector<heif_item_id> get_references(heif_item_id itemID, uint32_t ref_type) const;
1023
1024
  std::vector<Reference> get_references_from(heif_item_id itemID) const;
1025
1026
  void add_references(heif_item_id from_id, uint32_t type, const std::vector<heif_item_id>& to_ids);
1027
1028
  void overwrite_reference(heif_item_id from_id, uint32_t type, uint32_t reference_idx, heif_item_id to_item);
1029
1030
protected:
1031
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1032
1033
  Error write(StreamWriter& writer) const override;
1034
1035
  void derive_box_version() override;
1036
1037
  Error check_for_double_references() const;
1038
1039
private:
1040
  std::vector<Reference> m_references;
1041
};
1042
1043
1044
class Box_idat : public Box
1045
{
1046
public:
1047
  std::string dump(Indent&) const override;
1048
1049
5.61k
  const char* debug_box_name() const override { return "Item Data"; }
1050
1051
  Error read_data(const std::shared_ptr<StreamReader>& istr,
1052
                  uint64_t start, uint64_t length,
1053
                  std::vector<uint8_t>& out_data,
1054
                  const heif_security_limits* limits) const;
1055
1056
  int append_data(const std::vector<uint8_t>& data)
1057
0
  {
1058
0
    auto pos = m_data_for_writing.size();
1059
0
1060
0
    m_data_for_writing.insert(m_data_for_writing.end(),
1061
0
                              data.begin(),
1062
0
                              data.end());
1063
0
1064
0
    return (int) pos;
1065
0
  }
1066
1067
  Error write(StreamWriter& writer) const override;
1068
1069
protected:
1070
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1071
1072
  std::streampos m_data_start_pos;
1073
1074
  std::vector<uint8_t> m_data_for_writing;
1075
};
1076
1077
1078
class Box_grpl : public Box
1079
{
1080
public:
1081
  Box_grpl()
1082
1.57k
  {
1083
1.57k
    set_short_type(fourcc("grpl"));
1084
1.57k
  }
1085
1086
  std::string dump(Indent&) const override;
1087
1088
1.12k
  const char* debug_box_name() const override { return "Groups List"; }
1089
1090
protected:
1091
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1092
};
1093
1094
1095
class Box_EntityToGroup : public FullBox
1096
{
1097
public:
1098
  std::string dump(Indent&) const override;
1099
1100
  Error write(StreamWriter& writer) const override;
1101
1102
0
  void set_group_id(heif_entity_group_id id) { group_id = id; }
1103
1104
0
  heif_entity_group_id get_group_id() const { return group_id; }
1105
1106
0
  void set_item_ids(const std::vector<heif_item_id>& ids) { entity_ids = ids; }
1107
1108
0
  const std::vector<heif_item_id>& get_item_ids() const { return entity_ids; }
1109
1110
protected:
1111
  heif_entity_group_id group_id = 0;
1112
  std::vector<heif_item_id> entity_ids;
1113
1114
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1115
1116
  void write_entity_group_ids(StreamWriter& writer) const;
1117
};
1118
1119
1120
class Box_ster : public Box_EntityToGroup
1121
{
1122
public:
1123
  Box_ster()
1124
605
  {
1125
605
    set_short_type(fourcc("ster"));
1126
605
  }
1127
1128
  std::string dump(Indent&) const override;
1129
1130
485
  const char* debug_box_name() const override { return "Stereo pair"; }
1131
1132
0
  heif_item_id get_left_image() const { return entity_ids[0]; }
1133
0
  heif_item_id get_right_image() const { return entity_ids[1]; }
1134
1135
protected:
1136
1137
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1138
};
1139
1140
1141
class Box_pymd : public Box_EntityToGroup
1142
{
1143
public:
1144
  Box_pymd()
1145
921
  {
1146
921
    set_short_type(fourcc("pymd"));
1147
921
  }
1148
1149
  std::string dump(Indent&) const override;
1150
1151
655
  const char* debug_box_name() const override { return "Image pyramid group"; }
1152
1153
  Error write(StreamWriter& writer) const override;
1154
1155
  struct LayerInfo {
1156
    uint16_t layer_binning;
1157
    uint16_t tiles_in_layer_row_minus1;
1158
    uint16_t tiles_in_layer_column_minus1;
1159
  };
1160
1161
  void set_layers(uint16_t _tile_size_x,
1162
                  uint16_t _tile_size_y,
1163
                  const std::vector<LayerInfo>& layers,
1164
                  const std::vector<heif_item_id>& layer_item_ids) // low to high resolution
1165
0
  {
1166
0
    set_item_ids(layer_item_ids);
1167
0
    m_layer_infos = layers;
1168
0
    tile_size_x = _tile_size_x;
1169
0
    tile_size_y = _tile_size_y;
1170
0
  }
1171
1172
0
  const std::vector<LayerInfo>& get_layers() const { return m_layer_infos; }
1173
1174
145
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::ignorable; }
1175
1176
protected:
1177
  uint16_t tile_size_x = 0;
1178
  uint16_t tile_size_y = 0;
1179
1180
  std::vector<LayerInfo> m_layer_infos;
1181
1182
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1183
};
1184
1185
1186
1187
1188
class Box_dinf : public Box
1189
{
1190
public:
1191
  std::string dump(Indent&) const override;
1192
1193
6.84k
  const char* debug_box_name() const override { return "Data Information"; }
1194
1195
protected:
1196
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1197
};
1198
1199
1200
class Box_dref : public FullBox
1201
{
1202
public:
1203
  std::string dump(Indent&) const override;
1204
1205
908
  const char* debug_box_name() const override { return "Data Reference"; }
1206
1207
protected:
1208
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1209
};
1210
1211
1212
class Box_url : public FullBox
1213
{
1214
public:
1215
  std::string dump(Indent&) const override;
1216
1217
2.93k
  const char* debug_box_name() const override { return "Data Entry URL"; }
1218
1219
0
  bool is_same_file() const { return m_location.empty(); }
1220
1221
protected:
1222
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1223
1224
  std::string m_location;
1225
};
1226
1227
class Box_pixi : public FullBox
1228
{
1229
public:
1230
  Box_pixi()
1231
2.95k
  {
1232
2.95k
    set_short_type(fourcc("pixi"));
1233
2.95k
  }
1234
1235
0
  int get_num_channels() const { return (int) m_bits_per_channel.size(); }
1236
1237
0
  int get_bits_per_channel(int channel) const { return m_bits_per_channel[channel]; }
1238
1239
  void add_channel_bits(uint8_t c)
1240
0
  {
1241
0
    m_bits_per_channel.push_back(c);
1242
0
  }
1243
1244
  std::string dump(Indent&) const override;
1245
1246
1.79k
  const char* debug_box_name() const override { return "Pixel Information"; }
1247
1248
  Error write(StreamWriter& writer) const override;
1249
1250
551
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1251
1252
protected:
1253
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1254
1255
private:
1256
  std::vector<uint8_t> m_bits_per_channel;
1257
};
1258
1259
1260
class Box_pasp : public Box
1261
{
1262
public:
1263
  Box_pasp()
1264
14.2k
  {
1265
14.2k
    set_short_type(fourcc("pasp"));
1266
14.2k
  }
1267
1268
  uint32_t hSpacing = 1;
1269
  uint32_t vSpacing = 1;
1270
1271
  std::string dump(Indent&) const override;
1272
1273
12.4k
  const char* debug_box_name() const override { return "Pixel Aspect Ratio"; }
1274
1275
  Error write(StreamWriter& writer) const override;
1276
1277
98
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1278
1279
protected:
1280
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1281
};
1282
1283
1284
class Box_lsel : public Box
1285
{
1286
public:
1287
  Box_lsel()
1288
6.88k
  {
1289
6.88k
    set_short_type(fourcc("lsel"));
1290
6.88k
  }
1291
1292
  uint16_t layer_id = 0;
1293
1294
  std::string dump(Indent&) const override;
1295
1296
5.04k
  const char* debug_box_name() const override { return "Layer Selection"; }
1297
1298
  Error write(StreamWriter& writer) const override;
1299
1300
1.09k
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1301
1302
protected:
1303
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1304
};
1305
1306
1307
class Box_clli : public Box
1308
{
1309
public:
1310
  Box_clli()
1311
2.57k
  {
1312
2.57k
    set_short_type(fourcc("clli"));
1313
1314
2.57k
    clli.max_content_light_level = 0;
1315
2.57k
    clli.max_pic_average_light_level = 0;
1316
2.57k
  }
1317
1318
  heif_content_light_level clli;
1319
1320
  std::string dump(Indent&) const override;
1321
1322
1.92k
  const char* debug_box_name() const override { return "Content Light Level Information"; }
1323
1324
  Error write(StreamWriter& writer) const override;
1325
1326
130
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1327
1328
protected:
1329
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1330
};
1331
1332
1333
class Box_mdcv : public Box
1334
{
1335
public:
1336
  Box_mdcv();
1337
1338
  heif_mastering_display_colour_volume mdcv;
1339
1340
  std::string dump(Indent&) const override;
1341
1342
490
  const char* debug_box_name() const override { return "Master Display Colour Volume"; }
1343
1344
  Error write(StreamWriter& writer) const override;
1345
1346
389
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1347
1348
protected:
1349
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1350
};
1351
1352
1353
class Box_amve : public Box
1354
{
1355
public:
1356
  Box_amve();
1357
1358
  heif_ambient_viewing_environment amve;
1359
1360
  std::string dump(Indent&) const override;
1361
1362
431
  const char* debug_box_name() const override { return "Ambient Viewing Environment"; }
1363
1364
  Error write(StreamWriter& writer) const override;
1365
1366
1.25k
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1367
1368
protected:
1369
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1370
};
1371
1372
1373
class Box_cclv : public Box
1374
{
1375
public:
1376
  Box_cclv();
1377
1378
0
  bool ccv_primaries_are_valid() const { return m_ccv_primaries_valid; }
1379
0
  int32_t get_ccv_primary_x0() const { return m_ccv_primaries_x[0]; }
1380
0
  int32_t get_ccv_primary_y0() const { return m_ccv_primaries_y[0]; }
1381
0
  int32_t get_ccv_primary_x1() const { return m_ccv_primaries_x[1]; }
1382
0
  int32_t get_ccv_primary_y1() const { return m_ccv_primaries_y[1]; }
1383
0
  int32_t get_ccv_primary_x2() const { return m_ccv_primaries_x[2]; }
1384
0
  int32_t get_ccv_primary_y2() const { return m_ccv_primaries_y[2]; }
1385
  void set_primaries(int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t x2, int32_t y2);
1386
1387
0
  bool min_luminance_is_valid() const { return m_ccv_min_luminance_value.has_value(); }
1388
0
  uint32_t get_min_luminance() const { return *m_ccv_min_luminance_value; }
1389
0
  void set_min_luminance(uint32_t luminance) { m_ccv_min_luminance_value = luminance; }
1390
1391
0
  bool max_luminance_is_valid() const { return m_ccv_max_luminance_value.has_value(); }
1392
0
  uint32_t get_max_luminance() const { return *m_ccv_max_luminance_value; }
1393
0
  void set_max_luminance(uint32_t luminance) { m_ccv_max_luminance_value = luminance; }
1394
1395
0
  bool avg_luminance_is_valid() const { return m_ccv_avg_luminance_value.has_value(); }
1396
0
  uint32_t get_avg_luminance() const { return *m_ccv_avg_luminance_value; }
1397
0
  void set_avg_luminance(uint32_t luminance) { m_ccv_avg_luminance_value = luminance; }
1398
1399
  std::string dump(Indent&) const override;
1400
1401
  // TODO const char* debug_box_name() const override { return ""; }
1402
1403
  Error write(StreamWriter& writer) const override;
1404
1405
0
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1406
1407
protected:
1408
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1409
1410
private:
1411
  bool m_ccv_primaries_valid = false;
1412
  int32_t m_ccv_primaries_x[3] {};
1413
  int32_t m_ccv_primaries_y[3] {};
1414
1415
  std::optional<uint32_t> m_ccv_min_luminance_value;
1416
  std::optional<uint32_t> m_ccv_max_luminance_value;
1417
  std::optional<uint32_t> m_ccv_avg_luminance_value;
1418
};
1419
1420
1421
class Box_cmin : public FullBox
1422
{
1423
public:
1424
  Box_cmin()
1425
5.45k
  {
1426
5.45k
    set_short_type(fourcc("cmin"));
1427
5.45k
  }
1428
1429
  struct AbsoluteIntrinsicMatrix;
1430
1431
  struct RelativeIntrinsicMatrix
1432
  {
1433
    double focal_length_x = 0;
1434
    double principal_point_x = 0;
1435
    double principal_point_y = 0;
1436
1437
    bool is_anisotropic = false;
1438
    double focal_length_y = 0;
1439
    double skew = 0;
1440
1441
    void compute_focal_length(int image_width, int image_height,
1442
                              double& out_focal_length_x, double& out_focal_length_y) const;
1443
1444
    void compute_principal_point(int image_width, int image_height,
1445
                                 double& out_principal_point_x, double& out_principal_point_y) const;
1446
1447
    struct AbsoluteIntrinsicMatrix to_absolute(int image_width, int image_height) const;
1448
  };
1449
1450
  struct AbsoluteIntrinsicMatrix
1451
  {
1452
    double focal_length_x;
1453
    double focal_length_y;
1454
    double principal_point_x;
1455
    double principal_point_y;
1456
    double skew = 0;
1457
1458
0
    void apply_clap(const Box_clap* clap, int image_width, int image_height) {
1459
0
      principal_point_x -= clap->left(image_width);
1460
0
      principal_point_y -= clap->top(image_height);
1461
0
    }
1462
1463
0
    void apply_imir(const Box_imir* imir, int image_width, int image_height) {
1464
0
      switch (imir->get_mirror_direction()) {
1465
0
        case heif_transform_mirror_direction_horizontal:
1466
0
          focal_length_x *= -1;
1467
0
          skew *= -1;
1468
0
          principal_point_x = image_width - 1 - principal_point_x;
1469
0
          break;
1470
0
        case heif_transform_mirror_direction_vertical:
1471
0
          focal_length_y *= -1;
1472
0
          principal_point_y = image_height - 1 - principal_point_y;
1473
0
          break;
1474
0
        case heif_transform_mirror_direction_invalid:
1475
0
          break;
1476
0
      }
1477
0
    }
1478
  };
1479
1480
  std::string dump(Indent&) const override;
1481
1482
2.67k
  const char* debug_box_name() const override { return "Camera Intrinsic Matrix"; }
1483
1484
0
  RelativeIntrinsicMatrix get_intrinsic_matrix() const { return m_matrix; }
1485
1486
  void set_intrinsic_matrix(RelativeIntrinsicMatrix matrix);
1487
1488
2.46k
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1489
1490
protected:
1491
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1492
1493
  Error write(StreamWriter& writer) const override;
1494
1495
private:
1496
  RelativeIntrinsicMatrix m_matrix;
1497
1498
  uint32_t m_denominatorShift = 0;
1499
  uint32_t m_skewDenominatorShift = 0;
1500
};
1501
1502
1503
class Box_cmex : public FullBox
1504
{
1505
public:
1506
  Box_cmex()
1507
10.2k
  {
1508
10.2k
    set_short_type(fourcc("cmex"));
1509
10.2k
  }
1510
1511
  struct ExtrinsicMatrix
1512
  {
1513
    // in micrometers (um)
1514
    int32_t pos_x = 0;
1515
    int32_t pos_y = 0;
1516
    int32_t pos_z = 0;
1517
1518
    bool rotation_as_quaternions = true;
1519
    bool orientation_is_32bit = false;
1520
1521
    double quaternion_x = 0;
1522
    double quaternion_y = 0;
1523
    double quaternion_z = 0;
1524
    double quaternion_w = 1.0;
1525
1526
    // rotation angle in degrees
1527
    double rotation_yaw = 0;   //  [-180 ; 180)
1528
    double rotation_pitch = 0; //  [-90 ; 90]
1529
    double rotation_roll = 0;  //  [-180 ; 180)
1530
1531
    uint32_t world_coordinate_system_id = 0;
1532
1533
    // Returns rotation matrix in row-major order.
1534
    std::array<double,9> calculate_rotation_matrix() const;
1535
  };
1536
1537
  std::string dump(Indent&) const override;
1538
1539
4.40k
  const char* debug_box_name() const override { return "Camera Extrinsic Matrix"; }
1540
1541
0
  ExtrinsicMatrix get_extrinsic_matrix() const { return m_matrix; }
1542
1543
  Error set_extrinsic_matrix(ExtrinsicMatrix matrix);
1544
1545
4.31k
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1546
1547
protected:
1548
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1549
1550
  Error write(StreamWriter& writer) const override;
1551
1552
private:
1553
  ExtrinsicMatrix m_matrix;
1554
1555
  bool m_has_pos_x = false;
1556
  bool m_has_pos_y = false;
1557
  bool m_has_pos_z = false;
1558
  bool m_has_orientation = false;
1559
  bool m_has_world_coordinate_system_id = false;
1560
1561
  enum Flags
1562
  {
1563
    pos_x_present = 0x01,
1564
    pos_y_present = 0x02,
1565
    pos_z_present = 0x04,
1566
    orientation_present = 0x08,
1567
    rot_large_field_size = 0x10,
1568
    id_present = 0x20
1569
  };
1570
};
1571
1572
1573
1574
1575
/**
1576
 * User Description property.
1577
 *
1578
 * Permits the association of items or entity groups with a user-defined name, description and tags;
1579
 * there may be multiple udes properties, each with a different language code.
1580
 *
1581
 * See ISO/IEC 23008-12:2022(E) Section 6.5.20.
1582
 */
1583
class Box_udes : public FullBox
1584
{
1585
public:
1586
  Box_udes()
1587
4.54k
  {
1588
4.54k
    set_short_type(fourcc("udes"));
1589
4.54k
  }
1590
1591
  std::string dump(Indent&) const override;
1592
1593
2.55k
  const char* debug_box_name() const override { return "User Description"; }
1594
1595
  Error write(StreamWriter& writer) const override;
1596
1597
  /**
1598
   * Language tag.
1599
   *
1600
   * An RFC 5646 compliant language identifier for the language of the text contained in the other properties.
1601
   * Examples: "en-AU", "de-DE", or "zh-CN“.
1602
   * When is empty, the language is unknown or not undefined.
1603
   */
1604
0
  std::string get_lang() const { return m_lang; }
1605
1606
  /**
1607
   * Set the language tag.
1608
   *
1609
   * An RFC 5646 compliant language identifier for the language of the text contained in the other properties.
1610
   * Examples: "en-AU", "de-DE", or "zh-CN“.
1611
   */
1612
0
  void set_lang(const std::string lang) { m_lang = lang; }
1613
1614
  /**
1615
   * Name.
1616
   *
1617
   * Human readable name for the item or group being described.
1618
   * May be empty, indicating no name is applicable.
1619
   */
1620
0
  std::string get_name() const { return m_name; }
1621
1622
  /**
1623
  * Set the name.
1624
  *
1625
  * Human readable name for the item or group being described.
1626
  */
1627
0
  void set_name(const std::string name) { m_name = name; }
1628
1629
  /**
1630
   * Description.
1631
   *
1632
   * Human readable description for the item or group.
1633
   * May be empty, indicating no description has been provided.
1634
   */
1635
0
  std::string get_description() const { return m_description; }
1636
1637
  /**
1638
   * Set the description.
1639
   *
1640
   * Human readable description for the item or group.
1641
   */
1642
0
  void set_description(const std::string description) { m_description = description; }
1643
1644
  /**
1645
   * Tags.
1646
   *
1647
   * Comma separated user defined tags applicable to the item or group.
1648
   * May be empty, indicating no tags have been assigned.
1649
   */
1650
0
  std::string get_tags() const { return m_tags; }
1651
1652
  /**
1653
   * Set the tags.
1654
   *
1655
   * Comma separated user defined tags applicable to the item or group.
1656
   */
1657
0
  void set_tags(const std::string tags) { m_tags = tags; }
1658
1659
1.72k
  [[nodiscard]] parse_error_fatality get_parse_error_fatality() const override { return parse_error_fatality::optional; }
1660
1661
protected:
1662
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1663
1664
private:
1665
  std::string m_lang;
1666
  std::string m_name;
1667
  std::string m_description;
1668
  std::string m_tags;
1669
};
1670
1671
1672
void initialize_heif_tai_clock_info(heif_tai_clock_info* taic);
1673
void initialize_heif_tai_timestamp_packet(heif_tai_timestamp_packet* itai);
1674
1675
1676
class Box_taic : public FullBox
1677
{
1678
public:
1679
  Box_taic()
1680
282
  {
1681
282
    set_short_type(fourcc("taic"));
1682
282
    initialize_heif_tai_clock_info(&m_info);
1683
282
  }
1684
1685
  static std::string dump(const heif_tai_clock_info& info, Indent&);
1686
1687
  std::string dump(Indent&) const override;
1688
1689
280
  const char* debug_box_name() const override { return "TAI Clock Information"; }
1690
1691
  Error write(StreamWriter& writer) const override;
1692
1693
  /**
1694
   * time_uncertainty.
1695
   * 
1696
   * The standard deviation measurement uncertainty in nanoseconds
1697
   * for the timestamp generation process. 
1698
   */
1699
0
  void set_time_uncertainty(uint64_t time_uncertainty) { m_info.time_uncertainty = time_uncertainty;}
1700
  
1701
  /**
1702
   * clock_resolution.
1703
   * 
1704
   * Specifies the resolution of the receptor clock in nanoseconds.
1705
   * For example, a microsecond clock has a clock_resolution of 1000.
1706
   */
1707
0
  void set_clock_resolution(uint32_t clock_resolution) { m_info.clock_resolution = clock_resolution; }
1708
  
1709
  /**
1710
   * clock_drift_rate.
1711
   * 
1712
   * The difference between the synchronized and unsynchronized
1713
   * time, over a period of one second. 
1714
   */
1715
0
  void set_clock_drift_rate(int32_t clock_drift_rate) { m_info.clock_drift_rate = clock_drift_rate; }
1716
  
1717
  /**
1718
   * clock_type.
1719
   * 
1720
   * 0 = Clock type is unknown
1721
   * 1 = The clock does not synchronize to an atomic source of absolute TAI time
1722
   * 2 = The clock can synchronize to an atomic source of absolute TAI time
1723
   */
1724
0
  void set_clock_type(uint8_t clock_type) { m_info.clock_type = clock_type; }
1725
1726
0
  uint64_t get_time_uncertainty() const { return m_info.time_uncertainty; }
1727
  
1728
0
  uint32_t get_clock_resolution() const { return m_info.clock_resolution; }
1729
  
1730
0
  int32_t get_clock_drift_rate() const { return m_info.clock_drift_rate; }
1731
  
1732
0
  uint8_t get_clock_type() const { return m_info.clock_type; }
1733
1734
0
  void set_from_tai_clock_info(const heif_tai_clock_info* info) {
1735
0
    heif_tai_clock_info_copy(&m_info, info);
1736
0
  }
1737
1738
  const heif_tai_clock_info* get_tai_clock_info() const
1739
0
  {
1740
0
    return &m_info;
1741
0
  }
1742
1743
  bool operator==(const Box& other) const override;
1744
1745
protected:
1746
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1747
1748
private:
1749
  heif_tai_clock_info m_info;
1750
};
1751
1752
bool operator==(const heif_tai_clock_info& a,
1753
                const heif_tai_clock_info& b);
1754
1755
1756
class Box_itai : public FullBox
1757
{
1758
public:
1759
  Box_itai()
1760
329
  {
1761
329
    set_short_type(fourcc("itai"));
1762
329
    initialize_heif_tai_timestamp_packet(&m_timestamp);
1763
329
  }
1764
1765
  std::string dump(Indent&) const override;
1766
1767
163
  const char* debug_box_name() const override { return "Item TAI Timestamp"; }
1768
1769
  Error write(StreamWriter& writer) const override;
1770
1771
  static std::vector<uint8_t> encode_tai_to_bitstream(const heif_tai_timestamp_packet*);
1772
1773
  static Result<heif_tai_timestamp_packet> decode_tai_from_vector(const std::vector<uint8_t>&);
1774
1775
  /**
1776
   * The number of nanoseconds since the TAI epoch of 1958-01-01T00:00:00.0Z.
1777
   */
1778
0
  void set_tai_timestamp(uint64_t timestamp) { m_timestamp.tai_timestamp = timestamp; }
1779
1780
  /**
1781
  * synchronization_state (0=unsynchronized, 1=synchronized)
1782
  */
1783
0
  void set_synchronization_state(bool state) { m_timestamp.synchronization_state = state; }
1784
1785
  /**
1786
  * timestamp_generation_failure (0=generated, 1=failed)
1787
  */
1788
0
  void set_timestamp_generation_failure(bool failure) { m_timestamp.timestamp_generation_failure = failure; }
1789
1790
  /**
1791
   * timestamp_is_modified (0=original 1=modified)
1792
   */
1793
0
  void set_timestamp_is_modified(bool is_modified) { m_timestamp.timestamp_is_modified = is_modified; }
1794
1795
0
  uint64_t get_tai_timestamp() const { return m_timestamp.tai_timestamp; }
1796
1797
0
  bool get_synchronization_state() const { return m_timestamp.synchronization_state; }
1798
1799
0
  bool get_timestamp_generation_failure() const { return m_timestamp.timestamp_generation_failure; }
1800
1801
0
  bool get_timestamp_is_modified() const { return m_timestamp.timestamp_is_modified; }
1802
1803
0
  void set_from_tai_timestamp_packet(const heif_tai_timestamp_packet* tai) {
1804
0
    heif_tai_timestamp_packet_copy(&m_timestamp, tai);
1805
0
  }
1806
1807
  const heif_tai_timestamp_packet* get_tai_timestamp_packet() const
1808
0
  {
1809
0
    return &m_timestamp;
1810
0
  }
1811
1812
  bool operator==(const Box& other) const override;
1813
1814
protected:
1815
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1816
1817
private:
1818
  heif_tai_timestamp_packet m_timestamp;
1819
};
1820
1821
bool operator==(const heif_tai_timestamp_packet& a,
1822
                const heif_tai_timestamp_packet& b);
1823
1824
#endif