2ef3f8360723cd4e99e9dbc825b686bd6b29c038
[platform/framework/web/crosswalk.git] / src / media / formats / mp4 / track_run_iterator_unittest.cc
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.
4
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"
12
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;
16
17 static const int kAudioScale = 48000;
18 static const int kVideoScale = 25;
19
20 static const uint32 kSampleIsDifferenceSampleFlagMask = 0x10000;
21
22 static const uint8 kAuxInfo[] = {
23   0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31,
24   0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x32,
25   0x00, 0x02,
26   0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
27   0x00, 0x03, 0x00, 0x00, 0x00, 0x04
28 };
29
30 static const char kIv1[] = {
31   0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31,
32   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
33 };
34
35 static const uint8 kKeyId[] = {
36   0x41, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x54,
37   0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x44
38 };
39
40 static const uint8 kCencSampleGroupKeyId[] = {
41   0x46, 0x72, 0x61, 0x67, 0x53, 0x61, 0x6d, 0x70,
42   0x6c, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4b
43 };
44
45 namespace media {
46 namespace mp4 {
47
48 class TrackRunIteratorTest : public testing::Test {
49  public:
50   TrackRunIteratorTest() {
51     CreateMovie();
52   }
53
54  protected:
55   Movie moov_;
56   LogCB log_cb_;
57   scoped_ptr<TrackRunIterator> iter_;
58
59   void CreateMovie() {
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;
70     desc1.type = kAudio;
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 =
75         true;
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;
83     desc2.type = kVideo;
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 =
88         true;
89
90     moov_.tracks[2].header.track_id = 3;
91     moov_.tracks[2].media.information.sample_table.description.type = kHint;
92   }
93
94   MovieFragment CreateFragment() {
95     MovieFragment moof;
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);
106
107     moof.tracks[0].runs[1].sample_count = 10;
108     moof.tracks[0].runs[1].data_offset = 10000;
109
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;
122     }
123
124     return moof;
125   }
126
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;
134     } else {
135        sinf = &stsd->audio_entries[0].sinf;
136     }
137
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));
143   }
144
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));
159
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);
163   }
164
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;
174   }
175
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;
182     }
183
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());
188   }
189
190   void SetAscending(std::vector<uint32>* vec) {
191     vec->resize(10);
192     for (size_t i = 0; i < vec->size(); i++)
193       (*vec)[i] = i+1;
194   }
195 };
196
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());
202 }
203
204 TEST_F(TrackRunIteratorTest, BasicOperationTest) {
205   iter_.reset(new TrackRunIterator(&moov_, log_cb_));
206   MovieFragment moof = CreateFragment();
207
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());
220
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());
229
230   // Test end-of-run
231   iter_->AdvanceSample();
232   EXPECT_FALSE(iter_->IsSampleValid());
233
234   // Test last sample of next run
235   iter_->AdvanceRun();
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());
245
246   // Test final run
247   iter_->AdvanceRun();
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());
254   iter_->AdvanceRun();
255   EXPECT_FALSE(iter_->IsRunValid());
256 }
257
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));
276 }
277
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));
289   iter_->AdvanceRun();
290   EXPECT_TRUE(iter_->is_keyframe());
291   iter_->AdvanceSample();
292   EXPECT_FALSE(iter_->is_keyframe());
293 }
294
295 TEST_F(TrackRunIteratorTest, ReorderingTest) {
296   // Test frame reordering and edit list support. The frames have the following
297   // decode timestamps:
298   //
299   //   0ms 40ms   120ms     240ms
300   //   | 0 | 1  - | 2  -  - |
301   //
302   // ...and these composition timestamps, after edit list adjustment:
303   //
304   //   0ms 40ms       160ms  240ms
305   //   | 0 | 2  -  -  | 1 - |
306
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_));
312   EditListEntry entry;
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);
318
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);
327   cts_offsets[0] = 2;
328   cts_offsets[1] = 5;
329   cts_offsets[2] = 0;
330   moof.tracks[1].decode_time.decode_time = 0;
331
332   ASSERT_TRUE(iter_->Init(moof));
333   iter_->AdvanceRun();
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));
345 }
346
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));
355   iter_->AdvanceRun();
356   EXPECT_FALSE(iter_->AuxInfoNeedsToBeCached());
357 }
358
359 TEST_F(TrackRunIteratorTest, DecryptConfigTest) {
360   AddEncryption(&moov_.tracks[1]);
361   iter_.reset(new TrackRunIterator(&moov_, log_cb_));
362
363   MovieFragment moof = CreateFragment();
364   AddAuxInfoHeaders(50, &moof.tracks[1]);
365
366   ASSERT_TRUE(iter_->Init(moof));
367
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);
395 }
396
397 TEST_F(TrackRunIteratorTest, CencSampleGroupTest) {
398   MovieFragment moof = CreateFragment();
399
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}};
405   AddCencSampleGroup(
406       &moof.tracks[0], kSampleToGroupTable, arraysize(kSampleToGroupTable));
407
408   iter_.reset(new TrackRunIterator(&moov_, log_cb_));
409   ASSERT_TRUE(InitMoofWithArbitraryAuxInfo(&moof));
410
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());
419 }
420
421 TEST_F(TrackRunIteratorTest, CencSampleGroupWithTrackEncryptionBoxTest) {
422   // Add TrackEncryption Box.
423   AddEncryption(&moov_.tracks[0]);
424
425   MovieFragment moof = CreateFragment();
426
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.
431       {4, 0},
432       // Associated with the first entry in SampleGroupDescription Box.
433       {3, SampleToGroupEntry::kFragmentGroupDescriptionIndexBase + 1}};
434   AddCencSampleGroup(
435       &moof.tracks[0], kSampleToGroupTable, arraysize(kSampleToGroupTable));
436
437   iter_.reset(new TrackRunIterator(&moov_, log_cb_));
438   ASSERT_TRUE(InitMoofWithArbitraryAuxInfo(&moof));
439
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));
444
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();
449   }
450
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();
455   }
456
457   for (size_t i = 0; i < kSampleToGroupTable[2].sample_count; ++i) {
458     EXPECT_FALSE(iter_->is_encrypted());
459     iter_->AdvanceSample();
460   }
461
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());
466 }
467
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_));
473
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;
479
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);
489   iter_->AdvanceRun();
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);
498 }
499
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_));
515
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;
524
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);
531   iter_->AdvanceRun();
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);
539   iter_->AdvanceRun();
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);
546 }
547
548 TEST_F(TrackRunIteratorTest, MissingStssMakesAllSamplesKeyframes) {
549   iter_.reset(new TrackRunIterator(&moov_, log_cb_));
550   MovieFragment moof = CreateFragment();
551
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());
556
557   // Count the number of non-keyframes for each run with the default
558   // sync_sample info.
559
560   EXPECT_TRUE(moov_.tracks[0].media.information.sample_table.sync_sample.
561               is_present);
562   EXPECT_TRUE(moov_.tracks[1].media.information.sample_table.sync_sample.
563               is_present);
564
565   int first_run_non_keyframe_count = 0;
566   int second_run_non_keyframe_count = 0;
567
568   EXPECT_TRUE(iter_->IsRunValid());
569   while (iter_->IsSampleValid()) {
570     EXPECT_EQ(iter_->track_id(), 1u);
571
572     if (!iter_->is_keyframe())
573       first_run_non_keyframe_count++;
574
575     iter_->AdvanceSample();
576   }
577
578   iter_->AdvanceRun();
579
580   EXPECT_TRUE(iter_->IsRunValid());
581   while (iter_->IsSampleValid()) {
582     EXPECT_EQ(iter_->track_id(), 2u);
583
584     if (!iter_->is_keyframe())
585       second_run_non_keyframe_count++;
586
587     iter_->AdvanceSample();
588   }
589
590   EXPECT_EQ(0, first_run_non_keyframe_count);
591   EXPECT_EQ(9, second_run_non_keyframe_count);
592
593   // Update sync_sample info to reflect that the box is not present on
594   // both tracks.
595   moov_.tracks[0].media.information.sample_table.sync_sample.is_present =
596       false;
597   moov_.tracks[1].media.information.sample_table.sync_sample.is_present =
598       false;
599
600   // Reinitialize the iterator and verify that all samples are keyframes
601   // on both tracks now.
602
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();
609   }
610
611   iter_->AdvanceRun();
612   EXPECT_TRUE(iter_->IsRunValid());
613
614   while (iter_->IsSampleValid()) {
615     EXPECT_EQ(iter_->track_id(), 2u);
616     EXPECT_TRUE(iter_->is_keyframe());
617     iter_->AdvanceSample();
618   }
619 }
620
621
622 }  // namespace mp4
623 }  // namespace media