/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 |