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