Coverage Report

Created: 2026-09-01 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libheif/libheif/sequences/seq_boxes.h
Line
Count
Source
1
/*
2
 * HEIF codec.
3
 * Copyright (c) 2024 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 SEQ_BOXES_H
22
#define SEQ_BOXES_H
23
24
#include "box.h"
25
#include "security_limits.h"
26
27
#include <string>
28
#include <memory>
29
#include <utility>
30
#include <vector>
31
#include <limits>
32
33
34
class Box_container : public Box {
35
public:
36
  Box_container(const char* type)
37
2.93k
  {
38
2.93k
    set_short_type(fourcc(type));
39
2.93k
  }
40
41
  std::string dump(Indent&) const override;
42
43
protected:
44
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
45
};
46
47
48
// Movie Box
49
class Box_moov : public Box_container {
50
public:
51
2.65k
  Box_moov() : Box_container("moov") {}
52
53
0
  const char* debug_box_name() const override { return "Movie"; }
54
};
55
56
57
// Movie Header Box
58
class Box_mvhd : public FullBox {
59
public:
60
  Box_mvhd()
61
96
  {
62
96
    set_short_type(fourcc("mvhd"));
63
96
  }
64
65
  std::string dump(Indent&) const override;
66
67
0
  const char* debug_box_name() const override { return "Movie Header"; }
68
69
  Error write(StreamWriter& writer) const override;
70
71
  void derive_box_version() override;
72
73
0
  double get_rate() const { return m_rate / double(0x10000); }
74
75
0
  float get_volume() const { return float(m_volume) / float(0x100); }
76
77
  double get_matrix_element(int idx) const;
78
79
0
  uint32_t get_time_scale() const { return m_timescale; }
80
81
0
  uint64_t get_duration() const { return m_duration; }
82
83
  // True when the duration field carries the ISOBMFF "duration unknown / indefinite"
84
  // sentinel (all-1s for the field width corresponding to the box version).
85
  // Files written with such a duration alongside an editlist in repeat mode signal
86
  // that the media should be looped indefinitely.
87
  bool is_duration_indefinite() const
88
0
  {
89
0
    if (get_version() == 1) {
90
0
      return m_duration == std::numeric_limits<uint64_t>::max();
91
0
    }
92
0
    return m_duration == std::numeric_limits<uint32_t>::max();
93
0
  }
94
95
0
  void set_duration(uint64_t duration) { m_duration = duration; }
96
97
0
  void set_time_scale(uint32_t timescale) { m_timescale = timescale; }
98
99
0
  void set_next_track_id(uint32_t next_id) { m_next_track_ID = next_id; }
100
101
protected:
102
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
103
104
private:
105
  uint64_t m_creation_time = 0;
106
  uint64_t m_modification_time = 0;
107
  uint32_t m_timescale = 0;
108
  uint64_t m_duration = 0;
109
110
  uint32_t m_rate = 0x00010000; // typically 1.0
111
  uint16_t m_volume = 0x0100; // typically, full volume
112
113
  uint32_t m_matrix[9] = {0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000};
114
  uint32_t m_next_track_ID = 0;
115
};
116
117
118
// Track Box
119
class Box_trak : public Box_container {
120
public:
121
106
  Box_trak() : Box_container("trak") {}
122
123
0
  const char* debug_box_name() const override { return "Track"; }
124
};
125
126
127
// Track Header Box
128
class Box_tkhd : public FullBox {
129
public:
130
  Box_tkhd()
131
93
  {
132
93
    set_short_type(fourcc("tkhd"));
133
134
    // set default flags according to ISO 14496-12
135
93
    set_flags(Track_enabled | Track_in_movie | Track_in_preview);
136
93
  }
137
138
  enum Flags : uint32_t {
139
    Track_enabled = 0x01,
140
    Track_in_movie = 0x02,
141
    Track_in_preview = 0x04,
142
    Track_size_is_aspect_ratio = 0x08
143
  };
144
145
  std::string dump(Indent&) const override;
146
147
0
  const char* debug_box_name() const override { return "Track Header"; }
148
149
  Error write(StreamWriter& writer) const override;
150
151
  void derive_box_version() override;
152
153
0
  float get_volume() const { return float(m_volume) / float(0x100); }
154
155
  double get_matrix_element(int idx) const;
156
157
0
  double get_width() const { return float(m_width) / double(0x10000); }
158
159
0
  double get_height() const { return float(m_height) / double(0x10000); }
160
161
73
  uint32_t get_track_id() const { return m_track_id; }
162
163
0
  void set_track_id(uint32_t track_id) { m_track_id = track_id; }
164
165
  void set_resolution(double width, double height)
166
0
  {
167
0
    m_width = (uint32_t) (width * 0x10000);
168
0
    m_height = (uint32_t) (height * 0x10000);
169
0
  }
170
171
0
  uint64_t get_duration() const { return m_duration; }
172
173
0
  void set_duration(uint64_t duration) { m_duration = duration; }
174
175
protected:
176
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
177
178
private:
179
  uint64_t m_creation_time = 0;
180
  uint64_t m_modification_time = 0;
181
  uint32_t m_track_id = 0;
182
  uint64_t m_duration = 0;
183
184
  uint16_t m_layer = 0;
185
  uint16_t m_alternate_group = 0;
186
  uint16_t m_volume = 0x0100; // typically, full volume
187
188
  uint32_t m_matrix[9] = {0x00010000, 0, 0, 0, 0x00010000, 0, 0, 0, 0x40000000};
189
190
  uint32_t m_width = 0;
191
  uint32_t m_height = 0;
192
};
193
194
195
// Media Box
196
class Box_mdia : public Box_container {
197
public:
198
99
  Box_mdia() : Box_container("mdia") {}
199
200
0
  const char* debug_box_name() const override { return "Media"; }
201
};
202
203
204
// Media Header Box
205
class Box_mdhd : public FullBox {
206
public:
207
  Box_mdhd()
208
30
  {
209
30
    set_short_type(fourcc("mdhd"));
210
30
  }
211
212
  std::string dump(Indent&) const override;
213
214
0
  const char* debug_box_name() const override { return "Media Header"; }
215
216
  Error write(StreamWriter& writer) const override;
217
218
  void derive_box_version() override;
219
220
  double get_matrix_element(int idx) const;
221
222
0
  uint32_t get_timescale() const { return m_timescale; }
223
224
0
  void set_timescale(uint32_t timescale) { m_timescale = timescale; }
225
226
0
  uint64_t get_duration() const { return m_duration; }
227
228
0
  void set_duration(uint64_t duration) { m_duration = duration; }
229
230
protected:
231
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
232
233
private:
234
  uint64_t m_creation_time = 0;
235
  uint64_t m_modification_time = 0;
236
  uint32_t m_timescale = 0;
237
  uint64_t m_duration = 0;
238
239
  char m_language[4] = {'u', 'n', 'k', 0};
240
};
241
242
243
// Media Information Box (container)
244
class Box_minf : public Box_container {
245
public:
246
31
  Box_minf() : Box_container("minf") {}
247
248
0
  const char* debug_box_name() const override { return "Media Information"; }
249
};
250
251
252
// Video Media Header
253
class Box_vmhd : public FullBox {
254
public:
255
  Box_vmhd()
256
13
  {
257
13
    set_short_type(fourcc("vmhd"));
258
13
    set_flags(1);
259
13
  }
260
261
  std::string dump(Indent&) const override;
262
263
0
  const char* debug_box_name() const override { return "Video Media Header"; }
264
265
  Error write(StreamWriter& writer) const override;
266
267
protected:
268
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
269
270
private:
271
  uint16_t m_graphics_mode = 0;
272
  uint16_t m_op_color[3] = {0, 0, 0};
273
};
274
275
276
// Null Media Header
277
class Box_nmhd : public FullBox {
278
public:
279
  Box_nmhd()
280
0
  {
281
0
    set_short_type(fourcc("nmhd"));
282
0
    set_flags(1);
283
0
  }
284
285
  std::string dump(Indent&) const override;
286
287
0
  const char* debug_box_name() const override { return "Null Media Header"; }
288
289
  Error write(StreamWriter& writer) const override;
290
291
protected:
292
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
293
};
294
295
296
// Sample Table Box (container)
297
class Box_stbl : public Box_container {
298
public:
299
15
  Box_stbl() : Box_container("stbl") {}
300
301
0
  const char* debug_box_name() const override { return "Sample Table"; }
302
};
303
304
305
// Sample Description Box
306
class Box_stsd : public FullBox {
307
public:
308
  Box_stsd()
309
17
  {
310
17
    set_short_type(fourcc("stsd"));
311
17
  }
312
313
  std::string dump(Indent&) const override;
314
315
0
  const char* debug_box_name() const override { return "Sample Description"; }
316
317
  Error write(StreamWriter& writer) const override;
318
319
  std::shared_ptr<const class Box> get_sample_entry(size_t idx) const
320
0
  {
321
0
    if (idx >= m_sample_entries.size()) {
322
0
      return nullptr;
323
0
    } else {
324
0
      return m_sample_entries[idx];
325
0
    }
326
0
  }
327
328
  void add_sample_entry(const std::shared_ptr<class Box>& entry)
329
0
  {
330
0
    m_sample_entries.push_back(entry);
331
0
  }
332
333
0
  size_t get_num_sample_entries() const { return m_sample_entries.size(); }
334
335
protected:
336
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
337
338
private:
339
  std::vector<std::shared_ptr<class Box>> m_sample_entries;
340
};
341
342
343
// Decoding Time to Sample Box
344
class Box_stts : public FullBox {
345
public:
346
  Box_stts()
347
6
  {
348
6
    set_short_type(fourcc("stts"));
349
6
  }
350
351
  std::string dump(Indent&) const override;
352
353
0
  const char* debug_box_name() const override { return "Decoding Time to Sample"; }
354
355
  Error write(StreamWriter& writer) const override;
356
357
  struct TimeToSample {
358
    uint32_t sample_count;
359
    uint32_t sample_delta;
360
361
    // Index one past the last sample described by this entry, i.e. the prefix sum
362
    // of sample_count over the entries up to and including this one. Derived (not
363
    // stored in the file); kept in sync by parse() and append_sample_duration() so
364
    // get_sample_duration() can binary-search instead of scanning linearly.
365
    uint32_t cumulative_sample_count = 0;
366
  };
367
368
  // O(log entries) lookup of the sample duration (delta) for a given sample index.
369
  // Called once per output sample on the decode/raw paths, so a linear scan would
370
  // be O(entries) per sample, i.e. O(entries * samples) overall (GHSA-xw34-mjcp-jqh8,
371
  // variant V1).
372
  uint32_t get_sample_duration(uint32_t sample_idx);
373
374
  void append_sample_duration(uint32_t duration);
375
376
  uint64_t get_total_duration(bool include_last_frame_duration);
377
378
  uint32_t get_number_of_samples() const;
379
380
protected:
381
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
382
383
private:
384
  std::vector<TimeToSample> m_entries;
385
  MemoryHandle m_memory_handle;
386
};
387
388
389
// Composition Time to Sample Box
390
class Box_ctts : public FullBox {
391
public:
392
  Box_ctts()
393
4
  {
394
4
    set_short_type(fourcc("ctts"));
395
4
  }
396
397
  std::string dump(Indent&) const override;
398
399
0
  const char* debug_box_name() const override { return "Composition Time to Sample"; }
400
401
  Error write(StreamWriter& writer) const override;
402
403
  struct OffsetToSample {
404
    uint32_t sample_count;
405
    int32_t sample_offset;   // either uint32_t or int32_t, we assume that all uint32_t values will also fit into int32_t
406
  };
407
408
  int32_t get_sample_offset(uint32_t sample_idx);
409
410
  void append_sample_offset(int32_t offset);
411
412
  bool is_constant_offset() const;
413
414
  void derive_box_version() override;
415
416
  int32_t compute_min_offset() const;
417
418
  uint32_t get_number_of_samples() const;
419
420
protected:
421
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
422
423
private:
424
  std::vector<OffsetToSample> m_entries;
425
  MemoryHandle m_memory_handle;
426
};
427
428
429
// Sample to Chunk Box
430
class Box_stsc : public FullBox {
431
public:
432
  Box_stsc()
433
5
  {
434
5
    set_short_type(fourcc("stsc"));
435
5
  }
436
437
  std::string dump(Indent&) const override;
438
439
0
  const char* debug_box_name() const override { return "Sample to Chunk"; }
440
441
  Error write(StreamWriter& writer) const override;
442
443
  struct SampleToChunk {
444
    uint32_t first_chunk;
445
    uint32_t samples_per_chunk;
446
    uint32_t sample_description_index;
447
  };
448
449
0
  const std::vector<SampleToChunk>& get_chunks() const { return m_entries; }
450
451
  // idx counting starts at 1
452
  const SampleToChunk* get_chunk(uint32_t idx) const;
453
454
  void add_chunk(uint32_t description_index);
455
456
  void increase_samples_in_chunk(uint32_t nFrames);
457
458
0
  bool last_chunk_empty() const {
459
0
    assert(!m_entries.empty());
460
0
461
0
    return m_entries.back().samples_per_chunk == 0;
462
0
  }
463
464
protected:
465
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
466
467
private:
468
  std::vector<SampleToChunk> m_entries;
469
  MemoryHandle m_memory_handle;
470
};
471
472
473
// Chunk Offset Box
474
class Box_stco : public FullBox {
475
public:
476
  Box_stco()
477
2
  {
478
2
    set_short_type(fourcc("stco"));
479
2
  }
480
481
  std::string dump(Indent&) const override;
482
483
0
  const char* debug_box_name() const override { return "Sample Offset"; }
484
485
  Error write(StreamWriter& writer) const override;
486
487
0
  void add_chunk_offset(uint32_t offset) { m_offsets.push_back(offset); }
488
489
0
  const std::vector<uint32_t>& get_offsets() const { return m_offsets; }
490
491
0
  size_t get_number_of_chunks() const { return m_offsets.size(); }
492
493
  void patch_file_pointers(StreamWriter&, size_t offset) override;
494
495
protected:
496
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
497
498
private:
499
  std::vector<uint32_t> m_offsets;
500
  MemoryHandle m_memory_handle;
501
502
  mutable size_t m_offset_start_pos = 0;
503
};
504
505
506
// Sample Size Box
507
class Box_stsz : public FullBox {
508
public:
509
  Box_stsz()
510
3
  {
511
3
    set_short_type(fourcc("stsz"));
512
3
  }
513
514
  std::string dump(Indent&) const override;
515
516
0
  const char* debug_box_name() const override { return "Sample Size"; }
517
518
  Error write(StreamWriter& writer) const override;
519
520
0
  bool has_fixed_sample_size() const { return m_fixed_sample_size != 0; }
521
522
0
  uint32_t get_fixed_sample_size() const { return m_fixed_sample_size; }
523
524
0
  uint32_t num_samples() const { return m_sample_count; }
525
526
0
  const std::vector<uint32_t>& get_sample_sizes() const { return m_sample_sizes; }
527
528
  void append_sample_size(uint32_t size);
529
530
protected:
531
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
532
533
private:
534
  uint32_t m_fixed_sample_size = 0;
535
  uint32_t m_sample_count = 0;
536
  std::vector<uint32_t> m_sample_sizes;
537
  MemoryHandle m_memory_handle;
538
};
539
540
541
// Sync Sample Box
542
class Box_stss : public FullBox {
543
public:
544
  Box_stss()
545
16
  {
546
16
    set_short_type(fourcc("stss"));
547
16
  }
548
549
  std::string dump(Indent&) const override;
550
551
0
  const char* debug_box_name() const override { return "Sync Sample"; }
552
553
  Error write(StreamWriter& writer) const override;
554
555
0
  void add_sync_sample(uint32_t sample_idx) { m_sync_samples.push_back(sample_idx); }
556
557
  // when this is set, the Box will compute whether it can be skipped
558
  void set_total_number_of_samples(uint32_t num_samples);
559
560
  // bool skip_box() const override { return m_all_samples_are_sync_samples; }
561
562
protected:
563
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
564
565
private:
566
  std::vector<uint32_t> m_sync_samples;
567
  MemoryHandle m_memory_handle;
568
569
  bool m_all_samples_are_sync_samples = false;
570
};
571
572
573
struct CodingConstraints {
574
  bool all_ref_pics_intra = false;
575
  bool intra_pred_used = false;
576
  uint8_t max_ref_per_pic = 0; // 4 bit
577
};
578
579
580
// Coding Constraints Box
581
class Box_ccst : public FullBox {
582
public:
583
  Box_ccst()
584
0
  {
585
0
    set_short_type(fourcc("ccst"));
586
0
  }
587
588
  std::string dump(Indent&) const override;
589
590
0
  const char* debug_box_name() const override { return "Coding Constraints"; }
591
592
  Error write(StreamWriter& writer) const override;
593
594
0
  void set_coding_constraints(const CodingConstraints& c) { m_codingConstraints = c; }
595
596
0
  const CodingConstraints& get_coding_constraints() const { return m_codingConstraints; }
597
598
protected:
599
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
600
601
private:
602
  CodingConstraints m_codingConstraints;
603
};
604
605
606
class Box_auxi : public FullBox {
607
public:
608
  Box_auxi()
609
10
  {
610
10
    set_short_type(fourcc("auxi"));
611
10
  }
612
613
  std::string dump(Indent&) const override;
614
615
0
  const char* debug_box_name() const override { return "Auxiliary Info Type"; }
616
617
  Error write(StreamWriter& writer) const override;
618
619
0
  void set_aux_track_type_urn(const std::string& t) { m_aux_track_type = t; }
620
621
0
  std::string get_aux_track_type_urn() const { return m_aux_track_type; }
622
623
protected:
624
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
625
626
private:
627
  std::string m_aux_track_type;
628
};
629
630
631
struct VisualSampleEntry {
632
  // from SampleEntry
633
  //const unsigned int(8)[6] reserved = 0;
634
  uint16_t data_reference_index = 1;
635
636
  // VisualSampleEntry
637
638
  uint16_t pre_defined = 0;
639
  //uint16_t reserved = 0;
640
  uint32_t pre_defined2[3] = {0, 0, 0};
641
  uint16_t width = 0;
642
  uint16_t height = 0;
643
  uint32_t horizresolution = 0x00480000; // 72 dpi
644
  uint32_t vertresolution = 0x00480000; // 72 dpi
645
  //uint32_t reserved = 0;
646
  uint16_t frame_count = 1;
647
  std::string compressorname; // max 32 characters
648
  uint16_t depth = 0x0018;
649
  int16_t pre_defined3 = -1;
650
  // other boxes from derived specifications
651
  //std::shared_ptr<Box_clap> clap; // optional
652
  //std::shared_ptr<Box_pixi> pixi; // optional
653
654
0
  double get_horizontal_resolution() const { return horizresolution / double(0x10000); }
655
656
0
  double get_vertical_resolution() const { return vertresolution / double(0x10000); }
657
658
  Error parse(BitstreamRange& range, const heif_security_limits*);
659
660
  Error write(StreamWriter& writer) const;
661
662
  std::string dump(Indent&) const;
663
};
664
665
666
class Box_VisualSampleEntry : public Box {
667
public:
668
  Error write(StreamWriter& writer) const override;
669
670
  std::string dump(Indent&) const override;
671
672
0
  const VisualSampleEntry& get_VisualSampleEntry_const() const { return m_visualSampleEntry; }
673
674
0
  VisualSampleEntry& get_VisualSampleEntry() { return m_visualSampleEntry; }
675
676
protected:
677
  Error parse(BitstreamRange& range, const heif_security_limits* limits) override;
678
679
private:
680
  VisualSampleEntry m_visualSampleEntry;
681
};
682
683
684
class Box_URIMetaSampleEntry : public Box {
685
public:
686
  Box_URIMetaSampleEntry()
687
0
  {
688
0
    set_short_type(fourcc("urim"));
689
0
  }
690
691
  Error write(StreamWriter& writer) const override;
692
693
  std::string dump(Indent&) const override;
694
695
0
  const char* debug_box_name() const override { return "URI Meta Sample Entry"; }
696
697
protected:
698
  Error parse(BitstreamRange& range, const heif_security_limits* limits) override;
699
700
private:
701
  // from SampleEntry
702
  //const unsigned int(8)[6] reserved = 0;
703
  uint16_t data_reference_index;
704
};
705
706
707
class Box_uri : public FullBox {
708
public:
709
  Box_uri()
710
1
  {
711
1
    set_short_type(fourcc("uri "));
712
1
  }
713
714
0
  void set_uri(std::string uri) { m_uri = std::move(uri); }
715
716
0
  std::string get_uri() const { return m_uri; }
717
718
  Error write(StreamWriter& writer) const override;
719
720
  std::string dump(Indent&) const override;
721
722
0
  const char* debug_box_name() const override { return "URI"; }
723
724
protected:
725
  Error parse(BitstreamRange& range, const heif_security_limits* limits) override;
726
727
private:
728
  std::string m_uri;
729
};
730
731
732
// Sample to Group
733
class Box_sbgp : public FullBox {
734
public:
735
  Box_sbgp()
736
1
  {
737
1
    set_short_type(fourcc("sbgp"));
738
1
  }
739
740
  void derive_box_version() override;
741
742
  std::string dump(Indent&) const override;
743
744
0
  const char* debug_box_name() const override { return "Sample to Group"; }
745
746
  Error write(StreamWriter& writer) const override;
747
748
protected:
749
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
750
751
private:
752
  uint32_t m_grouping_type = 0; // 4cc
753
  std::optional<uint32_t> m_grouping_type_parameter;
754
755
  struct Entry {
756
    uint32_t sample_count;
757
    uint32_t group_description_index;
758
  };
759
760
  std::vector<Entry> m_entries;
761
  MemoryHandle m_memory_handle;
762
};
763
764
765
class SampleGroupEntry
766
{
767
public:
768
216
  virtual ~SampleGroupEntry() = default;
769
770
  virtual std::string dump() const = 0;
771
772
  virtual Error write(StreamWriter& writer) const = 0;
773
774
  virtual Error parse(BitstreamRange& range, const heif_security_limits*) = 0;
775
};
776
777
778
class SampleGroupEntry_refs : public SampleGroupEntry
779
{
780
public:
781
  std::string dump() const override;
782
783
  Error write(StreamWriter& writer) const override;
784
785
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
786
787
private:
788
  uint32_t m_sample_id;
789
  std::vector<uint32_t> m_direct_reference_sample_id;
790
};
791
792
793
// Sample Group Description
794
class Box_sgpd : public FullBox {
795
public:
796
  Box_sgpd()
797
22
  {
798
22
    set_short_type(fourcc("sgpd"));
799
22
  }
800
801
  void derive_box_version() override;
802
803
  std::string dump(Indent&) const override;
804
805
0
  const char* debug_box_name() const override { return "Sample Group Description"; }
806
807
  Error write(StreamWriter& writer) const override;
808
809
protected:
810
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
811
812
private:
813
  uint32_t m_grouping_type = 0; // 4cc
814
  std::optional<uint32_t> m_default_length; // version 1  (0 -> variable length)
815
  std::optional<uint32_t> m_default_sample_description_index;; // version >= 2
816
817
  struct Entry {
818
    uint32_t description_length = 0; // if version==1 && m_default_length == 0
819
    std::shared_ptr<SampleGroupEntry> sample_group_entry;
820
  };
821
822
  std::vector<Entry> m_entries;
823
  MemoryHandle m_memory_handle;
824
};
825
826
// Bitrate
827
class Box_btrt : public FullBox {
828
public:
829
  Box_btrt()
830
0
  {
831
0
    set_short_type(fourcc("btrt"));
832
0
  }
833
834
  std::string dump(Indent&) const override;
835
836
0
  const char* debug_box_name() const override { return "Bitrate"; }
837
838
  Error write(StreamWriter& writer) const override;
839
840
protected:
841
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
842
843
private:
844
  uint32_t m_bufferSizeDB;
845
  uint32_t m_maxBitrate;
846
  uint32_t m_avgBitrate;
847
};
848
849
850
class Box_saiz : public FullBox {
851
public:
852
  Box_saiz()
853
31
  {
854
31
    set_short_type(fourcc("saiz"));
855
31
  }
856
857
  void set_aux_info_type(uint32_t aux_info_type, uint32_t aux_info_type_parameter = 0);
858
859
0
  uint32_t get_aux_info_type() const { return m_aux_info_type; }
860
861
0
  uint32_t get_aux_info_type_parameter() const { return m_aux_info_type_parameter; }
862
863
  void add_sample_size(uint8_t s);
864
865
0
  void add_nonpresent_sample() { add_sample_size(0); }
866
867
  uint8_t get_sample_size(uint32_t idx);
868
869
0
  bool have_samples_constant_size() const { return m_default_sample_info_size != 0; }
870
871
0
  uint32_t get_num_samples() const { return m_num_samples; }
872
873
  std::string dump(Indent&) const override;
874
875
0
  const char* debug_box_name() const override { return "Sample Auxiliary Information Sizes"; }
876
877
  Error write(StreamWriter& writer) const override;
878
879
protected:
880
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
881
882
private:
883
  uint32_t m_aux_info_type = 0;
884
  uint32_t m_aux_info_type_parameter = 0;
885
  uint8_t  m_default_sample_info_size = 0;  // 0 -> variable length
886
  uint32_t m_num_samples = 0; // needed in case we are using the default sample size
887
888
  std::vector<uint8_t> m_sample_sizes;
889
  MemoryHandle m_memory_handle;
890
};
891
892
893
class Box_saio : public FullBox {
894
public:
895
  Box_saio()
896
0
  {
897
0
    set_short_type(fourcc("saio"));
898
0
  }
899
900
  void set_aux_info_type(uint32_t aux_info_type, uint32_t aux_info_type_parameter = 0);
901
902
0
  uint32_t get_aux_info_type() const { return m_aux_info_type; }
903
904
0
  uint32_t get_aux_info_type_parameter() const { return m_aux_info_type_parameter; }
905
906
  void add_chunk_offset(uint64_t offset);
907
908
  // If this is 1, the SAI data of all samples is written contiguously in the file.
909
0
  size_t get_num_chunks() const { return m_chunk_offset.size(); }
910
911
  uint64_t get_chunk_offset(uint32_t idx) const;
912
913
  std::string dump(Indent&) const override;
914
915
0
  const char* debug_box_name() const override { return "Sample Auxiliary Information Offsets"; }
916
917
  Error write(StreamWriter& writer) const override;
918
919
protected:
920
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
921
922
  void patch_file_pointers(StreamWriter& writer, size_t offset) override;
923
924
private:
925
  uint32_t m_aux_info_type = 0;
926
  uint32_t m_aux_info_type_parameter = 0;
927
928
  bool m_need_64bit = false;
929
  mutable uint64_t m_offset_start_pos;
930
931
  // If |chunk_offset|==1, the SAI data of all samples is stored contiguously in the file
932
  std::vector<uint64_t> m_chunk_offset;
933
934
  MemoryHandle m_memory_handle;
935
};
936
937
938
class Box_sdtp : public FullBox {
939
public:
940
  Box_sdtp()
941
1
  {
942
1
    set_short_type(fourcc("sdtp"));
943
1
  }
944
945
  std::string dump(Indent&) const override;
946
947
0
  const char* debug_box_name() const override { return "Independent and Disposable Samples"; }
948
949
  // Error write(StreamWriter& writer) const override;
950
951
0
  uint8_t get_is_leading(uint32_t sampleIdx) const { return (m_sample_information[sampleIdx] >> 6) & 3; }
952
953
0
  uint8_t get_depends_on(uint32_t sampleIdx) const { return (m_sample_information[sampleIdx] >> 4) & 3; }
954
955
0
  uint8_t get_is_depended_on(uint32_t sampleIdx) const { return (m_sample_information[sampleIdx] >> 2) & 3; }
956
957
0
  uint8_t get_has_redundancy(uint32_t sampleIdx) const { return (m_sample_information[sampleIdx]) & 3; }
958
959
protected:
960
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
961
962
private:
963
  std::vector<uint8_t> m_sample_information;
964
};
965
966
967
class Box_tref : public Box
968
{
969
public:
970
  Box_tref()
971
4
  {
972
4
    set_short_type(fourcc("tref"));
973
4
  }
974
975
  struct Reference {
976
    uint32_t reference_type;
977
    std::vector<uint32_t> to_track_id;
978
  };
979
980
  std::string dump(Indent&) const override;
981
982
0
  const char* debug_box_name() const override { return "Track Reference"; }
983
984
  std::vector<uint32_t> get_references(uint32_t ref_type) const;
985
986
  size_t get_number_of_references_of_type(uint32_t ref_type) const;
987
988
0
  size_t get_number_of_reference_types() const { return m_references.size(); }
989
990
  std::vector<uint32_t> get_reference_types() const;
991
992
  void add_references(uint32_t to_track_id, uint32_t type);
993
994
protected:
995
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
996
997
  Error write(StreamWriter& writer) const override;
998
999
  Error check_for_double_references() const;
1000
1001
private:
1002
  std::vector<Reference> m_references;
1003
};
1004
1005
1006
// Edit List container
1007
class Box_edts : public Box_container {
1008
public:
1009
22
  Box_edts() : Box_container("edts") {}
1010
1011
0
  const char* debug_box_name() const override { return "Edit List Container"; }
1012
};
1013
1014
1015
class Box_elst : public FullBox
1016
{
1017
public:
1018
  Box_elst()
1019
22
  {
1020
22
    set_short_type(fourcc("elst"));
1021
22
  }
1022
1023
  enum Flags {
1024
    Repeat_EditList = 0x01
1025
  };
1026
1027
  std::string dump(Indent&) const override;
1028
1029
0
  const char* debug_box_name() const override { return "Edit List"; }
1030
1031
  void enable_repeat_mode(bool enable);
1032
1033
0
  bool is_repeat_mode() const { return get_flags() & Flags::Repeat_EditList; }
1034
1035
  struct Entry {
1036
    uint64_t segment_duration = 0;
1037
    int64_t media_time = 0;
1038
    int16_t media_rate_integer = 1;
1039
    int16_t media_rate_fraction = 0;
1040
  };
1041
1042
  void add_entry(const Entry&);
1043
1044
0
  size_t num_entries() const { return m_entries.size(); }
1045
1046
0
  Entry get_entry(uint32_t entry) const { return m_entries[entry]; }
1047
1048
protected:
1049
  Error parse(BitstreamRange& range, const heif_security_limits*) override;
1050
1051
  Error write(StreamWriter& writer) const override;
1052
1053
public:
1054
  void derive_box_version() override;
1055
1056
private:
1057
  std::vector<Entry> m_entries;
1058
};
1059
1060
#endif //SEQ_BOXES_H