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: 45 TrackRunIteratorTest() { 46 CreateMovie(); 47 } 48 49 protected: 50 Movie moov_; 51 LogCB log_cb_; 52 scoped_ptr<TrackRunIterator> iter_; 53 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 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 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. 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 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 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 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 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 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 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 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 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. 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 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