Shaka Packager SDK
Loading...
Searching...
No Matches
box_definitions.cc
1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include <packager/media/formats/mp4/box_definitions.h>
6
7#include <algorithm>
8#include <cstddef>
9#include <cstdint>
10#include <iterator>
11#include <limits>
12#include <memory>
13#include <utility>
14#include <vector>
15
16#include <absl/flags/flag.h>
17#include <absl/log/check.h>
18#include <absl/log/log.h>
19
20#include <packager/macros/logging.h>
21#include <packager/media/base/bit_reader.h>
22#include <packager/media/base/buffer_writer.h>
23#include <packager/media/base/fourccs.h>
24#include <packager/media/base/rcheck.h>
25#include <packager/media/codecs/es_descriptor.h>
26#include <packager/media/formats/mp4/box_buffer.h>
27#include <packager/media/formats/mp4/box_reader.h>
28
29ABSL_FLAG(bool,
30 mvex_before_trak,
31 false,
32 "Android MediaExtractor requires mvex to be written before trak. "
33 "Set the flag to true to comply with the requirement.");
34
35namespace {
36const uint32_t kFourCCSize = 4;
37
38// Key Id size as defined in CENC spec.
39const uint32_t kCencKeyIdSize = 16;
40
41// 9 uint32_t in big endian formatted array.
42const uint8_t kUnityMatrix[] = {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
43 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
44 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0, 0, 0};
45
46// Default entries for HandlerReference box.
47const char kVideoHandlerName[] = "VideoHandler";
48const char kAudioHandlerName[] = "SoundHandler";
49const char kTextHandlerName[] = "TextHandler";
50const char kSubtitleHandlerName[] = "SubtitleHandler";
51
52// Default values for VideoSampleEntry box.
53const uint32_t kVideoResolution = 0x00480000; // 72 dpi.
54const uint16_t kVideoFrameCount = 1;
55const uint16_t kVideoDepth = 0x0018;
56
57const uint32_t kCompressorNameSize = 32u;
58const char kAv1CompressorName[] = "\012AOM Coding";
59const char kAvcCompressorName[] = "\012AVC Coding";
60const char kDolbyVisionCompressorName[] = "\013DOVI Coding";
61const char kHevcCompressorName[] = "\013HEVC Coding";
62const char kVpcCompressorName[] = "\012VPC Coding";
63
64// According to ISO/IEC FDIS 23001-7: CENC spec, IV should be either
65// 64-bit (8-byte) or 128-bit (16-byte).
66// |per_sample_iv_size| of 0 means constant_iv is used.
67bool IsIvSizeValid(uint8_t per_sample_iv_size) {
68 return per_sample_iv_size == 0 || per_sample_iv_size == 8 ||
69 per_sample_iv_size == 16;
70}
71
72// Default values to construct the following fields in ddts box. Values are set
73// according to FFMPEG.
74// bit(2) FrameDuration; // 3 = 4096
75// bit(5) StreamConstruction; // 18
76// bit(1) CoreLFEPresent; // 0 = none
77// bit(6) CoreLayout; // 31 = ignore core layout
78// bit(14) CoreSize; // 0
79// bit(1) StereoDownmix // 0 = none
80// bit(3) RepresentationType; // 4
81// bit(16) ChannelLayout; // 0xf = 5.1 channel layout.
82// bit(1) MultiAssetFlag // 0 = single asset
83// bit(1) LBRDurationMod // 0 = ignore
84// bit(1) ReservedBoxPresent // 0 = none
85// bit(5) Reserved // 0
86const uint8_t kDdtsExtraData[] = {0xe4, 0x7c, 0, 4, 0, 0x0f, 0};
87
88// Utility functions to check if the 64bit integers can fit in 32bit integer.
89bool IsFitIn32Bits(uint64_t a) {
90 return a <= std::numeric_limits<uint32_t>::max();
91}
92
93bool IsFitIn32Bits(int64_t a) {
94 return a <= std::numeric_limits<int32_t>::max() &&
95 a >= std::numeric_limits<int32_t>::min();
96}
97
98template <typename T1, typename T2>
99bool IsFitIn32Bits(T1 a1, T2 a2) {
100 return IsFitIn32Bits(a1) && IsFitIn32Bits(a2);
101}
102
103template <typename T1, typename T2, typename T3>
104bool IsFitIn32Bits(T1 a1, T2 a2, T3 a3) {
105 return IsFitIn32Bits(a1) && IsFitIn32Bits(a2) && IsFitIn32Bits(a3);
106}
107
108} // namespace
109
110namespace shaka {
111namespace media {
112namespace mp4 {
113
114namespace {
115
116TrackType FourCCToTrackType(FourCC fourcc) {
117 switch (fourcc) {
118 case FOURCC_vide:
119 return kVideo;
120 case FOURCC_soun:
121 return kAudio;
122 case FOURCC_text:
123 return kText;
124 case FOURCC_subt:
125 return kSubtitle;
126 default:
127 return kInvalid;
128 }
129}
130
131FourCC TrackTypeToFourCC(TrackType track_type) {
132 switch (track_type) {
133 case kVideo:
134 return FOURCC_vide;
135 case kAudio:
136 return FOURCC_soun;
137 case kText:
138 return FOURCC_text;
139 case kSubtitle:
140 return FOURCC_subt;
141 default:
142 return FOURCC_NULL;
143 }
144}
145
146bool IsProtectionSchemeSupported(FourCC scheme) {
147 return scheme == FOURCC_cenc || scheme == FOURCC_cens ||
148 scheme == FOURCC_cbc1 || scheme == FOURCC_cbcs;
149}
150
151} // namespace
152
153FileType::FileType() = default;
154FileType::~FileType() = default;
155
156FourCC FileType::BoxType() const {
157 return FOURCC_ftyp;
158}
159
160bool FileType::ReadWriteInternal(BoxBuffer* buffer) {
161 RCHECK(ReadWriteHeaderInternal(buffer) &&
162 buffer->ReadWriteFourCC(&major_brand) &&
163 buffer->ReadWriteUInt32(&minor_version));
164 size_t num_brands;
165 if (buffer->Reading()) {
166 RCHECK(buffer->BytesLeft() % sizeof(FourCC) == 0);
167 num_brands = buffer->BytesLeft() / sizeof(FourCC);
168 compatible_brands.resize(num_brands);
169 } else {
170 num_brands = compatible_brands.size();
171 }
172 for (size_t i = 0; i < num_brands; ++i)
173 RCHECK(buffer->ReadWriteFourCC(&compatible_brands[i]));
174 return true;
175}
176
177size_t FileType::ComputeSizeInternal() {
178 return HeaderSize() + kFourCCSize + sizeof(minor_version) +
179 kFourCCSize * compatible_brands.size();
180}
181
182FourCC SegmentType::BoxType() const {
183 return FOURCC_styp;
184}
185
186ProtectionSystemSpecificHeader::ProtectionSystemSpecificHeader() = default;
187ProtectionSystemSpecificHeader::~ProtectionSystemSpecificHeader() = default;
188
190 return FOURCC_pssh;
191}
192
193bool ProtectionSystemSpecificHeader::ReadWriteInternal(BoxBuffer* buffer) {
194 if (buffer->Reading()) {
195 BoxReader* reader = buffer->reader();
196 DCHECK(reader);
197 raw_box.assign(reader->data(), reader->data() + reader->size());
198 } else {
199 DCHECK(!raw_box.empty());
200 buffer->writer()->AppendVector(raw_box);
201 }
202
203 return true;
204}
205
206size_t ProtectionSystemSpecificHeader::ComputeSizeInternal() {
207 return raw_box.size();
208}
209
210SampleAuxiliaryInformationOffset::SampleAuxiliaryInformationOffset() = default;
211SampleAuxiliaryInformationOffset::~SampleAuxiliaryInformationOffset() = default;
212
214 return FOURCC_saio;
215}
216
217bool SampleAuxiliaryInformationOffset::ReadWriteInternal(BoxBuffer* buffer) {
218 RCHECK(ReadWriteHeaderInternal(buffer));
219 if (flags & 1)
220 RCHECK(buffer->IgnoreBytes(8)); // aux_info_type and parameter.
221
222 uint32_t count = static_cast<uint32_t>(offsets.size());
223 RCHECK(buffer->ReadWriteUInt32(&count));
224 offsets.resize(count);
225
226 size_t num_bytes = (version == 1) ? sizeof(uint64_t) : sizeof(uint32_t);
227 for (uint32_t i = 0; i < count; ++i)
228 RCHECK(buffer->ReadWriteUInt64NBytes(&offsets[i], num_bytes));
229 return true;
230}
231
232size_t SampleAuxiliaryInformationOffset::ComputeSizeInternal() {
233 // This box is optional. Skip it if it is empty.
234 if (offsets.size() == 0)
235 return 0;
236 size_t num_bytes = (version == 1) ? sizeof(uint64_t) : sizeof(uint32_t);
237 return HeaderSize() + sizeof(uint32_t) + num_bytes * offsets.size();
238}
239
240SampleAuxiliaryInformationSize::SampleAuxiliaryInformationSize() = default;
241SampleAuxiliaryInformationSize::~SampleAuxiliaryInformationSize() = default;
242
244 return FOURCC_saiz;
245}
246
247bool SampleAuxiliaryInformationSize::ReadWriteInternal(BoxBuffer* buffer) {
248 RCHECK(ReadWriteHeaderInternal(buffer));
249 if (flags & 1)
250 RCHECK(buffer->IgnoreBytes(8));
251
252 RCHECK(buffer->ReadWriteUInt8(&default_sample_info_size) &&
253 buffer->ReadWriteUInt32(&sample_count));
254 if (default_sample_info_size == 0)
255 RCHECK(buffer->ReadWriteVector(&sample_info_sizes, sample_count));
256 return true;
257}
258
259size_t SampleAuxiliaryInformationSize::ComputeSizeInternal() {
260 // This box is optional. Skip it if it is empty.
261 if (sample_count == 0)
262 return 0;
263 return HeaderSize() + sizeof(default_sample_info_size) +
264 sizeof(sample_count) +
265 (default_sample_info_size == 0 ? sample_info_sizes.size() : 0);
266}
267
269 bool has_subsamples,
270 BoxBuffer* buffer) {
271 DCHECK(IsIvSizeValid(iv_size));
272 DCHECK(buffer);
273
274 RCHECK(buffer->ReadWriteVector(&initialization_vector, iv_size));
275
276 if (!has_subsamples) {
277 subsamples.clear();
278 return true;
279 }
280
281 uint16_t subsample_count = static_cast<uint16_t>(subsamples.size());
282 RCHECK(buffer->ReadWriteUInt16(&subsample_count));
283 RCHECK(subsample_count > 0);
284 subsamples.resize(subsample_count);
285 for (auto& subsample : subsamples) {
286 RCHECK(buffer->ReadWriteUInt16(&subsample.clear_bytes) &&
287 buffer->ReadWriteUInt32(&subsample.cipher_bytes));
288 }
289 return true;
290}
291
293 bool has_subsamples,
294 BufferReader* reader) {
295 DCHECK(IsIvSizeValid(iv_size));
296 DCHECK(reader);
297
298 initialization_vector.resize(iv_size);
299 RCHECK(reader->ReadToVector(&initialization_vector, iv_size));
300
301 if (!has_subsamples) {
302 subsamples.clear();
303 return true;
304 }
305
306 uint16_t subsample_count;
307 RCHECK(reader->Read2(&subsample_count));
308 RCHECK(subsample_count > 0);
309 subsamples.resize(subsample_count);
310 for (auto& subsample : subsamples) {
311 RCHECK(reader->Read2(&subsample.clear_bytes) &&
312 reader->Read4(&subsample.cipher_bytes));
313 }
314 return true;
315}
316
318 const uint32_t subsample_entry_size = sizeof(uint16_t) + sizeof(uint32_t);
319 const uint16_t subsample_count = static_cast<uint16_t>(subsamples.size());
320 return static_cast<uint32_t>(
321 initialization_vector.size() +
322 (subsample_count > 0
323 ? (sizeof(subsample_count) + subsample_entry_size * subsample_count)
324 : 0));
325}
326
328 uint32_t size = 0;
329 for (uint32_t i = 0; i < subsamples.size(); ++i)
330 size += subsamples[i].clear_bytes + subsamples[i].cipher_bytes;
331 return size;
332}
333
334SampleEncryption::SampleEncryption() = default;
335SampleEncryption::~SampleEncryption() = default;
336
338 return FOURCC_senc;
339}
340
341bool SampleEncryption::ReadWriteInternal(BoxBuffer* buffer) {
342 RCHECK(ReadWriteHeaderInternal(buffer));
343
344 // If we don't know |iv_size|, store sample encryption data to parse later
345 // after we know iv_size.
346 if (buffer->Reading() && iv_size == SampleEncryption::kInvalidIvSize) {
347 RCHECK(
348 buffer->ReadWriteVector(&sample_encryption_data, buffer->BytesLeft()));
349 return true;
350 }
351
352 if (!IsIvSizeValid(iv_size)) {
353 LOG(ERROR)
354 << "IV_size can only be 8 or 16 or 0 for constant iv, but seeing "
355 << iv_size;
356 return false;
357 }
358
359 uint32_t sample_count =
360 static_cast<uint32_t>(sample_encryption_entries.size());
361 RCHECK(buffer->ReadWriteUInt32(&sample_count));
362
363 sample_encryption_entries.resize(sample_count);
364 for (auto& sample_encryption_entry : sample_encryption_entries) {
365 RCHECK(sample_encryption_entry.ReadWrite(
366 iv_size, (flags & kUseSubsampleEncryption) != 0, buffer) != 0);
367 }
368 return true;
369}
370
371size_t SampleEncryption::ComputeSizeInternal() {
372 const uint32_t sample_count =
373 static_cast<uint32_t>(sample_encryption_entries.size());
374 if (sample_count == 0) {
375 // Sample encryption box is optional. Skip it if it is empty.
376 return 0;
377 }
378
379 DCHECK(IsIvSizeValid(iv_size));
380 size_t box_size = HeaderSize() + sizeof(sample_count);
381 if (flags & kUseSubsampleEncryption) {
382 for (const SampleEncryptionEntry& sample_encryption_entry :
383 sample_encryption_entries) {
384 box_size += sample_encryption_entry.ComputeSize();
385 }
386 } else {
387 box_size += sample_count * iv_size;
388 }
389 return box_size;
390}
391
393 uint8_t l_iv_size,
394 std::vector<SampleEncryptionEntry>* l_sample_encryption_entries) const {
395 DCHECK(IsIvSizeValid(l_iv_size));
396
399 uint32_t sample_count = 0;
400 RCHECK(reader.Read4(&sample_count));
401
402 l_sample_encryption_entries->resize(sample_count);
403 for (auto& sample_encryption_entry : *l_sample_encryption_entries) {
404 RCHECK(sample_encryption_entry.ParseFromBuffer(
405 l_iv_size, (flags & kUseSubsampleEncryption) != 0, &reader) !=
406 0);
407 }
408 return true;
409}
410
411OriginalFormat::OriginalFormat() = default;
412OriginalFormat::~OriginalFormat() = default;
413
415 return FOURCC_frma;
416}
417
418bool OriginalFormat::ReadWriteInternal(BoxBuffer* buffer) {
419 return ReadWriteHeaderInternal(buffer) && buffer->ReadWriteFourCC(&format);
420}
421
422size_t OriginalFormat::ComputeSizeInternal() {
423 return HeaderSize() + kFourCCSize;
424}
425
426SchemeType::SchemeType() = default;
427SchemeType::~SchemeType() = default;
428
429FourCC SchemeType::BoxType() const {
430 return FOURCC_schm;
431}
432
433bool SchemeType::ReadWriteInternal(BoxBuffer* buffer) {
434 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->ReadWriteFourCC(&type) &&
435 buffer->ReadWriteUInt32(&version));
436 return true;
437}
438
439size_t SchemeType::ComputeSizeInternal() {
440 return HeaderSize() + kFourCCSize + sizeof(version);
441}
442
443TrackEncryption::TrackEncryption() = default;
444TrackEncryption::~TrackEncryption() = default;
445
447 return FOURCC_tenc;
448}
449
450bool TrackEncryption::ReadWriteInternal(BoxBuffer* buffer) {
451 if (!buffer->Reading()) {
452 if (default_kid.size() != kCencKeyIdSize) {
453 LOG(WARNING) << "CENC defines key id length of " << kCencKeyIdSize
454 << " bytes; got " << default_kid.size()
455 << ". Resized accordingly.";
456 default_kid.resize(kCencKeyIdSize);
457 }
458 RCHECK(default_crypt_byte_block < 16 && default_skip_byte_block < 16);
459 if (default_crypt_byte_block != 0 && default_skip_byte_block != 0) {
460 // Version 1 box is needed for pattern-based encryption.
461 version = 1;
462 }
463 }
464
465 RCHECK(ReadWriteHeaderInternal(buffer) &&
466 buffer->IgnoreBytes(1)); // reserved.
467
468 uint8_t pattern = default_crypt_byte_block << 4 | default_skip_byte_block;
469 RCHECK(buffer->ReadWriteUInt8(&pattern));
470 default_crypt_byte_block = pattern >> 4;
471 default_skip_byte_block = pattern & 0x0F;
472
473 RCHECK(buffer->ReadWriteUInt8(&default_is_protected) &&
474 buffer->ReadWriteUInt8(&default_per_sample_iv_size) &&
475 buffer->ReadWriteVector(&default_kid, kCencKeyIdSize));
476
477 if (default_is_protected == 1) {
478 if (default_per_sample_iv_size == 0) { // For constant iv.
479 uint8_t default_constant_iv_size =
480 static_cast<uint8_t>(default_constant_iv.size());
481 RCHECK(buffer->ReadWriteUInt8(&default_constant_iv_size));
482 RCHECK(default_constant_iv_size == 8 || default_constant_iv_size == 16);
483 RCHECK(buffer->ReadWriteVector(&default_constant_iv,
484 default_constant_iv_size));
485 } else {
486 RCHECK(default_per_sample_iv_size == 8 ||
487 default_per_sample_iv_size == 16);
488 RCHECK(default_constant_iv.empty());
489 }
490 } else {
491 // Expect |default_is_protected| to be 0, i.e. not protected. Other values
492 // of |default_is_protected| is not supported.
493 RCHECK(default_is_protected == 0);
494 RCHECK(default_per_sample_iv_size == 0);
495 RCHECK(default_constant_iv.empty());
496 }
497 return true;
498}
499
500size_t TrackEncryption::ComputeSizeInternal() {
501 return HeaderSize() + sizeof(uint32_t) + kCencKeyIdSize +
502 (default_constant_iv.empty()
503 ? 0
504 : (sizeof(uint8_t) + default_constant_iv.size()));
505}
506
507SchemeInfo::SchemeInfo() = default;
508SchemeInfo::~SchemeInfo() = default;
509
510FourCC SchemeInfo::BoxType() const {
511 return FOURCC_schi;
512}
513
514bool SchemeInfo::ReadWriteInternal(BoxBuffer* buffer) {
515 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
516 buffer->ReadWriteChild(&track_encryption));
517 return true;
518}
519
520size_t SchemeInfo::ComputeSizeInternal() {
521 return HeaderSize() + track_encryption.ComputeSize();
522}
523
524ProtectionSchemeInfo::ProtectionSchemeInfo() = default;
525ProtectionSchemeInfo::~ProtectionSchemeInfo() = default;
526
528 return FOURCC_sinf;
529}
530
531bool ProtectionSchemeInfo::ReadWriteInternal(BoxBuffer* buffer) {
532 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
533 buffer->ReadWriteChild(&format) && buffer->ReadWriteChild(&type));
534 if (IsProtectionSchemeSupported(type.type)) {
535 RCHECK(buffer->ReadWriteChild(&info));
536 } else {
537 DLOG(WARNING) << "Ignore unsupported protection scheme: "
538 << FourCCToString(type.type);
539 }
540 // Other protection schemes are silently ignored. Since the protection scheme
541 // type can't be determined until this box is opened, we return 'true' for
542 // non-CENC protection scheme types. It is the parent box's responsibility to
543 // ensure that this scheme type is a supported one.
544 return true;
545}
546
547size_t ProtectionSchemeInfo::ComputeSizeInternal() {
548 // Skip sinf box if it is not initialized.
549 if (format.format == FOURCC_NULL)
550 return 0;
551 return HeaderSize() + format.ComputeSize() + type.ComputeSize() +
552 info.ComputeSize();
553}
554
555MovieHeader::MovieHeader() = default;
556MovieHeader::~MovieHeader() = default;
557
558FourCC MovieHeader::BoxType() const {
559 return FOURCC_mvhd;
560}
561
562bool MovieHeader::ReadWriteInternal(BoxBuffer* buffer) {
563 RCHECK(ReadWriteHeaderInternal(buffer));
564
565 size_t num_bytes = (version == 1) ? sizeof(uint64_t) : sizeof(uint32_t);
566 RCHECK(buffer->ReadWriteUInt64NBytes(&creation_time, num_bytes) &&
567 buffer->ReadWriteUInt64NBytes(&modification_time, num_bytes) &&
568 buffer->ReadWriteUInt32(&timescale) &&
569 buffer->ReadWriteUInt64NBytes(&duration, num_bytes));
570
571 std::vector<uint8_t> matrix(kUnityMatrix,
572 kUnityMatrix + std::size(kUnityMatrix));
573 RCHECK(buffer->ReadWriteInt32(&rate) && buffer->ReadWriteInt16(&volume) &&
574 buffer->IgnoreBytes(10) && // reserved
575 buffer->ReadWriteVector(&matrix, matrix.size()) &&
576 buffer->IgnoreBytes(24) && // predefined zero
577 buffer->ReadWriteUInt32(&next_track_id));
578 return true;
579}
580
581size_t MovieHeader::ComputeSizeInternal() {
582 version = IsFitIn32Bits(creation_time, modification_time, duration) ? 0 : 1;
583 return HeaderSize() + sizeof(uint32_t) * (1 + version) * 3 +
584 sizeof(timescale) + sizeof(rate) + sizeof(volume) +
585 sizeof(next_track_id) + sizeof(kUnityMatrix) + 10 +
586 24; // 10 bytes reserved, 24 bytes predefined.
587}
588
589TrackHeader::TrackHeader() {
590 flags = kTrackEnabled | kTrackInMovie | kTrackInPreview;
591}
592
593TrackHeader::~TrackHeader() = default;
594
595FourCC TrackHeader::BoxType() const {
596 return FOURCC_tkhd;
597}
598
599bool TrackHeader::ReadWriteInternal(BoxBuffer* buffer) {
600 RCHECK(ReadWriteHeaderInternal(buffer));
601
602 size_t num_bytes = (version == 1) ? sizeof(uint64_t) : sizeof(uint32_t);
603 RCHECK(buffer->ReadWriteUInt64NBytes(&creation_time, num_bytes) &&
604 buffer->ReadWriteUInt64NBytes(&modification_time, num_bytes) &&
605 buffer->ReadWriteUInt32(&track_id) &&
606 buffer->IgnoreBytes(4) && // reserved
607 buffer->ReadWriteUInt64NBytes(&duration, num_bytes));
608
609 if (!buffer->Reading()) {
610 // Set default value for volume, if track is audio, 0x100 else 0.
611 if (volume == -1)
612 volume = (width != 0 && height != 0) ? 0 : 0x100;
613 }
614 std::vector<uint8_t> matrix(kUnityMatrix,
615 kUnityMatrix + std::size(kUnityMatrix));
616 RCHECK(buffer->IgnoreBytes(8) && // reserved
617 buffer->ReadWriteInt16(&layer) &&
618 buffer->ReadWriteInt16(&alternate_group) &&
619 buffer->ReadWriteInt16(&volume) &&
620 buffer->IgnoreBytes(2) && // reserved
621 buffer->ReadWriteVector(&matrix, matrix.size()) &&
622 buffer->ReadWriteUInt32(&width) && buffer->ReadWriteUInt32(&height));
623 return true;
624}
625
626size_t TrackHeader::ComputeSizeInternal() {
627 version = IsFitIn32Bits(creation_time, modification_time, duration) ? 0 : 1;
628 return HeaderSize() + sizeof(track_id) +
629 sizeof(uint32_t) * (1 + version) * 3 + sizeof(layer) +
630 sizeof(alternate_group) + sizeof(volume) + sizeof(width) +
631 sizeof(height) + sizeof(kUnityMatrix) + 14; // 14 bytes reserved.
632}
633
634SampleDescription::SampleDescription() = default;
635SampleDescription::~SampleDescription() = default;
636
638 return FOURCC_stsd;
639}
640
641bool SampleDescription::ReadWriteInternal(BoxBuffer* buffer) {
642 uint32_t count = 0;
643 switch (type) {
644 case kVideo:
645 count = static_cast<uint32_t>(video_entries.size());
646 break;
647 case kAudio:
648 count = static_cast<uint32_t>(audio_entries.size());
649 break;
650 case kText:
651 case kSubtitle:
652 count = static_cast<uint32_t>(text_entries.size());
653 break;
654 default:
655 NOTIMPLEMENTED() << "SampleDecryption type " << type
656 << " is not handled. Skipping.";
657 }
658 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->ReadWriteUInt32(&count));
659
660 if (buffer->Reading()) {
661 BoxReader* reader = buffer->reader();
662 DCHECK(reader);
663 video_entries.clear();
664 audio_entries.clear();
665 // Note: this value is preset before scanning begins. See comments in the
666 // Parse(Media*) function.
667 if (type == kVideo) {
668 RCHECK(reader->ReadAllChildren(&video_entries));
669 RCHECK(video_entries.size() == count);
670 } else if (type == kAudio) {
671 RCHECK(reader->ReadAllChildren(&audio_entries));
672 RCHECK(audio_entries.size() == count);
673 } else if (type == kText || type == kSubtitle) {
674 RCHECK(reader->ReadAllChildren(&text_entries));
675 RCHECK(text_entries.size() == count);
676 }
677 } else {
678 DCHECK_LT(0u, count);
679 if (type == kVideo) {
680 for (uint32_t i = 0; i < count; ++i)
681 RCHECK(buffer->ReadWriteChild(&video_entries[i]));
682 } else if (type == kAudio) {
683 for (uint32_t i = 0; i < count; ++i)
684 RCHECK(buffer->ReadWriteChild(&audio_entries[i]));
685 } else if (type == kText || type == kSubtitle) {
686 for (uint32_t i = 0; i < count; ++i)
687 RCHECK(buffer->ReadWriteChild(&text_entries[i]));
688 } else {
689 NOTIMPLEMENTED();
690 }
691 }
692 return true;
693}
694
695size_t SampleDescription::ComputeSizeInternal() {
696 size_t box_size = HeaderSize() + sizeof(uint32_t);
697 if (type == kVideo) {
698 for (uint32_t i = 0; i < video_entries.size(); ++i)
699 box_size += video_entries[i].ComputeSize();
700 } else if (type == kAudio) {
701 for (uint32_t i = 0; i < audio_entries.size(); ++i)
702 box_size += audio_entries[i].ComputeSize();
703 } else if (type == kText || type == kSubtitle) {
704 for (uint32_t i = 0; i < text_entries.size(); ++i)
705 box_size += text_entries[i].ComputeSize();
706 }
707 return box_size;
708}
709
710DecodingTimeToSample::DecodingTimeToSample() = default;
711DecodingTimeToSample::~DecodingTimeToSample() = default;
712
714 return FOURCC_stts;
715}
716
717bool DecodingTimeToSample::ReadWriteInternal(BoxBuffer* buffer) {
718 uint32_t count = static_cast<uint32_t>(decoding_time.size());
719 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->ReadWriteUInt32(&count));
720
721 if (buffer->Reading())
722 RCHECK(count <= buffer->BytesLeft() / sizeof(DecodingTime));
723
724 decoding_time.resize(count);
725 for (uint32_t i = 0; i < count; ++i) {
726 RCHECK(buffer->ReadWriteUInt32(&decoding_time[i].sample_count) &&
727 buffer->ReadWriteUInt32(&decoding_time[i].sample_delta));
728 }
729 return true;
730}
731
732size_t DecodingTimeToSample::ComputeSizeInternal() {
733 return HeaderSize() + sizeof(uint32_t) +
734 sizeof(DecodingTime) * decoding_time.size();
735}
736
737CompositionTimeToSample::CompositionTimeToSample() = default;
738CompositionTimeToSample::~CompositionTimeToSample() = default;
739
741 return FOURCC_ctts;
742}
743
744bool CompositionTimeToSample::ReadWriteInternal(BoxBuffer* buffer) {
745 uint32_t count = static_cast<uint32_t>(composition_offset.size());
746 if (!buffer->Reading()) {
747 // Determine whether version 0 or version 1 should be used.
748 // Use version 0 if possible, use version 1 if there is a negative
749 // sample_offset value.
750 version = 0;
751 for (uint32_t i = 0; i < count; ++i) {
752 if (composition_offset[i].sample_offset < 0) {
753 version = 1;
754 break;
755 }
756 }
757 }
758
759 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->ReadWriteUInt32(&count));
760
761 composition_offset.resize(count);
762 for (uint32_t i = 0; i < count; ++i) {
763 RCHECK(buffer->ReadWriteUInt32(&composition_offset[i].sample_count));
764
765 if (version == 0) {
766 uint32_t sample_offset = composition_offset[i].sample_offset;
767 RCHECK(buffer->ReadWriteUInt32(&sample_offset));
768 composition_offset[i].sample_offset = sample_offset;
769 } else {
770 int32_t sample_offset = composition_offset[i].sample_offset;
771 RCHECK(buffer->ReadWriteInt32(&sample_offset));
772 composition_offset[i].sample_offset = sample_offset;
773 }
774 }
775 return true;
776}
777
778size_t CompositionTimeToSample::ComputeSizeInternal() {
779 // This box is optional. Skip it if it is empty.
780 if (composition_offset.empty())
781 return 0;
782 // Structure CompositionOffset contains |sample_offset| (uint32_t) and
783 // |sample_offset| (int64_t). The actual size of |sample_offset| is
784 // 4 bytes (uint32_t for version 0 and int32_t for version 1).
785 const size_t kCompositionOffsetSize = sizeof(uint32_t) * 2;
786 return HeaderSize() + sizeof(uint32_t) +
787 kCompositionOffsetSize * composition_offset.size();
788}
789
790SampleToChunk::SampleToChunk() = default;
791SampleToChunk::~SampleToChunk() = default;
792
794 return FOURCC_stsc;
795}
796
797bool SampleToChunk::ReadWriteInternal(BoxBuffer* buffer) {
798 uint32_t count = static_cast<uint32_t>(chunk_info.size());
799 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->ReadWriteUInt32(&count));
800
801 chunk_info.resize(count);
802 for (uint32_t i = 0; i < count; ++i) {
803 RCHECK(buffer->ReadWriteUInt32(&chunk_info[i].first_chunk) &&
804 buffer->ReadWriteUInt32(&chunk_info[i].samples_per_chunk) &&
805 buffer->ReadWriteUInt32(&chunk_info[i].sample_description_index));
806 // first_chunk values are always increasing.
807 RCHECK(i == 0 ? chunk_info[i].first_chunk == 1
808 : chunk_info[i].first_chunk > chunk_info[i - 1].first_chunk);
809 }
810 return true;
811}
812
813size_t SampleToChunk::ComputeSizeInternal() {
814 return HeaderSize() + sizeof(uint32_t) +
815 sizeof(ChunkInfo) * chunk_info.size();
816}
817
818SampleSize::SampleSize() = default;
819SampleSize::~SampleSize() = default;
820
821FourCC SampleSize::BoxType() const {
822 return FOURCC_stsz;
823}
824
825bool SampleSize::ReadWriteInternal(BoxBuffer* buffer) {
826 RCHECK(ReadWriteHeaderInternal(buffer) &&
827 buffer->ReadWriteUInt32(&sample_size) &&
828 buffer->ReadWriteUInt32(&sample_count));
829
830 if (sample_size == 0) {
831 if (buffer->Reading())
832 sizes.resize(sample_count);
833 else
834 DCHECK(sample_count == sizes.size());
835 for (uint32_t i = 0; i < sample_count; ++i)
836 RCHECK(buffer->ReadWriteUInt32(&sizes[i]));
837 }
838 return true;
839}
840
841size_t SampleSize::ComputeSizeInternal() {
842 return HeaderSize() + sizeof(sample_size) + sizeof(sample_count) +
843 (sample_size == 0 ? sizeof(uint32_t) * sizes.size() : 0);
844}
845
846CompactSampleSize::CompactSampleSize() = default;
847CompactSampleSize::~CompactSampleSize() = default;
848
850 return FOURCC_stz2;
851}
852
853bool CompactSampleSize::ReadWriteInternal(BoxBuffer* buffer) {
854 uint32_t sample_count = static_cast<uint32_t>(sizes.size());
855 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->IgnoreBytes(3) &&
856 buffer->ReadWriteUInt8(&field_size) &&
857 buffer->ReadWriteUInt32(&sample_count));
858
859 // Reserve one more entry if field size is 4 bits.
860 sizes.resize(sample_count + (field_size == 4 ? 1 : 0), 0);
861 switch (field_size) {
862 case 4:
863 for (uint32_t i = 0; i < sample_count; i += 2) {
864 if (buffer->Reading()) {
865 uint8_t size = 0;
866 RCHECK(buffer->ReadWriteUInt8(&size));
867 sizes[i] = size >> 4;
868 sizes[i + 1] = size & 0x0F;
869 } else {
870 DCHECK_LT(sizes[i], 16u);
871 DCHECK_LT(sizes[i + 1], 16u);
872 uint8_t size = (sizes[i] << 4) | sizes[i + 1];
873 RCHECK(buffer->ReadWriteUInt8(&size));
874 }
875 }
876 break;
877 case 8:
878 for (uint32_t i = 0; i < sample_count; ++i) {
879 uint8_t size = sizes[i];
880 RCHECK(buffer->ReadWriteUInt8(&size));
881 sizes[i] = size;
882 }
883 break;
884 case 16:
885 for (uint32_t i = 0; i < sample_count; ++i) {
886 uint16_t size = sizes[i];
887 RCHECK(buffer->ReadWriteUInt16(&size));
888 sizes[i] = size;
889 }
890 break;
891 default:
892 RCHECK(false);
893 }
894 sizes.resize(sample_count);
895 return true;
896}
897
898size_t CompactSampleSize::ComputeSizeInternal() {
899 return HeaderSize() + sizeof(uint32_t) + sizeof(uint32_t) +
900 (field_size * sizes.size() + 7) / 8;
901}
902
903ChunkOffset::ChunkOffset() = default;
904ChunkOffset::~ChunkOffset() = default;
905
906FourCC ChunkOffset::BoxType() const {
907 return FOURCC_stco;
908}
909
910bool ChunkOffset::ReadWriteInternal(BoxBuffer* buffer) {
911 uint32_t count = static_cast<uint32_t>(offsets.size());
912 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->ReadWriteUInt32(&count));
913
914 offsets.resize(count);
915 for (uint32_t i = 0; i < count; ++i)
916 RCHECK(buffer->ReadWriteUInt64NBytes(&offsets[i], sizeof(uint32_t)));
917 return true;
918}
919
920size_t ChunkOffset::ComputeSizeInternal() {
921 return HeaderSize() + sizeof(uint32_t) + sizeof(uint32_t) * offsets.size();
922}
923
924ChunkLargeOffset::ChunkLargeOffset() = default;
925ChunkLargeOffset::~ChunkLargeOffset() = default;
926
928 return FOURCC_co64;
929}
930
931bool ChunkLargeOffset::ReadWriteInternal(BoxBuffer* buffer) {
932 uint32_t count = static_cast<uint32_t>(offsets.size());
933
934 if (!buffer->Reading()) {
935 // Switch to ChunkOffset box if it is able to fit in 32 bits offset.
936 if (count == 0 || IsFitIn32Bits(offsets[count - 1])) {
937 ChunkOffset stco;
938 stco.offsets.swap(offsets);
939 DCHECK(buffer->writer());
940 stco.Write(buffer->writer());
941 stco.offsets.swap(offsets);
942 return true;
943 }
944 }
945
946 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->ReadWriteUInt32(&count));
947
948 offsets.resize(count);
949 for (uint32_t i = 0; i < count; ++i)
950 RCHECK(buffer->ReadWriteUInt64(&offsets[i]));
951 return true;
952}
953
954size_t ChunkLargeOffset::ComputeSizeInternal() {
955 uint32_t count = static_cast<uint32_t>(offsets.size());
956 int use_large_offset =
957 (count > 0 && !IsFitIn32Bits(offsets[count - 1])) ? 1 : 0;
958 return HeaderSize() + sizeof(count) +
959 sizeof(uint32_t) * (1 + use_large_offset) * offsets.size();
960}
961
962SyncSample::SyncSample() = default;
963SyncSample::~SyncSample() = default;
964
965FourCC SyncSample::BoxType() const {
966 return FOURCC_stss;
967}
968
969bool SyncSample::ReadWriteInternal(BoxBuffer* buffer) {
970 uint32_t count = static_cast<uint32_t>(sample_number.size());
971 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->ReadWriteUInt32(&count));
972
973 sample_number.resize(count);
974 for (uint32_t i = 0; i < count; ++i)
975 RCHECK(buffer->ReadWriteUInt32(&sample_number[i]));
976 return true;
977}
978
979size_t SyncSample::ComputeSizeInternal() {
980 // Sync sample box is optional. Skip it if it is empty.
981 if (sample_number.empty())
982 return 0;
983 return HeaderSize() + sizeof(uint32_t) +
984 sizeof(uint32_t) * sample_number.size();
985}
986
987bool CencSampleEncryptionInfoEntry::ReadWrite(BoxBuffer* buffer) {
988 if (!buffer->Reading()) {
989 if (key_id.size() != kCencKeyIdSize) {
990 LOG(WARNING) << "CENC defines key id length of " << kCencKeyIdSize
991 << " bytes; got " << key_id.size()
992 << ". Resized accordingly.";
993 key_id.resize(kCencKeyIdSize);
994 }
995 RCHECK(crypt_byte_block < 16 && skip_byte_block < 16);
996 }
997
998 RCHECK(buffer->IgnoreBytes(1)); // reserved.
999
1000 uint8_t pattern = crypt_byte_block << 4 | skip_byte_block;
1001 RCHECK(buffer->ReadWriteUInt8(&pattern));
1002 crypt_byte_block = pattern >> 4;
1003 skip_byte_block = pattern & 0x0F;
1004
1005 RCHECK(buffer->ReadWriteUInt8(&is_protected) &&
1006 buffer->ReadWriteUInt8(&per_sample_iv_size) &&
1007 buffer->ReadWriteVector(&key_id, kCencKeyIdSize));
1008
1009 if (is_protected == 1) {
1010 if (per_sample_iv_size == 0) { // For constant iv.
1011 uint8_t constant_iv_size = static_cast<uint8_t>(constant_iv.size());
1012 RCHECK(buffer->ReadWriteUInt8(&constant_iv_size));
1013 RCHECK(constant_iv_size == 8 || constant_iv_size == 16);
1014 RCHECK(buffer->ReadWriteVector(&constant_iv, constant_iv_size));
1015 } else {
1016 RCHECK(per_sample_iv_size == 8 || per_sample_iv_size == 16);
1017 DCHECK(constant_iv.empty());
1018 }
1019 } else {
1020 // Expect |is_protected| to be 0, i.e. not protected. Other values of
1021 // |is_protected| is not supported.
1022 RCHECK(is_protected == 0);
1023 RCHECK(per_sample_iv_size == 0);
1024 }
1025 return true;
1026}
1027
1028uint32_t CencSampleEncryptionInfoEntry::ComputeSize() const {
1029 return static_cast<uint32_t>(
1030 sizeof(uint32_t) + kCencKeyIdSize +
1031 (constant_iv.empty() ? 0 : (sizeof(uint8_t) + constant_iv.size())));
1032}
1033
1034bool AudioRollRecoveryEntry::ReadWrite(BoxBuffer* buffer) {
1035 RCHECK(buffer->ReadWriteInt16(&roll_distance));
1036 return true;
1037}
1038
1039uint32_t AudioRollRecoveryEntry::ComputeSize() const {
1040 return sizeof(roll_distance);
1041}
1042
1043SampleGroupDescription::SampleGroupDescription() = default;
1044SampleGroupDescription::~SampleGroupDescription() = default;
1045
1047 return FOURCC_sgpd;
1048}
1049
1050bool SampleGroupDescription::ReadWriteInternal(BoxBuffer* buffer) {
1051 RCHECK(ReadWriteHeaderInternal(buffer) &&
1052 buffer->ReadWriteUInt32(&grouping_type));
1053
1054 switch (grouping_type) {
1055 case FOURCC_seig:
1056 return ReadWriteEntries(buffer, &cenc_sample_encryption_info_entries);
1057 case FOURCC_roll:
1058 return ReadWriteEntries(buffer, &audio_roll_recovery_entries);
1059 default:
1060 DCHECK(buffer->Reading());
1061 DLOG(WARNING) << "Ignore unsupported sample group: "
1062 << FourCCToString(static_cast<FourCC>(grouping_type));
1063 return true;
1064 }
1065}
1066
1067template <typename T>
1068bool SampleGroupDescription::ReadWriteEntries(BoxBuffer* buffer,
1069 std::vector<T>* entries) {
1070 uint32_t default_length = 0;
1071 if (!buffer->Reading()) {
1072 DCHECK(!entries->empty());
1073 default_length = (*entries)[0].ComputeSize();
1074 DCHECK_NE(default_length, 0u);
1075 }
1076 if (version == 1)
1077 RCHECK(buffer->ReadWriteUInt32(&default_length));
1078 if (version >= 2) {
1079 NOTIMPLEMENTED() << "Unsupported SampleGroupDescriptionBox 'sgpd' version "
1080 << static_cast<int>(version);
1081 return false;
1082 }
1083
1084 uint32_t count = static_cast<uint32_t>(entries->size());
1085 RCHECK(buffer->ReadWriteUInt32(&count));
1086 if (buffer->Reading()) {
1087 if (count == 0)
1088 return true;
1089 } else {
1090 RCHECK(count != 0);
1091 }
1092 entries->resize(count);
1093
1094 for (T& entry : *entries) {
1095 if (version == 1) {
1096 uint32_t description_length = default_length;
1097 if (buffer->Reading() && default_length == 0)
1098 RCHECK(buffer->ReadWriteUInt32(&description_length));
1099 RCHECK(entry.ReadWrite(buffer));
1100 RCHECK(entry.ComputeSize() == description_length);
1101 } else {
1102 RCHECK(entry.ReadWrite(buffer));
1103 }
1104 }
1105 return true;
1106}
1107
1108size_t SampleGroupDescription::ComputeSizeInternal() {
1109 // Version 0 is obsoleted, so always generate version 1 box.
1110 version = 1;
1111 size_t entries_size = 0;
1112 switch (grouping_type) {
1113 case FOURCC_seig:
1114 for (const auto& entry : cenc_sample_encryption_info_entries)
1115 entries_size += entry.ComputeSize();
1116 break;
1117 case FOURCC_roll:
1118 for (const auto& entry : audio_roll_recovery_entries)
1119 entries_size += entry.ComputeSize();
1120 break;
1121 }
1122 // This box is optional. Skip it if it is not used.
1123 if (entries_size == 0)
1124 return 0;
1125 return HeaderSize() + sizeof(grouping_type) +
1126 (version == 1 ? sizeof(uint32_t) : 0) + sizeof(uint32_t) +
1127 entries_size;
1128}
1129
1130SampleToGroup::SampleToGroup() = default;
1131SampleToGroup::~SampleToGroup() = default;
1132
1134 return FOURCC_sbgp;
1135}
1136
1137bool SampleToGroup::ReadWriteInternal(BoxBuffer* buffer) {
1138 RCHECK(ReadWriteHeaderInternal(buffer) &&
1139 buffer->ReadWriteUInt32(&grouping_type));
1140 if (version == 1)
1141 RCHECK(buffer->ReadWriteUInt32(&grouping_type_parameter));
1142
1143 if (grouping_type != FOURCC_seig && grouping_type != FOURCC_roll) {
1144 DCHECK(buffer->Reading());
1145 DLOG(WARNING) << "Ignore unsupported sample group: "
1146 << FourCCToString(static_cast<FourCC>(grouping_type));
1147 return true;
1148 }
1149
1150 uint32_t count = static_cast<uint32_t>(entries.size());
1151 RCHECK(buffer->ReadWriteUInt32(&count));
1152 entries.resize(count);
1153 for (uint32_t i = 0; i < count; ++i) {
1154 RCHECK(buffer->ReadWriteUInt32(&entries[i].sample_count) &&
1155 buffer->ReadWriteUInt32(&entries[i].group_description_index));
1156 }
1157 return true;
1158}
1159
1160size_t SampleToGroup::ComputeSizeInternal() {
1161 // This box is optional. Skip it if it is not used.
1162 if (entries.empty())
1163 return 0;
1164 return HeaderSize() + sizeof(grouping_type) +
1165 (version == 1 ? sizeof(grouping_type_parameter) : 0) +
1166 sizeof(uint32_t) + entries.size() * sizeof(entries[0]);
1167}
1168
1169SampleTable::SampleTable() = default;
1170SampleTable::~SampleTable() = default;
1171
1172FourCC SampleTable::BoxType() const {
1173 return FOURCC_stbl;
1174}
1175
1176bool SampleTable::ReadWriteInternal(BoxBuffer* buffer) {
1177 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
1178 buffer->ReadWriteChild(&description) &&
1179 buffer->ReadWriteChild(&decoding_time_to_sample) &&
1180 buffer->TryReadWriteChild(&composition_time_to_sample) &&
1181 buffer->ReadWriteChild(&sample_to_chunk));
1182
1183 if (buffer->Reading()) {
1184 BoxReader* reader = buffer->reader();
1185 DCHECK(reader);
1186
1187 // Either SampleSize or CompactSampleSize must present.
1188 if (reader->ChildExist(&sample_size)) {
1189 RCHECK(reader->ReadChild(&sample_size));
1190 } else {
1191 CompactSampleSize compact_sample_size;
1192 RCHECK(reader->ReadChild(&compact_sample_size));
1193 sample_size.sample_size = 0;
1194 sample_size.sample_count =
1195 static_cast<uint32_t>(compact_sample_size.sizes.size());
1196 sample_size.sizes.swap(compact_sample_size.sizes);
1197 }
1198
1199 // Either ChunkOffset or ChunkLargeOffset must present.
1200 if (reader->ChildExist(&chunk_large_offset)) {
1201 RCHECK(reader->ReadChild(&chunk_large_offset));
1202 } else {
1203 ChunkOffset chunk_offset;
1204 RCHECK(reader->ReadChild(&chunk_offset));
1205 chunk_large_offset.offsets.swap(chunk_offset.offsets);
1206 }
1207 } else {
1208 RCHECK(buffer->ReadWriteChild(&sample_size) &&
1209 buffer->ReadWriteChild(&chunk_large_offset));
1210 }
1211 RCHECK(buffer->TryReadWriteChild(&sync_sample));
1212 if (buffer->Reading()) {
1213 RCHECK(buffer->reader()->TryReadChildren(&sample_group_descriptions) &&
1214 buffer->reader()->TryReadChildren(&sample_to_groups));
1215 } else {
1216 for (auto& sample_group_description : sample_group_descriptions)
1217 RCHECK(buffer->ReadWriteChild(&sample_group_description));
1218 for (auto& sample_to_group : sample_to_groups)
1219 RCHECK(buffer->ReadWriteChild(&sample_to_group));
1220 }
1221 return true;
1222}
1223
1224size_t SampleTable::ComputeSizeInternal() {
1225 size_t box_size = HeaderSize() + description.ComputeSize() +
1226 decoding_time_to_sample.ComputeSize() +
1227 composition_time_to_sample.ComputeSize() +
1228 sample_to_chunk.ComputeSize() + sample_size.ComputeSize() +
1229 chunk_large_offset.ComputeSize() +
1230 sync_sample.ComputeSize();
1231 for (auto& sample_group_description : sample_group_descriptions)
1232 box_size += sample_group_description.ComputeSize();
1233 for (auto& sample_to_group : sample_to_groups)
1234 box_size += sample_to_group.ComputeSize();
1235 return box_size;
1236}
1237
1238EditList::EditList() = default;
1239EditList::~EditList() = default;
1240
1241FourCC EditList::BoxType() const {
1242 return FOURCC_elst;
1243}
1244
1245bool EditList::ReadWriteInternal(BoxBuffer* buffer) {
1246 uint32_t count = static_cast<uint32_t>(edits.size());
1247 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->ReadWriteUInt32(&count));
1248 edits.resize(count);
1249
1250 size_t num_bytes = (version == 1) ? sizeof(uint64_t) : sizeof(uint32_t);
1251 for (uint32_t i = 0; i < count; ++i) {
1252 RCHECK(
1253 buffer->ReadWriteUInt64NBytes(&edits[i].segment_duration, num_bytes) &&
1254 buffer->ReadWriteInt64NBytes(&edits[i].media_time, num_bytes) &&
1255 buffer->ReadWriteInt16(&edits[i].media_rate_integer) &&
1256 buffer->ReadWriteInt16(&edits[i].media_rate_fraction));
1257 }
1258 return true;
1259}
1260
1261size_t EditList::ComputeSizeInternal() {
1262 // EditList box is optional. Skip it if it is empty.
1263 if (edits.empty())
1264 return 0;
1265
1266 version = 0;
1267 for (uint32_t i = 0; i < edits.size(); ++i) {
1268 if (!IsFitIn32Bits(edits[i].segment_duration, edits[i].media_time)) {
1269 version = 1;
1270 break;
1271 }
1272 }
1273 return HeaderSize() + sizeof(uint32_t) +
1274 (sizeof(uint32_t) * (1 + version) * 2 + sizeof(int16_t) * 2) *
1275 edits.size();
1276}
1277
1278Edit::Edit() = default;
1279Edit::~Edit() = default;
1280
1281FourCC Edit::BoxType() const {
1282 return FOURCC_edts;
1283}
1284
1285bool Edit::ReadWriteInternal(BoxBuffer* buffer) {
1286 return ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
1287 buffer->ReadWriteChild(&list);
1288}
1289
1290size_t Edit::ComputeSizeInternal() {
1291 // Edit box is optional. Skip it if it is empty.
1292 if (list.edits.empty())
1293 return 0;
1294 return HeaderSize() + list.ComputeSize();
1295}
1296
1297HandlerReference::HandlerReference() = default;
1298HandlerReference::~HandlerReference() = default;
1299
1301 return FOURCC_hdlr;
1302}
1303
1304bool HandlerReference::ReadWriteInternal(BoxBuffer* buffer) {
1305 std::vector<uint8_t> handler_name;
1306 if (!buffer->Reading()) {
1307 switch (handler_type) {
1308 case FOURCC_vide:
1309 handler_name.assign(kVideoHandlerName,
1310 kVideoHandlerName + std::size(kVideoHandlerName));
1311 break;
1312 case FOURCC_soun:
1313 handler_name.assign(kAudioHandlerName,
1314 kAudioHandlerName + std::size(kAudioHandlerName));
1315 break;
1316 case FOURCC_text:
1317 handler_name.assign(kTextHandlerName,
1318 kTextHandlerName + std::size(kTextHandlerName));
1319 break;
1320 case FOURCC_subt:
1321 handler_name.assign(
1322 kSubtitleHandlerName,
1323 kSubtitleHandlerName + std::size(kSubtitleHandlerName));
1324 break;
1325 case FOURCC_ID32:
1326 break;
1327 default:
1328 NOTIMPLEMENTED();
1329 return false;
1330 }
1331 }
1332 RCHECK(ReadWriteHeaderInternal(buffer) &&
1333 buffer->IgnoreBytes(4) && // predefined.
1334 buffer->ReadWriteFourCC(&handler_type));
1335 if (!buffer->Reading()) {
1336 RCHECK(buffer->IgnoreBytes(12) && // reserved.
1337 buffer->ReadWriteVector(&handler_name, handler_name.size()));
1338 }
1339 return true;
1340}
1341
1342size_t HandlerReference::ComputeSizeInternal() {
1343 size_t box_size = HeaderSize() + kFourCCSize + 16; // 16 bytes Reserved
1344 switch (handler_type) {
1345 case FOURCC_vide:
1346 box_size += sizeof(kVideoHandlerName);
1347 break;
1348 case FOURCC_soun:
1349 box_size += sizeof(kAudioHandlerName);
1350 break;
1351 case FOURCC_text:
1352 box_size += sizeof(kTextHandlerName);
1353 break;
1354 case FOURCC_subt:
1355 box_size += sizeof(kSubtitleHandlerName);
1356 break;
1357 case FOURCC_ID32:
1358 break;
1359 default:
1360 NOTIMPLEMENTED();
1361 }
1362 return box_size;
1363}
1364
1365bool Language::ReadWrite(BoxBuffer* buffer) {
1366 if (buffer->Reading()) {
1367 // Read language codes into temp first then use BitReader to read the
1368 // values. ISO-639-2/T language code: unsigned int(5)[3] language (2 bytes).
1369 std::vector<uint8_t> temp;
1370 RCHECK(buffer->ReadWriteVector(&temp, 2));
1371
1372 BitReader bit_reader(&temp[0], 2);
1373 bit_reader.SkipBits(1);
1374 char language[3];
1375 for (int i = 0; i < 3; ++i) {
1376 CHECK(bit_reader.ReadBits(5, &language[i]));
1377 language[i] += 0x60;
1378 }
1379 code.assign(language, 3);
1380 } else {
1381 // Set up default language if it is not set.
1382 const char kUndefinedLanguage[] = "und";
1383 if (code.empty())
1384 code = kUndefinedLanguage;
1385 DCHECK_EQ(code.size(), 3u);
1386
1387 // Lang format: bit(1) pad, unsigned int(5)[3] language.
1388 uint16_t lang = 0;
1389 for (int i = 0; i < 3; ++i)
1390 lang |= (code[i] - 0x60) << ((2 - i) * 5);
1391 RCHECK(buffer->ReadWriteUInt16(&lang));
1392 }
1393 return true;
1394}
1395
1396uint32_t Language::ComputeSize() const {
1397 // ISO-639-2/T language code: unsigned int(5)[3] language (2 bytes).
1398 return 2;
1399}
1400
1401ID3v2::ID3v2() = default;
1402ID3v2::~ID3v2() = default;
1403
1404FourCC ID3v2::BoxType() const {
1405 return FOURCC_ID32;
1406}
1407
1408bool ID3v2::ReadWriteInternal(BoxBuffer* buffer) {
1409 RCHECK(ReadWriteHeaderInternal(buffer) && language.ReadWrite(buffer) &&
1410 buffer->ReadWriteVector(&id3v2_data, buffer->Reading()
1411 ? buffer->BytesLeft()
1412 : id3v2_data.size()));
1413 return true;
1414}
1415
1416size_t ID3v2::ComputeSizeInternal() {
1417 // Skip ID3v2 box generation if there is no id3 data.
1418 return id3v2_data.size() == 0
1419 ? 0
1420 : HeaderSize() + language.ComputeSize() + id3v2_data.size();
1421}
1422
1423Metadata::Metadata() = default;
1424Metadata::~Metadata() = default;
1425
1426FourCC Metadata::BoxType() const {
1427 return FOURCC_meta;
1428}
1429
1430bool Metadata::ReadWriteInternal(BoxBuffer* buffer) {
1431 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
1432 buffer->ReadWriteChild(&handler) && buffer->TryReadWriteChild(&id3v2));
1433 return true;
1434}
1435
1436size_t Metadata::ComputeSizeInternal() {
1437 size_t id3v2_size = id3v2.ComputeSize();
1438 // Skip metadata box generation if there is no metadata box.
1439 return id3v2_size == 0 ? 0
1440 : HeaderSize() + handler.ComputeSize() + id3v2_size;
1441}
1442
1443CodecConfiguration::CodecConfiguration() = default;
1444CodecConfiguration::~CodecConfiguration() = default;
1445
1447 // CodecConfiguration box should be parsed according to format recovered in
1448 // VideoSampleEntry. |box_type| is determined dynamically there.
1449 return box_type;
1450}
1451
1452bool CodecConfiguration::ReadWriteInternal(BoxBuffer* buffer) {
1453 DCHECK_NE(box_type, FOURCC_NULL);
1454 RCHECK(ReadWriteHeaderInternal(buffer));
1455
1456 // VPCodecConfiguration box inherits from FullBox instead of Box. The extra 4
1457 // bytes are handled here.
1458 if (box_type == FOURCC_vpcC) {
1459 // Only version 1 box is supported.
1460 uint8_t vpcc_version = 1;
1461 uint32_t version_flags = vpcc_version << 24;
1462 RCHECK(buffer->ReadWriteUInt32(&version_flags));
1463 vpcc_version = version_flags >> 24;
1464 RCHECK(vpcc_version == 1);
1465 }
1466
1467 if (buffer->Reading()) {
1468 RCHECK(buffer->ReadWriteVector(&data, buffer->BytesLeft()));
1469 } else {
1470 RCHECK(buffer->ReadWriteVector(&data, data.size()));
1471 }
1472 return true;
1473}
1474
1475size_t CodecConfiguration::ComputeSizeInternal() {
1476 if (data.empty())
1477 return 0;
1478 DCHECK_NE(box_type, FOURCC_NULL);
1479 return HeaderSize() + (box_type == FOURCC_vpcC ? 4 : 0) + data.size();
1480}
1481
1482ColorParameters::ColorParameters() = default;
1483ColorParameters::~ColorParameters() = default;
1484
1486 return FOURCC_colr;
1487}
1488
1489bool ColorParameters::ReadWriteInternal(BoxBuffer* buffer) {
1490 if (buffer->Reading()) {
1491 BoxReader* reader = buffer->reader();
1492 DCHECK(reader);
1493
1494 // Parse and store the raw box for colr atom preservation in the output mp4.
1495 raw_box.assign(reader->data(), reader->data() + reader->size());
1496
1497 // Parse individual parameters for full codec string formation.
1498 RCHECK(reader->ReadFourCC(&color_parameter_type) &&
1499 reader->Read2(&color_primaries) &&
1500 reader->Read2(&transfer_characteristics) &&
1501 reader->Read2(&matrix_coefficients));
1502 // Type nclc does not contain video_full_range_flag data, and thus, it has 1
1503 // less byte than nclx. Only extract video_full_range_flag if of type nclx.
1504 if (color_parameter_type == FOURCC_nclx) {
1505 RCHECK(reader->Read1(&video_full_range_flag));
1506 }
1507 } else {
1508 // When writing, only need to write the raw_box.
1509 DCHECK(!raw_box.empty());
1510 buffer->writer()->AppendVector(raw_box);
1511 }
1512 return true;
1513}
1514
1515size_t ColorParameters::ComputeSizeInternal() {
1516 return raw_box.size();
1517}
1518
1519PixelAspectRatio::PixelAspectRatio() = default;
1520PixelAspectRatio::~PixelAspectRatio() = default;
1521
1523 return FOURCC_pasp;
1524}
1525
1526bool PixelAspectRatio::ReadWriteInternal(BoxBuffer* buffer) {
1527 RCHECK(ReadWriteHeaderInternal(buffer) &&
1528 buffer->ReadWriteUInt32(&h_spacing) &&
1529 buffer->ReadWriteUInt32(&v_spacing));
1530 return true;
1531}
1532
1533size_t PixelAspectRatio::ComputeSizeInternal() {
1534 // This box is optional. Skip it if it is not initialized.
1535 if (h_spacing == 0 && v_spacing == 0)
1536 return 0;
1537 // Both values must be positive.
1538 DCHECK(h_spacing != 0 && v_spacing != 0);
1539 return HeaderSize() + sizeof(h_spacing) + sizeof(v_spacing);
1540}
1541
1542VideoSampleEntry::VideoSampleEntry() = default;
1543VideoSampleEntry::~VideoSampleEntry() = default;
1544
1546 if (format == FOURCC_NULL) {
1547 LOG(ERROR) << "VideoSampleEntry should be parsed according to the "
1548 << "handler type recovered in its Media ancestor.";
1549 }
1550 return format;
1551}
1552
1553bool VideoSampleEntry::ReadWriteInternal(BoxBuffer* buffer) {
1554 std::vector<uint8_t> compressor_name;
1555 if (buffer->Reading()) {
1556 DCHECK(buffer->reader());
1557 format = buffer->reader()->type();
1558 } else {
1559 RCHECK(ReadWriteHeaderInternal(buffer));
1560
1561 const FourCC actual_format = GetActualFormat();
1562 switch (actual_format) {
1563 case FOURCC_av01:
1564 compressor_name.assign(std::begin(kAv1CompressorName),
1565 std::end(kAv1CompressorName));
1566 break;
1567 case FOURCC_avc1:
1568 case FOURCC_avc3:
1569 compressor_name.assign(std::begin(kAvcCompressorName),
1570 std::end(kAvcCompressorName));
1571 break;
1572 case FOURCC_dvh1:
1573 case FOURCC_dvhe:
1574 compressor_name.assign(std::begin(kDolbyVisionCompressorName),
1575 std::end(kDolbyVisionCompressorName));
1576 break;
1577 case FOURCC_hev1:
1578 case FOURCC_hvc1:
1579 compressor_name.assign(std::begin(kHevcCompressorName),
1580 std::end(kHevcCompressorName));
1581 break;
1582 case FOURCC_vp08:
1583 case FOURCC_vp09:
1584 compressor_name.assign(std::begin(kVpcCompressorName),
1585 std::end(kVpcCompressorName));
1586 break;
1587 default:
1588 LOG(ERROR) << FourCCToString(actual_format) << " is not supported.";
1589 return false;
1590 }
1591 compressor_name.resize(kCompressorNameSize);
1592 }
1593
1594 uint32_t video_resolution = kVideoResolution;
1595 uint16_t video_frame_count = kVideoFrameCount;
1596 uint16_t video_depth = kVideoDepth;
1597 int16_t predefined = -1;
1598 RCHECK(buffer->IgnoreBytes(6) && // reserved.
1599 buffer->ReadWriteUInt16(&data_reference_index) &&
1600 buffer->IgnoreBytes(16) && // predefined 0.
1601 buffer->ReadWriteUInt16(&width) && buffer->ReadWriteUInt16(&height) &&
1602 buffer->ReadWriteUInt32(&video_resolution) &&
1603 buffer->ReadWriteUInt32(&video_resolution) &&
1604 buffer->IgnoreBytes(4) && // reserved.
1605 buffer->ReadWriteUInt16(&video_frame_count) &&
1606 buffer->ReadWriteVector(&compressor_name, kCompressorNameSize) &&
1607 buffer->ReadWriteUInt16(&video_depth) &&
1608 buffer->ReadWriteInt16(&predefined));
1609
1610 RCHECK(buffer->PrepareChildren());
1611
1612 // This has to happen before reading codec configuration box as the actual
1613 // format is read from sinf.format.format, which is needed to parse the codec
1614 // configuration box.
1615 if (format == FOURCC_encv && buffer->Reading()) {
1616 // Continue scanning until a supported protection scheme is found, or
1617 // until we run out of protection schemes.
1618 while (!IsProtectionSchemeSupported(sinf.type.type))
1619 RCHECK(buffer->ReadWriteChild(&sinf));
1620 }
1621
1622 const FourCC actual_format = GetActualFormat();
1623 if (buffer->Reading()) {
1624 codec_configuration.box_type = GetCodecConfigurationBoxType(actual_format);
1625 } else {
1626 DCHECK_EQ(codec_configuration.box_type,
1627 GetCodecConfigurationBoxType(actual_format));
1628 }
1629 if (codec_configuration.box_type == FOURCC_NULL)
1630 return false;
1631
1632 RCHECK(buffer->ReadWriteChild(&codec_configuration));
1633
1634 if (buffer->Reading()) {
1635 extra_codec_configs.clear();
1636 // Handle Dolby Vision boxes and stereo/multiview related boxes.
1637 const bool is_hevc =
1638 actual_format == FOURCC_dvhe || actual_format == FOURCC_dvh1 ||
1639 actual_format == FOURCC_hev1 || actual_format == FOURCC_hvc1;
1640 if (is_hevc) {
1641 for (FourCC fourcc : {FOURCC_dvcC, FOURCC_dvvC, FOURCC_hvcE}) {
1642 CodecConfiguration dv_box;
1643 dv_box.box_type = fourcc;
1644 RCHECK(buffer->TryReadWriteChild(&dv_box));
1645 if (!dv_box.data.empty())
1646 extra_codec_configs.push_back(std::move(dv_box));
1647 }
1648 for (FourCC fourcc : {FOURCC_lhvC, FOURCC_vexu, FOURCC_hfov}) {
1649 CodecConfiguration stereo_box;
1650 stereo_box.box_type = fourcc;
1651 RCHECK(buffer->TryReadWriteChild(&stereo_box));
1652 if (!stereo_box.data.empty())
1653 extra_codec_configs.push_back(std::move(stereo_box));
1654 }
1655 }
1656 const bool is_av1 = actual_format == FOURCC_av01;
1657 if (is_av1) {
1658 for (FourCC fourcc : {FOURCC_dvvC}) {
1659 CodecConfiguration dv_box;
1660 dv_box.box_type = fourcc;
1661 RCHECK(buffer->TryReadWriteChild(&dv_box));
1662 if (!dv_box.data.empty())
1663 extra_codec_configs.push_back(std::move(dv_box));
1664 }
1665 }
1666 } else {
1667 for (CodecConfiguration& extra_codec_config : extra_codec_configs)
1668 RCHECK(buffer->ReadWriteChild(&extra_codec_config));
1669 }
1670
1671 RCHECK(buffer->TryReadWriteChild(&colr));
1672 RCHECK(buffer->TryReadWriteChild(&pixel_aspect));
1673
1674 // Somehow Edge does not support having sinf box before codec_configuration,
1675 // box, so just do it in the end of VideoSampleEntry. See
1676 // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12658991/
1677 if (format == FOURCC_encv && !buffer->Reading()) {
1678 DCHECK(IsProtectionSchemeSupported(sinf.type.type));
1679 RCHECK(buffer->ReadWriteChild(&sinf));
1680 }
1681 return true;
1682}
1683
1684size_t VideoSampleEntry::ComputeSizeInternal() {
1685 const FourCC actual_format = GetActualFormat();
1686 if (actual_format == FOURCC_NULL)
1687 return 0;
1688 codec_configuration.box_type = GetCodecConfigurationBoxType(actual_format);
1689 DCHECK_NE(codec_configuration.box_type, FOURCC_NULL);
1690 size_t size = HeaderSize() + sizeof(data_reference_index) + sizeof(width) +
1691 sizeof(height) + sizeof(kVideoResolution) * 2 +
1692 sizeof(kVideoFrameCount) + sizeof(kVideoDepth) +
1693 colr.ComputeSize() + pixel_aspect.ComputeSize() +
1694 sinf.ComputeSize() + codec_configuration.ComputeSize() +
1695 kCompressorNameSize + 6 + 4 + 16 +
1696 2; // 6 + 4 bytes reserved, 16 + 2 bytes predefined.
1697 for (CodecConfiguration& codec_config : extra_codec_configs)
1698 size += codec_config.ComputeSize();
1699 return size;
1700}
1701
1702FourCC VideoSampleEntry::GetCodecConfigurationBoxType(FourCC l_format) const {
1703 switch (l_format) {
1704 case FOURCC_av01:
1705 return FOURCC_av1C;
1706 case FOURCC_avc1:
1707 case FOURCC_avc3:
1708 return FOURCC_avcC;
1709 case FOURCC_dvh1:
1710 case FOURCC_dvhe:
1711 case FOURCC_hev1:
1712 case FOURCC_hvc1:
1713 return FOURCC_hvcC;
1714 case FOURCC_vp08:
1715 case FOURCC_vp09:
1716 return FOURCC_vpcC;
1717 default:
1718 LOG(ERROR) << FourCCToString(l_format) << " is not supported.";
1719 return FOURCC_NULL;
1720 }
1721}
1722
1723std::vector<uint8_t> VideoSampleEntry::ExtraCodecConfigsAsVector() const {
1724 BufferWriter buffer;
1725 for (CodecConfiguration codec_config : extra_codec_configs)
1726 codec_config.Write(&buffer);
1727 return std::vector<uint8_t>(buffer.Buffer(), buffer.Buffer() + buffer.Size());
1728}
1729
1730bool VideoSampleEntry::ParseExtraCodecConfigsVector(
1731 const std::vector<uint8_t>& data) {
1732 extra_codec_configs.clear();
1733 size_t pos = 0;
1734 while (pos < data.size()) {
1735 bool err = false;
1736 std::unique_ptr<BoxReader> box_reader(
1737 BoxReader::ReadBox(data.data() + pos, data.size() - pos, &err));
1738 RCHECK(!err && box_reader);
1739
1740 CodecConfiguration codec_config;
1741 codec_config.box_type = box_reader->type();
1742 RCHECK(codec_config.Parse(box_reader.get()));
1743 extra_codec_configs.push_back(std::move(codec_config));
1744
1745 pos += box_reader->pos();
1746 }
1747 return true;
1748}
1749
1750bool VideoSampleEntry::HaveDolbyVisionConfig() const {
1751 for (CodecConfiguration codec_config : extra_codec_configs) {
1752 if (codec_config.box_type == FOURCC_dvcC ||
1753 codec_config.box_type == FOURCC_dvvC ||
1754 codec_config.box_type == FOURCC_hvcE)
1755 return true;
1756 }
1757 return false;
1758}
1759
1760bool VideoSampleEntry::HaveLHEVCConfig() const {
1761 for (CodecConfiguration codec_config : extra_codec_configs) {
1762 if (codec_config.box_type == FOURCC_lhvC)
1763 return true;
1764 }
1765 return false;
1766}
1767
1768ElementaryStreamDescriptor::ElementaryStreamDescriptor() = default;
1769ElementaryStreamDescriptor::~ElementaryStreamDescriptor() = default;
1770
1772 return FOURCC_esds;
1773}
1774
1775bool ElementaryStreamDescriptor::ReadWriteInternal(BoxBuffer* buffer) {
1776 RCHECK(ReadWriteHeaderInternal(buffer));
1777 if (buffer->Reading()) {
1778 std::vector<uint8_t> data;
1779 RCHECK(buffer->ReadWriteVector(&data, buffer->BytesLeft()));
1780 RCHECK(es_descriptor.Parse(data));
1781 if (es_descriptor.decoder_config_descriptor().IsAAC()) {
1782 RCHECK(aac_audio_specific_config.Parse(
1783 es_descriptor.decoder_config_descriptor()
1784 .decoder_specific_info_descriptor()
1785 .data()));
1786 }
1787 } else {
1788 DCHECK(buffer->writer());
1789 es_descriptor.Write(buffer->writer());
1790 }
1791 return true;
1792}
1793
1794size_t ElementaryStreamDescriptor::ComputeSizeInternal() {
1795 // This box is optional. Skip it if not initialized.
1796 if (es_descriptor.decoder_config_descriptor().object_type() ==
1797 ObjectType::kForbidden) {
1798 return 0;
1799 }
1800 return HeaderSize() + es_descriptor.ComputeSize();
1801}
1802
1803MHAConfiguration::MHAConfiguration() = default;
1804MHAConfiguration::~MHAConfiguration() = default;
1805
1807 return FOURCC_mhaC;
1808}
1809
1810bool MHAConfiguration::ReadWriteInternal(BoxBuffer* buffer) {
1811 RCHECK(ReadWriteHeaderInternal(buffer) &&
1812 buffer->ReadWriteVector(
1813 &data, buffer->Reading() ? buffer->BytesLeft() : data.size()));
1814 RCHECK(data.size() > 1);
1815 mpeg_h_3da_profile_level_indication = data[1];
1816 return true;
1817}
1818
1819size_t MHAConfiguration::ComputeSizeInternal() {
1820 // This box is optional. Skip it if not initialized.
1821 if (data.empty())
1822 return 0;
1823 return HeaderSize() + data.size();
1824}
1825
1826DTSSpecific::DTSSpecific() = default;
1827DTSSpecific::~DTSSpecific() = default;
1828;
1829
1830FourCC DTSSpecific::BoxType() const {
1831 return FOURCC_ddts;
1832}
1833
1834bool DTSSpecific::ReadWriteInternal(BoxBuffer* buffer) {
1835 RCHECK(ReadWriteHeaderInternal(buffer) &&
1836 buffer->ReadWriteUInt32(&sampling_frequency) &&
1837 buffer->ReadWriteUInt32(&max_bitrate) &&
1838 buffer->ReadWriteUInt32(&avg_bitrate) &&
1839 buffer->ReadWriteUInt8(&pcm_sample_depth));
1840
1841 if (buffer->Reading()) {
1842 RCHECK(buffer->ReadWriteVector(&extra_data, buffer->BytesLeft()));
1843 } else {
1844 if (extra_data.empty()) {
1845 extra_data.assign(kDdtsExtraData,
1846 kDdtsExtraData + sizeof(kDdtsExtraData));
1847 }
1848 RCHECK(buffer->ReadWriteVector(&extra_data, extra_data.size()));
1849 }
1850 return true;
1851}
1852
1853size_t DTSSpecific::ComputeSizeInternal() {
1854 // This box is optional. Skip it if not initialized.
1855 if (sampling_frequency == 0)
1856 return 0;
1857 return HeaderSize() + sizeof(sampling_frequency) + sizeof(max_bitrate) +
1858 sizeof(avg_bitrate) + sizeof(pcm_sample_depth) +
1859 sizeof(kDdtsExtraData);
1860}
1861
1862UDTSSpecific::UDTSSpecific() = default;
1863UDTSSpecific::~UDTSSpecific() = default;
1864
1866 return FOURCC_udts;
1867}
1868
1869bool UDTSSpecific::ReadWriteInternal(BoxBuffer* buffer) {
1870 RCHECK(ReadWriteHeaderInternal(buffer) &&
1871 buffer->ReadWriteVector(
1872 &data, buffer->Reading() ? buffer->BytesLeft() : data.size()));
1873 return true;
1874}
1875
1876size_t UDTSSpecific::ComputeSizeInternal() {
1877 // This box is optional. Skip it if not initialized.
1878 if (data.empty())
1879 return 0;
1880 return HeaderSize() + data.size();
1881}
1882
1883AC3Specific::AC3Specific() = default;
1884AC3Specific::~AC3Specific() = default;
1885
1886FourCC AC3Specific::BoxType() const {
1887 return FOURCC_dac3;
1888}
1889
1890bool AC3Specific::ReadWriteInternal(BoxBuffer* buffer) {
1891 RCHECK(ReadWriteHeaderInternal(buffer) &&
1892 buffer->ReadWriteVector(
1893 &data, buffer->Reading() ? buffer->BytesLeft() : data.size()));
1894 return true;
1895}
1896
1897size_t AC3Specific::ComputeSizeInternal() {
1898 // This box is optional. Skip it if not initialized.
1899 if (data.empty())
1900 return 0;
1901 return HeaderSize() + data.size();
1902}
1903
1904EC3Specific::EC3Specific() = default;
1905EC3Specific::~EC3Specific() = default;
1906
1907FourCC EC3Specific::BoxType() const {
1908 return FOURCC_dec3;
1909}
1910
1911bool EC3Specific::ReadWriteInternal(BoxBuffer* buffer) {
1912 RCHECK(ReadWriteHeaderInternal(buffer));
1913 size_t size = buffer->Reading() ? buffer->BytesLeft() : data.size();
1914 RCHECK(buffer->ReadWriteVector(&data, size));
1915 return true;
1916}
1917
1918size_t EC3Specific::ComputeSizeInternal() {
1919 // This box is optional. Skip it if not initialized.
1920 if (data.empty())
1921 return 0;
1922 return HeaderSize() + data.size();
1923}
1924
1925AC4Specific::AC4Specific() = default;
1926AC4Specific::~AC4Specific() = default;
1927
1928FourCC AC4Specific::BoxType() const {
1929 return FOURCC_dac4;
1930}
1931
1932bool AC4Specific::ReadWriteInternal(BoxBuffer* buffer) {
1933 RCHECK(ReadWriteHeaderInternal(buffer));
1934 size_t size = buffer->Reading() ? buffer->BytesLeft() : data.size();
1935 RCHECK(buffer->ReadWriteVector(&data, size));
1936 return true;
1937}
1938
1939size_t AC4Specific::ComputeSizeInternal() {
1940 // This box is optional. Skip it if not initialized.
1941 if (data.empty())
1942 return 0;
1943 return HeaderSize() + data.size();
1944}
1945
1946OpusSpecific::OpusSpecific() = default;
1947OpusSpecific::~OpusSpecific() = default;
1948
1950 return FOURCC_dOps;
1951}
1952
1953bool OpusSpecific::ReadWriteInternal(BoxBuffer* buffer) {
1954 RCHECK(ReadWriteHeaderInternal(buffer));
1955 if (buffer->Reading()) {
1956 std::vector<uint8_t> data;
1957 const int kMinOpusSpecificBoxDataSize = 11;
1958 RCHECK(buffer->BytesLeft() >= kMinOpusSpecificBoxDataSize);
1959 RCHECK(buffer->ReadWriteVector(&data, buffer->BytesLeft()));
1960 preskip = data[2] + (data[3] << 8);
1961
1962 // https://tools.ietf.org/html/draft-ietf-codec-oggopus-06#section-5
1963 BufferWriter writer;
1964 writer.AppendInt(FOURCC_Opus);
1965 writer.AppendInt(FOURCC_Head);
1966 // The version must always be 1.
1967 const uint8_t kOpusIdentificationHeaderVersion = 1;
1968 data[0] = kOpusIdentificationHeaderVersion;
1969 writer.AppendVector(data);
1970 writer.SwapBuffer(&opus_identification_header);
1971 } else {
1972 // https://tools.ietf.org/html/draft-ietf-codec-oggopus-06#section-5
1973 // The first 8 bytes is "magic signature".
1974 const size_t kOpusMagicSignatureSize = 8u;
1975 DCHECK_GT(opus_identification_header.size(), kOpusMagicSignatureSize);
1976 // https://www.opus-codec.org/docs/opus_in_isobmff.html
1977 // The version field shall be set to 0.
1978 const uint8_t kOpusSpecificBoxVersion = 0;
1979 buffer->writer()->AppendInt(kOpusSpecificBoxVersion);
1980 buffer->writer()->AppendArray(
1981 &opus_identification_header[kOpusMagicSignatureSize + 1],
1982 opus_identification_header.size() - kOpusMagicSignatureSize - 1);
1983 }
1984 return true;
1985}
1986
1987size_t OpusSpecific::ComputeSizeInternal() {
1988 // This box is optional. Skip it if not initialized.
1989 if (opus_identification_header.empty())
1990 return 0;
1991 // https://tools.ietf.org/html/draft-ietf-codec-oggopus-06#section-5
1992 // The first 8 bytes is "magic signature".
1993 const size_t kOpusMagicSignatureSize = 8u;
1994 DCHECK_GT(opus_identification_header.size(), kOpusMagicSignatureSize);
1995 return HeaderSize() + opus_identification_header.size() -
1996 kOpusMagicSignatureSize;
1997}
1998
1999IAMFSpecific::IAMFSpecific() = default;
2000IAMFSpecific::~IAMFSpecific() = default;
2001
2003 return FOURCC_iacb;
2004}
2005
2006bool IAMFSpecific::ReadWriteInternal(BoxBuffer* buffer) {
2007 RCHECK(ReadWriteHeaderInternal(buffer));
2008 size_t size = buffer->Reading() ? buffer->BytesLeft() : data.size();
2009 RCHECK(buffer->ReadWriteVector(&data, size));
2010 return true;
2011}
2012
2013size_t IAMFSpecific::ComputeSizeInternal() {
2014 // This box is optional. Skip it if not initialized.
2015 if (data.empty())
2016 return 0;
2017 return HeaderSize() + data.size();
2018}
2019
2020FlacSpecific::FlacSpecific() = default;
2021FlacSpecific::~FlacSpecific() = default;
2022
2024 return FOURCC_dfLa;
2025}
2026
2027bool FlacSpecific::ReadWriteInternal(BoxBuffer* buffer) {
2028 RCHECK(ReadWriteHeaderInternal(buffer));
2029 size_t size = buffer->Reading() ? buffer->BytesLeft() : data.size();
2030 RCHECK(buffer->ReadWriteVector(&data, size));
2031 return true;
2032}
2033
2034size_t FlacSpecific::ComputeSizeInternal() {
2035 // This box is optional. Skip it if not initialized.
2036 if (data.empty())
2037 return 0;
2038 return HeaderSize() + data.size();
2039}
2040
2041ALACSpecific::ALACSpecific() = default;
2042ALACSpecific::~ALACSpecific() = default;
2043
2045 return FOURCC_alac;
2046}
2047
2048bool ALACSpecific::ReadWriteInternal(BoxBuffer* buffer) {
2049 RCHECK(ReadWriteHeaderInternal(buffer));
2050 size_t size = buffer->Reading() ? buffer->BytesLeft() : data.size();
2051 RCHECK(buffer->ReadWriteVector(&data, size));
2052 return true;
2053}
2054
2055size_t ALACSpecific::ComputeSizeInternal() {
2056 // This box is optional. Skip it if not initialized.
2057 if (data.empty())
2058 return 0;
2059 return HeaderSize() + data.size();
2060}
2061
2062AudioSampleEntry::AudioSampleEntry() = default;
2063AudioSampleEntry::~AudioSampleEntry() = default;
2064
2066 if (format == FOURCC_NULL) {
2067 LOG(ERROR) << "AudioSampleEntry should be parsed according to the "
2068 << "handler type recovered in its Media ancestor.";
2069 }
2070 return format;
2071}
2072
2073bool AudioSampleEntry::ReadWriteInternal(BoxBuffer* buffer) {
2074 if (buffer->Reading()) {
2075 DCHECK(buffer->reader());
2076 format = buffer->reader()->type();
2077 } else {
2078 RCHECK(ReadWriteHeaderInternal(buffer));
2079 }
2080
2081 // Convert from integer to 16.16 fixed point for writing.
2082 samplerate <<= 16;
2083 RCHECK(buffer->IgnoreBytes(6) && // reserved.
2084 buffer->ReadWriteUInt16(&data_reference_index) &&
2085 buffer->IgnoreBytes(8) && // reserved.
2086 buffer->ReadWriteUInt16(&channelcount) &&
2087 buffer->ReadWriteUInt16(&samplesize) &&
2088 buffer->IgnoreBytes(4) && // predefined.
2089 buffer->ReadWriteUInt32(&samplerate));
2090 // Convert from 16.16 fixed point to integer.
2091 samplerate >>= 16;
2092
2093 RCHECK(buffer->PrepareChildren());
2094
2095 RCHECK(buffer->TryReadWriteChild(&esds));
2096 RCHECK(buffer->TryReadWriteChild(&ddts));
2097 RCHECK(buffer->TryReadWriteChild(&udts));
2098 RCHECK(buffer->TryReadWriteChild(&dac3));
2099 RCHECK(buffer->TryReadWriteChild(&dec3));
2100 RCHECK(buffer->TryReadWriteChild(&dac4));
2101 RCHECK(buffer->TryReadWriteChild(&dops));
2102 RCHECK(buffer->TryReadWriteChild(&iacb));
2103 RCHECK(buffer->TryReadWriteChild(&dfla));
2104 RCHECK(buffer->TryReadWriteChild(&mhac));
2105 RCHECK(buffer->TryReadWriteChild(&alac));
2106
2107 // Somehow Edge does not support having sinf box before codec_configuration,
2108 // box, so just do it in the end of AudioSampleEntry. See
2109 // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12658991/
2110 if (format == FOURCC_enca) {
2111 if (buffer->Reading()) {
2112 // Continue scanning until a supported protection scheme is found, or
2113 // until we run out of protection schemes.
2114 while (!IsProtectionSchemeSupported(sinf.type.type))
2115 RCHECK(buffer->ReadWriteChild(&sinf));
2116 } else {
2117 DCHECK(IsProtectionSchemeSupported(sinf.type.type));
2118 RCHECK(buffer->ReadWriteChild(&sinf));
2119 }
2120 }
2121 return true;
2122}
2123
2124size_t AudioSampleEntry::ComputeSizeInternal() {
2125 if (GetActualFormat() == FOURCC_NULL)
2126 return 0;
2127 return HeaderSize() + sizeof(data_reference_index) + sizeof(channelcount) +
2128 sizeof(samplesize) + sizeof(samplerate) + sinf.ComputeSize() +
2129 esds.ComputeSize() + ddts.ComputeSize() + dac3.ComputeSize() +
2130 dec3.ComputeSize() + dops.ComputeSize() + dfla.ComputeSize() +
2131 dac4.ComputeSize() + mhac.ComputeSize() + udts.ComputeSize() +
2132 alac.ComputeSize() + iacb.ComputeSize() +
2133 // Reserved and predefined bytes.
2134 6 + 8 + // 6 + 8 bytes reserved.
2135 4; // 4 bytes predefined.
2136}
2137
2138WebVTTConfigurationBox::WebVTTConfigurationBox() = default;
2139WebVTTConfigurationBox::~WebVTTConfigurationBox() = default;
2140
2142 return FOURCC_vttC;
2143}
2144
2145bool WebVTTConfigurationBox::ReadWriteInternal(BoxBuffer* buffer) {
2146 RCHECK(ReadWriteHeaderInternal(buffer));
2147 return buffer->ReadWriteString(
2148 &config, buffer->Reading() ? buffer->BytesLeft() : config.size());
2149}
2150
2151size_t WebVTTConfigurationBox::ComputeSizeInternal() {
2152 return HeaderSize() + config.size();
2153}
2154
2155WebVTTSourceLabelBox::WebVTTSourceLabelBox() = default;
2156WebVTTSourceLabelBox::~WebVTTSourceLabelBox() = default;
2157
2159 return FOURCC_vlab;
2160}
2161
2162bool WebVTTSourceLabelBox::ReadWriteInternal(BoxBuffer* buffer) {
2163 RCHECK(ReadWriteHeaderInternal(buffer));
2164 return buffer->ReadWriteString(&source_label, buffer->Reading()
2165 ? buffer->BytesLeft()
2166 : source_label.size());
2167}
2168
2169size_t WebVTTSourceLabelBox::ComputeSizeInternal() {
2170 if (source_label.empty())
2171 return 0;
2172 return HeaderSize() + source_label.size();
2173}
2174
2175TextSampleEntry::TextSampleEntry() = default;
2176TextSampleEntry::~TextSampleEntry() = default;
2177
2179 if (format == FOURCC_NULL) {
2180 LOG(ERROR) << "TextSampleEntry should be parsed according to the "
2181 << "handler type recovered in its Media ancestor.";
2182 }
2183 return format;
2184}
2185
2186bool TextSampleEntry::ReadWriteInternal(BoxBuffer* buffer) {
2187 if (buffer->Reading()) {
2188 DCHECK(buffer->reader());
2189 format = buffer->reader()->type();
2190 } else {
2191 RCHECK(ReadWriteHeaderInternal(buffer));
2192 }
2193 RCHECK(buffer->IgnoreBytes(6) && // reserved for SampleEntry.
2194 buffer->ReadWriteUInt16(&data_reference_index));
2195
2196 if (format == FOURCC_wvtt) {
2197 // TODO(rkuroiwa): Handle the optional MPEG4BitRateBox.
2198 RCHECK(buffer->PrepareChildren() && buffer->ReadWriteChild(&config) &&
2199 buffer->ReadWriteChild(&label));
2200 } else if (format == FOURCC_stpp) {
2201 // These are marked as "optional"; but they should still have the
2202 // null-terminator, so this should still work.
2203 RCHECK(buffer->ReadWriteCString(&namespace_) &&
2204 buffer->ReadWriteCString(&schema_location));
2205 }
2206 return true;
2207}
2208
2209size_t TextSampleEntry::ComputeSizeInternal() {
2210 // 6 for the (anonymous) reserved bytes for SampleEntry class.
2211 size_t ret = HeaderSize() + 6 + sizeof(data_reference_index);
2212 if (format == FOURCC_wvtt) {
2213 ret += config.ComputeSize() + label.ComputeSize();
2214 } else if (format == FOURCC_stpp) {
2215 // +2 for the two null terminators for these strings.
2216 ret += namespace_.size() + schema_location.size() + 2;
2217 }
2218 return ret;
2219}
2220
2221MediaHeader::MediaHeader() = default;
2222MediaHeader::~MediaHeader() = default;
2223
2224FourCC MediaHeader::BoxType() const {
2225 return FOURCC_mdhd;
2226}
2227
2228bool MediaHeader::ReadWriteInternal(BoxBuffer* buffer) {
2229 RCHECK(ReadWriteHeaderInternal(buffer));
2230
2231 uint8_t num_bytes = (version == 1) ? sizeof(uint64_t) : sizeof(uint32_t);
2232 RCHECK(buffer->ReadWriteUInt64NBytes(&creation_time, num_bytes) &&
2233 buffer->ReadWriteUInt64NBytes(&modification_time, num_bytes) &&
2234 buffer->ReadWriteUInt32(&timescale) &&
2235 buffer->ReadWriteUInt64NBytes(&duration, num_bytes) &&
2236 language.ReadWrite(buffer) &&
2237 // predefined.
2238 buffer->IgnoreBytes(2));
2239 return true;
2240}
2241
2242size_t MediaHeader::ComputeSizeInternal() {
2243 version = IsFitIn32Bits(creation_time, modification_time, duration) ? 0 : 1;
2244 return HeaderSize() + sizeof(timescale) +
2245 sizeof(uint32_t) * (1 + version) * 3 + language.ComputeSize() +
2246 2; // 2 bytes predefined.
2247}
2248
2249VideoMediaHeader::VideoMediaHeader() {
2250 const uint32_t kVideoMediaHeaderFlags = 1;
2251 flags = kVideoMediaHeaderFlags;
2252}
2253
2254VideoMediaHeader::~VideoMediaHeader() = default;
2255
2257 return FOURCC_vmhd;
2258}
2259bool VideoMediaHeader::ReadWriteInternal(BoxBuffer* buffer) {
2260 RCHECK(ReadWriteHeaderInternal(buffer) &&
2261 buffer->ReadWriteUInt16(&graphicsmode) &&
2262 buffer->ReadWriteUInt16(&opcolor_red) &&
2263 buffer->ReadWriteUInt16(&opcolor_green) &&
2264 buffer->ReadWriteUInt16(&opcolor_blue));
2265 return true;
2266}
2267
2268size_t VideoMediaHeader::ComputeSizeInternal() {
2269 return HeaderSize() + sizeof(graphicsmode) + sizeof(opcolor_red) +
2270 sizeof(opcolor_green) + sizeof(opcolor_blue);
2271}
2272
2273SoundMediaHeader::SoundMediaHeader() = default;
2274SoundMediaHeader::~SoundMediaHeader() = default;
2275
2277 return FOURCC_smhd;
2278}
2279
2280bool SoundMediaHeader::ReadWriteInternal(BoxBuffer* buffer) {
2281 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->ReadWriteUInt16(&balance) &&
2282 buffer->IgnoreBytes(2)); // reserved.
2283 return true;
2284}
2285
2286size_t SoundMediaHeader::ComputeSizeInternal() {
2287 return HeaderSize() + sizeof(balance) + sizeof(uint16_t);
2288}
2289
2290NullMediaHeader::NullMediaHeader() = default;
2291NullMediaHeader::~NullMediaHeader() = default;
2292
2294 return FOURCC_nmhd;
2295}
2296
2297bool NullMediaHeader::ReadWriteInternal(BoxBuffer* buffer) {
2298 return ReadWriteHeaderInternal(buffer);
2299}
2300
2301size_t NullMediaHeader::ComputeSizeInternal() {
2302 return HeaderSize();
2303}
2304
2305SubtitleMediaHeader::SubtitleMediaHeader() = default;
2306SubtitleMediaHeader::~SubtitleMediaHeader() = default;
2307
2309 return FOURCC_sthd;
2310}
2311
2312bool SubtitleMediaHeader::ReadWriteInternal(BoxBuffer* buffer) {
2313 return ReadWriteHeaderInternal(buffer);
2314}
2315
2316size_t SubtitleMediaHeader::ComputeSizeInternal() {
2317 return HeaderSize();
2318}
2319
2320DataEntryUrl::DataEntryUrl() {
2321 const uint32_t kDataEntryUrlFlags = 1;
2322 flags = kDataEntryUrlFlags;
2323}
2324
2325DataEntryUrl::~DataEntryUrl() = default;
2326
2328 return FOURCC_url;
2329}
2330bool DataEntryUrl::ReadWriteInternal(BoxBuffer* buffer) {
2331 RCHECK(ReadWriteHeaderInternal(buffer));
2332 if (buffer->Reading()) {
2333 RCHECK(buffer->ReadWriteVector(&location, buffer->BytesLeft()));
2334 } else {
2335 RCHECK(buffer->ReadWriteVector(&location, location.size()));
2336 }
2337 return true;
2338}
2339
2340size_t DataEntryUrl::ComputeSizeInternal() {
2341 return HeaderSize() + location.size();
2342}
2343
2344DataReference::DataReference() = default;
2345DataReference::~DataReference() = default;
2346
2348 return FOURCC_dref;
2349}
2350bool DataReference::ReadWriteInternal(BoxBuffer* buffer) {
2351 uint32_t entry_count = static_cast<uint32_t>(data_entry.size());
2352 RCHECK(ReadWriteHeaderInternal(buffer) &&
2353 buffer->ReadWriteUInt32(&entry_count));
2354 data_entry.resize(entry_count);
2355 RCHECK(buffer->PrepareChildren());
2356 for (uint32_t i = 0; i < entry_count; ++i)
2357 RCHECK(buffer->ReadWriteChild(&data_entry[i]));
2358 return true;
2359}
2360
2361size_t DataReference::ComputeSizeInternal() {
2362 uint32_t count = static_cast<uint32_t>(data_entry.size());
2363 size_t box_size = HeaderSize() + sizeof(count);
2364 for (uint32_t i = 0; i < count; ++i)
2365 box_size += data_entry[i].ComputeSize();
2366 return box_size;
2367}
2368
2369DataInformation::DataInformation() = default;
2370DataInformation::~DataInformation() = default;
2371
2373 return FOURCC_dinf;
2374}
2375
2376bool DataInformation::ReadWriteInternal(BoxBuffer* buffer) {
2377 return ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
2378 buffer->ReadWriteChild(&dref);
2379}
2380
2381size_t DataInformation::ComputeSizeInternal() {
2382 return HeaderSize() + dref.ComputeSize();
2383}
2384
2385MediaInformation::MediaInformation() = default;
2386MediaInformation::~MediaInformation() = default;
2387
2389 return FOURCC_minf;
2390}
2391
2392bool MediaInformation::ReadWriteInternal(BoxBuffer* buffer) {
2393 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
2394 buffer->ReadWriteChild(&dinf) &&
2395 buffer->ReadWriteChild(&sample_table));
2396 switch (sample_table.description.type) {
2397 case kVideo:
2398 RCHECK(buffer->ReadWriteChild(&vmhd));
2399 break;
2400 case kAudio:
2401 RCHECK(buffer->ReadWriteChild(&smhd));
2402 break;
2403 case kText:
2404 RCHECK(buffer->TryReadWriteChild(&nmhd));
2405 break;
2406 case kSubtitle:
2407 RCHECK(buffer->TryReadWriteChild(&sthd));
2408 break;
2409 default:
2410 NOTIMPLEMENTED();
2411 }
2412 // Hint is not supported for now.
2413 return true;
2414}
2415
2416size_t MediaInformation::ComputeSizeInternal() {
2417 size_t box_size =
2418 HeaderSize() + dinf.ComputeSize() + sample_table.ComputeSize();
2419 switch (sample_table.description.type) {
2420 case kVideo:
2421 box_size += vmhd.ComputeSize();
2422 break;
2423 case kAudio:
2424 box_size += smhd.ComputeSize();
2425 break;
2426 case kText:
2427 box_size += nmhd.ComputeSize();
2428 break;
2429 case kSubtitle:
2430 box_size += sthd.ComputeSize();
2431 break;
2432 default:
2433 NOTIMPLEMENTED();
2434 }
2435 return box_size;
2436}
2437
2438Media::Media() = default;
2439Media::~Media() = default;
2440
2441FourCC Media::BoxType() const {
2442 return FOURCC_mdia;
2443}
2444
2445bool Media::ReadWriteInternal(BoxBuffer* buffer) {
2446 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
2447 buffer->ReadWriteChild(&header));
2448 if (buffer->Reading()) {
2449 RCHECK(buffer->ReadWriteChild(&handler));
2450 // Maddeningly, the HandlerReference box specifies how to parse the
2451 // SampleDescription box, making the latter the only box (of those that we
2452 // support) which cannot be parsed correctly on its own (or even with
2453 // information from its strict ancestor tree). We thus copy the handler type
2454 // to the sample description box *before* parsing it to provide this
2455 // information while parsing.
2456 information.sample_table.description.type =
2457 FourCCToTrackType(handler.handler_type);
2458 } else {
2459 handler.handler_type =
2460 TrackTypeToFourCC(information.sample_table.description.type);
2461 RCHECK(handler.handler_type != FOURCC_NULL);
2462 RCHECK(buffer->ReadWriteChild(&handler));
2463 }
2464 RCHECK(buffer->ReadWriteChild(&information));
2465 return true;
2466}
2467
2468size_t Media::ComputeSizeInternal() {
2469 handler.handler_type =
2470 TrackTypeToFourCC(information.sample_table.description.type);
2471 return HeaderSize() + header.ComputeSize() + handler.ComputeSize() +
2472 information.ComputeSize();
2473}
2474
2475Track::Track() = default;
2476Track::~Track() = default;
2477
2478FourCC Track::BoxType() const {
2479 return FOURCC_trak;
2480}
2481
2482bool Track::ReadWriteInternal(BoxBuffer* buffer) {
2483 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
2484 buffer->ReadWriteChild(&header) && buffer->ReadWriteChild(&media) &&
2485 buffer->TryReadWriteChild(&edit) &&
2486 buffer->TryReadWriteChild(&sample_encryption));
2487 return true;
2488}
2489
2490size_t Track::ComputeSizeInternal() {
2491 return HeaderSize() + header.ComputeSize() + media.ComputeSize() +
2492 edit.ComputeSize();
2493}
2494
2495MovieExtendsHeader::MovieExtendsHeader() = default;
2496MovieExtendsHeader::~MovieExtendsHeader() = default;
2497
2499 return FOURCC_mehd;
2500}
2501
2502bool MovieExtendsHeader::ReadWriteInternal(BoxBuffer* buffer) {
2503 RCHECK(ReadWriteHeaderInternal(buffer));
2504 size_t num_bytes = (version == 1) ? sizeof(uint64_t) : sizeof(uint32_t);
2505 RCHECK(buffer->ReadWriteUInt64NBytes(&fragment_duration, num_bytes));
2506 return true;
2507}
2508
2509size_t MovieExtendsHeader::ComputeSizeInternal() {
2510 // This box is optional. Skip it if it is not used.
2511 if (fragment_duration == 0)
2512 return 0;
2513 version = IsFitIn32Bits(fragment_duration) ? 0 : 1;
2514 return HeaderSize() + sizeof(uint32_t) * (1 + version);
2515}
2516
2517TrackExtends::TrackExtends() = default;
2518TrackExtends::~TrackExtends() = default;
2519
2521 return FOURCC_trex;
2522}
2523
2524bool TrackExtends::ReadWriteInternal(BoxBuffer* buffer) {
2525 RCHECK(ReadWriteHeaderInternal(buffer) &&
2526 buffer->ReadWriteUInt32(&track_id) &&
2527 buffer->ReadWriteUInt32(&default_sample_description_index) &&
2528 buffer->ReadWriteUInt32(&default_sample_duration) &&
2529 buffer->ReadWriteUInt32(&default_sample_size) &&
2530 buffer->ReadWriteUInt32(&default_sample_flags));
2531 return true;
2532}
2533
2534size_t TrackExtends::ComputeSizeInternal() {
2535 return HeaderSize() + sizeof(track_id) +
2536 sizeof(default_sample_description_index) +
2537 sizeof(default_sample_duration) + sizeof(default_sample_size) +
2538 sizeof(default_sample_flags);
2539}
2540
2541MovieExtends::MovieExtends() = default;
2542MovieExtends::~MovieExtends() = default;
2543
2545 return FOURCC_mvex;
2546}
2547
2548bool MovieExtends::ReadWriteInternal(BoxBuffer* buffer) {
2549 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
2550 buffer->TryReadWriteChild(&header));
2551 if (buffer->Reading()) {
2552 DCHECK(buffer->reader());
2553 RCHECK(buffer->reader()->ReadChildren(&tracks));
2554 } else {
2555 for (uint32_t i = 0; i < tracks.size(); ++i)
2556 RCHECK(buffer->ReadWriteChild(&tracks[i]));
2557 }
2558 return true;
2559}
2560
2561size_t MovieExtends::ComputeSizeInternal() {
2562 // This box is optional. Skip it if it does not contain any track.
2563 if (tracks.size() == 0)
2564 return 0;
2565 size_t box_size = HeaderSize() + header.ComputeSize();
2566 for (uint32_t i = 0; i < tracks.size(); ++i)
2567 box_size += tracks[i].ComputeSize();
2568 return box_size;
2569}
2570
2571Movie::Movie() = default;
2572Movie::~Movie() = default;
2573
2574FourCC Movie::BoxType() const {
2575 return FOURCC_moov;
2576}
2577
2578bool Movie::ReadWriteInternal(BoxBuffer* buffer) {
2579 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
2580 buffer->ReadWriteChild(&header));
2581 if (buffer->Reading()) {
2582 BoxReader* reader = buffer->reader();
2583 DCHECK(reader);
2584 RCHECK(reader->ReadChildren(&tracks) && reader->TryReadChild(&extends) &&
2585 reader->TryReadChildren(&pssh));
2586 } else {
2587 // The 'meta' box is not well formed in the video captured by Android's
2588 // default camera app: spec indicates that it is a FullBox but it is written
2589 // as a Box. This results in the box failed to be parsed. See
2590 // https://github.com/shaka-project/shaka-packager/issues/319 for details.
2591 // We do not care the content of metadata box in the source content, so just
2592 // skip reading the box.
2593 RCHECK(buffer->TryReadWriteChild(&metadata));
2594 if (absl::GetFlag(FLAGS_mvex_before_trak)) {
2595 // |extends| has to be written before |tracks| to workaround Android
2596 // MediaExtractor bug which requires |mvex| to be placed before |trak|.
2597 // See https://github.com/shaka-project/shaka-packager/issues/711 for
2598 // details.
2599 RCHECK(buffer->TryReadWriteChild(&extends));
2600 }
2601 for (uint32_t i = 0; i < tracks.size(); ++i)
2602 RCHECK(buffer->ReadWriteChild(&tracks[i]));
2603 if (!absl::GetFlag(FLAGS_mvex_before_trak)) {
2604 RCHECK(buffer->TryReadWriteChild(&extends));
2605 }
2606 for (uint32_t i = 0; i < pssh.size(); ++i)
2607 RCHECK(buffer->ReadWriteChild(&pssh[i]));
2608 }
2609 return true;
2610}
2611
2612size_t Movie::ComputeSizeInternal() {
2613 size_t box_size = HeaderSize() + header.ComputeSize() +
2614 metadata.ComputeSize() + extends.ComputeSize();
2615 for (uint32_t i = 0; i < tracks.size(); ++i)
2616 box_size += tracks[i].ComputeSize();
2617 for (uint32_t i = 0; i < pssh.size(); ++i)
2618 box_size += pssh[i].ComputeSize();
2619 return box_size;
2620}
2621
2622TrackFragmentDecodeTime::TrackFragmentDecodeTime() = default;
2623TrackFragmentDecodeTime::~TrackFragmentDecodeTime() = default;
2624
2626 return FOURCC_tfdt;
2627}
2628
2629bool TrackFragmentDecodeTime::ReadWriteInternal(BoxBuffer* buffer) {
2630 RCHECK(ReadWriteHeaderInternal(buffer));
2631 size_t num_bytes = (version == 1) ? sizeof(uint64_t) : sizeof(uint32_t);
2632 RCHECK(buffer->ReadWriteUInt64NBytes(&decode_time, num_bytes));
2633 return true;
2634}
2635
2636size_t TrackFragmentDecodeTime::ComputeSizeInternal() {
2637 version = IsFitIn32Bits(decode_time) ? 0 : 1;
2638 return HeaderSize() + sizeof(uint32_t) * (1 + version);
2639}
2640
2641MovieFragmentHeader::MovieFragmentHeader() = default;
2642MovieFragmentHeader::~MovieFragmentHeader() = default;
2643
2645 return FOURCC_mfhd;
2646}
2647
2648bool MovieFragmentHeader::ReadWriteInternal(BoxBuffer* buffer) {
2649 return ReadWriteHeaderInternal(buffer) &&
2650 buffer->ReadWriteUInt32(&sequence_number);
2651}
2652
2653size_t MovieFragmentHeader::ComputeSizeInternal() {
2654 return HeaderSize() + sizeof(sequence_number);
2655}
2656
2657TrackFragmentHeader::TrackFragmentHeader() = default;
2658TrackFragmentHeader::~TrackFragmentHeader() = default;
2659
2661 return FOURCC_tfhd;
2662}
2663
2664bool TrackFragmentHeader::ReadWriteInternal(BoxBuffer* buffer) {
2665 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->ReadWriteUInt32(&track_id));
2666
2667 if (flags & kBaseDataOffsetPresentMask) {
2668 // MSE requires 'default-base-is-moof' to be set and
2669 // 'base-data-offset-present' not to be set. We omit these checks as some
2670 // valid files in the wild don't follow these rules, though they use moof as
2671 // base.
2672 uint64_t base_data_offset;
2673 RCHECK(buffer->ReadWriteUInt64(&base_data_offset));
2674 DLOG(WARNING) << "base-data-offset-present is not expected. Assumes "
2675 "default-base-is-moof.";
2676 }
2677
2678 if (flags & kSampleDescriptionIndexPresentMask) {
2679 RCHECK(buffer->ReadWriteUInt32(&sample_description_index));
2680 } else if (buffer->Reading()) {
2681 sample_description_index = 0;
2682 }
2683
2684 if (flags & kDefaultSampleDurationPresentMask) {
2685 RCHECK(buffer->ReadWriteUInt32(&default_sample_duration));
2686 } else if (buffer->Reading()) {
2687 default_sample_duration = 0;
2688 }
2689
2690 if (flags & kDefaultSampleSizePresentMask) {
2691 RCHECK(buffer->ReadWriteUInt32(&default_sample_size));
2692 } else if (buffer->Reading()) {
2693 default_sample_size = 0;
2694 }
2695
2696 if (flags & kDefaultSampleFlagsPresentMask)
2697 RCHECK(buffer->ReadWriteUInt32(&default_sample_flags));
2698 return true;
2699}
2700
2701size_t TrackFragmentHeader::ComputeSizeInternal() {
2702 size_t box_size = HeaderSize() + sizeof(track_id);
2703 if (flags & kSampleDescriptionIndexPresentMask)
2704 box_size += sizeof(sample_description_index);
2705 if (flags & kDefaultSampleDurationPresentMask)
2706 box_size += sizeof(default_sample_duration);
2707 if (flags & kDefaultSampleSizePresentMask)
2708 box_size += sizeof(default_sample_size);
2709 if (flags & kDefaultSampleFlagsPresentMask)
2710 box_size += sizeof(default_sample_flags);
2711 return box_size;
2712}
2713
2714TrackFragmentRun::TrackFragmentRun() = default;
2715TrackFragmentRun::~TrackFragmentRun() = default;
2716
2718 return FOURCC_trun;
2719}
2720
2721bool TrackFragmentRun::ReadWriteInternal(BoxBuffer* buffer) {
2722 if (!buffer->Reading()) {
2723 // Determine whether version 0 or version 1 should be used.
2724 // Use version 0 if possible, use version 1 if there is a negative
2725 // sample_offset value.
2726 version = 0;
2727 if (flags & kSampleCompTimeOffsetsPresentMask) {
2728 for (uint32_t i = 0; i < sample_count; ++i) {
2729 if (sample_composition_time_offsets[i] < 0) {
2730 version = 1;
2731 break;
2732 }
2733 }
2734 }
2735 }
2736
2737 RCHECK(ReadWriteHeaderInternal(buffer) &&
2738 buffer->ReadWriteUInt32(&sample_count));
2739
2740 bool data_offset_present = (flags & kDataOffsetPresentMask) != 0;
2741 bool first_sample_flags_present = (flags & kFirstSampleFlagsPresentMask) != 0;
2742 bool sample_duration_present = (flags & kSampleDurationPresentMask) != 0;
2743 bool sample_size_present = (flags & kSampleSizePresentMask) != 0;
2744 bool sample_flags_present = (flags & kSampleFlagsPresentMask) != 0;
2745 bool sample_composition_time_offsets_present =
2746 (flags & kSampleCompTimeOffsetsPresentMask) != 0;
2747
2748 if (data_offset_present) {
2749 RCHECK(buffer->ReadWriteUInt32(&data_offset));
2750 } else {
2751 // NOTE: If the data-offset is not present, then the data for this run
2752 // starts immediately after the data of the previous run, or at the
2753 // base-data-offset defined by the track fragment header if this is the
2754 // first run in a track fragment. If the data-offset is present, it is
2755 // relative to the base-data-offset established in the track fragment
2756 // header.
2757 NOTIMPLEMENTED();
2758 }
2759
2760 uint32_t first_sample_flags(0);
2761
2762 if (buffer->Reading()) {
2763 if (first_sample_flags_present)
2764 RCHECK(buffer->ReadWriteUInt32(&first_sample_flags));
2765
2766 if (sample_duration_present)
2767 sample_durations.resize(sample_count);
2768 if (sample_size_present)
2769 sample_sizes.resize(sample_count);
2770 if (sample_flags_present)
2771 sample_flags.resize(sample_count);
2772 if (sample_composition_time_offsets_present)
2773 sample_composition_time_offsets.resize(sample_count);
2774 } else {
2775 if (first_sample_flags_present) {
2776 first_sample_flags = sample_flags[0];
2777 DCHECK(sample_flags.size() == 1);
2778 RCHECK(buffer->ReadWriteUInt32(&first_sample_flags));
2779 }
2780
2781 if (sample_duration_present)
2782 DCHECK(sample_durations.size() == sample_count);
2783 if (sample_size_present)
2784 DCHECK(sample_sizes.size() == sample_count);
2785 if (sample_flags_present)
2786 DCHECK(sample_flags.size() == sample_count);
2787 if (sample_composition_time_offsets_present)
2788 DCHECK(sample_composition_time_offsets.size() == sample_count);
2789 }
2790
2791 for (uint32_t i = 0; i < sample_count; ++i) {
2792 if (sample_duration_present)
2793 RCHECK(buffer->ReadWriteUInt32(&sample_durations[i]));
2794 if (sample_size_present)
2795 RCHECK(buffer->ReadWriteUInt32(&sample_sizes[i]));
2796 if (sample_flags_present)
2797 RCHECK(buffer->ReadWriteUInt32(&sample_flags[i]));
2798
2799 if (sample_composition_time_offsets_present) {
2800 if (version == 0) {
2801 uint32_t sample_offset = sample_composition_time_offsets[i];
2802 RCHECK(buffer->ReadWriteUInt32(&sample_offset));
2803 sample_composition_time_offsets[i] = sample_offset;
2804 } else {
2805 int32_t sample_offset = sample_composition_time_offsets[i];
2806 RCHECK(buffer->ReadWriteInt32(&sample_offset));
2807 sample_composition_time_offsets[i] = sample_offset;
2808 }
2809 }
2810 }
2811
2812 if (buffer->Reading()) {
2813 if (first_sample_flags_present) {
2814 if (sample_flags.size() == 0) {
2815 sample_flags.push_back(first_sample_flags);
2816 } else {
2817 sample_flags[0] = first_sample_flags;
2818 }
2819 }
2820 }
2821 return true;
2822}
2823
2824size_t TrackFragmentRun::ComputeSizeInternal() {
2825 size_t box_size = HeaderSize() + sizeof(sample_count);
2826 if (flags & kDataOffsetPresentMask)
2827 box_size += sizeof(data_offset);
2828 if (flags & kFirstSampleFlagsPresentMask)
2829 box_size += sizeof(uint32_t);
2830 uint32_t fields = (flags & kSampleDurationPresentMask ? 1 : 0) +
2831 (flags & kSampleSizePresentMask ? 1 : 0) +
2832 (flags & kSampleFlagsPresentMask ? 1 : 0) +
2833 (flags & kSampleCompTimeOffsetsPresentMask ? 1 : 0);
2834 box_size += fields * sizeof(uint32_t) * sample_count;
2835 return box_size;
2836}
2837
2838TrackFragment::TrackFragment() = default;
2839TrackFragment::~TrackFragment() = default;
2840
2842 return FOURCC_traf;
2843}
2844
2845bool TrackFragment::ReadWriteInternal(BoxBuffer* buffer) {
2846 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
2847 buffer->ReadWriteChild(&header));
2848 if (buffer->Reading()) {
2849 DCHECK(buffer->reader());
2850 decode_time_absent = !buffer->reader()->ChildExist(&decode_time);
2851 if (!decode_time_absent)
2852 RCHECK(buffer->ReadWriteChild(&decode_time));
2853 RCHECK(buffer->reader()->TryReadChildren(&runs) &&
2854 buffer->reader()->TryReadChildren(&sample_group_descriptions) &&
2855 buffer->reader()->TryReadChildren(&sample_to_groups));
2856 } else {
2857 if (!decode_time_absent)
2858 RCHECK(buffer->ReadWriteChild(&decode_time));
2859 for (uint32_t i = 0; i < runs.size(); ++i)
2860 RCHECK(buffer->ReadWriteChild(&runs[i]));
2861 for (uint32_t i = 0; i < sample_to_groups.size(); ++i)
2862 RCHECK(buffer->ReadWriteChild(&sample_to_groups[i]));
2863 for (uint32_t i = 0; i < sample_group_descriptions.size(); ++i)
2864 RCHECK(buffer->ReadWriteChild(&sample_group_descriptions[i]));
2865 }
2866 return buffer->TryReadWriteChild(&auxiliary_size) &&
2867 buffer->TryReadWriteChild(&auxiliary_offset) &&
2868 buffer->TryReadWriteChild(&sample_encryption);
2869}
2870
2871size_t TrackFragment::ComputeSizeInternal() {
2872 size_t box_size = HeaderSize() + header.ComputeSize() +
2873 decode_time.ComputeSize() + auxiliary_size.ComputeSize() +
2874 auxiliary_offset.ComputeSize() +
2875 sample_encryption.ComputeSize();
2876 for (uint32_t i = 0; i < runs.size(); ++i)
2877 box_size += runs[i].ComputeSize();
2878 for (uint32_t i = 0; i < sample_group_descriptions.size(); ++i)
2879 box_size += sample_group_descriptions[i].ComputeSize();
2880 for (uint32_t i = 0; i < sample_to_groups.size(); ++i)
2881 box_size += sample_to_groups[i].ComputeSize();
2882 return box_size;
2883}
2884
2885MovieFragment::MovieFragment() = default;
2886MovieFragment::~MovieFragment() = default;
2887
2889 return FOURCC_moof;
2890}
2891
2892bool MovieFragment::ReadWriteInternal(BoxBuffer* buffer) {
2893 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
2894 buffer->ReadWriteChild(&header));
2895 if (buffer->Reading()) {
2896 BoxReader* reader = buffer->reader();
2897 DCHECK(reader);
2898 RCHECK(reader->ReadChildren(&tracks) && reader->TryReadChildren(&pssh));
2899 } else {
2900 for (uint32_t i = 0; i < tracks.size(); ++i)
2901 RCHECK(buffer->ReadWriteChild(&tracks[i]));
2902 for (uint32_t i = 0; i < pssh.size(); ++i)
2903 RCHECK(buffer->ReadWriteChild(&pssh[i]));
2904 }
2905 return true;
2906}
2907
2908size_t MovieFragment::ComputeSizeInternal() {
2909 size_t box_size = HeaderSize() + header.ComputeSize();
2910 for (uint32_t i = 0; i < tracks.size(); ++i)
2911 box_size += tracks[i].ComputeSize();
2912 for (uint32_t i = 0; i < pssh.size(); ++i)
2913 box_size += pssh[i].ComputeSize();
2914 return box_size;
2915}
2916
2917SegmentIndex::SegmentIndex() = default;
2918SegmentIndex::~SegmentIndex() = default;
2919
2921 return FOURCC_sidx;
2922}
2923
2924bool SegmentIndex::ReadWriteInternal(BoxBuffer* buffer) {
2925 RCHECK(ReadWriteHeaderInternal(buffer) &&
2926 buffer->ReadWriteUInt32(&reference_id) &&
2927 buffer->ReadWriteUInt32(&timescale));
2928
2929 size_t num_bytes = (version == 1) ? sizeof(uint64_t) : sizeof(uint32_t);
2930 RCHECK(
2931 buffer->ReadWriteUInt64NBytes(&earliest_presentation_time, num_bytes) &&
2932 buffer->ReadWriteUInt64NBytes(&first_offset, num_bytes));
2933
2934 uint16_t reference_count;
2935 if (references.size() <= std::numeric_limits<uint16_t>::max()) {
2936 reference_count = static_cast<uint16_t>(references.size());
2937 } else {
2938 reference_count = std::numeric_limits<uint16_t>::max();
2939 LOG(WARNING) << "Seeing " << references.size()
2940 << " subsegment references, but at most " << reference_count
2941 << " references can be stored in 'sidx' box."
2942 << " The extra references are truncated.";
2943 LOG(WARNING) << "The stream will not play to the end in DASH.";
2944 LOG(WARNING) << "A possible workaround is to increase segment duration.";
2945 }
2946 RCHECK(buffer->IgnoreBytes(2) && // reserved.
2947 buffer->ReadWriteUInt16(&reference_count));
2948 if (buffer->Reading())
2949 references.resize(reference_count);
2950
2951 uint32_t reference_type_size;
2952 uint32_t sap;
2953 for (uint32_t i = 0; i < reference_count; ++i) {
2954 if (!buffer->Reading()) {
2955 reference_type_size = references[i].referenced_size;
2956 if (references[i].reference_type)
2957 reference_type_size |= (1 << 31);
2958 sap = (references[i].sap_type << 28) | references[i].sap_delta_time;
2959 if (references[i].starts_with_sap)
2960 sap |= (1 << 31);
2961 }
2962 RCHECK(buffer->ReadWriteUInt32(&reference_type_size) &&
2963 buffer->ReadWriteUInt32(&references[i].subsegment_duration) &&
2964 buffer->ReadWriteUInt32(&sap));
2965 if (buffer->Reading()) {
2966 references[i].reference_type = (reference_type_size >> 31) ? true : false;
2967 references[i].referenced_size = reference_type_size & ~(1 << 31);
2968 references[i].starts_with_sap = (sap >> 31) ? true : false;
2969 references[i].sap_type =
2970 static_cast<SegmentReference::SAPType>((sap >> 28) & 0x07);
2971 references[i].sap_delta_time = sap & ~(0xF << 28);
2972 }
2973 }
2974 return true;
2975}
2976
2977size_t SegmentIndex::ComputeSizeInternal() {
2978 version = IsFitIn32Bits(earliest_presentation_time, first_offset) ? 0 : 1;
2979 return HeaderSize() + sizeof(reference_id) + sizeof(timescale) +
2980 sizeof(uint32_t) * (1 + version) * 2 + 2 * sizeof(uint16_t) +
2981 3 * sizeof(uint32_t) *
2982 std::min(
2983 references.size(),
2984 static_cast<size_t>(std::numeric_limits<uint16_t>::max()));
2985}
2986
2987MediaData::MediaData() = default;
2988MediaData::~MediaData() = default;
2989
2990FourCC MediaData::BoxType() const {
2991 return FOURCC_mdat;
2992}
2993
2994bool MediaData::ReadWriteInternal(BoxBuffer* buffer) {
2995 NOTIMPLEMENTED() << "Actual data is parsed and written separately.";
2996 return false;
2997}
2998
2999size_t MediaData::ComputeSizeInternal() {
3000 return HeaderSize() + data_size;
3001}
3002
3003CueSourceIDBox::CueSourceIDBox() = default;
3004CueSourceIDBox::~CueSourceIDBox() = default;
3005
3007 return FOURCC_vsid;
3008}
3009
3010bool CueSourceIDBox::ReadWriteInternal(BoxBuffer* buffer) {
3011 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->ReadWriteInt32(&source_id));
3012 return true;
3013}
3014
3015size_t CueSourceIDBox::ComputeSizeInternal() {
3016 if (source_id == kCueSourceIdNotSet)
3017 return 0;
3018 return HeaderSize() + sizeof(source_id);
3019}
3020
3021CueTimeBox::CueTimeBox() = default;
3022CueTimeBox::~CueTimeBox() = default;
3023
3024FourCC CueTimeBox::BoxType() const {
3025 return FOURCC_ctim;
3026}
3027
3028bool CueTimeBox::ReadWriteInternal(BoxBuffer* buffer) {
3029 RCHECK(ReadWriteHeaderInternal(buffer));
3030 return buffer->ReadWriteString(
3031 &cue_current_time,
3032 buffer->Reading() ? buffer->BytesLeft() : cue_current_time.size());
3033}
3034
3035size_t CueTimeBox::ComputeSizeInternal() {
3036 if (cue_current_time.empty())
3037 return 0;
3038 return HeaderSize() + cue_current_time.size();
3039}
3040
3041CueIDBox::CueIDBox() = default;
3042CueIDBox::~CueIDBox() = default;
3043
3044FourCC CueIDBox::BoxType() const {
3045 return FOURCC_iden;
3046}
3047
3048bool CueIDBox::ReadWriteInternal(BoxBuffer* buffer) {
3049 RCHECK(ReadWriteHeaderInternal(buffer));
3050 return buffer->ReadWriteString(
3051 &cue_id, buffer->Reading() ? buffer->BytesLeft() : cue_id.size());
3052}
3053
3054size_t CueIDBox::ComputeSizeInternal() {
3055 if (cue_id.empty())
3056 return 0;
3057 return HeaderSize() + cue_id.size();
3058}
3059
3060CueSettingsBox::CueSettingsBox() = default;
3061CueSettingsBox::~CueSettingsBox() = default;
3062
3064 return FOURCC_sttg;
3065}
3066
3067bool CueSettingsBox::ReadWriteInternal(BoxBuffer* buffer) {
3068 RCHECK(ReadWriteHeaderInternal(buffer));
3069 return buffer->ReadWriteString(
3070 &settings, buffer->Reading() ? buffer->BytesLeft() : settings.size());
3071}
3072
3073size_t CueSettingsBox::ComputeSizeInternal() {
3074 if (settings.empty())
3075 return 0;
3076 return HeaderSize() + settings.size();
3077}
3078
3079CuePayloadBox::CuePayloadBox() = default;
3080CuePayloadBox::~CuePayloadBox() = default;
3081
3083 return FOURCC_payl;
3084}
3085
3086bool CuePayloadBox::ReadWriteInternal(BoxBuffer* buffer) {
3087 RCHECK(ReadWriteHeaderInternal(buffer));
3088 return buffer->ReadWriteString(
3089 &cue_text, buffer->Reading() ? buffer->BytesLeft() : cue_text.size());
3090}
3091
3092size_t CuePayloadBox::ComputeSizeInternal() {
3093 return HeaderSize() + cue_text.size();
3094}
3095
3096VTTEmptyCueBox::VTTEmptyCueBox() = default;
3097VTTEmptyCueBox::~VTTEmptyCueBox() = default;
3098
3100 return FOURCC_vtte;
3101}
3102
3103bool VTTEmptyCueBox::ReadWriteInternal(BoxBuffer* buffer) {
3104 return ReadWriteHeaderInternal(buffer);
3105}
3106
3107size_t VTTEmptyCueBox::ComputeSizeInternal() {
3108 return HeaderSize();
3109}
3110
3111VTTAdditionalTextBox::VTTAdditionalTextBox() = default;
3112VTTAdditionalTextBox::~VTTAdditionalTextBox() = default;
3113
3115 return FOURCC_vtta;
3116}
3117
3118bool VTTAdditionalTextBox::ReadWriteInternal(BoxBuffer* buffer) {
3119 RCHECK(ReadWriteHeaderInternal(buffer));
3120 return buffer->ReadWriteString(
3121 &cue_additional_text,
3122 buffer->Reading() ? buffer->BytesLeft() : cue_additional_text.size());
3123}
3124
3125size_t VTTAdditionalTextBox::ComputeSizeInternal() {
3126 return HeaderSize() + cue_additional_text.size();
3127}
3128
3129VTTCueBox::VTTCueBox() = default;
3130VTTCueBox::~VTTCueBox() = default;
3131
3132FourCC VTTCueBox::BoxType() const {
3133 return FOURCC_vttc;
3134}
3135
3136bool VTTCueBox::ReadWriteInternal(BoxBuffer* buffer) {
3137 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
3138 buffer->TryReadWriteChild(&cue_source_id) &&
3139 buffer->TryReadWriteChild(&cue_id) &&
3140 buffer->TryReadWriteChild(&cue_time) &&
3141 buffer->TryReadWriteChild(&cue_settings) &&
3142 buffer->ReadWriteChild(&cue_payload));
3143 return true;
3144}
3145
3146size_t VTTCueBox::ComputeSizeInternal() {
3147 return HeaderSize() + cue_source_id.ComputeSize() + cue_id.ComputeSize() +
3148 cue_time.ComputeSize() + cue_settings.ComputeSize() +
3149 cue_payload.ComputeSize();
3150}
3151
3152} // namespace mp4
3153} // namespace media
3154} // namespace shaka
virtual bool Parse(const std::vector< uint8_t > &data)
bool Parse(const std::vector< uint8_t > &data)
void Write(BufferWriter *writer)
bool IgnoreBytes(size_t num_bytes)
Definition box_buffer.h:205
bool ReadWriteUInt64NBytes(uint64_t *v, size_t num_bytes)
Definition box_buffer.h:123
bool TryReadWriteChild(Box *box)
Definition box_buffer.h:193
bool ReadWriteString(std::string *str, size_t size)
Definition box_buffer.h:145
bool ReadWriteChild(Box *box)
Definition box_buffer.h:182
Class for reading MP4 boxes.
Definition box_reader.h:30
bool ReadChildren(std::vector< T > *children)
Definition box_reader.h:133
bool ChildExist(Box *child)
bool ReadChild(Box *child)
Definition box_reader.cc:99
bool TryReadChild(Box *child)
static BoxReader * ReadBox(const uint8_t *buf, const size_t buf_size, bool *err)
Definition box_reader.cc:45
bool TryReadChildren(std::vector< T > *children)
Definition box_reader.h:139
All the methods that are virtual are virtual for mocking.
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
virtual uint32_t HeaderSize() const
Definition box.cc:61
void Write(BufferWriter *writer)
Definition box.cc:31
virtual bool ReadWriteHeaderInternal(BoxBuffer *buffer)
Definition box.cc:67
uint32_t ComputeSize()
Definition box.cc:56
uint32_t box_size()
Definition box.h:56
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
uint32_t HeaderSize() const final
Definition box.cc:81
bool ReadWriteHeaderInternal(BoxBuffer *buffer) final
Definition box.cc:86
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
bool ParseFromBuffer(uint8_t iv_size, bool has_subsamples, BufferReader *reader)
bool ReadWrite(uint8_t iv_size, bool has_subsamples, BoxBuffer *buffer)
std::vector< uint8_t > sample_encryption_data
bool ParseFromSampleEncryptionData(uint8_t l_iv_size, std::vector< SampleEncryptionEntry > *l_sample_encryption_entries) const
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override
FourCC BoxType() const override