5 #include "packager/media/formats/mp4/box_definitions.h"
9 #include "packager/base/logging.h"
10 #include "packager/media/base/bit_reader.h"
11 #include "packager/media/formats/mp4/box_buffer.h"
12 #include "packager/media/formats/mp4/rcheck.h"
15 const uint32_t kFourCCSize = 4;
17 const uint32_t kBoxSize = kFourCCSize +
sizeof(uint32_t);
19 const uint32_t kFullBoxSize = kBoxSize + 4;
22 const uint32_t kCencKeyIdSize = 16;
25 const uint8_t kUnityMatrix[] = {0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
26 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
27 0, 0, 0, 0, 0, 0, 0, 0, 0x40, 0, 0, 0};
30 const char kVideoHandlerName[] =
"VideoHandler";
31 const char kAudioHandlerName[] =
"SoundHandler";
34 const uint32_t kVideoResolution = 0x00480000;
35 const uint16_t kVideoFrameCount = 1;
36 const uint16_t kVideoDepth = 0x0018;
38 const uint32_t kCompressorNameSize = 32u;
39 const char kAvcCompressorName[] =
"\012AVC Coding";
40 const char kHevcCompressorName[] =
"\013HEVC Coding";
41 const char kVpcCompressorName[] =
"\012VPC Coding";
44 bool IsFitIn32Bits(uint64_t a) {
45 return a <= std::numeric_limits<uint32_t>::max();
48 bool IsFitIn32Bits(int64_t a) {
49 return a <= std::numeric_limits<int32_t>::max() &&
50 a >= std::numeric_limits<int32_t>::min();
53 template <
typename T1,
typename T2>
54 bool IsFitIn32Bits(T1 a1, T2 a2) {
55 return IsFitIn32Bits(a1) && IsFitIn32Bits(a2);
58 template <
typename T1,
typename T2,
typename T3>
59 bool IsFitIn32Bits(T1 a1, T2 a2, T3 a3) {
60 return IsFitIn32Bits(a1) && IsFitIn32Bits(a2) && IsFitIn32Bits(a3);
65 namespace edash_packager {
69 FileType::FileType() : major_brand(FOURCC_NULL), minor_version(0) {}
70 FileType::~FileType() {}
71 FourCC FileType::BoxType()
const {
return FOURCC_FTYP; }
75 buffer->ReadWriteFourCC(&major_brand) &&
76 buffer->ReadWriteUInt32(&minor_version));
79 num_brands = (buffer->
Size() - buffer->
Pos()) /
sizeof(FourCC);
80 compatible_brands.resize(num_brands);
82 num_brands = compatible_brands.size();
84 for (
size_t i = 0; i < num_brands; ++i)
85 RCHECK(buffer->ReadWriteFourCC(&compatible_brands[i]));
90 atom_size = kBoxSize + kFourCCSize +
sizeof(minor_version) +
91 kFourCCSize * compatible_brands.size();
95 SegmentType::SegmentType() {}
96 SegmentType::~SegmentType() {}
97 FourCC SegmentType::BoxType()
const {
return FOURCC_STYP; }
107 ProtectionSystemSpecificHeader::ProtectionSystemSpecificHeader() {}
108 ProtectionSystemSpecificHeader::~ProtectionSystemSpecificHeader() {}
109 FourCC ProtectionSystemSpecificHeader::BoxType()
const {
return FOURCC_PSSH; }
112 if (!buffer->
Reading() && !raw_box.empty()) {
114 buffer->
writer()->AppendVector(raw_box);
118 uint32_t size = data.size();
120 buffer->ReadWriteVector(&system_id, 16) &&
121 buffer->ReadWriteUInt32(&size) &&
122 buffer->ReadWriteVector(&data, size));
127 DCHECK(raw_box.empty());
130 raw_box.assign(reader->data(), reader->data() + reader->size());
136 if (!raw_box.empty()) {
140 kFullBoxSize + system_id.size() +
sizeof(uint32_t) + data.size();
145 SampleAuxiliaryInformationOffset::SampleAuxiliaryInformationOffset() {}
146 SampleAuxiliaryInformationOffset::~SampleAuxiliaryInformationOffset() {}
147 FourCC SampleAuxiliaryInformationOffset::BoxType()
const {
return FOURCC_SAIO; }
154 uint32_t count = offsets.size();
155 RCHECK(buffer->ReadWriteUInt32(&count));
156 offsets.resize(count);
158 size_t num_bytes = (version == 1) ?
sizeof(uint64_t) :
sizeof(uint32_t);
159 for (uint32_t i = 0; i < count; ++i)
167 if (offsets.size() != 0) {
168 size_t num_bytes = (version == 1) ?
sizeof(uint64_t) :
sizeof(uint32_t);
169 atom_size = kFullBoxSize +
sizeof(uint32_t) + num_bytes * offsets.size();
174 SampleAuxiliaryInformationSize::SampleAuxiliaryInformationSize()
175 : default_sample_info_size(0), sample_count(0) {}
176 SampleAuxiliaryInformationSize::~SampleAuxiliaryInformationSize() {}
177 FourCC SampleAuxiliaryInformationSize::BoxType()
const {
return FOURCC_SAIZ; }
184 RCHECK(buffer->ReadWriteUInt8(&default_sample_info_size) &&
185 buffer->ReadWriteUInt32(&sample_count));
186 if (default_sample_info_size == 0)
187 RCHECK(buffer->ReadWriteVector(&sample_info_sizes, sample_count));
194 if (sample_count != 0) {
195 atom_size = kFullBoxSize +
sizeof(default_sample_info_size) +
196 sizeof(sample_count) +
197 (default_sample_info_size == 0 ? sample_info_sizes.size() : 0);
202 OriginalFormat::OriginalFormat() : format(FOURCC_NULL) {}
203 OriginalFormat::~OriginalFormat() {}
204 FourCC OriginalFormat::BoxType()
const {
return FOURCC_FRMA; }
207 return Box::ReadWrite(buffer) && buffer->ReadWriteFourCC(&format);
215 SchemeType::SchemeType() : type(FOURCC_NULL), version(0) {}
216 SchemeType::~SchemeType() {}
217 FourCC SchemeType::BoxType()
const {
return FOURCC_SCHM; }
221 buffer->ReadWriteFourCC(&type) &&
222 buffer->ReadWriteUInt32(&version));
227 atom_size = kFullBoxSize + kFourCCSize +
sizeof(version);
231 TrackEncryption::TrackEncryption()
232 : is_encrypted(false), default_iv_size(0), default_kid(16, 0) {}
233 TrackEncryption::~TrackEncryption() {}
234 FourCC TrackEncryption::BoxType()
const {
return FOURCC_TENC; }
238 if (default_kid.size() != kCencKeyIdSize) {
239 LOG(WARNING) <<
"CENC defines key id length of " << kCencKeyIdSize
240 <<
" bytes; got " << default_kid.size()
241 <<
". Resized accordingly.";
242 default_kid.resize(kCencKeyIdSize);
246 uint8_t flag = is_encrypted ? 1 : 0;
249 buffer->ReadWriteUInt8(&flag) &&
250 buffer->ReadWriteUInt8(&default_iv_size) &&
251 buffer->ReadWriteVector(&default_kid, kCencKeyIdSize));
253 is_encrypted = (flag != 0);
255 RCHECK(default_iv_size == 8 || default_iv_size == 16);
257 RCHECK(default_iv_size == 0);
264 atom_size = kFullBoxSize +
sizeof(uint32_t) + kCencKeyIdSize;
268 SchemeInfo::SchemeInfo() {}
269 SchemeInfo::~SchemeInfo() {}
270 FourCC SchemeInfo::BoxType()
const {
return FOURCC_SCHI; }
283 ProtectionSchemeInfo::ProtectionSchemeInfo() {}
284 ProtectionSchemeInfo::~ProtectionSchemeInfo() {}
285 FourCC ProtectionSchemeInfo::BoxType()
const {
return FOURCC_SINF; }
292 if (type.type == FOURCC_CENC)
304 if (format.format != FOURCC_NULL) {
311 MovieHeader::MovieHeader()
313 modification_time(0),
319 MovieHeader::~MovieHeader() {}
320 FourCC MovieHeader::BoxType()
const {
return FOURCC_MVHD; }
325 size_t num_bytes = (version == 1) ?
sizeof(uint64_t) :
sizeof(uint32_t);
328 buffer->ReadWriteUInt32(×cale) &&
331 std::vector<uint8_t> matrix(kUnityMatrix,
332 kUnityMatrix + arraysize(kUnityMatrix));
333 RCHECK(buffer->ReadWriteInt32(&rate) &&
334 buffer->ReadWriteInt16(&volume) &&
336 buffer->ReadWriteVector(&matrix, matrix.size()) &&
338 buffer->ReadWriteUInt32(&next_track_id));
343 version = IsFitIn32Bits(creation_time, modification_time, duration) ? 0 : 1;
344 atom_size = kFullBoxSize +
sizeof(uint32_t) * (1 + version) * 3 +
345 sizeof(timescale) +
sizeof(rate) +
sizeof(volume) +
346 sizeof(next_track_id) +
sizeof(kUnityMatrix) + 10 +
351 TrackHeader::TrackHeader()
353 modification_time(0),
361 flags = kTrackEnabled | kTrackInMovie;
363 TrackHeader::~TrackHeader() {}
364 FourCC TrackHeader::BoxType()
const {
return FOURCC_TKHD; }
369 size_t num_bytes = (version == 1) ?
sizeof(uint64_t) :
sizeof(uint32_t);
372 buffer->ReadWriteUInt32(&track_id) &&
379 volume = (width != 0 && height != 0) ? 0 : 0x100;
381 std::vector<uint8_t> matrix(kUnityMatrix,
382 kUnityMatrix + arraysize(kUnityMatrix));
384 buffer->ReadWriteInt16(&layer) &&
385 buffer->ReadWriteInt16(&alternate_group) &&
386 buffer->ReadWriteInt16(&volume) &&
388 buffer->ReadWriteVector(&matrix, matrix.size()) &&
389 buffer->ReadWriteUInt32(&width) &&
390 buffer->ReadWriteUInt32(&height));
395 version = IsFitIn32Bits(creation_time, modification_time, duration) ? 0 : 1;
396 atom_size = kFullBoxSize +
sizeof(track_id) +
397 sizeof(uint32_t) * (1 + version) * 3 +
sizeof(layer) +
398 sizeof(alternate_group) +
sizeof(volume) +
sizeof(width) +
399 sizeof(height) +
sizeof(kUnityMatrix) + 14;
403 SampleDescription::SampleDescription() : type(kInvalid) {}
404 SampleDescription::~SampleDescription() {}
405 FourCC SampleDescription::BoxType()
const {
return FOURCC_STSD; }
410 count = video_entries.size();
412 count = audio_entries.size();
414 buffer->ReadWriteUInt32(&count));
419 video_entries.clear();
420 audio_entries.clear();
423 if (type == kVideo) {
425 RCHECK(video_entries.size() == count);
426 }
else if (type == kAudio) {
428 RCHECK(audio_entries.size() == count);
431 DCHECK_LT(0u, count);
432 if (type == kVideo) {
433 for (uint32_t i = 0; i < count; ++i)
434 RCHECK(video_entries[i].
ReadWrite(buffer));
435 }
else if (type == kAudio) {
436 for (uint32_t i = 0; i < count; ++i)
437 RCHECK(audio_entries[i].
ReadWrite(buffer));
446 atom_size = kFullBoxSize +
sizeof(uint32_t);
447 if (type == kVideo) {
448 for (uint32_t i = 0; i < video_entries.size(); ++i)
450 }
else if (type == kAudio) {
451 for (uint32_t i = 0; i < audio_entries.size(); ++i)
457 DecodingTimeToSample::DecodingTimeToSample() {}
458 DecodingTimeToSample::~DecodingTimeToSample() {}
459 FourCC DecodingTimeToSample::BoxType()
const {
return FOURCC_STTS; }
462 uint32_t count = decoding_time.size();
464 buffer->ReadWriteUInt32(&count));
466 decoding_time.resize(count);
467 for (uint32_t i = 0; i < count; ++i) {
468 RCHECK(buffer->ReadWriteUInt32(&decoding_time[i].sample_count) &&
469 buffer->ReadWriteUInt32(&decoding_time[i].sample_delta));
475 atom_size = kFullBoxSize +
sizeof(uint32_t) +
480 CompositionTimeToSample::CompositionTimeToSample() {}
481 CompositionTimeToSample::~CompositionTimeToSample() {}
482 FourCC CompositionTimeToSample::BoxType()
const {
return FOURCC_CTTS; }
485 uint32_t count = composition_offset.size();
491 for (uint32_t i = 0; i < count; ++i) {
492 if (composition_offset[i].sample_offset < 0) {
500 buffer->ReadWriteUInt32(&count));
502 composition_offset.resize(count);
503 for (uint32_t i = 0; i < count; ++i) {
504 RCHECK(buffer->ReadWriteUInt32(&composition_offset[i].sample_count));
507 uint32_t sample_offset = composition_offset[i].sample_offset;
508 RCHECK(buffer->ReadWriteUInt32(&sample_offset));
509 composition_offset[i].sample_offset = sample_offset;
511 int32_t sample_offset = composition_offset[i].sample_offset;
512 RCHECK(buffer->ReadWriteInt32(&sample_offset));
513 composition_offset[i].sample_offset = sample_offset;
522 if (!composition_offset.empty()) {
526 const uint32_t kCompositionOffsetSize =
sizeof(uint32_t) * 2;
527 atom_size = kFullBoxSize +
sizeof(uint32_t) +
528 kCompositionOffsetSize * composition_offset.size();
533 SampleToChunk::SampleToChunk() {}
534 SampleToChunk::~SampleToChunk() {}
535 FourCC SampleToChunk::BoxType()
const {
return FOURCC_STSC; }
538 uint32_t count = chunk_info.size();
540 buffer->ReadWriteUInt32(&count));
542 chunk_info.resize(count);
543 for (uint32_t i = 0; i < count; ++i) {
544 RCHECK(buffer->ReadWriteUInt32(&chunk_info[i].first_chunk) &&
545 buffer->ReadWriteUInt32(&chunk_info[i].samples_per_chunk) &&
546 buffer->ReadWriteUInt32(&chunk_info[i].sample_description_index));
548 RCHECK(i == 0 ? chunk_info[i].first_chunk == 1
549 : chunk_info[i].first_chunk > chunk_info[i - 1].first_chunk);
556 kFullBoxSize +
sizeof(uint32_t) +
sizeof(
ChunkInfo) * chunk_info.size();
560 SampleSize::SampleSize() : sample_size(0), sample_count(0) {}
561 SampleSize::~SampleSize() {}
562 FourCC SampleSize::BoxType()
const {
return FOURCC_STSZ; }
566 buffer->ReadWriteUInt32(&sample_size) &&
567 buffer->ReadWriteUInt32(&sample_count));
569 if (sample_size == 0) {
571 sizes.resize(sample_count);
573 DCHECK(sample_count == sizes.size());
574 for (uint32_t i = 0; i < sample_count; ++i)
575 RCHECK(buffer->ReadWriteUInt32(&sizes[i]));
581 atom_size = kFullBoxSize +
sizeof(sample_size) +
sizeof(sample_count) +
582 (sample_size == 0 ?
sizeof(uint32_t) * sizes.size() : 0);
586 CompactSampleSize::CompactSampleSize() : field_size(0) {}
587 CompactSampleSize::~CompactSampleSize() {}
588 FourCC CompactSampleSize::BoxType()
const {
return FOURCC_STZ2; }
591 uint32_t sample_count = sizes.size();
594 buffer->ReadWriteUInt8(&field_size) &&
595 buffer->ReadWriteUInt32(&sample_count));
598 sizes.resize(sample_count + (field_size == 4 ? 1 : 0), 0);
599 switch (field_size) {
601 for (uint32_t i = 0; i < sample_count; i += 2) {
604 RCHECK(buffer->ReadWriteUInt8(&size));
605 sizes[i] = size >> 4;
606 sizes[i + 1] = size & 0x0F;
608 DCHECK_LT(sizes[i], 16u);
609 DCHECK_LT(sizes[i + 1], 16u);
610 uint8_t size = (sizes[i] << 4) | sizes[i + 1];
611 RCHECK(buffer->ReadWriteUInt8(&size));
616 for (uint32_t i = 0; i < sample_count; ++i) {
617 uint8_t size = sizes[i];
618 RCHECK(buffer->ReadWriteUInt8(&size));
623 for (uint32_t i = 0; i < sample_count; ++i) {
624 uint16_t size = sizes[i];
625 RCHECK(buffer->ReadWriteUInt16(&size));
632 sizes.resize(sample_count);
637 atom_size = kFullBoxSize +
sizeof(uint32_t) +
sizeof(uint32_t) +
638 (field_size * sizes.size() + 7) / 8;
642 ChunkOffset::ChunkOffset() {}
643 ChunkOffset::~ChunkOffset() {}
644 FourCC ChunkOffset::BoxType()
const {
return FOURCC_STCO; }
647 uint32_t count = offsets.size();
649 buffer->ReadWriteUInt32(&count));
651 offsets.resize(count);
652 for (uint32_t i = 0; i < count; ++i)
659 kFullBoxSize +
sizeof(uint32_t) +
sizeof(uint32_t) * offsets.size();
663 ChunkLargeOffset::ChunkLargeOffset() {}
664 ChunkLargeOffset::~ChunkLargeOffset() {}
665 FourCC ChunkLargeOffset::BoxType()
const {
return FOURCC_CO64; }
668 uint32_t count = offsets.size();
672 if (count == 0 || IsFitIn32Bits(offsets[count - 1])) {
674 stco.offsets.swap(offsets);
677 stco.offsets.swap(offsets);
683 buffer->ReadWriteUInt32(&count));
685 offsets.resize(count);
686 for (uint32_t i = 0; i < count; ++i)
687 RCHECK(buffer->ReadWriteUInt64(&offsets[i]));
692 uint32_t count = offsets.size();
693 int use_large_offset =
694 (count > 0 && !IsFitIn32Bits(offsets[count - 1])) ? 1 : 0;
695 atom_size = kFullBoxSize +
sizeof(count) +
696 sizeof(uint32_t) * (1 + use_large_offset) * offsets.size();
700 SyncSample::SyncSample() {}
701 SyncSample::~SyncSample() {}
702 FourCC SyncSample::BoxType()
const {
return FOURCC_STSS; }
705 uint32_t count = sample_number.size();
707 buffer->ReadWriteUInt32(&count));
709 sample_number.resize(count);
710 for (uint32_t i = 0; i < count; ++i)
711 RCHECK(buffer->ReadWriteUInt32(&sample_number[i]));
718 if (!sample_number.empty()) {
719 atom_size = kFullBoxSize +
sizeof(uint32_t) +
720 sizeof(uint32_t) * sample_number.size();
725 SampleTable::SampleTable() {}
726 SampleTable::~SampleTable() {}
727 FourCC SampleTable::BoxType()
const {
return FOURCC_STBL; }
746 RCHECK(reader->
ReadChild(&compact_sample_size));
747 sample_size.sample_size = 0;
748 sample_size.sample_count = compact_sample_size.sizes.size();
749 sample_size.sizes.swap(compact_sample_size.sizes);
753 if (reader->
ChildExist(&chunk_large_offset)) {
754 RCHECK(reader->
ReadChild(&chunk_large_offset));
757 RCHECK(reader->
ReadChild(&chunk_offset));
758 chunk_large_offset.offsets.swap(chunk_offset.offsets);
777 EditList::EditList() {}
778 EditList::~EditList() {}
779 FourCC EditList::BoxType()
const {
return FOURCC_ELST; }
782 uint32_t count = edits.size();
786 size_t num_bytes = (version == 1) ?
sizeof(uint64_t) :
sizeof(uint32_t);
787 for (uint32_t i = 0; i < count; ++i) {
790 buffer->ReadWriteInt64NBytes(&edits[i].media_time, num_bytes) &&
791 buffer->ReadWriteInt16(&edits[i].media_rate_integer) &&
792 buffer->ReadWriteInt16(&edits[i].media_rate_fraction));
804 for (uint32_t i = 0; i < edits.size(); ++i) {
805 if (!IsFitIn32Bits(edits[i].segment_duration, edits[i].media_time)) {
810 atom_size = kFullBoxSize +
sizeof(uint32_t) +
811 (
sizeof(uint32_t) * (1 + version) * 2 +
sizeof(int16_t) * 2) *
818 FourCC Edit::BoxType()
const {
return FOURCC_EDTS; }
829 if (!list.edits.empty())
834 HandlerReference::HandlerReference() : type(kInvalid) {}
835 HandlerReference::~HandlerReference() {}
836 FourCC HandlerReference::BoxType()
const {
return FOURCC_HDLR; }
839 FourCC hdlr_type = FOURCC_NULL;
840 std::vector<uint8_t> handler_name;
842 if (type == kVideo) {
843 hdlr_type = FOURCC_VIDE;
844 handler_name.assign(kVideoHandlerName,
845 kVideoHandlerName + arraysize(kVideoHandlerName));
846 }
else if (type == kAudio) {
847 hdlr_type = FOURCC_SOUN;
848 handler_name.assign(kAudioHandlerName,
849 kAudioHandlerName + arraysize(kAudioHandlerName));
857 buffer->ReadWriteFourCC(&hdlr_type));
860 if (hdlr_type == FOURCC_VIDE) {
862 }
else if (hdlr_type == FOURCC_SOUN) {
869 buffer->ReadWriteVector(&handler_name, handler_name.size()));
876 kFullBoxSize + kFourCCSize + 16 +
877 (type == kVideo ?
sizeof(kVideoHandlerName) :
sizeof(kAudioHandlerName));
881 CodecConfigurationRecord::CodecConfigurationRecord() : box_type(FOURCC_NULL) {}
882 CodecConfigurationRecord::~CodecConfigurationRecord() {}
883 FourCC CodecConfigurationRecord::BoxType()
const {
892 RCHECK(buffer->ReadWriteVector(&data, buffer->
Size() - buffer->
Pos()));
894 RCHECK(buffer->ReadWriteVector(&data, data.size()));
906 PixelAspectRatioBox::PixelAspectRatioBox() : h_spacing(0), v_spacing(0) {}
907 PixelAspectRatioBox::~PixelAspectRatioBox() {}
908 FourCC PixelAspectRatioBox::BoxType()
const {
return FOURCC_PASP; }
912 buffer->ReadWriteUInt32(&h_spacing) &&
913 buffer->ReadWriteUInt32(&v_spacing));
920 if (h_spacing != 0 || v_spacing != 0) {
922 DCHECK(h_spacing != 0 && v_spacing != 0);
923 atom_size = kBoxSize +
sizeof(h_spacing) +
sizeof(v_spacing);
928 VideoSampleEntry::VideoSampleEntry()
929 : format(FOURCC_NULL), data_reference_index(1), width(0), height(0) {}
931 VideoSampleEntry::~VideoSampleEntry() {}
932 FourCC VideoSampleEntry::BoxType()
const {
933 LOG(ERROR) <<
"VideoSampleEntry should be parsed according to the "
934 <<
"handler type recovered in its Media ancestor.";
939 std::vector<uint8_t> compressor_name;
942 format = buffer->
reader()->type();
944 RCHECK(buffer->ReadWriteUInt32(&
atom_size) &&
945 buffer->ReadWriteFourCC(&format));
947 const FourCC actual_format = GetActualFormat();
948 switch (actual_format) {
950 compressor_name.assign(
952 kAvcCompressorName + arraysize(kAvcCompressorName));
956 compressor_name.assign(
958 kHevcCompressorName + arraysize(kHevcCompressorName));
963 compressor_name.assign(
965 kVpcCompressorName + arraysize(kVpcCompressorName));
968 LOG(ERROR) << FourCCToString(actual_format) <<
" is not supported.";
971 compressor_name.resize(kCompressorNameSize);
974 uint32_t video_resolution = kVideoResolution;
975 uint16_t video_frame_count = kVideoFrameCount;
976 uint16_t video_depth = kVideoDepth;
977 int16_t predefined = -1;
979 buffer->ReadWriteUInt16(&data_reference_index) &&
981 buffer->ReadWriteUInt16(&width) &&
982 buffer->ReadWriteUInt16(&height) &&
983 buffer->ReadWriteUInt32(&video_resolution) &&
984 buffer->ReadWriteUInt32(&video_resolution) &&
986 buffer->ReadWriteUInt16(&video_frame_count) &&
987 buffer->ReadWriteVector(&compressor_name, kCompressorNameSize) &&
988 buffer->ReadWriteUInt16(&video_depth) &&
989 buffer->ReadWriteInt16(&predefined));
993 if (format == FOURCC_ENCV) {
997 while (sinf.type.type != FOURCC_CENC) {
1006 const FourCC actual_format = GetActualFormat();
1007 switch (actual_format) {
1009 codec_config_record.box_type = FOURCC_AVCC;
1013 codec_config_record.box_type = FOURCC_HVCC;
1018 codec_config_record.box_type = FOURCC_VPCC;
1021 LOG(ERROR) << FourCCToString(actual_format) <<
" is not supported.";
1030 atom_size = kBoxSize +
sizeof(data_reference_index) +
sizeof(width) +
1031 sizeof(height) +
sizeof(kVideoResolution) * 2 +
1032 sizeof(kVideoFrameCount) +
sizeof(kVideoDepth) +
1034 codec_config_record.
ComputeSize() + kCompressorNameSize +
1039 ElementaryStreamDescriptor::ElementaryStreamDescriptor() {}
1040 ElementaryStreamDescriptor::~ElementaryStreamDescriptor() {}
1041 FourCC ElementaryStreamDescriptor::BoxType()
const {
return FOURCC_ESDS; }
1046 std::vector<uint8_t> data;
1047 RCHECK(buffer->ReadWriteVector(&data, buffer->
Size() - buffer->
Pos()));
1048 RCHECK(es_descriptor.Parse(data));
1049 if (es_descriptor.
IsAAC()) {
1050 RCHECK(aac_audio_specific_config.
Parse(
1051 es_descriptor.decoder_specific_info()));
1054 DCHECK(buffer->
writer());
1055 es_descriptor.Write(buffer->
writer());
1063 if (es_descriptor.object_type() != kForbidden)
1064 atom_size = kFullBoxSize + es_descriptor.ComputeSize();
1068 AudioSampleEntry::AudioSampleEntry()
1069 : format(FOURCC_NULL),
1070 data_reference_index(1),
1075 AudioSampleEntry::~AudioSampleEntry() {}
1077 FourCC AudioSampleEntry::BoxType()
const {
1078 LOG(ERROR) <<
"AudioSampleEntry should be parsed according to the "
1079 <<
"handler type recovered in its Media ancestor.";
1085 DCHECK(buffer->
reader());
1086 format = buffer->
reader()->type();
1088 RCHECK(buffer->ReadWriteUInt32(&
atom_size) &&
1089 buffer->ReadWriteFourCC(&format));
1095 buffer->ReadWriteUInt16(&data_reference_index) &&
1097 buffer->ReadWriteUInt16(&channelcount) &&
1098 buffer->ReadWriteUInt16(&samplesize) &&
1100 buffer->ReadWriteUInt32(&samplerate));
1104 if (format == FOURCC_ENCA || format == FOURCC_MP4A) {
1106 if (format == FOURCC_ENCA) {
1110 while (sinf.type.type != FOURCC_CENC) {
1125 LOG(INFO) <<
"read vector: " << buffer->
Size() <<
", " << buffer->
Pos();
1126 RCHECK(buffer->ReadWriteVector(&extra_data, buffer->
Size() - buffer->
Pos()));
1128 LOG(INFO) <<
"write vector: " << extra_data.size();
1129 RCHECK(buffer->ReadWriteVector(&extra_data, extra_data.size()));
1136 atom_size = kBoxSize +
sizeof(data_reference_index) +
sizeof(channelcount) +
1137 sizeof(samplesize) +
sizeof(samplerate) + sinf.
ComputeSize() +
1144 MediaHeader::MediaHeader()
1145 : creation_time(0), modification_time(0), timescale(0), duration(0) {
1148 MediaHeader::~MediaHeader() {}
1149 FourCC MediaHeader::BoxType()
const {
return FOURCC_MDHD; }
1154 uint8_t num_bytes = (version == 1) ?
sizeof(uint64_t) :
sizeof(uint32_t);
1157 buffer->ReadWriteUInt32(×cale) &&
1163 std::vector<uint8_t> temp;
1164 RCHECK(buffer->ReadWriteVector(&temp, 2));
1167 bit_reader.SkipBits(1);
1168 for (
int i = 0; i < 3; ++i) {
1169 CHECK(bit_reader.ReadBits(5, &language[i]));
1170 language[i] += 0x60;
1175 const char kUndefinedLanguage[] =
"und";
1176 if (language[0] == 0)
1177 strcpy(language, kUndefinedLanguage);
1181 for (
int i = 0; i < 3; ++i)
1182 lang |= (language[i] - 0x60) << ((2 - i) * 5);
1183 RCHECK(buffer->ReadWriteUInt16(&lang));
1191 version = IsFitIn32Bits(creation_time, modification_time, duration) ? 0 : 1;
1192 atom_size = kFullBoxSize +
sizeof(timescale) +
1193 sizeof(uint32_t) * (1 + version) * 3 + 2 +
1198 VideoMediaHeader::VideoMediaHeader()
1199 : graphicsmode(0), opcolor_red(0), opcolor_green(0), opcolor_blue(0) {
1200 const uint32_t kVideoMediaHeaderFlags = 1;
1201 flags = kVideoMediaHeaderFlags;
1203 VideoMediaHeader::~VideoMediaHeader() {}
1204 FourCC VideoMediaHeader::BoxType()
const {
return FOURCC_VMHD; }
1207 buffer->ReadWriteUInt16(&graphicsmode) &&
1208 buffer->ReadWriteUInt16(&opcolor_red) &&
1209 buffer->ReadWriteUInt16(&opcolor_green) &&
1210 buffer->ReadWriteUInt16(&opcolor_blue));
1215 atom_size = kFullBoxSize +
sizeof(graphicsmode) +
sizeof(opcolor_red) +
1216 sizeof(opcolor_green) +
sizeof(opcolor_blue);
1220 SoundMediaHeader::SoundMediaHeader() : balance(0) {}
1221 SoundMediaHeader::~SoundMediaHeader() {}
1222 FourCC SoundMediaHeader::BoxType()
const {
return FOURCC_SMHD; }
1225 buffer->ReadWriteUInt16(&balance) &&
1231 atom_size = kFullBoxSize +
sizeof(balance) +
sizeof(uint16_t);
1235 DataEntryUrl::DataEntryUrl() {
1236 const uint32_t kDataEntryUrlFlags = 1;
1237 flags = kDataEntryUrlFlags;
1239 DataEntryUrl::~DataEntryUrl() {}
1240 FourCC DataEntryUrl::BoxType()
const {
return FOURCC_URL; }
1244 RCHECK(buffer->ReadWriteVector(&location, buffer->
Size() - buffer->
Pos()));
1246 RCHECK(buffer->ReadWriteVector(&location, location.size()));
1252 atom_size = kBoxSize +
sizeof(flags) + location.size();
1256 DataReference::DataReference() {
1258 data_entry.resize(1);
1260 DataReference::~DataReference() {}
1261 FourCC DataReference::BoxType()
const {
return FOURCC_DREF; }
1263 uint32_t entry_count = data_entry.size();
1265 buffer->ReadWriteUInt32(&entry_count));
1266 data_entry.resize(entry_count);
1268 for (uint32_t i = 0; i < entry_count; ++i)
1274 uint32_t count = data_entry.size();
1275 atom_size = kFullBoxSize +
sizeof(count);
1276 for (uint32_t i = 0; i < count; ++i)
1281 DataInformation::DataInformation() {}
1282 DataInformation::~DataInformation() {}
1283 FourCC DataInformation::BoxType()
const {
return FOURCC_DINF; }
1296 MediaInformation::MediaInformation() {}
1297 MediaInformation::~MediaInformation() {}
1298 FourCC MediaInformation::BoxType()
const {
return FOURCC_MINF; }
1305 if (sample_table.description.type == kVideo)
1307 else if (sample_table.description.type == kAudio)
1317 if (sample_table.description.type == kVideo)
1319 else if (sample_table.description.type == kAudio)
1326 FourCC Media::BoxType()
const {
return FOURCC_MDIA; }
1340 information.sample_table.description.type = handler.type;
1342 DCHECK_EQ(information.sample_table.description.type, handler.type);
1356 FourCC Track::BoxType()
const {
return FOURCC_TRAK; }
1373 MovieExtendsHeader::MovieExtendsHeader() : fragment_duration(0) {}
1374 MovieExtendsHeader::~MovieExtendsHeader() {}
1375 FourCC MovieExtendsHeader::BoxType()
const {
return FOURCC_MEHD; }
1379 size_t num_bytes = (version == 1) ?
sizeof(uint64_t) :
sizeof(uint32_t);
1387 if (fragment_duration != 0) {
1388 version = IsFitIn32Bits(fragment_duration) ? 0 : 1;
1389 atom_size = kFullBoxSize +
sizeof(uint32_t) * (1 + version);
1394 TrackExtends::TrackExtends()
1396 default_sample_description_index(0),
1397 default_sample_duration(0),
1398 default_sample_size(0),
1399 default_sample_flags(0) {}
1400 TrackExtends::~TrackExtends() {}
1401 FourCC TrackExtends::BoxType()
const {
return FOURCC_TREX; }
1405 buffer->ReadWriteUInt32(&track_id) &&
1406 buffer->ReadWriteUInt32(&default_sample_description_index) &&
1407 buffer->ReadWriteUInt32(&default_sample_duration) &&
1408 buffer->ReadWriteUInt32(&default_sample_size) &&
1409 buffer->ReadWriteUInt32(&default_sample_flags));
1414 atom_size = kFullBoxSize +
sizeof(track_id) +
1415 sizeof(default_sample_description_index) +
1416 sizeof(default_sample_duration) +
sizeof(default_sample_size) +
1417 sizeof(default_sample_flags);
1421 MovieExtends::MovieExtends() {}
1422 MovieExtends::~MovieExtends() {}
1423 FourCC MovieExtends::BoxType()
const {
return FOURCC_MVEX; }
1430 DCHECK(buffer->
reader());
1433 for (uint32_t i = 0; i < tracks.size(); ++i)
1442 if (tracks.size() != 0) {
1444 for (uint32_t i = 0; i < tracks.size(); ++i)
1452 FourCC Movie::BoxType()
const {
return FOURCC_MOOV; }
1465 for (uint32_t i = 0; i < tracks.size(); ++i)
1467 for (uint32_t i = 0; i < pssh.size(); ++i)
1475 for (uint32_t i = 0; i < tracks.size(); ++i)
1477 for (uint32_t i = 0; i < pssh.size(); ++i)
1482 TrackFragmentDecodeTime::TrackFragmentDecodeTime() : decode_time(0) {}
1483 TrackFragmentDecodeTime::~TrackFragmentDecodeTime() {}
1484 FourCC TrackFragmentDecodeTime::BoxType()
const {
return FOURCC_TFDT; }
1488 size_t num_bytes = (version == 1) ?
sizeof(uint64_t) :
sizeof(uint32_t);
1494 version = IsFitIn32Bits(decode_time) ? 0 : 1;
1495 atom_size = kFullBoxSize +
sizeof(uint32_t) * (1 + version);
1499 MovieFragmentHeader::MovieFragmentHeader() : sequence_number(0) {}
1500 MovieFragmentHeader::~MovieFragmentHeader() {}
1501 FourCC MovieFragmentHeader::BoxType()
const {
return FOURCC_MFHD; }
1505 buffer->ReadWriteUInt32(&sequence_number);
1509 atom_size = kFullBoxSize +
sizeof(sequence_number);
1513 TrackFragmentHeader::TrackFragmentHeader()
1515 sample_description_index(0),
1516 default_sample_duration(0),
1517 default_sample_size(0),
1518 default_sample_flags(0) {}
1520 TrackFragmentHeader::~TrackFragmentHeader() {}
1521 FourCC TrackFragmentHeader::BoxType()
const {
return FOURCC_TFHD; }
1525 buffer->ReadWriteUInt32(&track_id));
1527 if (flags & kBaseDataOffsetPresentMask) {
1532 uint64_t base_data_offset;
1533 RCHECK(buffer->ReadWriteUInt64(&base_data_offset));
1534 DLOG(WARNING) <<
"base-data-offset-present is not expected. Assumes "
1535 "default-base-is-moof.";
1538 if (flags & kSampleDescriptionIndexPresentMask) {
1539 RCHECK(buffer->ReadWriteUInt32(&sample_description_index));
1540 }
else if (buffer->
Reading()) {
1541 sample_description_index = 0;
1544 if (flags & kDefaultSampleDurationPresentMask) {
1545 RCHECK(buffer->ReadWriteUInt32(&default_sample_duration));
1546 }
else if (buffer->
Reading()) {
1547 default_sample_duration = 0;
1550 if (flags & kDefaultSampleSizePresentMask) {
1551 RCHECK(buffer->ReadWriteUInt32(&default_sample_size));
1552 }
else if (buffer->
Reading()) {
1553 default_sample_size = 0;
1556 if (flags & kDefaultSampleFlagsPresentMask)
1557 RCHECK(buffer->ReadWriteUInt32(&default_sample_flags));
1562 atom_size = kFullBoxSize +
sizeof(track_id);
1563 if (flags & kSampleDescriptionIndexPresentMask)
1564 atom_size +=
sizeof(sample_description_index);
1565 if (flags & kDefaultSampleDurationPresentMask)
1566 atom_size +=
sizeof(default_sample_duration);
1567 if (flags & kDefaultSampleSizePresentMask)
1568 atom_size +=
sizeof(default_sample_size);
1569 if (flags & kDefaultSampleFlagsPresentMask)
1570 atom_size +=
sizeof(default_sample_flags);
1574 TrackFragmentRun::TrackFragmentRun() : sample_count(0), data_offset(0) {}
1575 TrackFragmentRun::~TrackFragmentRun() {}
1576 FourCC TrackFragmentRun::BoxType()
const {
return FOURCC_TRUN; }
1584 if (flags & kSampleCompTimeOffsetsPresentMask) {
1585 for (uint32_t i = 0; i < sample_count; ++i) {
1586 if (sample_composition_time_offsets[i] < 0) {
1595 buffer->ReadWriteUInt32(&sample_count));
1597 bool data_offset_present = (flags & kDataOffsetPresentMask) != 0;
1598 bool first_sample_flags_present = (flags & kFirstSampleFlagsPresentMask) != 0;
1599 bool sample_duration_present = (flags & kSampleDurationPresentMask) != 0;
1600 bool sample_size_present = (flags & kSampleSizePresentMask) != 0;
1601 bool sample_flags_present = (flags & kSampleFlagsPresentMask) != 0;
1602 bool sample_composition_time_offsets_present =
1603 (flags & kSampleCompTimeOffsetsPresentMask) != 0;
1605 if (data_offset_present) {
1606 RCHECK(buffer->ReadWriteUInt32(&data_offset));
1617 uint32_t first_sample_flags;
1620 if (first_sample_flags_present)
1621 RCHECK(buffer->ReadWriteUInt32(&first_sample_flags));
1623 if (sample_duration_present)
1624 sample_durations.resize(sample_count);
1625 if (sample_size_present)
1626 sample_sizes.resize(sample_count);
1627 if (sample_flags_present)
1628 sample_flags.resize(sample_count);
1629 if (sample_composition_time_offsets_present)
1630 sample_composition_time_offsets.resize(sample_count);
1632 if (first_sample_flags_present) {
1633 first_sample_flags = sample_flags[0];
1634 DCHECK(sample_flags.size() == 1);
1635 RCHECK(buffer->ReadWriteUInt32(&first_sample_flags));
1638 if (sample_duration_present)
1639 DCHECK(sample_durations.size() == sample_count);
1640 if (sample_size_present)
1641 DCHECK(sample_sizes.size() == sample_count);
1642 if (sample_flags_present)
1643 DCHECK(sample_flags.size() == sample_count);
1644 if (sample_composition_time_offsets_present)
1645 DCHECK(sample_composition_time_offsets.size() == sample_count);
1648 for (uint32_t i = 0; i < sample_count; ++i) {
1649 if (sample_duration_present)
1650 RCHECK(buffer->ReadWriteUInt32(&sample_durations[i]));
1651 if (sample_size_present)
1652 RCHECK(buffer->ReadWriteUInt32(&sample_sizes[i]));
1653 if (sample_flags_present)
1654 RCHECK(buffer->ReadWriteUInt32(&sample_flags[i]));
1656 if (sample_composition_time_offsets_present) {
1658 uint32_t sample_offset = sample_composition_time_offsets[i];
1659 RCHECK(buffer->ReadWriteUInt32(&sample_offset));
1660 sample_composition_time_offsets[i] = sample_offset;
1662 int32_t sample_offset = sample_composition_time_offsets[i];
1663 RCHECK(buffer->ReadWriteInt32(&sample_offset));
1664 sample_composition_time_offsets[i] = sample_offset;
1670 if (first_sample_flags_present) {
1671 if (sample_flags.size() == 0) {
1672 sample_flags.push_back(first_sample_flags);
1674 sample_flags[0] = first_sample_flags;
1682 atom_size = kFullBoxSize +
sizeof(sample_count);
1683 if (flags & kDataOffsetPresentMask)
1685 if (flags & kFirstSampleFlagsPresentMask)
1687 uint32_t fields = (flags & kSampleDurationPresentMask ? 1 : 0) +
1688 (flags & kSampleSizePresentMask ? 1 : 0) +
1689 (flags & kSampleFlagsPresentMask ? 1 : 0) +
1690 (flags & kSampleCompTimeOffsetsPresentMask ? 1 : 0);
1691 atom_size += fields *
sizeof(uint32_t) * sample_count;
1695 SampleToGroup::SampleToGroup() : grouping_type(0), grouping_type_parameter(0) {}
1696 SampleToGroup::~SampleToGroup() {}
1697 FourCC SampleToGroup::BoxType()
const {
return FOURCC_SBGP; }
1701 buffer->ReadWriteUInt32(&grouping_type));
1703 RCHECK(buffer->ReadWriteUInt32(&grouping_type_parameter));
1705 if (grouping_type != FOURCC_SEIG) {
1707 DLOG(WARNING) <<
"Sample group "
1708 << FourCCToString(static_cast<FourCC>(grouping_type))
1709 <<
" is not supported.";
1713 uint32_t count = entries.size();
1714 RCHECK(buffer->ReadWriteUInt32(&count));
1715 entries.resize(count);
1716 for (uint32_t i = 0; i < count; ++i) {
1717 RCHECK(buffer->ReadWriteUInt32(&entries[i].sample_count) &&
1718 buffer->ReadWriteUInt32(&entries[i].group_description_index));
1726 if (!entries.empty()) {
1727 atom_size = kFullBoxSize +
sizeof(grouping_type) +
1728 (version == 1 ?
sizeof(grouping_type_parameter) : 0) +
1729 sizeof(uint32_t) + entries.size() *
sizeof(entries[0]);
1734 CencSampleEncryptionInfoEntry::CencSampleEncryptionInfoEntry()
1735 : is_encrypted(false), iv_size(0) {
1737 CencSampleEncryptionInfoEntry::~CencSampleEncryptionInfoEntry() {};
1739 SampleGroupDescription::SampleGroupDescription() : grouping_type(0) {}
1740 SampleGroupDescription::~SampleGroupDescription() {}
1741 FourCC SampleGroupDescription::BoxType()
const {
return FOURCC_SGPD; }
1745 buffer->ReadWriteUInt32(&grouping_type));
1747 if (grouping_type != FOURCC_SEIG) {
1749 DLOG(WARNING) <<
"Sample group '" << grouping_type <<
"' is not supported.";
1753 const size_t kEntrySize =
sizeof(uint32_t) + kCencKeyIdSize;
1754 uint32_t default_length = 0;
1757 RCHECK(buffer->ReadWriteUInt32(&default_length));
1758 RCHECK(default_length == 0 || default_length >= kEntrySize);
1760 default_length = kEntrySize;
1761 RCHECK(buffer->ReadWriteUInt32(&default_length));
1765 uint32_t count = entries.size();
1766 RCHECK(buffer->ReadWriteUInt32(&count));
1767 entries.resize(count);
1768 for (uint32_t i = 0; i < count; ++i) {
1770 if (buffer->
Reading() && default_length == 0) {
1771 uint32_t description_length = 0;
1772 RCHECK(buffer->ReadWriteUInt32(&description_length));
1773 RCHECK(description_length >= kEntrySize);
1778 if (entries[i].key_id.size() != kCencKeyIdSize) {
1779 LOG(WARNING) <<
"CENC defines key id length of " << kCencKeyIdSize
1780 <<
" bytes; got " << entries[i].key_id.size()
1781 <<
". Resized accordingly.";
1782 entries[i].key_id.resize(kCencKeyIdSize);
1786 uint8_t flag = entries[i].is_encrypted ? 1 : 0;
1788 buffer->ReadWriteUInt8(&flag) &&
1789 buffer->ReadWriteUInt8(&entries[i].iv_size) &&
1790 buffer->ReadWriteVector(&entries[i].key_id, kCencKeyIdSize));
1793 entries[i].is_encrypted = (flag != 0);
1794 if (entries[i].is_encrypted) {
1795 RCHECK(entries[i].iv_size == 8 || entries[i].iv_size == 16);
1797 RCHECK(entries[i].iv_size == 0);
1809 if (!entries.empty()) {
1810 const size_t kEntrySize =
sizeof(uint32_t) + kCencKeyIdSize;
1811 atom_size = kFullBoxSize +
sizeof(grouping_type) +
1812 (version == 1 ?
sizeof(uint32_t) : 0) +
sizeof(uint32_t) +
1813 entries.size() * kEntrySize;
1818 TrackFragment::TrackFragment() : decode_time_absent(false) {}
1819 TrackFragment::~TrackFragment() {}
1820 FourCC TrackFragment::BoxType()
const {
return FOURCC_TRAF; }
1827 DCHECK(buffer->
reader());
1829 if (!decode_time_absent)
1837 while (sample_to_group.grouping_type != FOURCC_SEIG &&
1841 while (sample_group_description.grouping_type != FOURCC_SEIG &&
1846 if (!decode_time_absent)
1848 for (uint32_t i = 0; i < runs.size(); ++i)
1862 for (uint32_t i = 0; i < runs.size(); ++i)
1867 MovieFragment::MovieFragment() {}
1868 MovieFragment::~MovieFragment() {}
1869 FourCC MovieFragment::BoxType()
const {
return FOURCC_MOOF; }
1881 for (uint32_t i = 0; i < tracks.size(); ++i)
1883 for (uint32_t i = 0; i < pssh.size(); ++i)
1891 for (uint32_t i = 0; i < tracks.size(); ++i)
1893 for (uint32_t i = 0; i < pssh.size(); ++i)
1898 SegmentIndex::SegmentIndex()
1901 earliest_presentation_time(0),
1903 SegmentIndex::~SegmentIndex() {}
1904 FourCC SegmentIndex::BoxType()
const {
return FOURCC_SIDX; }
1908 buffer->ReadWriteUInt32(&reference_id) &&
1909 buffer->ReadWriteUInt32(×cale));
1911 size_t num_bytes = (version == 1) ?
sizeof(uint64_t) :
sizeof(uint32_t);
1916 uint16_t reference_count = references.size();
1918 buffer->ReadWriteUInt16(&reference_count));
1919 references.resize(reference_count);
1921 uint32_t reference_type_size;
1923 for (uint32_t i = 0; i < reference_count; ++i) {
1925 reference_type_size = references[i].referenced_size;
1926 if (references[i].reference_type)
1927 reference_type_size |= (1 << 31);
1928 sap = (references[i].sap_type << 28) | references[i].sap_delta_time;
1929 if (references[i].starts_with_sap)
1932 RCHECK(buffer->ReadWriteUInt32(&reference_type_size) &&
1933 buffer->ReadWriteUInt32(&references[i].subsegment_duration) &&
1934 buffer->ReadWriteUInt32(&sap));
1936 references[i].reference_type = (reference_type_size >> 31) ?
true :
false;
1937 references[i].referenced_size = reference_type_size & ~(1 << 31);
1938 references[i].starts_with_sap = (sap >> 31) ?
true :
false;
1939 references[i].sap_type =
1940 static_cast<SegmentReference::SAPType
>((sap >> 28) & 0x07);
1941 references[i].sap_delta_time = sap & ~(0xF << 28);
1948 version = IsFitIn32Bits(earliest_presentation_time, first_offset) ? 0 : 1;
1949 atom_size = kFullBoxSize +
sizeof(reference_id) +
sizeof(timescale) +
1950 sizeof(uint32_t) * (1 + version) * 2 + 2 *
sizeof(uint16_t) +
1951 3 *
sizeof(uint32_t) * references.size();
1955 MediaData::MediaData() : data_size(0) {}
1956 MediaData::~MediaData() {}
1957 FourCC MediaData::BoxType()
const {
return FOURCC_MDAT; }
1959 void MediaData::Write(BufferWriter* buffer) {
1960 buffer->AppendInt(ComputeSize());
1961 buffer->AppendInt(static_cast<uint32_t>(BoxType()));
1964 uint32_t MediaData::ComputeSize() {
1965 return kBoxSize + data_size;
bool ReadWrite(BoxBuffer *buffer) override
Read/write the mp4 box from/to BoxBuffer.
bool ReadWrite(BoxBuffer *buffer) override
Read/write the mp4 box from/to BoxBuffer.
uint32_t ComputeSize() override
uint32_t ComputeSize() override
uint32_t ComputeSize() override
bool ReadWrite(BoxBuffer *buffer) override
Read/write the mp4 box from/to BoxBuffer.