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 <algorithm>
      6 #include <string>
      7 
      8 #include "base/bind.h"
      9 #include "base/bind_helpers.h"
     10 #include "base/logging.h"
     11 #include "base/memory/ref_counted.h"
     12 #include "base/time/time.h"
     13 #include "media/base/audio_decoder_config.h"
     14 #include "media/base/decoder_buffer.h"
     15 #include "media/base/stream_parser_buffer.h"
     16 #include "media/base/test_data_util.h"
     17 #include "media/base/video_decoder_config.h"
     18 #include "media/mp4/es_descriptor.h"
     19 #include "media/mp4/mp4_stream_parser.h"
     20 #include "testing/gtest/include/gtest/gtest.h"
     21 
     22 using base::TimeDelta;
     23 
     24 namespace media {
     25 namespace mp4 {
     26 
     27 // TODO(xhwang): Figure out the init data type appropriately once it's spec'ed.
     28 static const char kMp4InitDataType[] = "video/mp4";
     29 
     30 class MP4StreamParserTest : public testing::Test {
     31  public:
     32   MP4StreamParserTest()
     33       : configs_received_(false) {
     34     std::set<int> audio_object_types;
     35     audio_object_types.insert(kISO_14496_3);
     36     parser_.reset(new MP4StreamParser(audio_object_types, false));
     37   }
     38 
     39  protected:
     40   scoped_ptr<MP4StreamParser> parser_;
     41   bool configs_received_;
     42 
     43   bool AppendData(const uint8* data, size_t length) {
     44     return parser_->Parse(data, length);
     45   }
     46 
     47   bool AppendDataInPieces(const uint8* data, size_t length, size_t piece_size) {
     48     const uint8* start = data;
     49     const uint8* end = data + length;
     50     while (start < end) {
     51       size_t append_size = std::min(piece_size,
     52                                     static_cast<size_t>(end - start));
     53       if (!AppendData(start, append_size))
     54         return false;
     55       start += append_size;
     56     }
     57     return true;
     58   }
     59 
     60   void InitF(bool init_ok, base::TimeDelta duration) {
     61     DVLOG(1) << "InitF: ok=" << init_ok
     62              << ", dur=" << duration.InMilliseconds();
     63   }
     64 
     65   bool NewConfigF(const AudioDecoderConfig& ac, const VideoDecoderConfig& vc) {
     66     DVLOG(1) << "NewConfigF: audio=" << ac.IsValidConfig()
     67              << ", video=" << vc.IsValidConfig();
     68     configs_received_ = true;
     69     return true;
     70   }
     71 
     72 
     73   void DumpBuffers(const std::string& label,
     74                    const StreamParser::BufferQueue& buffers) {
     75     DVLOG(2) << "DumpBuffers: " << label << " size " << buffers.size();
     76     for (StreamParser::BufferQueue::const_iterator buf = buffers.begin();
     77          buf != buffers.end(); buf++) {
     78       DVLOG(3) << "  n=" << buf - buffers.begin()
     79                << ", size=" << (*buf)->data_size()
     80                << ", dur=" << (*buf)->duration().InMilliseconds();
     81     }
     82   }
     83 
     84   bool NewBuffersF(const StreamParser::BufferQueue& audio_buffers,
     85                    const StreamParser::BufferQueue& video_buffers) {
     86     DumpBuffers("audio_buffers", audio_buffers);
     87     DumpBuffers("video_buffers", video_buffers);
     88     return true;
     89   }
     90 
     91   bool NewTextBuffersF(TextTrack* text_track,
     92                        const StreamParser::BufferQueue& buffers) {
     93     return true;
     94   }
     95 
     96   void KeyNeededF(const std::string& type,
     97                   scoped_ptr<uint8[]> init_data, int init_data_size) {
     98     DVLOG(1) << "KeyNeededF: " << init_data_size;
     99     EXPECT_EQ(kMp4InitDataType, type);
    100     EXPECT_TRUE(init_data.get());
    101     EXPECT_GT(init_data_size, 0);
    102   }
    103 
    104   scoped_ptr<TextTrack> AddTextTrackF(
    105       TextKind kind,
    106       const std::string& label,
    107       const std::string& language) {
    108     return scoped_ptr<TextTrack>();
    109   }
    110 
    111   void NewSegmentF() {
    112     DVLOG(1) << "NewSegmentF";
    113   }
    114 
    115   void EndOfSegmentF() {
    116     DVLOG(1) << "EndOfSegmentF()";
    117   }
    118 
    119   void InitializeParser() {
    120     parser_->Init(
    121         base::Bind(&MP4StreamParserTest::InitF, base::Unretained(this)),
    122         base::Bind(&MP4StreamParserTest::NewConfigF, base::Unretained(this)),
    123         base::Bind(&MP4StreamParserTest::NewBuffersF, base::Unretained(this)),
    124         base::Bind(&MP4StreamParserTest::NewTextBuffersF,
    125                    base::Unretained(this)),
    126         base::Bind(&MP4StreamParserTest::KeyNeededF, base::Unretained(this)),
    127         base::Bind(&MP4StreamParserTest::AddTextTrackF, base::Unretained(this)),
    128         base::Bind(&MP4StreamParserTest::NewSegmentF, base::Unretained(this)),
    129         base::Bind(&MP4StreamParserTest::EndOfSegmentF,
    130                    base::Unretained(this)),
    131         LogCB());
    132   }
    133 
    134   bool ParseMP4File(const std::string& filename, int append_bytes) {
    135     InitializeParser();
    136 
    137     scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(filename);
    138     EXPECT_TRUE(AppendDataInPieces(buffer->data(),
    139                                    buffer->data_size(),
    140                                    append_bytes));
    141     return true;
    142   }
    143 };
    144 
    145 TEST_F(MP4StreamParserTest, UnalignedAppend) {
    146   // Test small, non-segment-aligned appends (small enough to exercise
    147   // incremental append system)
    148   ParseMP4File("bear-1280x720-av_frag.mp4", 512);
    149 }
    150 
    151 TEST_F(MP4StreamParserTest, BytewiseAppend) {
    152   // Ensure no incremental errors occur when parsing
    153   ParseMP4File("bear-1280x720-av_frag.mp4", 1);
    154 }
    155 
    156 TEST_F(MP4StreamParserTest, MultiFragmentAppend) {
    157   // Large size ensures multiple fragments are appended in one call (size is
    158   // larger than this particular test file)
    159   ParseMP4File("bear-1280x720-av_frag.mp4", 768432);
    160 }
    161 
    162 TEST_F(MP4StreamParserTest, Flush) {
    163   // Flush while reading sample data, then start a new stream.
    164   InitializeParser();
    165 
    166   scoped_refptr<DecoderBuffer> buffer =
    167       ReadTestDataFile("bear-1280x720-av_frag.mp4");
    168   EXPECT_TRUE(AppendDataInPieces(buffer->data(), 65536, 512));
    169   parser_->Flush();
    170   EXPECT_TRUE(AppendDataInPieces(buffer->data(),
    171                                  buffer->data_size(),
    172                                  512));
    173 }
    174 
    175 TEST_F(MP4StreamParserTest, Reinitialization) {
    176   InitializeParser();
    177 
    178   scoped_refptr<DecoderBuffer> buffer =
    179       ReadTestDataFile("bear-1280x720-av_frag.mp4");
    180   EXPECT_TRUE(AppendDataInPieces(buffer->data(),
    181                                  buffer->data_size(),
    182                                  512));
    183   EXPECT_TRUE(AppendDataInPieces(buffer->data(),
    184                                  buffer->data_size(),
    185                                  512));
    186 }
    187 
    188 TEST_F(MP4StreamParserTest, MPEG2_AAC_LC) {
    189   std::set<int> audio_object_types;
    190   audio_object_types.insert(kISO_13818_7_AAC_LC);
    191   parser_.reset(new MP4StreamParser(audio_object_types, false));
    192   ParseMP4File("bear-mpeg2-aac-only_frag.mp4", 512);
    193 }
    194 
    195 // Test that a moov box is not always required after Flush() is called.
    196 TEST_F(MP4StreamParserTest, NoMoovAfterFlush) {
    197   InitializeParser();
    198 
    199   scoped_refptr<DecoderBuffer> buffer =
    200       ReadTestDataFile("bear-1280x720-av_frag.mp4");
    201   EXPECT_TRUE(AppendDataInPieces(buffer->data(),
    202                                  buffer->data_size(),
    203                                  512));
    204   parser_->Flush();
    205 
    206   const int kFirstMoofOffset = 1307;
    207   EXPECT_TRUE(AppendDataInPieces(buffer->data() + kFirstMoofOffset,
    208                                  buffer->data_size() - kFirstMoofOffset,
    209                                  512));
    210 }
    211 
    212 // TODO(strobe): Create and test media which uses CENC auxiliary info stored
    213 // inside a private box
    214 
    215 }  // namespace mp4
    216 }  // namespace media
    217