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.
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 }
1636 const bool is_av1 = actual_format == FOURCC_av01;
1637 if (is_av1) {
1638 for (FourCC fourcc : {FOURCC_dvvC}) {
1639 CodecConfiguration dv_box;
1640 dv_box.box_type = fourcc;
1641 RCHECK(buffer->TryReadWriteChild(&dv_box));
1642 if (!dv_box.data.empty())
1643 extra_codec_configs.push_back(std::move(dv_box));
1644 }
1645 }
1646 } else {
1647 for (CodecConfiguration& extra_codec_config : extra_codec_configs)
1648 RCHECK(buffer->ReadWriteChild(&extra_codec_config));
1649 }
1650
1651 RCHECK(buffer->TryReadWriteChild(&colr));
1652 RCHECK(buffer->TryReadWriteChild(&pixel_aspect));
1653
1654 // Somehow Edge does not support having sinf box before codec_configuration,
1655 // box, so just do it in the end of VideoSampleEntry. See
1656 // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12658991/
1657 if (format == FOURCC_encv && !buffer->Reading()) {
1658 DCHECK(IsProtectionSchemeSupported(sinf.type.type));
1659 RCHECK(buffer->ReadWriteChild(&sinf));
1660 }
1661 return true;
1662}
1663
1664size_t VideoSampleEntry::ComputeSizeInternal() {
1665 const FourCC actual_format = GetActualFormat();
1666 if (actual_format == FOURCC_NULL)
1667 return 0;
1668 codec_configuration.box_type = GetCodecConfigurationBoxType(actual_format);
1669 DCHECK_NE(codec_configuration.box_type, FOURCC_NULL);
1670 size_t size = HeaderSize() + sizeof(data_reference_index) + sizeof(width) +
1671 sizeof(height) + sizeof(kVideoResolution) * 2 +
1672 sizeof(kVideoFrameCount) + sizeof(kVideoDepth) +
1673 colr.ComputeSize() + pixel_aspect.ComputeSize() +
1674 sinf.ComputeSize() + codec_configuration.ComputeSize() +
1675 kCompressorNameSize + 6 + 4 + 16 +
1676 2; // 6 + 4 bytes reserved, 16 + 2 bytes predefined.
1677 for (CodecConfiguration& codec_config : extra_codec_configs)
1678 size += codec_config.ComputeSize();
1679 return size;
1680}
1681
1682FourCC VideoSampleEntry::GetCodecConfigurationBoxType(FourCC l_format) const {
1683 switch (l_format) {
1684 case FOURCC_av01:
1685 return FOURCC_av1C;
1686 case FOURCC_avc1:
1687 case FOURCC_avc3:
1688 return FOURCC_avcC;
1689 case FOURCC_dvh1:
1690 case FOURCC_dvhe:
1691 case FOURCC_hev1:
1692 case FOURCC_hvc1:
1693 return FOURCC_hvcC;
1694 case FOURCC_vp08:
1695 case FOURCC_vp09:
1696 return FOURCC_vpcC;
1697 default:
1698 LOG(ERROR) << FourCCToString(l_format) << " is not supported.";
1699 return FOURCC_NULL;
1700 }
1701}
1702
1703std::vector<uint8_t> VideoSampleEntry::ExtraCodecConfigsAsVector() const {
1704 BufferWriter buffer;
1705 for (CodecConfiguration codec_config : extra_codec_configs)
1706 codec_config.Write(&buffer);
1707 return std::vector<uint8_t>(buffer.Buffer(), buffer.Buffer() + buffer.Size());
1708}
1709
1710bool VideoSampleEntry::ParseExtraCodecConfigsVector(
1711 const std::vector<uint8_t>& data) {
1712 extra_codec_configs.clear();
1713 size_t pos = 0;
1714 while (pos < data.size()) {
1715 bool err = false;
1716 std::unique_ptr<BoxReader> box_reader(
1717 BoxReader::ReadBox(data.data() + pos, data.size() - pos, &err));
1718 RCHECK(!err && box_reader);
1719
1720 CodecConfiguration codec_config;
1721 codec_config.box_type = box_reader->type();
1722 RCHECK(codec_config.Parse(box_reader.get()));
1723 extra_codec_configs.push_back(std::move(codec_config));
1724
1725 pos += box_reader->pos();
1726 }
1727 return true;
1728}
1729
1730ElementaryStreamDescriptor::ElementaryStreamDescriptor() = default;
1731ElementaryStreamDescriptor::~ElementaryStreamDescriptor() = default;
1732
1734 return FOURCC_esds;
1735}
1736
1737bool ElementaryStreamDescriptor::ReadWriteInternal(BoxBuffer* buffer) {
1738 RCHECK(ReadWriteHeaderInternal(buffer));
1739 if (buffer->Reading()) {
1740 std::vector<uint8_t> data;
1741 RCHECK(buffer->ReadWriteVector(&data, buffer->BytesLeft()));
1742 RCHECK(es_descriptor.Parse(data));
1743 if (es_descriptor.decoder_config_descriptor().IsAAC()) {
1744 RCHECK(aac_audio_specific_config.Parse(
1745 es_descriptor.decoder_config_descriptor()
1746 .decoder_specific_info_descriptor()
1747 .data()));
1748 }
1749 } else {
1750 DCHECK(buffer->writer());
1751 es_descriptor.Write(buffer->writer());
1752 }
1753 return true;
1754}
1755
1756size_t ElementaryStreamDescriptor::ComputeSizeInternal() {
1757 // This box is optional. Skip it if not initialized.
1758 if (es_descriptor.decoder_config_descriptor().object_type() ==
1759 ObjectType::kForbidden) {
1760 return 0;
1761 }
1762 return HeaderSize() + es_descriptor.ComputeSize();
1763}
1764
1765MHAConfiguration::MHAConfiguration() = default;
1766MHAConfiguration::~MHAConfiguration() = default;
1767
1769 return FOURCC_mhaC;
1770}
1771
1772bool MHAConfiguration::ReadWriteInternal(BoxBuffer* buffer) {
1773 RCHECK(ReadWriteHeaderInternal(buffer) &&
1774 buffer->ReadWriteVector(
1775 &data, buffer->Reading() ? buffer->BytesLeft() : data.size()));
1776 RCHECK(data.size() > 1);
1777 mpeg_h_3da_profile_level_indication = data[1];
1778 return true;
1779}
1780
1781size_t MHAConfiguration::ComputeSizeInternal() {
1782 // This box is optional. Skip it if not initialized.
1783 if (data.empty())
1784 return 0;
1785 return HeaderSize() + data.size();
1786}
1787
1788DTSSpecific::DTSSpecific() = default;
1789DTSSpecific::~DTSSpecific() = default;
1790;
1791
1792FourCC DTSSpecific::BoxType() const {
1793 return FOURCC_ddts;
1794}
1795
1796bool DTSSpecific::ReadWriteInternal(BoxBuffer* buffer) {
1797 RCHECK(ReadWriteHeaderInternal(buffer) &&
1798 buffer->ReadWriteUInt32(&sampling_frequency) &&
1799 buffer->ReadWriteUInt32(&max_bitrate) &&
1800 buffer->ReadWriteUInt32(&avg_bitrate) &&
1801 buffer->ReadWriteUInt8(&pcm_sample_depth));
1802
1803 if (buffer->Reading()) {
1804 RCHECK(buffer->ReadWriteVector(&extra_data, buffer->BytesLeft()));
1805 } else {
1806 if (extra_data.empty()) {
1807 extra_data.assign(kDdtsExtraData,
1808 kDdtsExtraData + sizeof(kDdtsExtraData));
1809 }
1810 RCHECK(buffer->ReadWriteVector(&extra_data, extra_data.size()));
1811 }
1812 return true;
1813}
1814
1815size_t DTSSpecific::ComputeSizeInternal() {
1816 // This box is optional. Skip it if not initialized.
1817 if (sampling_frequency == 0)
1818 return 0;
1819 return HeaderSize() + sizeof(sampling_frequency) + sizeof(max_bitrate) +
1820 sizeof(avg_bitrate) + sizeof(pcm_sample_depth) +
1821 sizeof(kDdtsExtraData);
1822}
1823
1824UDTSSpecific::UDTSSpecific() = default;
1825UDTSSpecific::~UDTSSpecific() = default;
1826
1828 return FOURCC_udts;
1829}
1830
1831bool UDTSSpecific::ReadWriteInternal(BoxBuffer* buffer) {
1832 RCHECK(ReadWriteHeaderInternal(buffer) &&
1833 buffer->ReadWriteVector(
1834 &data, buffer->Reading() ? buffer->BytesLeft() : data.size()));
1835 return true;
1836}
1837
1838size_t UDTSSpecific::ComputeSizeInternal() {
1839 // This box is optional. Skip it if not initialized.
1840 if (data.empty())
1841 return 0;
1842 return HeaderSize() + data.size();
1843}
1844
1845AC3Specific::AC3Specific() = default;
1846AC3Specific::~AC3Specific() = default;
1847
1848FourCC AC3Specific::BoxType() const {
1849 return FOURCC_dac3;
1850}
1851
1852bool AC3Specific::ReadWriteInternal(BoxBuffer* buffer) {
1853 RCHECK(ReadWriteHeaderInternal(buffer) &&
1854 buffer->ReadWriteVector(
1855 &data, buffer->Reading() ? buffer->BytesLeft() : data.size()));
1856 return true;
1857}
1858
1859size_t AC3Specific::ComputeSizeInternal() {
1860 // This box is optional. Skip it if not initialized.
1861 if (data.empty())
1862 return 0;
1863 return HeaderSize() + data.size();
1864}
1865
1866EC3Specific::EC3Specific() = default;
1867EC3Specific::~EC3Specific() = default;
1868
1869FourCC EC3Specific::BoxType() const {
1870 return FOURCC_dec3;
1871}
1872
1873bool EC3Specific::ReadWriteInternal(BoxBuffer* buffer) {
1874 RCHECK(ReadWriteHeaderInternal(buffer));
1875 size_t size = buffer->Reading() ? buffer->BytesLeft() : data.size();
1876 RCHECK(buffer->ReadWriteVector(&data, size));
1877 return true;
1878}
1879
1880size_t EC3Specific::ComputeSizeInternal() {
1881 // This box is optional. Skip it if not initialized.
1882 if (data.empty())
1883 return 0;
1884 return HeaderSize() + data.size();
1885}
1886
1887AC4Specific::AC4Specific() = default;
1888AC4Specific::~AC4Specific() = default;
1889
1890FourCC AC4Specific::BoxType() const {
1891 return FOURCC_dac4;
1892}
1893
1894bool AC4Specific::ReadWriteInternal(BoxBuffer* buffer) {
1895 RCHECK(ReadWriteHeaderInternal(buffer));
1896 size_t size = buffer->Reading() ? buffer->BytesLeft() : data.size();
1897 RCHECK(buffer->ReadWriteVector(&data, size));
1898 return true;
1899}
1900
1901size_t AC4Specific::ComputeSizeInternal() {
1902 // This box is optional. Skip it if not initialized.
1903 if (data.empty())
1904 return 0;
1905 return HeaderSize() + data.size();
1906}
1907
1908OpusSpecific::OpusSpecific() = default;
1909OpusSpecific::~OpusSpecific() = default;
1910
1912 return FOURCC_dOps;
1913}
1914
1915bool OpusSpecific::ReadWriteInternal(BoxBuffer* buffer) {
1916 RCHECK(ReadWriteHeaderInternal(buffer));
1917 if (buffer->Reading()) {
1918 std::vector<uint8_t> data;
1919 const int kMinOpusSpecificBoxDataSize = 11;
1920 RCHECK(buffer->BytesLeft() >= kMinOpusSpecificBoxDataSize);
1921 RCHECK(buffer->ReadWriteVector(&data, buffer->BytesLeft()));
1922 preskip = data[2] + (data[3] << 8);
1923
1924 // https://tools.ietf.org/html/draft-ietf-codec-oggopus-06#section-5
1925 BufferWriter writer;
1926 writer.AppendInt(FOURCC_Opus);
1927 writer.AppendInt(FOURCC_Head);
1928 // The version must always be 1.
1929 const uint8_t kOpusIdentificationHeaderVersion = 1;
1930 data[0] = kOpusIdentificationHeaderVersion;
1931 writer.AppendVector(data);
1932 writer.SwapBuffer(&opus_identification_header);
1933 } else {
1934 // https://tools.ietf.org/html/draft-ietf-codec-oggopus-06#section-5
1935 // The first 8 bytes is "magic signature".
1936 const size_t kOpusMagicSignatureSize = 8u;
1937 DCHECK_GT(opus_identification_header.size(), kOpusMagicSignatureSize);
1938 // https://www.opus-codec.org/docs/opus_in_isobmff.html
1939 // The version field shall be set to 0.
1940 const uint8_t kOpusSpecificBoxVersion = 0;
1941 buffer->writer()->AppendInt(kOpusSpecificBoxVersion);
1942 buffer->writer()->AppendArray(
1943 &opus_identification_header[kOpusMagicSignatureSize + 1],
1944 opus_identification_header.size() - kOpusMagicSignatureSize - 1);
1945 }
1946 return true;
1947}
1948
1949size_t OpusSpecific::ComputeSizeInternal() {
1950 // This box is optional. Skip it if not initialized.
1951 if (opus_identification_header.empty())
1952 return 0;
1953 // https://tools.ietf.org/html/draft-ietf-codec-oggopus-06#section-5
1954 // The first 8 bytes is "magic signature".
1955 const size_t kOpusMagicSignatureSize = 8u;
1956 DCHECK_GT(opus_identification_header.size(), kOpusMagicSignatureSize);
1957 return HeaderSize() + opus_identification_header.size() -
1958 kOpusMagicSignatureSize;
1959}
1960
1961IAMFSpecific::IAMFSpecific() = default;
1962IAMFSpecific::~IAMFSpecific() = default;
1963
1965 return FOURCC_iacb;
1966}
1967
1968bool IAMFSpecific::ReadWriteInternal(BoxBuffer* buffer) {
1969 RCHECK(ReadWriteHeaderInternal(buffer));
1970 size_t size = buffer->Reading() ? buffer->BytesLeft() : data.size();
1971 RCHECK(buffer->ReadWriteVector(&data, size));
1972 return true;
1973}
1974
1975size_t IAMFSpecific::ComputeSizeInternal() {
1976 // This box is optional. Skip it if not initialized.
1977 if (data.empty())
1978 return 0;
1979 return HeaderSize() + data.size();
1980}
1981
1982FlacSpecific::FlacSpecific() = default;
1983FlacSpecific::~FlacSpecific() = default;
1984
1986 return FOURCC_dfLa;
1987}
1988
1989bool FlacSpecific::ReadWriteInternal(BoxBuffer* buffer) {
1990 RCHECK(ReadWriteHeaderInternal(buffer));
1991 size_t size = buffer->Reading() ? buffer->BytesLeft() : data.size();
1992 RCHECK(buffer->ReadWriteVector(&data, size));
1993 return true;
1994}
1995
1996size_t FlacSpecific::ComputeSizeInternal() {
1997 // This box is optional. Skip it if not initialized.
1998 if (data.empty())
1999 return 0;
2000 return HeaderSize() + data.size();
2001}
2002
2003ALACSpecific::ALACSpecific() = default;
2004ALACSpecific::~ALACSpecific() = default;
2005
2007 return FOURCC_alac;
2008}
2009
2010bool ALACSpecific::ReadWriteInternal(BoxBuffer* buffer) {
2011 RCHECK(ReadWriteHeaderInternal(buffer));
2012 size_t size = buffer->Reading() ? buffer->BytesLeft() : data.size();
2013 RCHECK(buffer->ReadWriteVector(&data, size));
2014 return true;
2015}
2016
2017size_t ALACSpecific::ComputeSizeInternal() {
2018 // This box is optional. Skip it if not initialized.
2019 if (data.empty())
2020 return 0;
2021 return HeaderSize() + data.size();
2022}
2023
2024AudioSampleEntry::AudioSampleEntry() = default;
2025AudioSampleEntry::~AudioSampleEntry() = default;
2026
2028 if (format == FOURCC_NULL) {
2029 LOG(ERROR) << "AudioSampleEntry should be parsed according to the "
2030 << "handler type recovered in its Media ancestor.";
2031 }
2032 return format;
2033}
2034
2035bool AudioSampleEntry::ReadWriteInternal(BoxBuffer* buffer) {
2036 if (buffer->Reading()) {
2037 DCHECK(buffer->reader());
2038 format = buffer->reader()->type();
2039 } else {
2040 RCHECK(ReadWriteHeaderInternal(buffer));
2041 }
2042
2043 // Convert from integer to 16.16 fixed point for writing.
2044 samplerate <<= 16;
2045 RCHECK(buffer->IgnoreBytes(6) && // reserved.
2046 buffer->ReadWriteUInt16(&data_reference_index) &&
2047 buffer->IgnoreBytes(8) && // reserved.
2048 buffer->ReadWriteUInt16(&channelcount) &&
2049 buffer->ReadWriteUInt16(&samplesize) &&
2050 buffer->IgnoreBytes(4) && // predefined.
2051 buffer->ReadWriteUInt32(&samplerate));
2052 // Convert from 16.16 fixed point to integer.
2053 samplerate >>= 16;
2054
2055 RCHECK(buffer->PrepareChildren());
2056
2057 RCHECK(buffer->TryReadWriteChild(&esds));
2058 RCHECK(buffer->TryReadWriteChild(&ddts));
2059 RCHECK(buffer->TryReadWriteChild(&udts));
2060 RCHECK(buffer->TryReadWriteChild(&dac3));
2061 RCHECK(buffer->TryReadWriteChild(&dec3));
2062 RCHECK(buffer->TryReadWriteChild(&dac4));
2063 RCHECK(buffer->TryReadWriteChild(&dops));
2064 RCHECK(buffer->TryReadWriteChild(&iacb));
2065 RCHECK(buffer->TryReadWriteChild(&dfla));
2066 RCHECK(buffer->TryReadWriteChild(&mhac));
2067 RCHECK(buffer->TryReadWriteChild(&alac));
2068
2069 // Somehow Edge does not support having sinf box before codec_configuration,
2070 // box, so just do it in the end of AudioSampleEntry. See
2071 // https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/12658991/
2072 if (format == FOURCC_enca) {
2073 if (buffer->Reading()) {
2074 // Continue scanning until a supported protection scheme is found, or
2075 // until we run out of protection schemes.
2076 while (!IsProtectionSchemeSupported(sinf.type.type))
2077 RCHECK(buffer->ReadWriteChild(&sinf));
2078 } else {
2079 DCHECK(IsProtectionSchemeSupported(sinf.type.type));
2080 RCHECK(buffer->ReadWriteChild(&sinf));
2081 }
2082 }
2083 return true;
2084}
2085
2086size_t AudioSampleEntry::ComputeSizeInternal() {
2087 if (GetActualFormat() == FOURCC_NULL)
2088 return 0;
2089 return HeaderSize() + sizeof(data_reference_index) + sizeof(channelcount) +
2090 sizeof(samplesize) + sizeof(samplerate) + sinf.ComputeSize() +
2091 esds.ComputeSize() + ddts.ComputeSize() + dac3.ComputeSize() +
2092 dec3.ComputeSize() + dops.ComputeSize() + dfla.ComputeSize() +
2093 dac4.ComputeSize() + mhac.ComputeSize() + udts.ComputeSize() +
2094 alac.ComputeSize() + iacb.ComputeSize() +
2095 // Reserved and predefined bytes.
2096 6 + 8 + // 6 + 8 bytes reserved.
2097 4; // 4 bytes predefined.
2098}
2099
2100WebVTTConfigurationBox::WebVTTConfigurationBox() = default;
2101WebVTTConfigurationBox::~WebVTTConfigurationBox() = default;
2102
2104 return FOURCC_vttC;
2105}
2106
2107bool WebVTTConfigurationBox::ReadWriteInternal(BoxBuffer* buffer) {
2108 RCHECK(ReadWriteHeaderInternal(buffer));
2109 return buffer->ReadWriteString(
2110 &config, buffer->Reading() ? buffer->BytesLeft() : config.size());
2111}
2112
2113size_t WebVTTConfigurationBox::ComputeSizeInternal() {
2114 return HeaderSize() + config.size();
2115}
2116
2117WebVTTSourceLabelBox::WebVTTSourceLabelBox() = default;
2118WebVTTSourceLabelBox::~WebVTTSourceLabelBox() = default;
2119
2121 return FOURCC_vlab;
2122}
2123
2124bool WebVTTSourceLabelBox::ReadWriteInternal(BoxBuffer* buffer) {
2125 RCHECK(ReadWriteHeaderInternal(buffer));
2126 return buffer->ReadWriteString(&source_label, buffer->Reading()
2127 ? buffer->BytesLeft()
2128 : source_label.size());
2129}
2130
2131size_t WebVTTSourceLabelBox::ComputeSizeInternal() {
2132 if (source_label.empty())
2133 return 0;
2134 return HeaderSize() + source_label.size();
2135}
2136
2137TextSampleEntry::TextSampleEntry() = default;
2138TextSampleEntry::~TextSampleEntry() = default;
2139
2141 if (format == FOURCC_NULL) {
2142 LOG(ERROR) << "TextSampleEntry should be parsed according to the "
2143 << "handler type recovered in its Media ancestor.";
2144 }
2145 return format;
2146}
2147
2148bool TextSampleEntry::ReadWriteInternal(BoxBuffer* buffer) {
2149 if (buffer->Reading()) {
2150 DCHECK(buffer->reader());
2151 format = buffer->reader()->type();
2152 } else {
2153 RCHECK(ReadWriteHeaderInternal(buffer));
2154 }
2155 RCHECK(buffer->IgnoreBytes(6) && // reserved for SampleEntry.
2156 buffer->ReadWriteUInt16(&data_reference_index));
2157
2158 if (format == FOURCC_wvtt) {
2159 // TODO(rkuroiwa): Handle the optional MPEG4BitRateBox.
2160 RCHECK(buffer->PrepareChildren() && buffer->ReadWriteChild(&config) &&
2161 buffer->ReadWriteChild(&label));
2162 } else if (format == FOURCC_stpp) {
2163 // These are marked as "optional"; but they should still have the
2164 // null-terminator, so this should still work.
2165 RCHECK(buffer->ReadWriteCString(&namespace_) &&
2166 buffer->ReadWriteCString(&schema_location));
2167 }
2168 return true;
2169}
2170
2171size_t TextSampleEntry::ComputeSizeInternal() {
2172 // 6 for the (anonymous) reserved bytes for SampleEntry class.
2173 size_t ret = HeaderSize() + 6 + sizeof(data_reference_index);
2174 if (format == FOURCC_wvtt) {
2175 ret += config.ComputeSize() + label.ComputeSize();
2176 } else if (format == FOURCC_stpp) {
2177 // +2 for the two null terminators for these strings.
2178 ret += namespace_.size() + schema_location.size() + 2;
2179 }
2180 return ret;
2181}
2182
2183MediaHeader::MediaHeader() = default;
2184MediaHeader::~MediaHeader() = default;
2185
2186FourCC MediaHeader::BoxType() const {
2187 return FOURCC_mdhd;
2188}
2189
2190bool MediaHeader::ReadWriteInternal(BoxBuffer* buffer) {
2191 RCHECK(ReadWriteHeaderInternal(buffer));
2192
2193 uint8_t num_bytes = (version == 1) ? sizeof(uint64_t) : sizeof(uint32_t);
2194 RCHECK(buffer->ReadWriteUInt64NBytes(&creation_time, num_bytes) &&
2195 buffer->ReadWriteUInt64NBytes(&modification_time, num_bytes) &&
2196 buffer->ReadWriteUInt32(&timescale) &&
2197 buffer->ReadWriteUInt64NBytes(&duration, num_bytes) &&
2198 language.ReadWrite(buffer) &&
2199 // predefined.
2200 buffer->IgnoreBytes(2));
2201 return true;
2202}
2203
2204size_t MediaHeader::ComputeSizeInternal() {
2205 version = IsFitIn32Bits(creation_time, modification_time, duration) ? 0 : 1;
2206 return HeaderSize() + sizeof(timescale) +
2207 sizeof(uint32_t) * (1 + version) * 3 + language.ComputeSize() +
2208 2; // 2 bytes predefined.
2209}
2210
2211VideoMediaHeader::VideoMediaHeader() {
2212 const uint32_t kVideoMediaHeaderFlags = 1;
2213 flags = kVideoMediaHeaderFlags;
2214}
2215
2216VideoMediaHeader::~VideoMediaHeader() = default;
2217
2219 return FOURCC_vmhd;
2220}
2221bool VideoMediaHeader::ReadWriteInternal(BoxBuffer* buffer) {
2222 RCHECK(ReadWriteHeaderInternal(buffer) &&
2223 buffer->ReadWriteUInt16(&graphicsmode) &&
2224 buffer->ReadWriteUInt16(&opcolor_red) &&
2225 buffer->ReadWriteUInt16(&opcolor_green) &&
2226 buffer->ReadWriteUInt16(&opcolor_blue));
2227 return true;
2228}
2229
2230size_t VideoMediaHeader::ComputeSizeInternal() {
2231 return HeaderSize() + sizeof(graphicsmode) + sizeof(opcolor_red) +
2232 sizeof(opcolor_green) + sizeof(opcolor_blue);
2233}
2234
2235SoundMediaHeader::SoundMediaHeader() = default;
2236SoundMediaHeader::~SoundMediaHeader() = default;
2237
2239 return FOURCC_smhd;
2240}
2241
2242bool SoundMediaHeader::ReadWriteInternal(BoxBuffer* buffer) {
2243 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->ReadWriteUInt16(&balance) &&
2244 buffer->IgnoreBytes(2)); // reserved.
2245 return true;
2246}
2247
2248size_t SoundMediaHeader::ComputeSizeInternal() {
2249 return HeaderSize() + sizeof(balance) + sizeof(uint16_t);
2250}
2251
2252NullMediaHeader::NullMediaHeader() = default;
2253NullMediaHeader::~NullMediaHeader() = default;
2254
2256 return FOURCC_nmhd;
2257}
2258
2259bool NullMediaHeader::ReadWriteInternal(BoxBuffer* buffer) {
2260 return ReadWriteHeaderInternal(buffer);
2261}
2262
2263size_t NullMediaHeader::ComputeSizeInternal() {
2264 return HeaderSize();
2265}
2266
2267SubtitleMediaHeader::SubtitleMediaHeader() = default;
2268SubtitleMediaHeader::~SubtitleMediaHeader() = default;
2269
2271 return FOURCC_sthd;
2272}
2273
2274bool SubtitleMediaHeader::ReadWriteInternal(BoxBuffer* buffer) {
2275 return ReadWriteHeaderInternal(buffer);
2276}
2277
2278size_t SubtitleMediaHeader::ComputeSizeInternal() {
2279 return HeaderSize();
2280}
2281
2282DataEntryUrl::DataEntryUrl() {
2283 const uint32_t kDataEntryUrlFlags = 1;
2284 flags = kDataEntryUrlFlags;
2285}
2286
2287DataEntryUrl::~DataEntryUrl() = default;
2288
2290 return FOURCC_url;
2291}
2292bool DataEntryUrl::ReadWriteInternal(BoxBuffer* buffer) {
2293 RCHECK(ReadWriteHeaderInternal(buffer));
2294 if (buffer->Reading()) {
2295 RCHECK(buffer->ReadWriteVector(&location, buffer->BytesLeft()));
2296 } else {
2297 RCHECK(buffer->ReadWriteVector(&location, location.size()));
2298 }
2299 return true;
2300}
2301
2302size_t DataEntryUrl::ComputeSizeInternal() {
2303 return HeaderSize() + location.size();
2304}
2305
2306DataReference::DataReference() = default;
2307DataReference::~DataReference() = default;
2308
2310 return FOURCC_dref;
2311}
2312bool DataReference::ReadWriteInternal(BoxBuffer* buffer) {
2313 uint32_t entry_count = static_cast<uint32_t>(data_entry.size());
2314 RCHECK(ReadWriteHeaderInternal(buffer) &&
2315 buffer->ReadWriteUInt32(&entry_count));
2316 data_entry.resize(entry_count);
2317 RCHECK(buffer->PrepareChildren());
2318 for (uint32_t i = 0; i < entry_count; ++i)
2319 RCHECK(buffer->ReadWriteChild(&data_entry[i]));
2320 return true;
2321}
2322
2323size_t DataReference::ComputeSizeInternal() {
2324 uint32_t count = static_cast<uint32_t>(data_entry.size());
2325 size_t box_size = HeaderSize() + sizeof(count);
2326 for (uint32_t i = 0; i < count; ++i)
2327 box_size += data_entry[i].ComputeSize();
2328 return box_size;
2329}
2330
2331DataInformation::DataInformation() = default;
2332DataInformation::~DataInformation() = default;
2333
2335 return FOURCC_dinf;
2336}
2337
2338bool DataInformation::ReadWriteInternal(BoxBuffer* buffer) {
2339 return ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
2340 buffer->ReadWriteChild(&dref);
2341}
2342
2343size_t DataInformation::ComputeSizeInternal() {
2344 return HeaderSize() + dref.ComputeSize();
2345}
2346
2347MediaInformation::MediaInformation() = default;
2348MediaInformation::~MediaInformation() = default;
2349
2351 return FOURCC_minf;
2352}
2353
2354bool MediaInformation::ReadWriteInternal(BoxBuffer* buffer) {
2355 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
2356 buffer->ReadWriteChild(&dinf) &&
2357 buffer->ReadWriteChild(&sample_table));
2358 switch (sample_table.description.type) {
2359 case kVideo:
2360 RCHECK(buffer->ReadWriteChild(&vmhd));
2361 break;
2362 case kAudio:
2363 RCHECK(buffer->ReadWriteChild(&smhd));
2364 break;
2365 case kText:
2366 RCHECK(buffer->TryReadWriteChild(&nmhd));
2367 break;
2368 case kSubtitle:
2369 RCHECK(buffer->TryReadWriteChild(&sthd));
2370 break;
2371 default:
2372 NOTIMPLEMENTED();
2373 }
2374 // Hint is not supported for now.
2375 return true;
2376}
2377
2378size_t MediaInformation::ComputeSizeInternal() {
2379 size_t box_size =
2380 HeaderSize() + dinf.ComputeSize() + sample_table.ComputeSize();
2381 switch (sample_table.description.type) {
2382 case kVideo:
2383 box_size += vmhd.ComputeSize();
2384 break;
2385 case kAudio:
2386 box_size += smhd.ComputeSize();
2387 break;
2388 case kText:
2389 box_size += nmhd.ComputeSize();
2390 break;
2391 case kSubtitle:
2392 box_size += sthd.ComputeSize();
2393 break;
2394 default:
2395 NOTIMPLEMENTED();
2396 }
2397 return box_size;
2398}
2399
2400Media::Media() = default;
2401Media::~Media() = default;
2402
2403FourCC Media::BoxType() const {
2404 return FOURCC_mdia;
2405}
2406
2407bool Media::ReadWriteInternal(BoxBuffer* buffer) {
2408 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
2409 buffer->ReadWriteChild(&header));
2410 if (buffer->Reading()) {
2411 RCHECK(buffer->ReadWriteChild(&handler));
2412 // Maddeningly, the HandlerReference box specifies how to parse the
2413 // SampleDescription box, making the latter the only box (of those that we
2414 // support) which cannot be parsed correctly on its own (or even with
2415 // information from its strict ancestor tree). We thus copy the handler type
2416 // to the sample description box *before* parsing it to provide this
2417 // information while parsing.
2418 information.sample_table.description.type =
2419 FourCCToTrackType(handler.handler_type);
2420 } else {
2421 handler.handler_type =
2422 TrackTypeToFourCC(information.sample_table.description.type);
2423 RCHECK(handler.handler_type != FOURCC_NULL);
2424 RCHECK(buffer->ReadWriteChild(&handler));
2425 }
2426 RCHECK(buffer->ReadWriteChild(&information));
2427 return true;
2428}
2429
2430size_t Media::ComputeSizeInternal() {
2431 handler.handler_type =
2432 TrackTypeToFourCC(information.sample_table.description.type);
2433 return HeaderSize() + header.ComputeSize() + handler.ComputeSize() +
2434 information.ComputeSize();
2435}
2436
2437Track::Track() = default;
2438Track::~Track() = default;
2439
2440FourCC Track::BoxType() const {
2441 return FOURCC_trak;
2442}
2443
2444bool Track::ReadWriteInternal(BoxBuffer* buffer) {
2445 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
2446 buffer->ReadWriteChild(&header) && buffer->ReadWriteChild(&media) &&
2447 buffer->TryReadWriteChild(&edit) &&
2448 buffer->TryReadWriteChild(&sample_encryption));
2449 return true;
2450}
2451
2452size_t Track::ComputeSizeInternal() {
2453 return HeaderSize() + header.ComputeSize() + media.ComputeSize() +
2454 edit.ComputeSize();
2455}
2456
2457MovieExtendsHeader::MovieExtendsHeader() = default;
2458MovieExtendsHeader::~MovieExtendsHeader() = default;
2459
2461 return FOURCC_mehd;
2462}
2463
2464bool MovieExtendsHeader::ReadWriteInternal(BoxBuffer* buffer) {
2465 RCHECK(ReadWriteHeaderInternal(buffer));
2466 size_t num_bytes = (version == 1) ? sizeof(uint64_t) : sizeof(uint32_t);
2467 RCHECK(buffer->ReadWriteUInt64NBytes(&fragment_duration, num_bytes));
2468 return true;
2469}
2470
2471size_t MovieExtendsHeader::ComputeSizeInternal() {
2472 // This box is optional. Skip it if it is not used.
2473 if (fragment_duration == 0)
2474 return 0;
2475 version = IsFitIn32Bits(fragment_duration) ? 0 : 1;
2476 return HeaderSize() + sizeof(uint32_t) * (1 + version);
2477}
2478
2479TrackExtends::TrackExtends() = default;
2480TrackExtends::~TrackExtends() = default;
2481
2483 return FOURCC_trex;
2484}
2485
2486bool TrackExtends::ReadWriteInternal(BoxBuffer* buffer) {
2487 RCHECK(ReadWriteHeaderInternal(buffer) &&
2488 buffer->ReadWriteUInt32(&track_id) &&
2489 buffer->ReadWriteUInt32(&default_sample_description_index) &&
2490 buffer->ReadWriteUInt32(&default_sample_duration) &&
2491 buffer->ReadWriteUInt32(&default_sample_size) &&
2492 buffer->ReadWriteUInt32(&default_sample_flags));
2493 return true;
2494}
2495
2496size_t TrackExtends::ComputeSizeInternal() {
2497 return HeaderSize() + sizeof(track_id) +
2498 sizeof(default_sample_description_index) +
2499 sizeof(default_sample_duration) + sizeof(default_sample_size) +
2500 sizeof(default_sample_flags);
2501}
2502
2503MovieExtends::MovieExtends() = default;
2504MovieExtends::~MovieExtends() = default;
2505
2507 return FOURCC_mvex;
2508}
2509
2510bool MovieExtends::ReadWriteInternal(BoxBuffer* buffer) {
2511 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
2512 buffer->TryReadWriteChild(&header));
2513 if (buffer->Reading()) {
2514 DCHECK(buffer->reader());
2515 RCHECK(buffer->reader()->ReadChildren(&tracks));
2516 } else {
2517 for (uint32_t i = 0; i < tracks.size(); ++i)
2518 RCHECK(buffer->ReadWriteChild(&tracks[i]));
2519 }
2520 return true;
2521}
2522
2523size_t MovieExtends::ComputeSizeInternal() {
2524 // This box is optional. Skip it if it does not contain any track.
2525 if (tracks.size() == 0)
2526 return 0;
2527 size_t box_size = HeaderSize() + header.ComputeSize();
2528 for (uint32_t i = 0; i < tracks.size(); ++i)
2529 box_size += tracks[i].ComputeSize();
2530 return box_size;
2531}
2532
2533Movie::Movie() = default;
2534Movie::~Movie() = default;
2535
2536FourCC Movie::BoxType() const {
2537 return FOURCC_moov;
2538}
2539
2540bool Movie::ReadWriteInternal(BoxBuffer* buffer) {
2541 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
2542 buffer->ReadWriteChild(&header));
2543 if (buffer->Reading()) {
2544 BoxReader* reader = buffer->reader();
2545 DCHECK(reader);
2546 RCHECK(reader->ReadChildren(&tracks) && reader->TryReadChild(&extends) &&
2547 reader->TryReadChildren(&pssh));
2548 } else {
2549 // The 'meta' box is not well formed in the video captured by Android's
2550 // default camera app: spec indicates that it is a FullBox but it is written
2551 // as a Box. This results in the box failed to be parsed. See
2552 // https://github.com/shaka-project/shaka-packager/issues/319 for details.
2553 // We do not care the content of metadata box in the source content, so just
2554 // skip reading the box.
2555 RCHECK(buffer->TryReadWriteChild(&metadata));
2556 if (absl::GetFlag(FLAGS_mvex_before_trak)) {
2557 // |extends| has to be written before |tracks| to workaround Android
2558 // MediaExtractor bug which requires |mvex| to be placed before |trak|.
2559 // See https://github.com/shaka-project/shaka-packager/issues/711 for
2560 // details.
2561 RCHECK(buffer->TryReadWriteChild(&extends));
2562 }
2563 for (uint32_t i = 0; i < tracks.size(); ++i)
2564 RCHECK(buffer->ReadWriteChild(&tracks[i]));
2565 if (!absl::GetFlag(FLAGS_mvex_before_trak)) {
2566 RCHECK(buffer->TryReadWriteChild(&extends));
2567 }
2568 for (uint32_t i = 0; i < pssh.size(); ++i)
2569 RCHECK(buffer->ReadWriteChild(&pssh[i]));
2570 }
2571 return true;
2572}
2573
2574size_t Movie::ComputeSizeInternal() {
2575 size_t box_size = HeaderSize() + header.ComputeSize() +
2576 metadata.ComputeSize() + extends.ComputeSize();
2577 for (uint32_t i = 0; i < tracks.size(); ++i)
2578 box_size += tracks[i].ComputeSize();
2579 for (uint32_t i = 0; i < pssh.size(); ++i)
2580 box_size += pssh[i].ComputeSize();
2581 return box_size;
2582}
2583
2584TrackFragmentDecodeTime::TrackFragmentDecodeTime() = default;
2585TrackFragmentDecodeTime::~TrackFragmentDecodeTime() = default;
2586
2588 return FOURCC_tfdt;
2589}
2590
2591bool TrackFragmentDecodeTime::ReadWriteInternal(BoxBuffer* buffer) {
2592 RCHECK(ReadWriteHeaderInternal(buffer));
2593 size_t num_bytes = (version == 1) ? sizeof(uint64_t) : sizeof(uint32_t);
2594 RCHECK(buffer->ReadWriteUInt64NBytes(&decode_time, num_bytes));
2595 return true;
2596}
2597
2598size_t TrackFragmentDecodeTime::ComputeSizeInternal() {
2599 version = IsFitIn32Bits(decode_time) ? 0 : 1;
2600 return HeaderSize() + sizeof(uint32_t) * (1 + version);
2601}
2602
2603MovieFragmentHeader::MovieFragmentHeader() = default;
2604MovieFragmentHeader::~MovieFragmentHeader() = default;
2605
2607 return FOURCC_mfhd;
2608}
2609
2610bool MovieFragmentHeader::ReadWriteInternal(BoxBuffer* buffer) {
2611 return ReadWriteHeaderInternal(buffer) &&
2612 buffer->ReadWriteUInt32(&sequence_number);
2613}
2614
2615size_t MovieFragmentHeader::ComputeSizeInternal() {
2616 return HeaderSize() + sizeof(sequence_number);
2617}
2618
2619TrackFragmentHeader::TrackFragmentHeader() = default;
2620TrackFragmentHeader::~TrackFragmentHeader() = default;
2621
2623 return FOURCC_tfhd;
2624}
2625
2626bool TrackFragmentHeader::ReadWriteInternal(BoxBuffer* buffer) {
2627 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->ReadWriteUInt32(&track_id));
2628
2629 if (flags & kBaseDataOffsetPresentMask) {
2630 // MSE requires 'default-base-is-moof' to be set and
2631 // 'base-data-offset-present' not to be set. We omit these checks as some
2632 // valid files in the wild don't follow these rules, though they use moof as
2633 // base.
2634 uint64_t base_data_offset;
2635 RCHECK(buffer->ReadWriteUInt64(&base_data_offset));
2636 DLOG(WARNING) << "base-data-offset-present is not expected. Assumes "
2637 "default-base-is-moof.";
2638 }
2639
2640 if (flags & kSampleDescriptionIndexPresentMask) {
2641 RCHECK(buffer->ReadWriteUInt32(&sample_description_index));
2642 } else if (buffer->Reading()) {
2643 sample_description_index = 0;
2644 }
2645
2646 if (flags & kDefaultSampleDurationPresentMask) {
2647 RCHECK(buffer->ReadWriteUInt32(&default_sample_duration));
2648 } else if (buffer->Reading()) {
2649 default_sample_duration = 0;
2650 }
2651
2652 if (flags & kDefaultSampleSizePresentMask) {
2653 RCHECK(buffer->ReadWriteUInt32(&default_sample_size));
2654 } else if (buffer->Reading()) {
2655 default_sample_size = 0;
2656 }
2657
2658 if (flags & kDefaultSampleFlagsPresentMask)
2659 RCHECK(buffer->ReadWriteUInt32(&default_sample_flags));
2660 return true;
2661}
2662
2663size_t TrackFragmentHeader::ComputeSizeInternal() {
2664 size_t box_size = HeaderSize() + sizeof(track_id);
2665 if (flags & kSampleDescriptionIndexPresentMask)
2666 box_size += sizeof(sample_description_index);
2667 if (flags & kDefaultSampleDurationPresentMask)
2668 box_size += sizeof(default_sample_duration);
2669 if (flags & kDefaultSampleSizePresentMask)
2670 box_size += sizeof(default_sample_size);
2671 if (flags & kDefaultSampleFlagsPresentMask)
2672 box_size += sizeof(default_sample_flags);
2673 return box_size;
2674}
2675
2676TrackFragmentRun::TrackFragmentRun() = default;
2677TrackFragmentRun::~TrackFragmentRun() = default;
2678
2680 return FOURCC_trun;
2681}
2682
2683bool TrackFragmentRun::ReadWriteInternal(BoxBuffer* buffer) {
2684 if (!buffer->Reading()) {
2685 // Determine whether version 0 or version 1 should be used.
2686 // Use version 0 if possible, use version 1 if there is a negative
2687 // sample_offset value.
2688 version = 0;
2689 if (flags & kSampleCompTimeOffsetsPresentMask) {
2690 for (uint32_t i = 0; i < sample_count; ++i) {
2691 if (sample_composition_time_offsets[i] < 0) {
2692 version = 1;
2693 break;
2694 }
2695 }
2696 }
2697 }
2698
2699 RCHECK(ReadWriteHeaderInternal(buffer) &&
2700 buffer->ReadWriteUInt32(&sample_count));
2701
2702 bool data_offset_present = (flags & kDataOffsetPresentMask) != 0;
2703 bool first_sample_flags_present = (flags & kFirstSampleFlagsPresentMask) != 0;
2704 bool sample_duration_present = (flags & kSampleDurationPresentMask) != 0;
2705 bool sample_size_present = (flags & kSampleSizePresentMask) != 0;
2706 bool sample_flags_present = (flags & kSampleFlagsPresentMask) != 0;
2707 bool sample_composition_time_offsets_present =
2708 (flags & kSampleCompTimeOffsetsPresentMask) != 0;
2709
2710 if (data_offset_present) {
2711 RCHECK(buffer->ReadWriteUInt32(&data_offset));
2712 } else {
2713 // NOTE: If the data-offset is not present, then the data for this run
2714 // starts immediately after the data of the previous run, or at the
2715 // base-data-offset defined by the track fragment header if this is the
2716 // first run in a track fragment. If the data-offset is present, it is
2717 // relative to the base-data-offset established in the track fragment
2718 // header.
2719 NOTIMPLEMENTED();
2720 }
2721
2722 uint32_t first_sample_flags(0);
2723
2724 if (buffer->Reading()) {
2725 if (first_sample_flags_present)
2726 RCHECK(buffer->ReadWriteUInt32(&first_sample_flags));
2727
2728 if (sample_duration_present)
2729 sample_durations.resize(sample_count);
2730 if (sample_size_present)
2731 sample_sizes.resize(sample_count);
2732 if (sample_flags_present)
2733 sample_flags.resize(sample_count);
2734 if (sample_composition_time_offsets_present)
2735 sample_composition_time_offsets.resize(sample_count);
2736 } else {
2737 if (first_sample_flags_present) {
2738 first_sample_flags = sample_flags[0];
2739 DCHECK(sample_flags.size() == 1);
2740 RCHECK(buffer->ReadWriteUInt32(&first_sample_flags));
2741 }
2742
2743 if (sample_duration_present)
2744 DCHECK(sample_durations.size() == sample_count);
2745 if (sample_size_present)
2746 DCHECK(sample_sizes.size() == sample_count);
2747 if (sample_flags_present)
2748 DCHECK(sample_flags.size() == sample_count);
2749 if (sample_composition_time_offsets_present)
2750 DCHECK(sample_composition_time_offsets.size() == sample_count);
2751 }
2752
2753 for (uint32_t i = 0; i < sample_count; ++i) {
2754 if (sample_duration_present)
2755 RCHECK(buffer->ReadWriteUInt32(&sample_durations[i]));
2756 if (sample_size_present)
2757 RCHECK(buffer->ReadWriteUInt32(&sample_sizes[i]));
2758 if (sample_flags_present)
2759 RCHECK(buffer->ReadWriteUInt32(&sample_flags[i]));
2760
2761 if (sample_composition_time_offsets_present) {
2762 if (version == 0) {
2763 uint32_t sample_offset = sample_composition_time_offsets[i];
2764 RCHECK(buffer->ReadWriteUInt32(&sample_offset));
2765 sample_composition_time_offsets[i] = sample_offset;
2766 } else {
2767 int32_t sample_offset = sample_composition_time_offsets[i];
2768 RCHECK(buffer->ReadWriteInt32(&sample_offset));
2769 sample_composition_time_offsets[i] = sample_offset;
2770 }
2771 }
2772 }
2773
2774 if (buffer->Reading()) {
2775 if (first_sample_flags_present) {
2776 if (sample_flags.size() == 0) {
2777 sample_flags.push_back(first_sample_flags);
2778 } else {
2779 sample_flags[0] = first_sample_flags;
2780 }
2781 }
2782 }
2783 return true;
2784}
2785
2786size_t TrackFragmentRun::ComputeSizeInternal() {
2787 size_t box_size = HeaderSize() + sizeof(sample_count);
2788 if (flags & kDataOffsetPresentMask)
2789 box_size += sizeof(data_offset);
2790 if (flags & kFirstSampleFlagsPresentMask)
2791 box_size += sizeof(uint32_t);
2792 uint32_t fields = (flags & kSampleDurationPresentMask ? 1 : 0) +
2793 (flags & kSampleSizePresentMask ? 1 : 0) +
2794 (flags & kSampleFlagsPresentMask ? 1 : 0) +
2795 (flags & kSampleCompTimeOffsetsPresentMask ? 1 : 0);
2796 box_size += fields * sizeof(uint32_t) * sample_count;
2797 return box_size;
2798}
2799
2800TrackFragment::TrackFragment() = default;
2801TrackFragment::~TrackFragment() = default;
2802
2804 return FOURCC_traf;
2805}
2806
2807bool TrackFragment::ReadWriteInternal(BoxBuffer* buffer) {
2808 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
2809 buffer->ReadWriteChild(&header));
2810 if (buffer->Reading()) {
2811 DCHECK(buffer->reader());
2812 decode_time_absent = !buffer->reader()->ChildExist(&decode_time);
2813 if (!decode_time_absent)
2814 RCHECK(buffer->ReadWriteChild(&decode_time));
2815 RCHECK(buffer->reader()->TryReadChildren(&runs) &&
2816 buffer->reader()->TryReadChildren(&sample_group_descriptions) &&
2817 buffer->reader()->TryReadChildren(&sample_to_groups));
2818 } else {
2819 if (!decode_time_absent)
2820 RCHECK(buffer->ReadWriteChild(&decode_time));
2821 for (uint32_t i = 0; i < runs.size(); ++i)
2822 RCHECK(buffer->ReadWriteChild(&runs[i]));
2823 for (uint32_t i = 0; i < sample_to_groups.size(); ++i)
2824 RCHECK(buffer->ReadWriteChild(&sample_to_groups[i]));
2825 for (uint32_t i = 0; i < sample_group_descriptions.size(); ++i)
2826 RCHECK(buffer->ReadWriteChild(&sample_group_descriptions[i]));
2827 }
2828 return buffer->TryReadWriteChild(&auxiliary_size) &&
2829 buffer->TryReadWriteChild(&auxiliary_offset) &&
2830 buffer->TryReadWriteChild(&sample_encryption);
2831}
2832
2833size_t TrackFragment::ComputeSizeInternal() {
2834 size_t box_size = HeaderSize() + header.ComputeSize() +
2835 decode_time.ComputeSize() + auxiliary_size.ComputeSize() +
2836 auxiliary_offset.ComputeSize() +
2837 sample_encryption.ComputeSize();
2838 for (uint32_t i = 0; i < runs.size(); ++i)
2839 box_size += runs[i].ComputeSize();
2840 for (uint32_t i = 0; i < sample_group_descriptions.size(); ++i)
2841 box_size += sample_group_descriptions[i].ComputeSize();
2842 for (uint32_t i = 0; i < sample_to_groups.size(); ++i)
2843 box_size += sample_to_groups[i].ComputeSize();
2844 return box_size;
2845}
2846
2847MovieFragment::MovieFragment() = default;
2848MovieFragment::~MovieFragment() = default;
2849
2851 return FOURCC_moof;
2852}
2853
2854bool MovieFragment::ReadWriteInternal(BoxBuffer* buffer) {
2855 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
2856 buffer->ReadWriteChild(&header));
2857 if (buffer->Reading()) {
2858 BoxReader* reader = buffer->reader();
2859 DCHECK(reader);
2860 RCHECK(reader->ReadChildren(&tracks) && reader->TryReadChildren(&pssh));
2861 } else {
2862 for (uint32_t i = 0; i < tracks.size(); ++i)
2863 RCHECK(buffer->ReadWriteChild(&tracks[i]));
2864 for (uint32_t i = 0; i < pssh.size(); ++i)
2865 RCHECK(buffer->ReadWriteChild(&pssh[i]));
2866 }
2867 return true;
2868}
2869
2870size_t MovieFragment::ComputeSizeInternal() {
2871 size_t box_size = HeaderSize() + header.ComputeSize();
2872 for (uint32_t i = 0; i < tracks.size(); ++i)
2873 box_size += tracks[i].ComputeSize();
2874 for (uint32_t i = 0; i < pssh.size(); ++i)
2875 box_size += pssh[i].ComputeSize();
2876 return box_size;
2877}
2878
2879SegmentIndex::SegmentIndex() = default;
2880SegmentIndex::~SegmentIndex() = default;
2881
2883 return FOURCC_sidx;
2884}
2885
2886bool SegmentIndex::ReadWriteInternal(BoxBuffer* buffer) {
2887 RCHECK(ReadWriteHeaderInternal(buffer) &&
2888 buffer->ReadWriteUInt32(&reference_id) &&
2889 buffer->ReadWriteUInt32(&timescale));
2890
2891 size_t num_bytes = (version == 1) ? sizeof(uint64_t) : sizeof(uint32_t);
2892 RCHECK(
2893 buffer->ReadWriteUInt64NBytes(&earliest_presentation_time, num_bytes) &&
2894 buffer->ReadWriteUInt64NBytes(&first_offset, num_bytes));
2895
2896 uint16_t reference_count;
2897 if (references.size() <= std::numeric_limits<uint16_t>::max()) {
2898 reference_count = static_cast<uint16_t>(references.size());
2899 } else {
2900 reference_count = std::numeric_limits<uint16_t>::max();
2901 LOG(WARNING) << "Seeing " << references.size()
2902 << " subsegment references, but at most " << reference_count
2903 << " references can be stored in 'sidx' box."
2904 << " The extra references are truncated.";
2905 LOG(WARNING) << "The stream will not play to the end in DASH.";
2906 LOG(WARNING) << "A possible workaround is to increase segment duration.";
2907 }
2908 RCHECK(buffer->IgnoreBytes(2) && // reserved.
2909 buffer->ReadWriteUInt16(&reference_count));
2910 if (buffer->Reading())
2911 references.resize(reference_count);
2912
2913 uint32_t reference_type_size;
2914 uint32_t sap;
2915 for (uint32_t i = 0; i < reference_count; ++i) {
2916 if (!buffer->Reading()) {
2917 reference_type_size = references[i].referenced_size;
2918 if (references[i].reference_type)
2919 reference_type_size |= (1 << 31);
2920 sap = (references[i].sap_type << 28) | references[i].sap_delta_time;
2921 if (references[i].starts_with_sap)
2922 sap |= (1 << 31);
2923 }
2924 RCHECK(buffer->ReadWriteUInt32(&reference_type_size) &&
2925 buffer->ReadWriteUInt32(&references[i].subsegment_duration) &&
2926 buffer->ReadWriteUInt32(&sap));
2927 if (buffer->Reading()) {
2928 references[i].reference_type = (reference_type_size >> 31) ? true : false;
2929 references[i].referenced_size = reference_type_size & ~(1 << 31);
2930 references[i].starts_with_sap = (sap >> 31) ? true : false;
2931 references[i].sap_type =
2932 static_cast<SegmentReference::SAPType>((sap >> 28) & 0x07);
2933 references[i].sap_delta_time = sap & ~(0xF << 28);
2934 }
2935 }
2936 return true;
2937}
2938
2939size_t SegmentIndex::ComputeSizeInternal() {
2940 version = IsFitIn32Bits(earliest_presentation_time, first_offset) ? 0 : 1;
2941 return HeaderSize() + sizeof(reference_id) + sizeof(timescale) +
2942 sizeof(uint32_t) * (1 + version) * 2 + 2 * sizeof(uint16_t) +
2943 3 * sizeof(uint32_t) *
2944 std::min(
2945 references.size(),
2946 static_cast<size_t>(std::numeric_limits<uint16_t>::max()));
2947}
2948
2949MediaData::MediaData() = default;
2950MediaData::~MediaData() = default;
2951
2952FourCC MediaData::BoxType() const {
2953 return FOURCC_mdat;
2954}
2955
2956bool MediaData::ReadWriteInternal(BoxBuffer* buffer) {
2957 NOTIMPLEMENTED() << "Actual data is parsed and written separately.";
2958 return false;
2959}
2960
2961size_t MediaData::ComputeSizeInternal() {
2962 return HeaderSize() + data_size;
2963}
2964
2965CueSourceIDBox::CueSourceIDBox() = default;
2966CueSourceIDBox::~CueSourceIDBox() = default;
2967
2969 return FOURCC_vsid;
2970}
2971
2972bool CueSourceIDBox::ReadWriteInternal(BoxBuffer* buffer) {
2973 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->ReadWriteInt32(&source_id));
2974 return true;
2975}
2976
2977size_t CueSourceIDBox::ComputeSizeInternal() {
2978 if (source_id == kCueSourceIdNotSet)
2979 return 0;
2980 return HeaderSize() + sizeof(source_id);
2981}
2982
2983CueTimeBox::CueTimeBox() = default;
2984CueTimeBox::~CueTimeBox() = default;
2985
2986FourCC CueTimeBox::BoxType() const {
2987 return FOURCC_ctim;
2988}
2989
2990bool CueTimeBox::ReadWriteInternal(BoxBuffer* buffer) {
2991 RCHECK(ReadWriteHeaderInternal(buffer));
2992 return buffer->ReadWriteString(
2993 &cue_current_time,
2994 buffer->Reading() ? buffer->BytesLeft() : cue_current_time.size());
2995}
2996
2997size_t CueTimeBox::ComputeSizeInternal() {
2998 if (cue_current_time.empty())
2999 return 0;
3000 return HeaderSize() + cue_current_time.size();
3001}
3002
3003CueIDBox::CueIDBox() = default;
3004CueIDBox::~CueIDBox() = default;
3005
3006FourCC CueIDBox::BoxType() const {
3007 return FOURCC_iden;
3008}
3009
3010bool CueIDBox::ReadWriteInternal(BoxBuffer* buffer) {
3011 RCHECK(ReadWriteHeaderInternal(buffer));
3012 return buffer->ReadWriteString(
3013 &cue_id, buffer->Reading() ? buffer->BytesLeft() : cue_id.size());
3014}
3015
3016size_t CueIDBox::ComputeSizeInternal() {
3017 if (cue_id.empty())
3018 return 0;
3019 return HeaderSize() + cue_id.size();
3020}
3021
3022CueSettingsBox::CueSettingsBox() = default;
3023CueSettingsBox::~CueSettingsBox() = default;
3024
3026 return FOURCC_sttg;
3027}
3028
3029bool CueSettingsBox::ReadWriteInternal(BoxBuffer* buffer) {
3030 RCHECK(ReadWriteHeaderInternal(buffer));
3031 return buffer->ReadWriteString(
3032 &settings, buffer->Reading() ? buffer->BytesLeft() : settings.size());
3033}
3034
3035size_t CueSettingsBox::ComputeSizeInternal() {
3036 if (settings.empty())
3037 return 0;
3038 return HeaderSize() + settings.size();
3039}
3040
3041CuePayloadBox::CuePayloadBox() = default;
3042CuePayloadBox::~CuePayloadBox() = default;
3043
3045 return FOURCC_payl;
3046}
3047
3048bool CuePayloadBox::ReadWriteInternal(BoxBuffer* buffer) {
3049 RCHECK(ReadWriteHeaderInternal(buffer));
3050 return buffer->ReadWriteString(
3051 &cue_text, buffer->Reading() ? buffer->BytesLeft() : cue_text.size());
3052}
3053
3054size_t CuePayloadBox::ComputeSizeInternal() {
3055 return HeaderSize() + cue_text.size();
3056}
3057
3058VTTEmptyCueBox::VTTEmptyCueBox() = default;
3059VTTEmptyCueBox::~VTTEmptyCueBox() = default;
3060
3062 return FOURCC_vtte;
3063}
3064
3065bool VTTEmptyCueBox::ReadWriteInternal(BoxBuffer* buffer) {
3066 return ReadWriteHeaderInternal(buffer);
3067}
3068
3069size_t VTTEmptyCueBox::ComputeSizeInternal() {
3070 return HeaderSize();
3071}
3072
3073VTTAdditionalTextBox::VTTAdditionalTextBox() = default;
3074VTTAdditionalTextBox::~VTTAdditionalTextBox() = default;
3075
3077 return FOURCC_vtta;
3078}
3079
3080bool VTTAdditionalTextBox::ReadWriteInternal(BoxBuffer* buffer) {
3081 RCHECK(ReadWriteHeaderInternal(buffer));
3082 return buffer->ReadWriteString(
3083 &cue_additional_text,
3084 buffer->Reading() ? buffer->BytesLeft() : cue_additional_text.size());
3085}
3086
3087size_t VTTAdditionalTextBox::ComputeSizeInternal() {
3088 return HeaderSize() + cue_additional_text.size();
3089}
3090
3091VTTCueBox::VTTCueBox() = default;
3092VTTCueBox::~VTTCueBox() = default;
3093
3094FourCC VTTCueBox::BoxType() const {
3095 return FOURCC_vttc;
3096}
3097
3098bool VTTCueBox::ReadWriteInternal(BoxBuffer* buffer) {
3099 RCHECK(ReadWriteHeaderInternal(buffer) && buffer->PrepareChildren() &&
3100 buffer->TryReadWriteChild(&cue_source_id) &&
3101 buffer->TryReadWriteChild(&cue_id) &&
3102 buffer->TryReadWriteChild(&cue_time) &&
3103 buffer->TryReadWriteChild(&cue_settings) &&
3104 buffer->ReadWriteChild(&cue_payload));
3105 return true;
3106}
3107
3108size_t VTTCueBox::ComputeSizeInternal() {
3109 return HeaderSize() + cue_source_id.ComputeSize() + cue_id.ComputeSize() +
3110 cue_time.ComputeSize() + cue_settings.ComputeSize() +
3111 cue_payload.ComputeSize();
3112}
3113
3114} // namespace mp4
3115} // namespace media
3116} // 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:201
bool ReadWriteUInt64NBytes(uint64_t *v, size_t num_bytes)
Definition box_buffer.h:119
bool TryReadWriteChild(Box *box)
Definition box_buffer.h:189
bool ReadWriteString(std::string *str, size_t size)
Definition box_buffer.h:141
bool ReadWriteChild(Box *box)
Definition box_buffer.h:178
Class for reading MP4 boxes.
Definition box_reader.h:28
bool ReadChildren(std::vector< T > *children)
Definition box_reader.h:131
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:137
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