Home | History | Annotate | Download | only in mp4
      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