diff --git a/media/base/decrypt_config.cc b/media/base/decrypt_config.cc index 53e20143e1..9648df2f78 100644 --- a/media/base/decrypt_config.cc +++ b/media/base/decrypt_config.cc @@ -17,8 +17,6 @@ DecryptConfig::DecryptConfig(const std::string& key_id, data_offset_(data_offset), subsamples_(subsamples) { CHECK_GT(key_id.size(), 0u); - CHECK(iv.size() == static_cast(DecryptConfig::kDecryptionKeySize) || - iv.empty()); CHECK_GE(data_offset, 0); } diff --git a/media/base/decrypt_config.h b/media/base/decrypt_config.h index 0597043748..aaa7ca9c37 100644 --- a/media/base/decrypt_config.h +++ b/media/base/decrypt_config.h @@ -23,7 +23,7 @@ namespace media { // result, and then copying each byte from the decrypted block over the // position of the corresponding encrypted byte. struct SubsampleEntry { - uint32 clear_bytes; + uint16 clear_bytes; uint32 cypher_bytes; }; @@ -31,12 +31,10 @@ struct SubsampleEntry { class DecryptConfig { public: // Keys are always 128 bits. - static const int kDecryptionKeySize = 16; + static const size_t kDecryptionKeySize = 16; // |key_id| is the ID that references the decryption key for this sample. // |iv| is the initialization vector defined by the encrypted format. - // Currently |iv| must be 16 bytes as defined by WebM and ISO. Or must be - // empty which signals an unencrypted frame. // |data_offset| is the amount of data that should be discarded from the // head of the sample buffer before applying subsample information. A // decrypted buffer will be shorter than an encrypted buffer by this amount. diff --git a/media/mp4/aac.cc b/media/mp4/aac.cc index 311c5ee0b0..81eb89512c 100644 --- a/media/mp4/aac.cc +++ b/media/mp4/aac.cc @@ -37,8 +37,6 @@ AAC::~AAC() { } bool AAC::Parse(const std::vector& data) { - codec_specific_data_ = data; - if (data.empty()) return false; diff --git a/media/mp4/aac.h b/media/mp4/aac.h index af1b235a45..9d829274b5 100644 --- a/media/mp4/aac.h +++ b/media/mp4/aac.h @@ -30,7 +30,6 @@ class AAC { // The function will parse the data and get the ElementaryStreamDescriptor, // then it will parse the ElementaryStreamDescriptor to get audio stream // configurations. - // |data| is always copied to |codec_specific_data_|. bool Parse(const std::vector& data); // Gets the output sample rate for the AAC stream. @@ -61,11 +60,6 @@ class AAC { return num_channels_; } - // Returns the codec specific data. - std::vector codec_specific_data() const { - return codec_specific_data_; - } - // Size in bytes of the ADTS header added by ConvertEsdsToADTS(). static const size_t kADTSHeaderSize = 7; @@ -82,8 +76,6 @@ class AAC { // Is Parametric Stereo on? bool ps_present_; - std::vector codec_specific_data_; - // The following variables store audio configuration information. // They are based on the AAC specific configuration but can be overridden // by extensions in elementary stream descriptor. diff --git a/media/mp4/cenc.cc b/media/mp4/cenc.cc index 104948dd4f..cdb60d79e9 100644 --- a/media/mp4/cenc.cc +++ b/media/mp4/cenc.cc @@ -6,46 +6,82 @@ #include -#include "media/mp4/box_reader.h" +#include "media/base/buffer_reader.h" +#include "media/base/buffer_writer.h" #include "media/mp4/rcheck.h" +namespace { +// According to ISO/IEC FDIS 23001-7: CENC spec, IV should be either +// 64-bit (8-byte) or 128-bit (16-byte). +bool IsIvSizeValid(size_t iv_size) { return iv_size == 8 || iv_size == 16; } + +// 16-bit |clear_bytes| and 32-bit |cypher_bytes|. +const size_t kSubsampleEntrySize = sizeof(uint16) + sizeof(uint32); +} // namespace + namespace media { namespace mp4 { FrameCENCInfo::FrameCENCInfo() {} +FrameCENCInfo::FrameCENCInfo(const std::vector& iv) : iv_(iv) {} FrameCENCInfo::~FrameCENCInfo() {} -bool FrameCENCInfo::Parse(int iv_size, BufferReader* reader) { - const int kEntrySize = 6; - // Mandated by CENC spec - RCHECK(iv_size == 8 || iv_size == 16); +bool FrameCENCInfo::Parse(uint8 iv_size, BufferReader* reader) { + DCHECK(reader); + // Mandated by CENC spec. + RCHECK(IsIvSizeValid(iv_size)); - memset(iv, 0, sizeof(iv)); - for (int i = 0; i < iv_size; i++) - RCHECK(reader->Read1(&iv[i])); + iv_.resize(iv_size); + RCHECK(reader->ReadToVector(&iv_, iv_size)); - if (!reader->HasBytes(1)) return true; + if (!reader->HasBytes(1)) + return true; uint16 subsample_count; RCHECK(reader->Read2(&subsample_count) && - reader->HasBytes(subsample_count * kEntrySize)); + reader->HasBytes(subsample_count * kSubsampleEntrySize)); - subsamples.resize(subsample_count); - for (int i = 0; i < subsample_count; i++) { + subsamples_.resize(subsample_count); + for (uint16 i = 0; i < subsample_count; ++i) { uint16 clear_bytes; uint32 cypher_bytes; RCHECK(reader->Read2(&clear_bytes) && reader->Read4(&cypher_bytes)); - subsamples[i].clear_bytes = clear_bytes; - subsamples[i].cypher_bytes = cypher_bytes; + subsamples_[i].clear_bytes = clear_bytes; + subsamples_[i].cypher_bytes = cypher_bytes; } return true; } +void FrameCENCInfo::Write(BufferWriter* writer) const { + DCHECK(writer); + DCHECK(IsIvSizeValid(iv_.size())); + writer->AppendVector(iv_); + + uint16 subsample_count = subsamples_.size(); + if (subsample_count == 0) + return; + writer->AppendInt(subsample_count); + + for (uint16 i = 0; i < subsample_count; ++i) { + writer->AppendInt(subsamples_[i].clear_bytes); + writer->AppendInt(subsamples_[i].cypher_bytes); + } +} + +size_t FrameCENCInfo::ComputeSize() const { + uint16 subsample_count = subsamples_.size(); + if (subsample_count == 0) + return iv_.size(); + + return iv_.size() + sizeof(subsample_count) + + subsample_count * kSubsampleEntrySize; +} + size_t FrameCENCInfo::GetTotalSizeOfSubsamples() const { size_t size = 0; - for (size_t i = 0; i < subsamples.size(); i++) { - size += subsamples[i].clear_bytes + subsamples[i].cypher_bytes; + for (size_t i = 0; i < subsamples_.size(); ++i) { + size += subsamples_[i].clear_bytes + subsamples_[i].cypher_bytes; } return size; } diff --git a/media/mp4/cenc.h b/media/mp4/cenc.h index e558559a93..dd459c854a 100644 --- a/media/mp4/cenc.h +++ b/media/mp4/cenc.h @@ -11,20 +11,37 @@ #include "media/base/decrypt_config.h" namespace media { -namespace mp4 { class BufferReader; +class BufferWriter; -struct FrameCENCInfo { - uint8 iv[16]; - std::vector subsamples; +namespace mp4 { +class FrameCENCInfo { + public: FrameCENCInfo(); + explicit FrameCENCInfo(const std::vector& iv); ~FrameCENCInfo(); - bool Parse(int iv_size, BufferReader* r); - size_t GetTotalSizeOfSubsamples() const; -}; + bool Parse(uint8 iv_size, BufferReader* reader); + void Write(BufferWriter* writer) const; + size_t ComputeSize() const; + size_t GetTotalSizeOfSubsamples() const; + + void AddSubsample(const SubsampleEntry& subsample) { + subsamples_.push_back(subsample); + } + + const std::vector& iv() const { return iv_; } + const std::vector& subsamples() const { return subsamples_; } + + private: + std::vector iv_; + std::vector subsamples_; + + // Not using DISALLOW_COPY_AND_ASSIGN here intentionally to allow the compiler + // generated copy constructor and assignment operator. +}; } // namespace mp4 } // namespace media diff --git a/media/mp4/chunk_info_iterator_unittest.cc b/media/mp4/chunk_info_iterator_unittest.cc index d9432e46fc..b8e5d6b633 100644 --- a/media/mp4/chunk_info_iterator_unittest.cc +++ b/media/mp4/chunk_info_iterator_unittest.cc @@ -4,6 +4,7 @@ #include "media/mp4/chunk_info_iterator.h" +#include "base/logging.h" #include "base/memory/scoped_ptr.h" #include "testing/gtest/include/gtest/gtest.h" @@ -18,8 +19,8 @@ namespace media { namespace mp4 { const uint32 kNumChunks = 100; -const ChunkInfo kChunkInfos[] = - {{1, 8, 1}, {9, 5, 1}, {25, 7, 2}, {48, 63, 2}, {80, 2, 1}}; +const ChunkInfo kChunkInfos[] = { + {1, 8, 1}, {9, 5, 1}, {25, 7, 2}, {48, 63, 2}, {80, 2, 1}}; class ChunkInfoIteratorTest : public testing::Test { public: @@ -33,9 +34,8 @@ class ChunkInfoIteratorTest : public testing::Test { uint32 next_first_chunk = (i == length - 1) ? kNumChunks + 1 : kChunkInfos[i + 1].first_chunk; for (; chunk_index < next_first_chunk; ++chunk_index) { - ChunkProperty chunk = {kChunkInfos[i].samples_per_chunk, kChunkInfos[i].sample_description_index}; - //chunk.samples_per_chunk = kChunkInfos[i].samples_per_chunk; - //chunk.sample_description_index = kChunkInfos[i].sample_description_index; + ChunkProperty chunk = {kChunkInfos[i].samples_per_chunk, + kChunkInfos[i].sample_description_index}; chunk_info_table_.push_back(chunk); } } diff --git a/media/mp4/es_descriptor.cc b/media/mp4/es_descriptor.cc index 9c337b8a54..dbe00fcdcc 100644 --- a/media/mp4/es_descriptor.cc +++ b/media/mp4/es_descriptor.cc @@ -5,11 +5,36 @@ #include "media/mp4/es_descriptor.h" #include "media/base/bit_reader.h" +#include "media/base/buffer_writer.h" #include "media/mp4/rcheck.h" +namespace { + +// ISO/IEC 14496-1:2004 Section 7.2.6.6 Table 6: StreamType values. +enum StreamType { + kForbiddenStreamType = 0x00, + kObjectDescriptorStreamType = 0x01, + kClockReferenceStreamType = 0x02, + kSceneDescriptionStreamType = 0x03, + kVisualStreamType = 0x04, + kAudioStreamType = 0x05, + kMPEG7StreamType = 0x06, + kIPMPStreamType = 0x07, + kObjectContentInfoStreamType = 0x08, + kMPEGJStreamType = 0x09, + kInteractionStream = 0x0A, + kIPMPToolStreamType = 0x0B, +}; + +// ISO/IEC 14496-1:2004 Section 7.3.2.3 Table 12: ISO SL Config Descriptor. +enum SLPredefinedTags { + kSLPredefinedNull = 0x01, + kSLPredefinedMP4 = 0x02, +}; + // The elementary stream size is specific by up to 4 bytes. // The MSB of a byte indicates if there are more bytes for the size. -static bool ReadESSize(media::BitReader* reader, uint32* size) { +bool ReadESSize(media::BitReader* reader, uint32* size) { uint8 msb; uint8 byte; @@ -27,18 +52,18 @@ static bool ReadESSize(media::BitReader* reader, uint32* size) { return true; } +// Descryptor Header Size: 1 byte tag and 1 byte size (we don't support +// multi-bytes size for now). +const size_t kHeaderSize = 2; +const size_t kMaxDecoderSpecificInfoSize = 64; + +} // namespace + namespace media { namespace mp4 { -// static -bool ESDescriptor::IsAAC(ObjectType object_type) { - return object_type == kISO_14496_3 || object_type == kISO_13818_7_AAC_LC; -} - -ESDescriptor::ESDescriptor() - : object_type_(kForbidden) { -} +ESDescriptor::ESDescriptor() : esid_(0), object_type_(kForbidden) {} ESDescriptor::~ESDescriptor() {} @@ -55,7 +80,7 @@ bool ESDescriptor::Parse(const std::vector& data) { RCHECK(tag == kESDescrTag); RCHECK(ReadESSize(&reader, &size)); - RCHECK(reader.ReadBits(16, &dummy)); // ES_ID + RCHECK(reader.ReadBits(16, &esid_)); // ES_ID RCHECK(reader.ReadBits(1, &stream_dependency_flag)); RCHECK(reader.ReadBits(1, &url_flag)); RCHECK(!url_flag); // We don't support url flag @@ -72,14 +97,6 @@ bool ESDescriptor::Parse(const std::vector& data) { return true; } -ObjectType ESDescriptor::object_type() const { - return object_type_; -} - -const std::vector& ESDescriptor::decoder_specific_info() const { - return decoder_specific_info_; -} - bool ESDescriptor::ParseDecoderConfigDescriptor(BitReader* reader) { uint8 tag; uint32 size; @@ -98,6 +115,7 @@ bool ESDescriptor::ParseDecoderConfigDescriptor(BitReader* reader) { } bool ESDescriptor::ParseDecoderSpecificInfo(BitReader* reader) { + DCHECK(reader); uint8 tag; uint32 size; @@ -112,6 +130,65 @@ bool ESDescriptor::ParseDecoderSpecificInfo(BitReader* reader) { return true; } +void ESDescriptor::Write(BufferWriter* writer) const { + // TODO(kqyang): Consider writing Descriptor classes. + // ElementaryStreamDescriptor, DecoderConfigDescriptor, SLConfigDescriptor, + // DecoderSpecificInfoDescriptor. + DCHECK(writer); + CHECK_LT(decoder_specific_info_.size(), kMaxDecoderSpecificInfoSize); + + const std::vector kEmptyDecodingBufferSize(3, 0); + const uint32 kUnknownBitrate = 0; + const uint8 kNoEsFlags = 0; + + const uint8 decoder_specific_info_size = decoder_specific_info_.size(); + + // 6 bit stream type. The last bit is reserved with 1. + const uint8 stream_type = (kAudioStreamType << 2) | 1; + const uint8 decoder_config_size = decoder_specific_info_size + kHeaderSize + + sizeof(uint8) + // object_type_. + sizeof(stream_type) + + kEmptyDecodingBufferSize.size() + + sizeof(kUnknownBitrate) * 2; + + const uint8 sl_config_size = sizeof(uint8); // predefined. + const uint8 es_size = decoder_config_size + kHeaderSize + sl_config_size + + kHeaderSize + sizeof(esid_) + sizeof(kNoEsFlags); + + writer->AppendInt(static_cast(kESDescrTag)); + writer->AppendInt(es_size); + writer->AppendInt(esid_); + writer->AppendInt(kNoEsFlags); + + writer->AppendInt(static_cast(kDecoderConfigDescrTag)); + writer->AppendInt(decoder_config_size); + writer->AppendInt(static_cast(object_type_)); + writer->AppendInt(stream_type); + writer->AppendVector(kEmptyDecodingBufferSize); + writer->AppendInt(kUnknownBitrate); // max_bitrate. + writer->AppendInt(kUnknownBitrate); // avg_bitrate. + + writer->AppendInt(static_cast(kDecoderSpecificInfoTag)); + writer->AppendInt(decoder_specific_info_size); + writer->AppendVector(decoder_specific_info_); + + writer->AppendInt(static_cast(kSLConfigTag)); + writer->AppendInt(sl_config_size); + writer->AppendInt(static_cast(kSLPredefinedMP4)); +} + +size_t ESDescriptor::ComputeSize() const { + // A bit magical. Refer to ESDescriptor::Write for details. + const uint8 decoder_specific_info_size = decoder_specific_info_.size(); + const uint8 decoder_config_size = decoder_specific_info_size + kHeaderSize + + sizeof(uint8) * 5 + sizeof(uint32) * 2; + const uint8 sl_config_size = sizeof(uint8); + const uint8 es_size = decoder_config_size + kHeaderSize + + sl_config_size + kHeaderSize + + sizeof(esid_) + sizeof(uint8); + return es_size + kHeaderSize; +} + } // namespace mp4 } // namespace media diff --git a/media/mp4/es_descriptor.h b/media/mp4/es_descriptor.h index b6412c978a..d5d2ba1f42 100644 --- a/media/mp4/es_descriptor.h +++ b/media/mp4/es_descriptor.h @@ -12,6 +12,7 @@ namespace media { class BitReader; +class BufferWriter; namespace mp4 { @@ -19,9 +20,9 @@ namespace mp4 { // objectTypeIndication Values. Only values currently in use are included. enum ObjectType { kForbidden = 0, - kISO_14496_3 = 0x40, // MPEG4 AAC + kISO_14496_3 = 0x40, // MPEG4 AAC kISO_13818_7_AAC_LC = 0x67, // MPEG2 AAC-LC - kEAC3 = 0xa6 // Dolby Digital Plus + kEAC3 = 0xa6 // Dolby Digital Plus }; // This class parse object type and decoder specific information from an @@ -29,27 +30,44 @@ enum ObjectType { // Please refer to ISO 14496 Part 1 7.2.6.5 for more details. class ESDescriptor { public: - // Utility function to check if the given object type is AAC. - static bool IsAAC(ObjectType object_type); - ESDescriptor(); ~ESDescriptor(); bool Parse(const std::vector& data); + void Write(BufferWriter* writer) const; + size_t ComputeSize() const; - ObjectType object_type() const; - const std::vector& decoder_specific_info() const; + uint16 esid() const { return esid_; } + void set_esid(uint16 esid) { esid_ = esid; } + + ObjectType object_type() const { return object_type_; } + void set_object_type(ObjectType object_type) { object_type_ = object_type; } + + const std::vector& decoder_specific_info() const { + return decoder_specific_info_; + } + void set_decoder_specific_info( + const std::vector& decoder_specific_info) { + decoder_specific_info_ = decoder_specific_info; + } + + // Check if the stream is AAC. + bool IsAAC() const { + return object_type_ == kISO_14496_3 || object_type_ == kISO_13818_7_AAC_LC; + } private: enum Tag { kESDescrTag = 0x03, kDecoderConfigDescrTag = 0x04, - kDecoderSpecificInfoTag = 0x05 + kDecoderSpecificInfoTag = 0x05, + kSLConfigTag = 0x06, }; bool ParseDecoderConfigDescriptor(BitReader* reader); bool ParseDecoderSpecificInfo(BitReader* reader); + uint16 esid_; // Elementary Stream ID. ObjectType object_type_; std::vector decoder_specific_info_; }; diff --git a/media/mp4/rcheck.h b/media/mp4/rcheck.h index 8165056067..b401bf1fcd 100644 --- a/media/mp4/rcheck.h +++ b/media/mp4/rcheck.h @@ -7,12 +7,12 @@ #include "base/logging.h" -#define RCHECK(x) \ - do { \ - if (!(x)) { \ - DLOG(ERROR) << "Failure while parsing MP4: " << #x; \ - return false; \ - } \ - } while (0) +#define RCHECK(x) \ + do { \ + if (!(x)) { \ + LOG(ERROR) << "Failure while processing MP4: " << #x; \ + return false; \ + } \ + } while (0) #endif // MEDIA_MP4_RCHECK_H_ diff --git a/media/mp4/track_run_iterator.cc b/media/mp4/track_run_iterator.cc index 835cb063e8..427a652a32 100644 --- a/media/mp4/track_run_iterator.cc +++ b/media/mp4/track_run_iterator.cc @@ -6,6 +6,7 @@ #include +#include "media/base/buffer_reader.h" #include "media/mp4/chunk_info_iterator.h" #include "media/mp4/composition_offset_iterator.h" #include "media/mp4/decoding_time_iterator.h" @@ -90,12 +91,12 @@ static void PopulateSampleInfo(const TrackExtends& trex, uint32 flags; if (i < trun.sample_flags.size()) { flags = trun.sample_flags[i]; - } else if (tfhd.flags & kDefaultSampleFlagsPresentMask) { + } else if (tfhd.flags & TrackFragmentHeader::kDefaultSampleFlagsPresentMask) { flags = tfhd.default_sample_flags; } else { flags = trex.default_sample_flags; } - sample_info->is_keyframe = !(flags & kNonKeySampleMask); + sample_info->is_keyframe = !(flags & TrackFragmentHeader::kNonKeySampleMask); } // In well-structured encrypted media, each track run will be immediately @@ -396,6 +397,7 @@ bool TrackRunIterator::AuxInfoNeedsToBeCached() { return is_encrypted() && aux_info_size() > 0 && cenc_info_.size() == 0; } +// TODO(kqyang): Revisit later. We might not need to cache cenc info. // This implementation currently only caches CENC auxiliary info. bool TrackRunIterator::CacheAuxInfo(const uint8* buf, int buf_size) { RCHECK(AuxInfoNeedsToBeCached() && buf_size >= aux_info_size()); @@ -525,8 +527,9 @@ scoped_ptr TrackRunIterator::GetDecryptConfig() { const FrameCENCInfo& cenc_info = cenc_info_[sample_idx]; DCHECK(is_encrypted() && !AuxInfoNeedsToBeCached()); - if (!cenc_info.subsamples.empty() && (cenc_info.GetTotalSizeOfSubsamples() != - static_cast(sample_size()))) { + const size_t total_size_of_subsamples = cenc_info.GetTotalSizeOfSubsamples(); + if (total_size_of_subsamples != 0 && + total_size_of_subsamples != static_cast(sample_size())) { LOG(ERROR) << "Incorrect CENC subsample size."; return scoped_ptr(); } @@ -534,9 +537,9 @@ scoped_ptr TrackRunIterator::GetDecryptConfig() { const std::vector& kid = track_encryption().default_kid; return scoped_ptr(new DecryptConfig( std::string(reinterpret_cast(&kid[0]), kid.size()), - std::string(cenc_info.iv.begin(), cenc_info.iv.end()), + std::string(cenc_info.iv().begin(), cenc_info.iv().end()), 0, // No offset to start of media data in MP4 using CENC. - cenc_info.subsamples)); + cenc_info.subsamples())); } } // namespace mp4 diff --git a/media/mp4/track_run_iterator_unittest.cc b/media/mp4/track_run_iterator_unittest.cc index b1b6e3bc63..8902778896 100644 --- a/media/mp4/track_run_iterator_unittest.cc +++ b/media/mp4/track_run_iterator_unittest.cc @@ -82,7 +82,8 @@ class TrackRunIteratorTest : public testing::Test { moof.tracks.resize(2); moof.tracks[0].decode_time.decode_time = 0; moof.tracks[0].header.track_id = 1; - moof.tracks[0].header.flags = kDefaultSampleFlagsPresentMask; + moof.tracks[0].header.flags = + TrackFragmentHeader::kDefaultSampleFlagsPresentMask; moof.tracks[0].header.default_sample_duration = 1024; moof.tracks[0].header.default_sample_size = 4; moof.tracks[0].runs.resize(2); @@ -103,7 +104,8 @@ class TrackRunIteratorTest : public testing::Test { SetAscending(&moof.tracks[1].runs[0].sample_durations); moof.tracks[1].runs[0].sample_flags.resize(10); for (size_t i = 1; i < moof.tracks[1].runs[0].sample_flags.size(); i++) { - moof.tracks[1].runs[0].sample_flags[i] = kNonKeySampleMask; + moof.tracks[1].runs[0].sample_flags[i] = + TrackFragmentHeader::kNonKeySampleMask; } return moof; @@ -211,7 +213,8 @@ TEST_F(TrackRunIteratorTest, BasicOperationTest) { TEST_F(TrackRunIteratorTest, TrackExtendsDefaultsTest) { moov_.extends.tracks[0].default_sample_duration = 50; moov_.extends.tracks[0].default_sample_size = 3; - moov_.extends.tracks[0].default_sample_flags = kNonKeySampleMask; + moov_.extends.tracks[0].default_sample_flags = + TrackFragmentHeader::kNonKeySampleMask; iter_.reset(new TrackRunIterator(&moov_)); MovieFragment moof = CreateFragment(); moof.tracks[0].header.flags = 0; @@ -233,8 +236,10 @@ TEST_F(TrackRunIteratorTest, FirstSampleFlagTest) { // defaults for all subsequent samples iter_.reset(new TrackRunIterator(&moov_)); MovieFragment moof = CreateFragment(); - moof.tracks[1].header.flags = kDefaultSampleFlagsPresentMask; - moof.tracks[1].header.default_sample_flags = kNonKeySampleMask; + moof.tracks[1].header.flags = + TrackFragmentHeader::kDefaultSampleFlagsPresentMask; + moof.tracks[1].header.default_sample_flags = + TrackFragmentHeader::kNonKeySampleMask; moof.tracks[1].runs[0].sample_flags.resize(1); ASSERT_TRUE(iter_->Init(moof)); iter_->AdvanceRun();