• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "base/basictypes.h"
6 #include "base/logging.h"
7 #include "base/memory/scoped_ptr.h"
8 #include "media/mp4/box_definitions.h"
9 #include "media/mp4/rcheck.h"
10 #include "media/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 namespace media {
41 namespace mp4 {
42 
43 class TrackRunIteratorTest : public testing::Test {
44  public:
TrackRunIteratorTest()45   TrackRunIteratorTest() {
46     CreateMovie();
47   }
48 
49  protected:
50   Movie moov_;
51   LogCB log_cb_;
52   scoped_ptr<TrackRunIterator> iter_;
53 
CreateMovie()54   void CreateMovie() {
55     moov_.header.timescale = 1000;
56     moov_.tracks.resize(3);
57     moov_.extends.tracks.resize(2);
58     moov_.tracks[0].header.track_id = 1;
59     moov_.tracks[0].media.header.timescale = kAudioScale;
60     SampleDescription& desc1 =
61         moov_.tracks[0].media.information.sample_table.description;
62     AudioSampleEntry aud_desc;
63     aud_desc.format = FOURCC_MP4A;
64     aud_desc.sinf.info.track_encryption.is_encrypted = false;
65     desc1.type = kAudio;
66     desc1.audio_entries.push_back(aud_desc);
67     moov_.extends.tracks[0].track_id = 1;
68     moov_.extends.tracks[0].default_sample_description_index = 1;
69 
70     moov_.tracks[1].header.track_id = 2;
71     moov_.tracks[1].media.header.timescale = kVideoScale;
72     SampleDescription& desc2 =
73         moov_.tracks[1].media.information.sample_table.description;
74     VideoSampleEntry vid_desc;
75     vid_desc.format = FOURCC_AVC1;
76     vid_desc.sinf.info.track_encryption.is_encrypted = false;
77     desc2.type = kVideo;
78     desc2.video_entries.push_back(vid_desc);
79     moov_.extends.tracks[1].track_id = 2;
80     moov_.extends.tracks[1].default_sample_description_index = 1;
81 
82     moov_.tracks[2].header.track_id = 3;
83     moov_.tracks[2].media.information.sample_table.description.type = kHint;
84   }
85 
CreateFragment()86   MovieFragment CreateFragment() {
87     MovieFragment moof;
88     moof.tracks.resize(2);
89     moof.tracks[0].decode_time.decode_time = 0;
90     moof.tracks[0].header.track_id = 1;
91     moof.tracks[0].header.has_default_sample_flags = true;
92     moof.tracks[0].header.default_sample_duration = 1024;
93     moof.tracks[0].header.default_sample_size = 4;
94     moof.tracks[0].runs.resize(2);
95     moof.tracks[0].runs[0].sample_count = 10;
96     moof.tracks[0].runs[0].data_offset = 100;
97     SetAscending(&moof.tracks[0].runs[0].sample_sizes);
98 
99     moof.tracks[0].runs[1].sample_count = 10;
100     moof.tracks[0].runs[1].data_offset = 10000;
101 
102     moof.tracks[1].header.track_id = 2;
103     moof.tracks[1].header.has_default_sample_flags = false;
104     moof.tracks[1].decode_time.decode_time = 10;
105     moof.tracks[1].runs.resize(1);
106     moof.tracks[1].runs[0].sample_count = 10;
107     moof.tracks[1].runs[0].data_offset = 200;
108     SetAscending(&moof.tracks[1].runs[0].sample_sizes);
109     SetAscending(&moof.tracks[1].runs[0].sample_durations);
110     moof.tracks[1].runs[0].sample_flags.resize(10);
111     for (size_t i = 1; i < moof.tracks[1].runs[0].sample_flags.size(); i++) {
112       moof.tracks[1].runs[0].sample_flags[i] =
113           kSampleIsDifferenceSampleFlagMask;
114     }
115 
116     return moof;
117   }
118 
119   // Update the first sample description of a Track to indicate encryption
AddEncryption(Track * track)120   void AddEncryption(Track* track) {
121     SampleDescription* stsd =
122         &track->media.information.sample_table.description;
123     ProtectionSchemeInfo* sinf;
124     if (!stsd->video_entries.empty()) {
125        sinf = &stsd->video_entries[0].sinf;
126     } else {
127        sinf = &stsd->audio_entries[0].sinf;
128     }
129 
130     sinf->type.type = FOURCC_CENC;
131     sinf->info.track_encryption.is_encrypted = true;
132     sinf->info.track_encryption.default_iv_size = 8;
133     sinf->info.track_encryption.default_kid.insert(
134         sinf->info.track_encryption.default_kid.begin(),
135         kKeyId, kKeyId + arraysize(kKeyId));
136   }
137 
138   // Add aux info covering the first track run to a TrackFragment, and update
139   // the run to ensure it matches length and subsample information.
AddAuxInfoHeaders(int offset,TrackFragment * frag)140   void AddAuxInfoHeaders(int offset, TrackFragment* frag) {
141     frag->auxiliary_offset.offsets.push_back(offset);
142     frag->auxiliary_size.sample_count = 2;
143     frag->auxiliary_size.sample_info_sizes.push_back(8);
144     frag->auxiliary_size.sample_info_sizes.push_back(22);
145     frag->runs[0].sample_count = 2;
146     frag->runs[0].sample_sizes[1] = 10;
147   }
148 
SetAscending(std::vector<uint32> * vec)149   void SetAscending(std::vector<uint32>* vec) {
150     vec->resize(10);
151     for (size_t i = 0; i < vec->size(); i++)
152       (*vec)[i] = i+1;
153   }
154 };
155 
TEST_F(TrackRunIteratorTest,NoRunsTest)156 TEST_F(TrackRunIteratorTest, NoRunsTest) {
157   iter_.reset(new TrackRunIterator(&moov_, log_cb_));
158   ASSERT_TRUE(iter_->Init(MovieFragment()));
159   EXPECT_FALSE(iter_->IsRunValid());
160   EXPECT_FALSE(iter_->IsSampleValid());
161 }
162 
TEST_F(TrackRunIteratorTest,BasicOperationTest)163 TEST_F(TrackRunIteratorTest, BasicOperationTest) {
164   iter_.reset(new TrackRunIterator(&moov_, log_cb_));
165   MovieFragment moof = CreateFragment();
166 
167   // Test that runs are sorted correctly, and that properties of the initial
168   // sample of the first run are correct
169   ASSERT_TRUE(iter_->Init(moof));
170   EXPECT_TRUE(iter_->IsRunValid());
171   EXPECT_FALSE(iter_->is_encrypted());
172   EXPECT_EQ(iter_->track_id(), 1u);
173   EXPECT_EQ(iter_->sample_offset(), 100);
174   EXPECT_EQ(iter_->sample_size(), 1);
175   EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(0, kAudioScale));
176   EXPECT_EQ(iter_->cts(), TimeDeltaFromRational(0, kAudioScale));
177   EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(1024, kAudioScale));
178   EXPECT_TRUE(iter_->is_keyframe());
179 
180   // Advance to the last sample in the current run, and test its properties
181   for (int i = 0; i < 9; i++) iter_->AdvanceSample();
182   EXPECT_EQ(iter_->track_id(), 1u);
183   EXPECT_EQ(iter_->sample_offset(), 100 + kSumAscending1);
184   EXPECT_EQ(iter_->sample_size(), 10);
185   EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(1024 * 9, kAudioScale));
186   EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(1024, kAudioScale));
187   EXPECT_TRUE(iter_->is_keyframe());
188 
189   // Test end-of-run
190   iter_->AdvanceSample();
191   EXPECT_FALSE(iter_->IsSampleValid());
192 
193   // Test last sample of next run
194   iter_->AdvanceRun();
195   EXPECT_TRUE(iter_->is_keyframe());
196   for (int i = 0; i < 9; i++) iter_->AdvanceSample();
197   EXPECT_EQ(iter_->track_id(), 2u);
198   EXPECT_EQ(iter_->sample_offset(), 200 + kSumAscending1);
199   EXPECT_EQ(iter_->sample_size(), 10);
200   int64 base_dts = kSumAscending1 + moof.tracks[1].decode_time.decode_time;
201   EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(base_dts, kVideoScale));
202   EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(10, kVideoScale));
203   EXPECT_FALSE(iter_->is_keyframe());
204 
205   // Test final run
206   iter_->AdvanceRun();
207   EXPECT_EQ(iter_->track_id(), 1u);
208   EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(1024 * 10, kAudioScale));
209   iter_->AdvanceSample();
210   EXPECT_EQ(moof.tracks[0].runs[1].data_offset +
211             moof.tracks[0].header.default_sample_size,
212             iter_->sample_offset());
213   iter_->AdvanceRun();
214   EXPECT_FALSE(iter_->IsRunValid());
215 }
216 
TEST_F(TrackRunIteratorTest,TrackExtendsDefaultsTest)217 TEST_F(TrackRunIteratorTest, TrackExtendsDefaultsTest) {
218   moov_.extends.tracks[0].default_sample_duration = 50;
219   moov_.extends.tracks[0].default_sample_size = 3;
220   moov_.extends.tracks[0].default_sample_flags =
221     kSampleIsDifferenceSampleFlagMask;
222   iter_.reset(new TrackRunIterator(&moov_, log_cb_));
223   MovieFragment moof = CreateFragment();
224   moof.tracks[0].header.has_default_sample_flags = false;
225   moof.tracks[0].header.default_sample_size = 0;
226   moof.tracks[0].header.default_sample_duration = 0;
227   moof.tracks[0].runs[0].sample_sizes.clear();
228   ASSERT_TRUE(iter_->Init(moof));
229   iter_->AdvanceSample();
230   EXPECT_FALSE(iter_->is_keyframe());
231   EXPECT_EQ(iter_->sample_size(), 3);
232   EXPECT_EQ(iter_->sample_offset(), moof.tracks[0].runs[0].data_offset + 3);
233   EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(50, kAudioScale));
234   EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(50, kAudioScale));
235 }
236 
TEST_F(TrackRunIteratorTest,FirstSampleFlagTest)237 TEST_F(TrackRunIteratorTest, FirstSampleFlagTest) {
238   // Ensure that keyframes are flagged correctly in the face of BMFF boxes which
239   // explicitly specify the flags for the first sample in a run and rely on
240   // defaults for all subsequent samples
241   iter_.reset(new TrackRunIterator(&moov_, log_cb_));
242   MovieFragment moof = CreateFragment();
243   moof.tracks[1].header.has_default_sample_flags = true;
244   moof.tracks[1].header.default_sample_flags =
245     kSampleIsDifferenceSampleFlagMask;
246   moof.tracks[1].runs[0].sample_flags.resize(1);
247   ASSERT_TRUE(iter_->Init(moof));
248   iter_->AdvanceRun();
249   EXPECT_TRUE(iter_->is_keyframe());
250   iter_->AdvanceSample();
251   EXPECT_FALSE(iter_->is_keyframe());
252 }
253 
TEST_F(TrackRunIteratorTest,ReorderingTest)254 TEST_F(TrackRunIteratorTest, ReorderingTest) {
255   // Test frame reordering and edit list support. The frames have the following
256   // decode timestamps:
257   //
258   //   0ms 40ms   120ms     240ms
259   //   | 0 | 1  - | 2  -  - |
260   //
261   // ...and these composition timestamps, after edit list adjustment:
262   //
263   //   0ms 40ms       160ms  240ms
264   //   | 0 | 2  -  -  | 1 - |
265 
266   // Create an edit list with one entry, with an initial start time of 80ms
267   // (that is, 2 / kVideoTimescale) and a duration of zero (which is treated as
268   // infinite according to 14496-12:2012). This will cause the first 80ms of the
269   // media timeline - which will be empty, due to CTS biasing - to be discarded.
270   iter_.reset(new TrackRunIterator(&moov_, log_cb_));
271   EditListEntry entry;
272   entry.segment_duration = 0;
273   entry.media_time = 2;
274   entry.media_rate_integer = 1;
275   entry.media_rate_fraction = 0;
276   moov_.tracks[1].edit.list.edits.push_back(entry);
277 
278   // Add CTS offsets. Without bias, the CTS offsets for the first three frames
279   // would simply be [0, 3, -2]. Since CTS offsets should be non-negative for
280   // maximum compatibility, these values are biased up to [2, 5, 0], and the
281   // extra 80ms is removed via the edit list.
282   MovieFragment moof = CreateFragment();
283   std::vector<int32>& cts_offsets =
284     moof.tracks[1].runs[0].sample_composition_time_offsets;
285   cts_offsets.resize(10);
286   cts_offsets[0] = 2;
287   cts_offsets[1] = 5;
288   cts_offsets[2] = 0;
289   moof.tracks[1].decode_time.decode_time = 0;
290 
291   ASSERT_TRUE(iter_->Init(moof));
292   iter_->AdvanceRun();
293   EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(0, kVideoScale));
294   EXPECT_EQ(iter_->cts(), TimeDeltaFromRational(0, kVideoScale));
295   EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(1, kVideoScale));
296   iter_->AdvanceSample();
297   EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(1, kVideoScale));
298   EXPECT_EQ(iter_->cts(), TimeDeltaFromRational(4, kVideoScale));
299   EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(2, kVideoScale));
300   iter_->AdvanceSample();
301   EXPECT_EQ(iter_->dts(), TimeDeltaFromRational(3, kVideoScale));
302   EXPECT_EQ(iter_->cts(), TimeDeltaFromRational(1, kVideoScale));
303   EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(3, kVideoScale));
304 }
305 
TEST_F(TrackRunIteratorTest,IgnoreUnknownAuxInfoTest)306 TEST_F(TrackRunIteratorTest, IgnoreUnknownAuxInfoTest) {
307   iter_.reset(new TrackRunIterator(&moov_, log_cb_));
308   MovieFragment moof = CreateFragment();
309   moof.tracks[1].auxiliary_offset.offsets.push_back(50);
310   moof.tracks[1].auxiliary_size.default_sample_info_size = 2;
311   moof.tracks[1].auxiliary_size.sample_count = 2;
312   moof.tracks[1].runs[0].sample_count = 2;
313   ASSERT_TRUE(iter_->Init(moof));
314   iter_->AdvanceRun();
315   EXPECT_FALSE(iter_->AuxInfoNeedsToBeCached());
316 }
317 
TEST_F(TrackRunIteratorTest,DecryptConfigTest)318 TEST_F(TrackRunIteratorTest, DecryptConfigTest) {
319   AddEncryption(&moov_.tracks[1]);
320   iter_.reset(new TrackRunIterator(&moov_, log_cb_));
321 
322   MovieFragment moof = CreateFragment();
323   AddAuxInfoHeaders(50, &moof.tracks[1]);
324 
325   ASSERT_TRUE(iter_->Init(moof));
326 
327   // The run for track 2 will be first, since its aux info offset is the first
328   // element in the file.
329   EXPECT_EQ(iter_->track_id(), 2u);
330   EXPECT_TRUE(iter_->is_encrypted());
331   EXPECT_TRUE(iter_->AuxInfoNeedsToBeCached());
332   EXPECT_EQ(static_cast<uint32>(iter_->aux_info_size()), arraysize(kAuxInfo));
333   EXPECT_EQ(iter_->aux_info_offset(), 50);
334   EXPECT_EQ(iter_->GetMaxClearOffset(), 50);
335   EXPECT_FALSE(iter_->CacheAuxInfo(NULL, 0));
336   EXPECT_FALSE(iter_->CacheAuxInfo(kAuxInfo, 3));
337   EXPECT_TRUE(iter_->AuxInfoNeedsToBeCached());
338   EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
339   EXPECT_FALSE(iter_->AuxInfoNeedsToBeCached());
340   EXPECT_EQ(iter_->sample_offset(), 200);
341   EXPECT_EQ(iter_->GetMaxClearOffset(), moof.tracks[0].runs[0].data_offset);
342   scoped_ptr<DecryptConfig> config = iter_->GetDecryptConfig();
343   ASSERT_EQ(arraysize(kKeyId), config->key_id().size());
344   EXPECT_TRUE(!memcmp(kKeyId, config->key_id().data(),
345                       config->key_id().size()));
346   ASSERT_EQ(arraysize(kIv1), config->iv().size());
347   EXPECT_TRUE(!memcmp(kIv1, config->iv().data(), config->iv().size()));
348   EXPECT_TRUE(config->subsamples().empty());
349   iter_->AdvanceSample();
350   config = iter_->GetDecryptConfig();
351   EXPECT_EQ(config->subsamples().size(), 2u);
352   EXPECT_EQ(config->subsamples()[0].clear_bytes, 1u);
353   EXPECT_EQ(config->subsamples()[1].cypher_bytes, 4u);
354 }
355 
356 // It is legal for aux info blocks to be shared among multiple formats.
TEST_F(TrackRunIteratorTest,SharedAuxInfoTest)357 TEST_F(TrackRunIteratorTest, SharedAuxInfoTest) {
358   AddEncryption(&moov_.tracks[0]);
359   AddEncryption(&moov_.tracks[1]);
360   iter_.reset(new TrackRunIterator(&moov_, log_cb_));
361 
362   MovieFragment moof = CreateFragment();
363   moof.tracks[0].runs.resize(1);
364   AddAuxInfoHeaders(50, &moof.tracks[0]);
365   AddAuxInfoHeaders(50, &moof.tracks[1]);
366   moof.tracks[0].auxiliary_size.default_sample_info_size = 8;
367 
368   ASSERT_TRUE(iter_->Init(moof));
369   EXPECT_EQ(iter_->track_id(), 1u);
370   EXPECT_EQ(iter_->aux_info_offset(), 50);
371   EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
372   scoped_ptr<DecryptConfig> config = iter_->GetDecryptConfig();
373   ASSERT_EQ(arraysize(kIv1), config->iv().size());
374   EXPECT_TRUE(!memcmp(kIv1, config->iv().data(), config->iv().size()));
375   iter_->AdvanceSample();
376   EXPECT_EQ(iter_->GetMaxClearOffset(), 50);
377   iter_->AdvanceRun();
378   EXPECT_EQ(iter_->GetMaxClearOffset(), 50);
379   EXPECT_EQ(iter_->aux_info_offset(), 50);
380   EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
381   EXPECT_EQ(iter_->GetMaxClearOffset(), 200);
382   ASSERT_EQ(arraysize(kIv1), config->iv().size());
383   EXPECT_TRUE(!memcmp(kIv1, config->iv().data(), config->iv().size()));
384   iter_->AdvanceSample();
385   EXPECT_EQ(iter_->GetMaxClearOffset(), 201);
386 }
387 
388 // Sensible files are expected to place auxiliary information for a run
389 // immediately before the main data for that run. Alternative schemes are
390 // possible, however, including the somewhat reasonable behavior of placing all
391 // aux info at the head of the 'mdat' box together, and the completely
392 // unreasonable behavior demonstrated here:
393 //  byte 50: track 2, run 1 aux info
394 //  byte 100: track 1, run 1 data
395 //  byte 200: track 2, run 1 data
396 //  byte 201: track 1, run 2 aux info (*inside* track 2, run 1 data)
397 //  byte 10000: track 1, run 2 data
398 //  byte 20000: track 1, run 1 aux info
TEST_F(TrackRunIteratorTest,UnexpectedOrderingTest)399 TEST_F(TrackRunIteratorTest, UnexpectedOrderingTest) {
400   AddEncryption(&moov_.tracks[0]);
401   AddEncryption(&moov_.tracks[1]);
402   iter_.reset(new TrackRunIterator(&moov_, log_cb_));
403 
404   MovieFragment moof = CreateFragment();
405   AddAuxInfoHeaders(20000, &moof.tracks[0]);
406   moof.tracks[0].auxiliary_offset.offsets.push_back(201);
407   moof.tracks[0].auxiliary_size.sample_count += 2;
408   moof.tracks[0].auxiliary_size.default_sample_info_size = 8;
409   moof.tracks[0].runs[1].sample_count = 2;
410   AddAuxInfoHeaders(50, &moof.tracks[1]);
411   moof.tracks[1].runs[0].sample_sizes[0] = 5;
412 
413   ASSERT_TRUE(iter_->Init(moof));
414   EXPECT_EQ(iter_->track_id(), 2u);
415   EXPECT_EQ(iter_->aux_info_offset(), 50);
416   EXPECT_EQ(iter_->sample_offset(), 200);
417   EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
418   EXPECT_EQ(iter_->GetMaxClearOffset(), 100);
419   iter_->AdvanceRun();
420   EXPECT_EQ(iter_->track_id(), 1u);
421   EXPECT_EQ(iter_->aux_info_offset(), 20000);
422   EXPECT_EQ(iter_->sample_offset(), 100);
423   EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
424   EXPECT_EQ(iter_->GetMaxClearOffset(), 100);
425   iter_->AdvanceSample();
426   EXPECT_EQ(iter_->GetMaxClearOffset(), 101);
427   iter_->AdvanceRun();
428   EXPECT_EQ(iter_->track_id(), 1u);
429   EXPECT_EQ(iter_->aux_info_offset(), 201);
430   EXPECT_EQ(iter_->sample_offset(), 10000);
431   EXPECT_EQ(iter_->GetMaxClearOffset(), 201);
432   EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
433   EXPECT_EQ(iter_->GetMaxClearOffset(), 10000);
434 }
435 
436 }  // namespace mp4
437 }  // namespace media
438