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