[chromedriver] Explicitly set page loading state when document.readyState != "complete".
[chromium-blink-merge.git] / media / formats / mp4 / track_run_iterator_unittest.cc
blob6bfab113cf954f16b3e26587e9d3bf79e335d18d
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 "base/strings/string_split.h"
9 #include "media/formats/mp4/box_definitions.h"
10 #include "media/formats/mp4/rcheck.h"
11 #include "media/formats/mp4/track_run_iterator.h"
12 #include "testing/gtest/include/gtest/gtest.h"
14 // The sum of the elements in a vector initialized with SumAscending,
15 // less the value of the last element.
16 static const int kSumAscending1 = 45;
18 static const int kAudioScale = 48000;
19 static const int kVideoScale = 25;
21 static const uint8 kAuxInfo[] = {
22 0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31,
23 0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x32,
24 0x00, 0x02,
25 0x00, 0x01, 0x00, 0x00, 0x00, 0x02,
26 0x00, 0x03, 0x00, 0x00, 0x00, 0x04
29 static const char kIv1[] = {
30 0x41, 0x54, 0x65, 0x73, 0x74, 0x49, 0x76, 0x31,
31 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
34 static const uint8 kKeyId[] = {
35 0x41, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x54,
36 0x65, 0x73, 0x74, 0x4b, 0x65, 0x79, 0x49, 0x44
39 static const uint8 kTrackCencSampleGroupKeyId[] = {
40 0x46, 0x72, 0x61, 0x67, 0x53, 0x61, 0x6d, 0x70,
41 0x6c, 0x65, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x4b
44 static const uint8 kFragmentCencSampleGroupKeyId[] = {
45 0x6b, 0x46, 0x72, 0x61, 0x67, 0x6d, 0x65, 0x6e,
46 0x74, 0x43, 0x65, 0x6e, 0x63, 0x53, 0x61, 0x6d
49 namespace media {
50 namespace mp4 {
52 class TrackRunIteratorTest : public testing::Test {
53 public:
54 TrackRunIteratorTest() : media_log_(new MediaLog()) { CreateMovie(); }
56 protected:
57 Movie moov_;
58 scoped_refptr<MediaLog> media_log_;
59 scoped_ptr<TrackRunIterator> iter_;
61 void CreateMovie() {
62 moov_.header.timescale = 1000;
63 moov_.tracks.resize(3);
64 moov_.extends.tracks.resize(2);
65 moov_.tracks[0].header.track_id = 1;
66 moov_.tracks[0].media.header.timescale = kAudioScale;
67 SampleDescription& desc1 =
68 moov_.tracks[0].media.information.sample_table.description;
69 AudioSampleEntry aud_desc;
70 aud_desc.format = FOURCC_MP4A;
71 aud_desc.sinf.info.track_encryption.is_encrypted = false;
72 desc1.type = kAudio;
73 desc1.audio_entries.push_back(aud_desc);
74 moov_.extends.tracks[0].track_id = 1;
75 moov_.extends.tracks[0].default_sample_description_index = 1;
76 moov_.tracks[0].media.information.sample_table.sync_sample.is_present =
77 false;
78 moov_.tracks[1].header.track_id = 2;
79 moov_.tracks[1].media.header.timescale = kVideoScale;
80 SampleDescription& desc2 =
81 moov_.tracks[1].media.information.sample_table.description;
82 VideoSampleEntry vid_desc;
83 vid_desc.format = FOURCC_AVC1;
84 vid_desc.sinf.info.track_encryption.is_encrypted = false;
85 desc2.type = kVideo;
86 desc2.video_entries.push_back(vid_desc);
87 moov_.extends.tracks[1].track_id = 2;
88 moov_.extends.tracks[1].default_sample_description_index = 1;
89 SyncSample& video_sync_sample =
90 moov_.tracks[1].media.information.sample_table.sync_sample;
91 video_sync_sample.is_present = true;
92 video_sync_sample.entries.resize(1);
93 video_sync_sample.entries[0] = 0;
95 moov_.tracks[2].header.track_id = 3;
96 moov_.tracks[2].media.information.sample_table.description.type = kHint;
99 uint32 ToSampleFlags(const std::string& str) {
100 CHECK_EQ(str.length(), 2u);
102 SampleDependsOn sample_depends_on = kSampleDependsOnReserved;
103 bool is_non_sync_sample = false;
104 switch(str[0]) {
105 case 'U':
106 sample_depends_on = kSampleDependsOnUnknown;
107 break;
108 case 'O':
109 sample_depends_on = kSampleDependsOnOthers;
110 break;
111 case 'N':
112 sample_depends_on = kSampleDependsOnNoOther;
113 break;
114 case 'R':
115 sample_depends_on = kSampleDependsOnReserved;
116 break;
117 default:
118 CHECK(false) << "Invalid sample dependency character '"
119 << str[0] << "'";
120 break;
123 switch(str[1]) {
124 case 'S':
125 is_non_sync_sample = false;
126 break;
127 case 'N':
128 is_non_sync_sample = true;
129 break;
130 default:
131 CHECK(false) << "Invalid sync sample character '"
132 << str[1] << "'";
133 break;
135 uint32 flags = static_cast<uint32>(sample_depends_on) << 24;
136 if (is_non_sync_sample)
137 flags |= kSampleIsNonSyncSample;
138 return flags;
141 void SetFlagsOnSamples(const std::string& sample_info,
142 TrackFragmentRun* trun) {
143 // US - SampleDependsOnUnknown & IsSyncSample
144 // UN - SampleDependsOnUnknown & IsNonSyncSample
145 // OS - SampleDependsOnOthers & IsSyncSample
146 // ON - SampleDependsOnOthers & IsNonSyncSample
147 // NS - SampleDependsOnNoOthers & IsSyncSample
148 // NN - SampleDependsOnNoOthers & IsNonSyncSample
149 std::vector<std::string> flags_data;
150 base::SplitString(sample_info, ' ', &flags_data);
152 if (flags_data.size() == 1u) {
153 // Simulates the first_sample_flags_present set scenario,
154 // where only one sample_flag value is set and the default
155 // flags are used for everything else.
156 ASSERT_GE(trun->sample_count, flags_data.size());
157 } else {
158 ASSERT_EQ(trun->sample_count, flags_data.size());
161 trun->sample_flags.resize(flags_data.size());
162 for (size_t i = 0; i < flags_data.size(); i++)
163 trun->sample_flags[i] = ToSampleFlags(flags_data[i]);
166 std::string KeyframeAndRAPInfo(TrackRunIterator* iter) {
167 CHECK(iter->IsRunValid());
168 std::stringstream ss;
169 ss << iter->track_id();
171 while (iter->IsSampleValid()) {
172 ss << " " << (iter->is_keyframe() ? "K" : "P");
173 if (iter->is_random_access_point())
174 ss << "R";
175 iter->AdvanceSample();
178 return ss.str();
181 MovieFragment CreateFragment() {
182 MovieFragment moof;
183 moof.tracks.resize(2);
184 moof.tracks[0].decode_time.decode_time = 0;
185 moof.tracks[0].header.track_id = 1;
186 moof.tracks[0].header.has_default_sample_flags = true;
187 moof.tracks[0].header.default_sample_flags = ToSampleFlags("US");
188 moof.tracks[0].header.default_sample_duration = 1024;
189 moof.tracks[0].header.default_sample_size = 4;
190 moof.tracks[0].runs.resize(2);
191 moof.tracks[0].runs[0].sample_count = 10;
192 moof.tracks[0].runs[0].data_offset = 100;
193 SetAscending(&moof.tracks[0].runs[0].sample_sizes);
195 moof.tracks[0].runs[1].sample_count = 10;
196 moof.tracks[0].runs[1].data_offset = 10000;
198 moof.tracks[1].header.track_id = 2;
199 moof.tracks[1].header.has_default_sample_flags = false;
200 moof.tracks[1].decode_time.decode_time = 10;
201 moof.tracks[1].runs.resize(1);
202 moof.tracks[1].runs[0].sample_count = 10;
203 moof.tracks[1].runs[0].data_offset = 200;
204 SetAscending(&moof.tracks[1].runs[0].sample_sizes);
205 SetAscending(&moof.tracks[1].runs[0].sample_durations);
206 SetFlagsOnSamples("US UN UN UN UN UN UN UN UN UN", &moof.tracks[1].runs[0]);
208 return moof;
211 // Update the first sample description of a Track to indicate encryption
212 void AddEncryption(Track* track) {
213 SampleDescription* stsd =
214 &track->media.information.sample_table.description;
215 ProtectionSchemeInfo* sinf;
216 if (!stsd->video_entries.empty()) {
217 sinf = &stsd->video_entries[0].sinf;
218 } else {
219 sinf = &stsd->audio_entries[0].sinf;
222 sinf->type.type = FOURCC_CENC;
223 sinf->info.track_encryption.is_encrypted = true;
224 sinf->info.track_encryption.default_iv_size = 8;
225 sinf->info.track_encryption.default_kid.assign(kKeyId,
226 kKeyId + arraysize(kKeyId));
229 // Add SampleGroupDescription Box to track level sample table and to
230 // fragment. Populate SampleToGroup Box from input array.
231 void AddCencSampleGroup(Track* track,
232 TrackFragment* frag,
233 const SampleToGroupEntry* sample_to_group_entries,
234 size_t num_entries) {
235 auto& track_cenc_group =
236 track->media.information.sample_table.sample_group_description;
237 track_cenc_group.grouping_type = FOURCC_SEIG;
238 track_cenc_group.entries.resize(1);
239 track_cenc_group.entries[0].is_encrypted = true;
240 track_cenc_group.entries[0].iv_size = 8;
241 track_cenc_group.entries[0].key_id.assign(
242 kTrackCencSampleGroupKeyId,
243 kTrackCencSampleGroupKeyId + arraysize(kTrackCencSampleGroupKeyId));
245 frag->sample_group_description.grouping_type = FOURCC_SEIG;
246 frag->sample_group_description.entries.resize(2);
247 frag->sample_group_description.entries[0].is_encrypted = false;
248 frag->sample_group_description.entries[0].iv_size = 0;
249 frag->sample_group_description.entries[1].is_encrypted = true;
250 frag->sample_group_description.entries[1].iv_size = 8;
251 frag->sample_group_description.entries[1].key_id.assign(
252 kFragmentCencSampleGroupKeyId,
253 kFragmentCencSampleGroupKeyId +
254 arraysize(kFragmentCencSampleGroupKeyId));
256 frag->sample_to_group.grouping_type = FOURCC_SEIG;
257 frag->sample_to_group.entries.assign(sample_to_group_entries,
258 sample_to_group_entries + num_entries);
261 // Add aux info covering the first track run to a TrackFragment, and update
262 // the run to ensure it matches length and subsample information.
263 void AddAuxInfoHeaders(int offset, TrackFragment* frag) {
264 frag->auxiliary_offset.offsets.push_back(offset);
265 frag->auxiliary_size.sample_count = 2;
266 frag->auxiliary_size.sample_info_sizes.push_back(8);
267 frag->auxiliary_size.sample_info_sizes.push_back(22);
268 frag->runs[0].sample_count = 2;
269 frag->runs[0].sample_sizes[1] = 10;
272 bool InitMoofWithArbitraryAuxInfo(MovieFragment* moof) {
273 // Add aux info header (equal sized aux info for every sample).
274 for (uint32 i = 0; i < moof->tracks.size(); ++i) {
275 moof->tracks[i].auxiliary_offset.offsets.push_back(50);
276 moof->tracks[i].auxiliary_size.sample_count = 10;
277 moof->tracks[i].auxiliary_size.default_sample_info_size = 8;
280 // We don't care about the actual data in aux.
281 std::vector<uint8> aux_info(1000);
282 return iter_->Init(*moof) &&
283 iter_->CacheAuxInfo(&aux_info[0], aux_info.size());
286 void SetAscending(std::vector<uint32>* vec) {
287 vec->resize(10);
288 for (size_t i = 0; i < vec->size(); i++)
289 (*vec)[i] = i+1;
293 TEST_F(TrackRunIteratorTest, NoRunsTest) {
294 iter_.reset(new TrackRunIterator(&moov_, media_log_));
295 ASSERT_TRUE(iter_->Init(MovieFragment()));
296 EXPECT_FALSE(iter_->IsRunValid());
297 EXPECT_FALSE(iter_->IsSampleValid());
300 TEST_F(TrackRunIteratorTest, BasicOperationTest) {
301 iter_.reset(new TrackRunIterator(&moov_, media_log_));
302 MovieFragment moof = CreateFragment();
304 // Test that runs are sorted correctly, and that properties of the initial
305 // sample of the first run are correct
306 ASSERT_TRUE(iter_->Init(moof));
307 EXPECT_TRUE(iter_->IsRunValid());
308 EXPECT_FALSE(iter_->is_encrypted());
309 EXPECT_EQ(iter_->track_id(), 1u);
310 EXPECT_EQ(iter_->sample_offset(), 100);
311 EXPECT_EQ(iter_->sample_size(), 1);
312 EXPECT_EQ(iter_->dts(), DecodeTimestampFromRational(0, kAudioScale));
313 EXPECT_EQ(iter_->cts(), TimeDeltaFromRational(0, kAudioScale));
314 EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(1024, kAudioScale));
315 EXPECT_TRUE(iter_->is_keyframe());
317 // Advance to the last sample in the current run, and test its properties
318 for (int i = 0; i < 9; i++) iter_->AdvanceSample();
319 EXPECT_EQ(iter_->track_id(), 1u);
320 EXPECT_EQ(iter_->sample_offset(), 100 + kSumAscending1);
321 EXPECT_EQ(iter_->sample_size(), 10);
322 EXPECT_EQ(iter_->dts(), DecodeTimestampFromRational(1024 * 9, kAudioScale));
323 EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(1024, kAudioScale));
324 EXPECT_TRUE(iter_->is_keyframe());
326 // Test end-of-run
327 iter_->AdvanceSample();
328 EXPECT_FALSE(iter_->IsSampleValid());
330 // Test last sample of next run
331 iter_->AdvanceRun();
332 EXPECT_TRUE(iter_->is_keyframe());
333 for (int i = 0; i < 9; i++) iter_->AdvanceSample();
334 EXPECT_EQ(iter_->track_id(), 2u);
335 EXPECT_EQ(iter_->sample_offset(), 200 + kSumAscending1);
336 EXPECT_EQ(iter_->sample_size(), 10);
337 int64 base_dts = kSumAscending1 + moof.tracks[1].decode_time.decode_time;
338 EXPECT_EQ(iter_->dts(), DecodeTimestampFromRational(base_dts, kVideoScale));
339 EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(10, kVideoScale));
340 EXPECT_FALSE(iter_->is_keyframe());
342 // Test final run
343 iter_->AdvanceRun();
344 EXPECT_EQ(iter_->track_id(), 1u);
345 EXPECT_EQ(iter_->dts(), DecodeTimestampFromRational(1024 * 10, kAudioScale));
346 iter_->AdvanceSample();
347 EXPECT_EQ(moof.tracks[0].runs[1].data_offset +
348 moof.tracks[0].header.default_sample_size,
349 iter_->sample_offset());
350 iter_->AdvanceRun();
351 EXPECT_FALSE(iter_->IsRunValid());
354 TEST_F(TrackRunIteratorTest, TrackExtendsDefaultsTest) {
355 moov_.extends.tracks[0].default_sample_duration = 50;
356 moov_.extends.tracks[0].default_sample_size = 3;
357 moov_.extends.tracks[0].default_sample_flags = ToSampleFlags("UN");
358 iter_.reset(new TrackRunIterator(&moov_, media_log_));
359 MovieFragment moof = CreateFragment();
360 moof.tracks[0].header.has_default_sample_flags = false;
361 moof.tracks[0].header.default_sample_size = 0;
362 moof.tracks[0].header.default_sample_duration = 0;
363 moof.tracks[0].runs[0].sample_sizes.clear();
364 ASSERT_TRUE(iter_->Init(moof));
365 iter_->AdvanceSample();
366 EXPECT_FALSE(iter_->is_keyframe());
367 EXPECT_EQ(iter_->sample_size(), 3);
368 EXPECT_EQ(iter_->sample_offset(), moof.tracks[0].runs[0].data_offset + 3);
369 EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(50, kAudioScale));
370 EXPECT_EQ(iter_->dts(), DecodeTimestampFromRational(50, kAudioScale));
373 TEST_F(TrackRunIteratorTest, FirstSampleFlagTest) {
374 // Ensure that keyframes are flagged correctly in the face of BMFF boxes which
375 // explicitly specify the flags for the first sample in a run and rely on
376 // defaults for all subsequent samples
377 iter_.reset(new TrackRunIterator(&moov_, media_log_));
378 MovieFragment moof = CreateFragment();
379 moof.tracks[1].header.has_default_sample_flags = true;
380 moof.tracks[1].header.default_sample_flags = ToSampleFlags("UN");
381 SetFlagsOnSamples("US", &moof.tracks[1].runs[0]);
383 ASSERT_TRUE(iter_->Init(moof));
384 EXPECT_EQ("1 KR KR KR KR KR KR KR KR KR KR", KeyframeAndRAPInfo(iter_.get()));
386 iter_->AdvanceRun();
387 EXPECT_EQ("2 KR P P P P P P P P P", KeyframeAndRAPInfo(iter_.get()));
390 // Verify that parsing fails if a reserved value is in the sample flags.
391 TEST_F(TrackRunIteratorTest, SampleInfoTest_ReservedInSampleFlags) {
392 iter_.reset(new TrackRunIterator(&moov_, media_log_));
393 MovieFragment moof = CreateFragment();
394 // Change the "depends on" field on one of the samples to a
395 // reserved value.
396 moof.tracks[1].runs[0].sample_flags[0] = ToSampleFlags("RS");
397 ASSERT_FALSE(iter_->Init(moof));
400 // Verify that parsing fails if a reserved value is in the default sample flags.
401 TEST_F(TrackRunIteratorTest, SampleInfoTest_ReservedInDefaultSampleFlags) {
402 iter_.reset(new TrackRunIterator(&moov_, media_log_));
403 MovieFragment moof = CreateFragment();
404 // Set the default flag to contain a reserved "depends on" value.
405 moof.tracks[0].header.default_sample_flags = ToSampleFlags("RN");
406 ASSERT_FALSE(iter_->Init(moof));
409 TEST_F(TrackRunIteratorTest, ReorderingTest) {
410 // Test frame reordering and edit list support. The frames have the following
411 // decode timestamps:
413 // 0ms 40ms 120ms 240ms
414 // | 0 | 1 - | 2 - - |
416 // ...and these composition timestamps, after edit list adjustment:
418 // 0ms 40ms 160ms 240ms
419 // | 0 | 2 - - | 1 - |
421 // Create an edit list with one entry, with an initial start time of 80ms
422 // (that is, 2 / kVideoTimescale) and a duration of zero (which is treated as
423 // infinite according to 14496-12:2012). This will cause the first 80ms of the
424 // media timeline - which will be empty, due to CTS biasing - to be discarded.
425 iter_.reset(new TrackRunIterator(&moov_, media_log_));
426 EditListEntry entry;
427 entry.segment_duration = 0;
428 entry.media_time = 2;
429 entry.media_rate_integer = 1;
430 entry.media_rate_fraction = 0;
431 moov_.tracks[1].edit.list.edits.push_back(entry);
433 // Add CTS offsets. Without bias, the CTS offsets for the first three frames
434 // would simply be [0, 3, -2]. Since CTS offsets should be non-negative for
435 // maximum compatibility, these values are biased up to [2, 5, 0], and the
436 // extra 80ms is removed via the edit list.
437 MovieFragment moof = CreateFragment();
438 std::vector<int32>& cts_offsets =
439 moof.tracks[1].runs[0].sample_composition_time_offsets;
440 cts_offsets.resize(10);
441 cts_offsets[0] = 2;
442 cts_offsets[1] = 5;
443 cts_offsets[2] = 0;
444 moof.tracks[1].decode_time.decode_time = 0;
446 ASSERT_TRUE(iter_->Init(moof));
447 iter_->AdvanceRun();
448 EXPECT_EQ(iter_->dts(), DecodeTimestampFromRational(0, kVideoScale));
449 EXPECT_EQ(iter_->cts(), TimeDeltaFromRational(0, kVideoScale));
450 EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(1, kVideoScale));
451 iter_->AdvanceSample();
452 EXPECT_EQ(iter_->dts(), DecodeTimestampFromRational(1, kVideoScale));
453 EXPECT_EQ(iter_->cts(), TimeDeltaFromRational(4, kVideoScale));
454 EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(2, kVideoScale));
455 iter_->AdvanceSample();
456 EXPECT_EQ(iter_->dts(), DecodeTimestampFromRational(3, kVideoScale));
457 EXPECT_EQ(iter_->cts(), TimeDeltaFromRational(1, kVideoScale));
458 EXPECT_EQ(iter_->duration(), TimeDeltaFromRational(3, kVideoScale));
461 TEST_F(TrackRunIteratorTest, IgnoreUnknownAuxInfoTest) {
462 iter_.reset(new TrackRunIterator(&moov_, media_log_));
463 MovieFragment moof = CreateFragment();
464 moof.tracks[1].auxiliary_offset.offsets.push_back(50);
465 moof.tracks[1].auxiliary_size.default_sample_info_size = 2;
466 moof.tracks[1].auxiliary_size.sample_count = 2;
467 moof.tracks[1].runs[0].sample_count = 2;
468 ASSERT_TRUE(iter_->Init(moof));
469 iter_->AdvanceRun();
470 EXPECT_FALSE(iter_->AuxInfoNeedsToBeCached());
473 TEST_F(TrackRunIteratorTest, DecryptConfigTest) {
474 AddEncryption(&moov_.tracks[1]);
475 iter_.reset(new TrackRunIterator(&moov_, media_log_));
477 MovieFragment moof = CreateFragment();
478 AddAuxInfoHeaders(50, &moof.tracks[1]);
480 ASSERT_TRUE(iter_->Init(moof));
482 // The run for track 2 will be first, since its aux info offset is the first
483 // element in the file.
484 EXPECT_EQ(iter_->track_id(), 2u);
485 EXPECT_TRUE(iter_->is_encrypted());
486 EXPECT_TRUE(iter_->AuxInfoNeedsToBeCached());
487 EXPECT_EQ(static_cast<uint32>(iter_->aux_info_size()), arraysize(kAuxInfo));
488 EXPECT_EQ(iter_->aux_info_offset(), 50);
489 EXPECT_EQ(iter_->GetMaxClearOffset(), 50);
490 EXPECT_FALSE(iter_->CacheAuxInfo(NULL, 0));
491 EXPECT_FALSE(iter_->CacheAuxInfo(kAuxInfo, 3));
492 EXPECT_TRUE(iter_->AuxInfoNeedsToBeCached());
493 EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
494 EXPECT_FALSE(iter_->AuxInfoNeedsToBeCached());
495 EXPECT_EQ(iter_->sample_offset(), 200);
496 EXPECT_EQ(iter_->GetMaxClearOffset(), moof.tracks[0].runs[0].data_offset);
497 scoped_ptr<DecryptConfig> config = iter_->GetDecryptConfig();
498 ASSERT_EQ(arraysize(kKeyId), config->key_id().size());
499 EXPECT_TRUE(!memcmp(kKeyId, config->key_id().data(),
500 config->key_id().size()));
501 ASSERT_EQ(arraysize(kIv1), config->iv().size());
502 EXPECT_TRUE(!memcmp(kIv1, config->iv().data(), config->iv().size()));
503 EXPECT_TRUE(config->subsamples().empty());
504 iter_->AdvanceSample();
505 config = iter_->GetDecryptConfig();
506 EXPECT_EQ(config->subsamples().size(), 2u);
507 EXPECT_EQ(config->subsamples()[0].clear_bytes, 1u);
508 EXPECT_EQ(config->subsamples()[1].cypher_bytes, 4u);
511 TEST_F(TrackRunIteratorTest, CencSampleGroupTest) {
512 MovieFragment moof = CreateFragment();
514 const SampleToGroupEntry kSampleToGroupTable[] = {
515 // Associated with the second entry in SampleGroupDescription Box.
516 {1, SampleToGroupEntry::kFragmentGroupDescriptionIndexBase + 2},
517 // Associated with the first entry in SampleGroupDescription Box.
518 {1, SampleToGroupEntry::kFragmentGroupDescriptionIndexBase + 1}};
519 AddCencSampleGroup(&moov_.tracks[0], &moof.tracks[0], kSampleToGroupTable,
520 arraysize(kSampleToGroupTable));
522 iter_.reset(new TrackRunIterator(&moov_, media_log_));
523 ASSERT_TRUE(InitMoofWithArbitraryAuxInfo(&moof));
525 std::string cenc_sample_group_key_id(
526 kFragmentCencSampleGroupKeyId,
527 kFragmentCencSampleGroupKeyId + arraysize(kFragmentCencSampleGroupKeyId));
528 // The first sample is encrypted and the second sample is unencrypted.
529 EXPECT_TRUE(iter_->is_encrypted());
530 EXPECT_EQ(cenc_sample_group_key_id, iter_->GetDecryptConfig()->key_id());
531 iter_->AdvanceSample();
532 EXPECT_FALSE(iter_->is_encrypted());
535 TEST_F(TrackRunIteratorTest, CencSampleGroupWithTrackEncryptionBoxTest) {
536 // Add TrackEncryption Box.
537 AddEncryption(&moov_.tracks[0]);
539 MovieFragment moof = CreateFragment();
541 const SampleToGroupEntry kSampleToGroupTable[] = {
542 // Associated with the 2nd entry in fragment SampleGroupDescription Box.
543 {2, SampleToGroupEntry::kFragmentGroupDescriptionIndexBase + 2},
544 // Associated with the default values specified in TrackEncryption Box.
545 {1, 0},
546 // Associated with the 1st entry in fragment SampleGroupDescription Box.
547 {3, SampleToGroupEntry::kFragmentGroupDescriptionIndexBase + 1},
548 // Associated with the 1st entry in track SampleGroupDescription Box.
549 {2, 1}};
550 AddCencSampleGroup(&moov_.tracks[0], &moof.tracks[0], kSampleToGroupTable,
551 arraysize(kSampleToGroupTable));
553 iter_.reset(new TrackRunIterator(&moov_, media_log_));
554 ASSERT_TRUE(InitMoofWithArbitraryAuxInfo(&moof));
556 std::string track_encryption_key_id(kKeyId, kKeyId + arraysize(kKeyId));
557 std::string track_cenc_sample_group_key_id(
558 kTrackCencSampleGroupKeyId,
559 kTrackCencSampleGroupKeyId + arraysize(kTrackCencSampleGroupKeyId));
560 std::string fragment_cenc_sample_group_key_id(
561 kFragmentCencSampleGroupKeyId,
562 kFragmentCencSampleGroupKeyId + arraysize(kFragmentCencSampleGroupKeyId));
564 for (size_t i = 0; i < kSampleToGroupTable[0].sample_count; ++i) {
565 EXPECT_TRUE(iter_->is_encrypted());
566 EXPECT_EQ(fragment_cenc_sample_group_key_id,
567 iter_->GetDecryptConfig()->key_id());
568 iter_->AdvanceSample();
571 for (size_t i = 0; i < kSampleToGroupTable[1].sample_count; ++i) {
572 EXPECT_TRUE(iter_->is_encrypted());
573 EXPECT_EQ(track_encryption_key_id, iter_->GetDecryptConfig()->key_id());
574 iter_->AdvanceSample();
577 for (size_t i = 0; i < kSampleToGroupTable[2].sample_count; ++i) {
578 EXPECT_FALSE(iter_->is_encrypted());
579 iter_->AdvanceSample();
582 for (size_t i = 0; i < kSampleToGroupTable[3].sample_count; ++i) {
583 EXPECT_TRUE(iter_->is_encrypted());
584 EXPECT_EQ(track_cenc_sample_group_key_id,
585 iter_->GetDecryptConfig()->key_id());
586 iter_->AdvanceSample();
589 // The remaining samples should be associated with the default values
590 // specified in TrackEncryption Box.
591 EXPECT_TRUE(iter_->is_encrypted());
592 EXPECT_EQ(track_encryption_key_id, iter_->GetDecryptConfig()->key_id());
595 // It is legal for aux info blocks to be shared among multiple formats.
596 TEST_F(TrackRunIteratorTest, SharedAuxInfoTest) {
597 AddEncryption(&moov_.tracks[0]);
598 AddEncryption(&moov_.tracks[1]);
599 iter_.reset(new TrackRunIterator(&moov_, media_log_));
601 MovieFragment moof = CreateFragment();
602 moof.tracks[0].runs.resize(1);
603 AddAuxInfoHeaders(50, &moof.tracks[0]);
604 AddAuxInfoHeaders(50, &moof.tracks[1]);
605 moof.tracks[0].auxiliary_size.default_sample_info_size = 8;
607 ASSERT_TRUE(iter_->Init(moof));
608 EXPECT_EQ(iter_->track_id(), 1u);
609 EXPECT_EQ(iter_->aux_info_offset(), 50);
610 EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
611 scoped_ptr<DecryptConfig> config = iter_->GetDecryptConfig();
612 ASSERT_EQ(arraysize(kIv1), config->iv().size());
613 EXPECT_TRUE(!memcmp(kIv1, config->iv().data(), config->iv().size()));
614 iter_->AdvanceSample();
615 EXPECT_EQ(iter_->GetMaxClearOffset(), 50);
616 iter_->AdvanceRun();
617 EXPECT_EQ(iter_->GetMaxClearOffset(), 50);
618 EXPECT_EQ(iter_->aux_info_offset(), 50);
619 EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
620 EXPECT_EQ(iter_->GetMaxClearOffset(), 200);
621 ASSERT_EQ(arraysize(kIv1), config->iv().size());
622 EXPECT_TRUE(!memcmp(kIv1, config->iv().data(), config->iv().size()));
623 iter_->AdvanceSample();
624 EXPECT_EQ(iter_->GetMaxClearOffset(), 201);
627 // Sensible files are expected to place auxiliary information for a run
628 // immediately before the main data for that run. Alternative schemes are
629 // possible, however, including the somewhat reasonable behavior of placing all
630 // aux info at the head of the 'mdat' box together, and the completely
631 // unreasonable behavior demonstrated here:
632 // byte 50: track 2, run 1 aux info
633 // byte 100: track 1, run 1 data
634 // byte 200: track 2, run 1 data
635 // byte 201: track 1, run 2 aux info (*inside* track 2, run 1 data)
636 // byte 10000: track 1, run 2 data
637 // byte 20000: track 1, run 1 aux info
638 TEST_F(TrackRunIteratorTest, UnexpectedOrderingTest) {
639 AddEncryption(&moov_.tracks[0]);
640 AddEncryption(&moov_.tracks[1]);
641 iter_.reset(new TrackRunIterator(&moov_, media_log_));
643 MovieFragment moof = CreateFragment();
644 AddAuxInfoHeaders(20000, &moof.tracks[0]);
645 moof.tracks[0].auxiliary_offset.offsets.push_back(201);
646 moof.tracks[0].auxiliary_size.sample_count += 2;
647 moof.tracks[0].auxiliary_size.default_sample_info_size = 8;
648 moof.tracks[0].runs[1].sample_count = 2;
649 AddAuxInfoHeaders(50, &moof.tracks[1]);
650 moof.tracks[1].runs[0].sample_sizes[0] = 5;
652 ASSERT_TRUE(iter_->Init(moof));
653 EXPECT_EQ(iter_->track_id(), 2u);
654 EXPECT_EQ(iter_->aux_info_offset(), 50);
655 EXPECT_EQ(iter_->sample_offset(), 200);
656 EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
657 EXPECT_EQ(iter_->GetMaxClearOffset(), 100);
658 iter_->AdvanceRun();
659 EXPECT_EQ(iter_->track_id(), 1u);
660 EXPECT_EQ(iter_->aux_info_offset(), 20000);
661 EXPECT_EQ(iter_->sample_offset(), 100);
662 EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
663 EXPECT_EQ(iter_->GetMaxClearOffset(), 100);
664 iter_->AdvanceSample();
665 EXPECT_EQ(iter_->GetMaxClearOffset(), 101);
666 iter_->AdvanceRun();
667 EXPECT_EQ(iter_->track_id(), 1u);
668 EXPECT_EQ(iter_->aux_info_offset(), 201);
669 EXPECT_EQ(iter_->sample_offset(), 10000);
670 EXPECT_EQ(iter_->GetMaxClearOffset(), 201);
671 EXPECT_TRUE(iter_->CacheAuxInfo(kAuxInfo, arraysize(kAuxInfo)));
672 EXPECT_EQ(iter_->GetMaxClearOffset(), 10000);
675 TEST_F(TrackRunIteratorTest, MissingAndEmptyStss) {
676 MovieFragment moof = CreateFragment();
678 // Setup track 0 to not have an stss box, which means that all samples should
679 // be marked as random access points unless the kSampleIsNonSyncSample flag is
680 // set in the sample flags.
681 moov_.tracks[0].media.information.sample_table.sync_sample.is_present = false;
682 moov_.tracks[0].media.information.sample_table.sync_sample.entries.resize(0);
683 moof.tracks[0].runs.resize(1);
684 moof.tracks[0].runs[0].sample_count = 6;
685 moof.tracks[0].runs[0].data_offset = 100;
686 SetFlagsOnSamples("US UN OS ON NS NN", &moof.tracks[0].runs[0]);
688 // Setup track 1 to have an stss box with no entries, which normally means
689 // that none of the samples should be random access points. If the
690 // kSampleIsNonSyncSample flag is NOT set though, the sample should be
691 // considered a random access point.
692 moov_.tracks[1].media.information.sample_table.sync_sample.is_present = true;
693 moov_.tracks[1].media.information.sample_table.sync_sample.entries.resize(0);
694 moof.tracks[1].runs.resize(1);
695 moof.tracks[1].runs[0].sample_count = 6;
696 moof.tracks[1].runs[0].data_offset = 200;
697 SetFlagsOnSamples("US UN OS ON NS NN", &moof.tracks[1].runs[0]);
699 iter_.reset(new TrackRunIterator(&moov_, media_log_));
701 ASSERT_TRUE(iter_->Init(moof));
702 EXPECT_TRUE(iter_->IsRunValid());
704 // Verify that all samples except for the ones that have the
705 // kSampleIsNonSyncSample flag set are marked as random access points.
706 EXPECT_EQ("1 KR P PR P KR K", KeyframeAndRAPInfo(iter_.get()));
708 iter_->AdvanceRun();
710 // Verify that nothing is marked as a random access point.
711 EXPECT_EQ("2 KR P PR P KR K", KeyframeAndRAPInfo(iter_.get()));
715 } // namespace mp4
716 } // namespace media