Coverage Report

Created: 2026-10-07 07:43

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