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