1 // Copyright 2014 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.
5 #include "base/basictypes.h"
6 #include "base/logging.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "media/formats/mp4/box_definitions.h"
9 #include "media/formats/mp4/rcheck.h"
10 #include "media/formats/mp4/track_run_iterator.h"
11 #include "testing/gtest/include/gtest/gtest.h"
13 // The sum of the elements in a vector initialized with SumAscending,
14 // less the value of the last element.
15 static const int kSumAscending1 = 45;
17 static const int kAudioScale = 48000;
18 static const int kVideoScale = 25;
20 static const uint32 kSampleIsDifferenceSampleFlagMask = 0x10000;
22 static const uint8 kAuxInfo[] = {
23 0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31,
24 0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x32,
26 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
27 0x00, 0x03, 0x00, 0x00, 0x00, 0x04
30 static const char kIv1[] = {
31 0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31,
32 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
35 static const uint8 kKeyId[] = {
36 0x41, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x54,
37 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x44
40 static const uint8 kCencSampleGroupKeyId[] = {
41 0x46, 0x72, 0x61, 0x67, 0x53, 0x61, 0x6d, 0x70,
42 0x6c, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4b
48 class TrackRunIteratorTest : public testing::Test {
50 TrackRunIteratorTest() {
57 scoped_ptr<TrackRunIterator> iter_;
60 moov_.header.timescale = 1000;
61 moov_.tracks.resize(3);
62 moov_.extends.tracks.resize(2);
63 moov_.tracks[0].header.track_id = 1;
64 moov_.tracks[0].media.header.timescale = kAudioScale;
65 SampleDescription& desc1 =
66 moov_.tracks[0].media.information.sample_table.description;
67 AudioSampleEntry aud_desc;
68 aud_desc.format = FOURCC_MP4A;
69 aud_desc.sinf.info.track_encryption.is_encrypted = false;
71 desc1.audio_entries.push_back(aud_desc);
72 moov_.extends.tracks[0].track_id = 1;
73 moov_.extends.tracks[0].default_sample_description_index = 1;
74 moov_.tracks[0].media.information.sample_table.sync_sample.is_present =
76 moov_.tracks[1].header.track_id = 2;
77 moov_.tracks[1].media.header.timescale = kVideoScale;
78 SampleDescription& desc2 =
79 moov_.tracks[1].media.information.sample_table.description;
80 VideoSampleEntry vid_desc;
81 vid_desc.format = FOURCC_AVC1;
82 vid_desc.sinf.info.track_encryption.is_encrypted = false;
84 desc2.video_entries.push_back(vid_desc);
85 moov_.extends.tracks[1].track_id = 2;
86 moov_.extends.tracks[1].default_sample_description_index = 1;
87 moov_.tracks[1].media.information.sample_table.sync_sample.is_present =
90 moov_.tracks[2].header.track_id = 3;
91 moov_.tracks[2].media.information.sample_table.description.type = kHint;
94 MovieFragment CreateFragment() {
96 moof.tracks.resize(2);
97 moof.tracks[0].decode_time.decode_time = 0;
98 moof.tracks[0].header.track_id = 1;
99 moof.tracks[0].header.has_default_sample_flags = true;
100 moof.tracks[0].header.default_sample_duration = 1024;
101 moof.tracks[0].header.default_sample_size = 4;
102 moof.tracks[0].runs.resize(2);
103 moof.tracks[0].runs[0].sample_count = 10;
104 moof.tracks[0].runs[0].data_offset = 100;
105 SetAscending(&moof.tracks[0].runs[0].sample_sizes);
107 moof.tracks[0].runs[1].sample_count = 10;
108 moof.tracks[0].runs[1].data_offset = 10000;
110 moof.tracks[1].header.track_id = 2;
111 moof.tracks[1].header.has_default_sample_flags = false;
112 moof.tracks[1].decode_time.decode_time = 10;
113 moof.tracks[1].runs.resize(1);
114 moof.tracks[1].runs[0].sample_count = 10;
115 moof.tracks[1].runs[0].data_offset = 200;
116 SetAscending(&moof.tracks[1].runs[0].sample_sizes);
117 SetAscending(&moof.tracks[1].runs[0].sample_durations);
118 moof.tracks[1].runs[0].sample_flags.resize(10);
119 for (size_t i = 1; i < moof.tracks[1].runs[0].sample_flags.size(); i++) {
120 moof.tracks[1].runs[0].sample_flags[i] =
121 kSampleIsDifferenceSampleFlagMask;
127 // Update the first sample description of a Track to indicate encryption
128 void AddEncryption(Track* track) {
129 SampleDescription* stsd =
130 &track->media.information.sample_table.description;
131 ProtectionSchemeInfo* sinf;
132 if (!stsd->video_entries.empty()) {
133 sinf = &stsd->video_entries[0].sinf;
135 sinf = &stsd->audio_entries[0].sinf;
138 sinf->type.type = FOURCC_CENC;
139 sinf->info.track_encryption.is_encrypted = true;
140 sinf->info.track_encryption.default_iv_size = 8;
141 sinf->info.track_encryption.default_kid.assign(kKeyId,
142 kKeyId + arraysize(kKeyId));
145 // Add SampleGroupDescription Box with two entries (an unencrypted entry and
146 // an encrypted entry). Populate SampleToGroup Box from input array.
147 void AddCencSampleGroup(TrackFragment* frag,
148 const SampleToGroupEntry* sample_to_group_entries,
149 size_t num_entries) {
150 frag->sample_group_description.grouping_type = FOURCC_SEIG;
151 frag->sample_group_description.entries.resize(2);
152 frag->sample_group_description.entries[0].is_encrypted = false;
153 frag->sample_group_description.entries[0].iv_size = 0;
154 frag->sample_group_description.entries[1].is_encrypted = true;
155 frag->sample_group_description.entries[1].iv_size = 8;
156 frag->sample_group_description.entries[1].key_id.assign(
157 kCencSampleGroupKeyId,
158 kCencSampleGroupKeyId + arraysize(kCencSampleGroupKeyId));
160 frag->sample_to_group.grouping_type = FOURCC_SEIG;
161 frag->sample_to_group.entries.assign(sample_to_group_entries,
162 sample_to_group_entries + num_entries);
165 // Add aux info covering the first track run to a TrackFragment, and update
166 // the run to ensure it matches length and subsample information.
167 void AddAuxInfoHeaders(int offset, TrackFragment* frag) {
168 frag->auxiliary_offset.offsets.push_back(offset);
169 frag->auxiliary_size.sample_count = 2;
170 frag->auxiliary_size.sample_info_sizes.push_back(8);
171 frag->auxiliary_size.sample_info_sizes.push_back(22);
172 frag->runs[0].sample_count = 2;
173 frag->runs[0].sample_sizes[1] = 10;
176 bool InitMoofWithArbitraryAuxInfo(MovieFragment* moof) {
177 // Add aux info header (equal sized aux info for every sample).
178 for (uint32 i = 0; i < moof->tracks.size(); ++i) {
179 moof->tracks[i].auxiliary_offset.offsets.push_back(50);
180 moof->tracks[i].auxiliary_size.sample_count = 10;
181 moof->tracks[i].auxiliary_size.default_sample_info_size = 8;
184 // We don't care about the actual data in aux.
185 std::vector<uint8> aux_info(1000);
186 return iter_->Init(*moof) &&
187 iter_->CacheAuxInfo(&aux_info[0], aux_info.size());
190 void SetAscending(std::vector<uint32>* vec) {
192 for (size_t i = 0; i < vec->size(); i++)
197 TEST_F(TrackRunIteratorTest, NoRunsTest) {
198 iter_.reset(new TrackRunIterator(&moov_, log_cb_));
199 ASSERT_TRUE(iter_->Init(MovieFragment()));
200 EXPECT_FALSE(iter_->IsRunValid());
201 EXPECT_FALSE(iter_->IsSampleValid());
204 TEST_F(TrackRunIteratorTest, BasicOperationTest) {
205 iter_.reset(new TrackRunIterator(&moov_, log_cb_));
206 MovieFragment moof = CreateFragment();
208 // Test that runs are sorted correctly, and that properties of the initial
209 // sample of the first run are correct
210 ASSERT_TRUE(iter_->Init(moof));
211 EXPECT_TRUE(iter_->IsRunValid());
212 EXPECT_FALSE(iter_->is_encrypted());
213 EXPECT_EQ(iter_->track_id(), 1u);
214 EXPECT_EQ(iter_->sample_offset(), 100);
215 EXPECT_EQ(iter_->sample_size(), 1);
216 EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(0, kAudioScale));
217 EXPECT_EQ(iter_->cts(), TimeDeltaFromRational(0, kAudioScale));
218 EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(1024, kAudioScale));
219 EXPECT_TRUE(iter_->is_keyframe());
221 // Advance to the last sample in the current run, and test its properties
222 for (int i = 0; i < 9; i++) iter_->AdvanceSample();
223 EXPECT_EQ(iter_->track_id(), 1u);
224 EXPECT_EQ(iter_->sample_offset(), 100 + kSumAscending1);
225 EXPECT_EQ(iter_->sample_size(), 10);
226 EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(1024 * 9, kAudioScale));
227 EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(1024, kAudioScale));
228 EXPECT_TRUE(iter_->is_keyframe());
231 iter_->AdvanceSample();
232 EXPECT_FALSE(iter_->IsSampleValid());
234 // Test last sample of next run
236 EXPECT_TRUE(iter_->is_keyframe());
237 for (int i = 0; i < 9; i++) iter_->AdvanceSample();
238 EXPECT_EQ(iter_->track_id(), 2u);
239 EXPECT_EQ(iter_->sample_offset(), 200 + kSumAscending1);
240 EXPECT_EQ(iter_->sample_size(), 10);
241 int64 base_dts = kSumAscending1 + moof.tracks[1].decode_time.decode_time;
242 EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(base_dts, kVideoScale));
243 EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(10, kVideoScale));
244 EXPECT_FALSE(iter_->is_keyframe());
248 EXPECT_EQ(iter_->track_id(), 1u);
249 EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(1024 * 10, kAudioScale));
250 iter_->AdvanceSample();
251 EXPECT_EQ(moof.tracks[0].runs[1].data_offset +
252 moof.tracks[0].header.default_sample_size,
253 iter_->sample_offset());
255 EXPECT_FALSE(iter_->IsRunValid());
258 TEST_F(TrackRunIteratorTest, TrackExtendsDefaultsTest) {
259 moov_.extends.tracks[0].default_sample_duration = 50;
260 moov_.extends.tracks[0].default_sample_size = 3;
261 moov_.extends.tracks[0].default_sample_flags =
262 kSampleIsDifferenceSampleFlagMask;
263 iter_.reset(new TrackRunIterator(&moov_, log_cb_));
264 MovieFragment moof = CreateFragment();
265 moof.tracks[0].header.has_default_sample_flags = false;
266 moof.tracks[0].header.default_sample_size = 0;
267 moof.tracks[0].header.default_sample_duration = 0;
268 moof.tracks[0].runs[0].sample_sizes.clear();
269 ASSERT_TRUE(iter_->Init(moof));
270 iter_->AdvanceSample();
271 EXPECT_FALSE(iter_->is_keyframe());
272 EXPECT_EQ(iter_->sample_size(), 3);
273 EXPECT_EQ(iter_->sample_offset(), moof.tracks[0].runs[0].data_offset + 3);
274 EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(50, kAudioScale));
275 EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(50, kAudioScale));
278 TEST_F(TrackRunIteratorTest, FirstSampleFlagTest) {
279 // Ensure that keyframes are flagged correctly in the face of BMFF boxes which
280 // explicitly specify the flags for the first sample in a run and rely on
281 // defaults for all subsequent samples
282 iter_.reset(new TrackRunIterator(&moov_, log_cb_));
283 MovieFragment moof = CreateFragment();
284 moof.tracks[1].header.has_default_sample_flags = true;
285 moof.tracks[1].header.default_sample_flags =
286 kSampleIsDifferenceSampleFlagMask;
287 moof.tracks[1].runs[0].sample_flags.resize(1);
288 ASSERT_TRUE(iter_->Init(moof));
290 EXPECT_TRUE(iter_->is_keyframe());
291 iter_->AdvanceSample();
292 EXPECT_FALSE(iter_->is_keyframe());
295 TEST_F(TrackRunIteratorTest, ReorderingTest) {
296 // Test frame reordering and edit list support. The frames have the following
297 // decode timestamps:
299 // 0ms 40ms 120ms 240ms
300 // | 0 | 1 - | 2 - - |
302 // ...and these composition timestamps, after edit list adjustment:
304 // 0ms 40ms 160ms 240ms
305 // | 0 | 2 - - | 1 - |
307 // Create an edit list with one entry, with an initial start time of 80ms
308 // (that is, 2 / kVideoTimescale) and a duration of zero (which is treated as
309 // infinite according to 14496-12:2012). This will cause the first 80ms of the
310 // media timeline - which will be empty, due to CTS biasing - to be discarded.
311 iter_.reset(new TrackRunIterator(&moov_, log_cb_));
313 entry.segment_duration = 0;
314 entry.media_time = 2;
315 entry.media_rate_integer = 1;
316 entry.media_rate_fraction = 0;
317 moov_.tracks[1].edit.list.edits.push_back(entry);
319 // Add CTS offsets. Without bias, the CTS offsets for the first three frames
320 // would simply be [0, 3, -2]. Since CTS offsets should be non-negative for
321 // maximum compatibility, these values are biased up to [2, 5, 0], and the
322 // extra 80ms is removed via the edit list.
323 MovieFragment moof = CreateFragment();
324 std::vector<int32>& cts_offsets =
325 moof.tracks[1].runs[0].sample_composition_time_offsets;
326 cts_offsets.resize(10);
330 moof.tracks[1].decode_time.decode_time = 0;
332 ASSERT_TRUE(iter_->Init(moof));
334 EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(0, kVideoScale));
335 EXPECT_EQ(iter_->cts(), TimeDeltaFromRational(0, kVideoScale));
336 EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(1, kVideoScale));
337 iter_->AdvanceSample();
338 EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(1, kVideoScale));
339 EXPECT_EQ(iter_->cts(), TimeDeltaFromRational(4, kVideoScale));
340 EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(2, kVideoScale));
341 iter_->AdvanceSample();
342 EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(3, kVideoScale));
343 EXPECT_EQ(iter_->cts(), TimeDeltaFromRational(1, kVideoScale));
344 EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(3, kVideoScale));
347 TEST_F(TrackRunIteratorTest, IgnoreUnknownAuxInfoTest) {
348 iter_.reset(new TrackRunIterator(&moov_, log_cb_));
349 MovieFragment moof = CreateFragment();
350 moof.tracks[1].auxiliary_offset.offsets.push_back(50);
351 moof.tracks[1].auxiliary_size.default_sample_info_size = 2;
352 moof.tracks[1].auxiliary_size.sample_count = 2;
353 moof.tracks[1].runs[0].sample_count = 2;
354 ASSERT_TRUE(iter_->Init(moof));
356 EXPECT_FALSE(iter_->AuxInfoNeedsToBeCached());
359 TEST_F(TrackRunIteratorTest, DecryptConfigTest) {
360 AddEncryption(&moov_.tracks[1]);
361 iter_.reset(new TrackRunIterator(&moov_, log_cb_));
363 MovieFragment moof = CreateFragment();
364 AddAuxInfoHeaders(50, &moof.tracks[1]);
366 ASSERT_TRUE(iter_->Init(moof));
368 // The run for track 2 will be first, since its aux info offset is the first
369 // element in the file.
370 EXPECT_EQ(iter_->track_id(), 2u);
371 EXPECT_TRUE(iter_->is_encrypted());
372 EXPECT_TRUE(iter_->AuxInfoNeedsToBeCached());
373 EXPECT_EQ(static_cast<uint32>(iter_->aux_info_size()), arraysize(kAuxInfo));
374 EXPECT_EQ(iter_->aux_info_offset(), 50);
375 EXPECT_EQ(iter_->GetMaxClearOffset(), 50);
376 EXPECT_FALSE(iter_->CacheAuxInfo(NULL, 0));
377 EXPECT_FALSE(iter_->CacheAuxInfo(kAuxInfo, 3));
378 EXPECT_TRUE(iter_->AuxInfoNeedsToBeCached());
379 EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
380 EXPECT_FALSE(iter_->AuxInfoNeedsToBeCached());
381 EXPECT_EQ(iter_->sample_offset(), 200);
382 EXPECT_EQ(iter_->GetMaxClearOffset(), moof.tracks[0].runs[0].data_offset);
383 scoped_ptr<DecryptConfig> config = iter_->GetDecryptConfig();
384 ASSERT_EQ(arraysize(kKeyId), config->key_id().size());
385 EXPECT_TRUE(!memcmp(kKeyId, config->key_id().data(),
386 config->key_id().size()));
387 ASSERT_EQ(arraysize(kIv1), config->iv().size());
388 EXPECT_TRUE(!memcmp(kIv1, config->iv().data(), config->iv().size()));
389 EXPECT_TRUE(config->subsamples().empty());
390 iter_->AdvanceSample();
391 config = iter_->GetDecryptConfig();
392 EXPECT_EQ(config->subsamples().size(), 2u);
393 EXPECT_EQ(config->subsamples()[0].clear_bytes, 1u);
394 EXPECT_EQ(config->subsamples()[1].cypher_bytes, 4u);
397 TEST_F(TrackRunIteratorTest, CencSampleGroupTest) {
398 MovieFragment moof = CreateFragment();
400 const SampleToGroupEntry kSampleToGroupTable[] = {
401 // Associated with the second entry in SampleGroupDescription Box.
402 {1, SampleToGroupEntry::kFragmentGroupDescriptionIndexBase + 2},
403 // Associated with the first entry in SampleGroupDescription Box.
404 {1, SampleToGroupEntry::kFragmentGroupDescriptionIndexBase + 1}};
406 &moof.tracks[0], kSampleToGroupTable, arraysize(kSampleToGroupTable));
408 iter_.reset(new TrackRunIterator(&moov_, log_cb_));
409 ASSERT_TRUE(InitMoofWithArbitraryAuxInfo(&moof));
411 std::string cenc_sample_group_key_id(
412 kCencSampleGroupKeyId,
413 kCencSampleGroupKeyId + arraysize(kCencSampleGroupKeyId));
414 // The first sample is encrypted and the second sample is unencrypted.
415 EXPECT_TRUE(iter_->is_encrypted());
416 EXPECT_EQ(cenc_sample_group_key_id, iter_->GetDecryptConfig()->key_id());
417 iter_->AdvanceSample();
418 EXPECT_FALSE(iter_->is_encrypted());
421 TEST_F(TrackRunIteratorTest, CencSampleGroupWithTrackEncryptionBoxTest) {
422 // Add TrackEncryption Box.
423 AddEncryption(&moov_.tracks[0]);
425 MovieFragment moof = CreateFragment();
427 const SampleToGroupEntry kSampleToGroupTable[] = {
428 // Associated with the second entry in SampleGroupDescription Box.
429 {2, SampleToGroupEntry::kFragmentGroupDescriptionIndexBase + 2},
430 // Associated with the default values specified in TrackEncryption Box.
432 // Associated with the first entry in SampleGroupDescription Box.
433 {3, SampleToGroupEntry::kFragmentGroupDescriptionIndexBase + 1}};
435 &moof.tracks[0], kSampleToGroupTable, arraysize(kSampleToGroupTable));
437 iter_.reset(new TrackRunIterator(&moov_, log_cb_));
438 ASSERT_TRUE(InitMoofWithArbitraryAuxInfo(&moof));
440 std::string track_encryption_key_id(kKeyId, kKeyId + arraysize(kKeyId));
441 std::string cenc_sample_group_key_id(
442 kCencSampleGroupKeyId,
443 kCencSampleGroupKeyId + arraysize(kCencSampleGroupKeyId));
445 for (size_t i = 0; i < kSampleToGroupTable[0].sample_count; ++i) {
446 EXPECT_TRUE(iter_->is_encrypted());
447 EXPECT_EQ(cenc_sample_group_key_id, iter_->GetDecryptConfig()->key_id());
448 iter_->AdvanceSample();
451 for (size_t i = 0; i < kSampleToGroupTable[1].sample_count; ++i) {
452 EXPECT_TRUE(iter_->is_encrypted());
453 EXPECT_EQ(track_encryption_key_id, iter_->GetDecryptConfig()->key_id());
454 iter_->AdvanceSample();
457 for (size_t i = 0; i < kSampleToGroupTable[2].sample_count; ++i) {
458 EXPECT_FALSE(iter_->is_encrypted());
459 iter_->AdvanceSample();
462 // The remaining samples should be associated with the default values
463 // specified in TrackEncryption Box.
464 EXPECT_TRUE(iter_->is_encrypted());
465 EXPECT_EQ(track_encryption_key_id, iter_->GetDecryptConfig()->key_id());
468 // It is legal for aux info blocks to be shared among multiple formats.
469 TEST_F(TrackRunIteratorTest, SharedAuxInfoTest) {
470 AddEncryption(&moov_.tracks[0]);
471 AddEncryption(&moov_.tracks[1]);
472 iter_.reset(new TrackRunIterator(&moov_, log_cb_));
474 MovieFragment moof = CreateFragment();
475 moof.tracks[0].runs.resize(1);
476 AddAuxInfoHeaders(50, &moof.tracks[0]);
477 AddAuxInfoHeaders(50, &moof.tracks[1]);
478 moof.tracks[0].auxiliary_size.default_sample_info_size = 8;
480 ASSERT_TRUE(iter_->Init(moof));
481 EXPECT_EQ(iter_->track_id(), 1u);
482 EXPECT_EQ(iter_->aux_info_offset(), 50);
483 EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
484 scoped_ptr<DecryptConfig> config = iter_->GetDecryptConfig();
485 ASSERT_EQ(arraysize(kIv1), config->iv().size());
486 EXPECT_TRUE(!memcmp(kIv1, config->iv().data(), config->iv().size()));
487 iter_->AdvanceSample();
488 EXPECT_EQ(iter_->GetMaxClearOffset(), 50);
490 EXPECT_EQ(iter_->GetMaxClearOffset(), 50);
491 EXPECT_EQ(iter_->aux_info_offset(), 50);
492 EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
493 EXPECT_EQ(iter_->GetMaxClearOffset(), 200);
494 ASSERT_EQ(arraysize(kIv1), config->iv().size());
495 EXPECT_TRUE(!memcmp(kIv1, config->iv().data(), config->iv().size()));
496 iter_->AdvanceSample();
497 EXPECT_EQ(iter_->GetMaxClearOffset(), 201);
500 // Sensible files are expected to place auxiliary information for a run
501 // immediately before the main data for that run. Alternative schemes are
502 // possible, however, including the somewhat reasonable behavior of placing all
503 // aux info at the head of the 'mdat' box together, and the completely
504 // unreasonable behavior demonstrated here:
505 // byte 50: track 2, run 1 aux info
506 // byte 100: track 1, run 1 data
507 // byte 200: track 2, run 1 data
508 // byte 201: track 1, run 2 aux info (*inside* track 2, run 1 data)
509 // byte 10000: track 1, run 2 data
510 // byte 20000: track 1, run 1 aux info
511 TEST_F(TrackRunIteratorTest, UnexpectedOrderingTest) {
512 AddEncryption(&moov_.tracks[0]);
513 AddEncryption(&moov_.tracks[1]);
514 iter_.reset(new TrackRunIterator(&moov_, log_cb_));
516 MovieFragment moof = CreateFragment();
517 AddAuxInfoHeaders(20000, &moof.tracks[0]);
518 moof.tracks[0].auxiliary_offset.offsets.push_back(201);
519 moof.tracks[0].auxiliary_size.sample_count += 2;
520 moof.tracks[0].auxiliary_size.default_sample_info_size = 8;
521 moof.tracks[0].runs[1].sample_count = 2;
522 AddAuxInfoHeaders(50, &moof.tracks[1]);
523 moof.tracks[1].runs[0].sample_sizes[0] = 5;
525 ASSERT_TRUE(iter_->Init(moof));
526 EXPECT_EQ(iter_->track_id(), 2u);
527 EXPECT_EQ(iter_->aux_info_offset(), 50);
528 EXPECT_EQ(iter_->sample_offset(), 200);
529 EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
530 EXPECT_EQ(iter_->GetMaxClearOffset(), 100);
532 EXPECT_EQ(iter_->track_id(), 1u);
533 EXPECT_EQ(iter_->aux_info_offset(), 20000);
534 EXPECT_EQ(iter_->sample_offset(), 100);
535 EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
536 EXPECT_EQ(iter_->GetMaxClearOffset(), 100);
537 iter_->AdvanceSample();
538 EXPECT_EQ(iter_->GetMaxClearOffset(), 101);
540 EXPECT_EQ(iter_->track_id(), 1u);
541 EXPECT_EQ(iter_->aux_info_offset(), 201);
542 EXPECT_EQ(iter_->sample_offset(), 10000);
543 EXPECT_EQ(iter_->GetMaxClearOffset(), 201);
544 EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
545 EXPECT_EQ(iter_->GetMaxClearOffset(), 10000);
548 TEST_F(TrackRunIteratorTest, MissingStssMakesAllSamplesKeyframes) {
549 iter_.reset(new TrackRunIterator(&moov_, log_cb_));
550 MovieFragment moof = CreateFragment();
552 // Test that runs are sorted correctly, and that properties of the initial
553 // sample of the first run are correct
554 ASSERT_TRUE(iter_->Init(moof));
555 EXPECT_TRUE(iter_->IsRunValid());
557 // Count the number of non-keyframes for each run with the default
560 EXPECT_TRUE(moov_.tracks[0].media.information.sample_table.sync_sample.
562 EXPECT_TRUE(moov_.tracks[1].media.information.sample_table.sync_sample.
565 int first_run_non_keyframe_count = 0;
566 int second_run_non_keyframe_count = 0;
568 EXPECT_TRUE(iter_->IsRunValid());
569 while (iter_->IsSampleValid()) {
570 EXPECT_EQ(iter_->track_id(), 1u);
572 if (!iter_->is_keyframe())
573 first_run_non_keyframe_count++;
575 iter_->AdvanceSample();
580 EXPECT_TRUE(iter_->IsRunValid());
581 while (iter_->IsSampleValid()) {
582 EXPECT_EQ(iter_->track_id(), 2u);
584 if (!iter_->is_keyframe())
585 second_run_non_keyframe_count++;
587 iter_->AdvanceSample();
590 EXPECT_EQ(0, first_run_non_keyframe_count);
591 EXPECT_EQ(9, second_run_non_keyframe_count);
593 // Update sync_sample info to reflect that the box is not present on
595 moov_.tracks[0].media.information.sample_table.sync_sample.is_present =
597 moov_.tracks[1].media.information.sample_table.sync_sample.is_present =
600 // Reinitialize the iterator and verify that all samples are keyframes
601 // on both tracks now.
603 ASSERT_TRUE(iter_->Init(moof));
604 EXPECT_TRUE(iter_->IsRunValid());
605 while (iter_->IsSampleValid()) {
606 EXPECT_EQ(iter_->track_id(), 1u);
607 EXPECT_TRUE(iter_->is_keyframe());
608 iter_->AdvanceSample();
612 EXPECT_TRUE(iter_->IsRunValid());
614 while (iter_->IsSampleValid()) {
615 EXPECT_EQ(iter_->track_id(), 2u);
616 EXPECT_TRUE(iter_->is_keyframe());
617 iter_->AdvanceSample();