Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / media / formats / mp4 / mp4_stream_parser_unittest.cc
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 <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/text_track_config.h"
18 #include "media/base/video_decoder_config.h"
19 #include "media/formats/mp4/es_descriptor.h"
20 #include "media/formats/mp4/mp4_stream_parser.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
23 using base::TimeDelta;
24
25 namespace media {
26 namespace mp4 {
27
28 static const char kCencInitDataType[] = "cenc";
29
30 class MP4StreamParserTest : public testing::Test {
31  public:
32   MP4StreamParserTest()
33       : configs_received_(false),
34         lower_bound_(
35             DecodeTimestamp::FromPresentationTime(base::TimeDelta::Max())) {
36     std::set<int> audio_object_types;
37     audio_object_types.insert(kISO_14496_3);
38     parser_.reset(new MP4StreamParser(audio_object_types, false));
39   }
40
41  protected:
42   scoped_ptr<MP4StreamParser> parser_;
43   bool configs_received_;
44   DecodeTimestamp lower_bound_;
45
46   bool AppendData(const uint8* data, size_t length) {
47     return parser_->Parse(data, length);
48   }
49
50   bool AppendDataInPieces(const uint8* data, size_t length, size_t piece_size) {
51     const uint8* start = data;
52     const uint8* end = data + length;
53     while (start < end) {
54       size_t append_size = std::min(piece_size,
55                                     static_cast<size_t>(end - start));
56       if (!AppendData(start, append_size))
57         return false;
58       start += append_size;
59     }
60     return true;
61   }
62
63   void InitF(bool init_ok, const StreamParser::InitParameters& params) {
64     DVLOG(1) << "InitF: ok=" << init_ok
65              << ", dur=" << params.duration.InMilliseconds()
66              << ", autoTimestampOffset=" << params.auto_update_timestamp_offset;
67   }
68
69   bool NewConfigF(const AudioDecoderConfig& ac,
70                   const VideoDecoderConfig& vc,
71                   const StreamParser::TextTrackConfigMap& tc) {
72     DVLOG(1) << "NewConfigF: audio=" << ac.IsValidConfig()
73              << ", video=" << vc.IsValidConfig();
74     configs_received_ = true;
75     return true;
76   }
77
78   void DumpBuffers(const std::string& label,
79                    const StreamParser::BufferQueue& buffers) {
80     DVLOG(2) << "DumpBuffers: " << label << " size " << buffers.size();
81     for (StreamParser::BufferQueue::const_iterator buf = buffers.begin();
82          buf != buffers.end(); buf++) {
83       DVLOG(3) << "  n=" << buf - buffers.begin()
84                << ", size=" << (*buf)->data_size()
85                << ", dur=" << (*buf)->duration().InMilliseconds();
86     }
87   }
88
89   bool NewBuffersF(const StreamParser::BufferQueue& audio_buffers,
90                    const StreamParser::BufferQueue& video_buffers,
91                    const StreamParser::TextBufferQueueMap& text_map) {
92     DumpBuffers("audio_buffers", audio_buffers);
93     DumpBuffers("video_buffers", video_buffers);
94
95     // TODO(wolenetz/acolwell): Add text track support to more MSE parsers. See
96     // http://crbug.com/336926.
97     if (!text_map.empty())
98       return false;
99
100     // Find the second highest timestamp so that we know what the
101     // timestamps on the next set of buffers must be >= than.
102     DecodeTimestamp audio = !audio_buffers.empty() ?
103         audio_buffers.back()->GetDecodeTimestamp() : kNoDecodeTimestamp();
104     DecodeTimestamp video = !video_buffers.empty() ?
105         video_buffers.back()->GetDecodeTimestamp() : kNoDecodeTimestamp();
106     DecodeTimestamp second_highest_timestamp =
107         (audio == kNoDecodeTimestamp() ||
108          (video != kNoDecodeTimestamp() && audio > video)) ? video : audio;
109
110     DCHECK(second_highest_timestamp != kNoDecodeTimestamp());
111
112     if (lower_bound_ != kNoDecodeTimestamp() &&
113         second_highest_timestamp < lower_bound_) {
114       return false;
115     }
116
117     lower_bound_ = second_highest_timestamp;
118     return true;
119   }
120
121   void KeyNeededF(const std::string& type,
122                   const std::vector<uint8>& init_data) {
123     DVLOG(1) << "KeyNeededF: " << init_data.size();
124     EXPECT_EQ(kCencInitDataType, type);
125     EXPECT_FALSE(init_data.empty());
126   }
127
128   void NewSegmentF() {
129     DVLOG(1) << "NewSegmentF";
130     lower_bound_ = kNoDecodeTimestamp();
131   }
132
133   void EndOfSegmentF() {
134     DVLOG(1) << "EndOfSegmentF()";
135     lower_bound_ =
136         DecodeTimestamp::FromPresentationTime(base::TimeDelta::Max());
137   }
138
139   void InitializeParser() {
140     parser_->Init(
141         base::Bind(&MP4StreamParserTest::InitF, base::Unretained(this)),
142         base::Bind(&MP4StreamParserTest::NewConfigF, base::Unretained(this)),
143         base::Bind(&MP4StreamParserTest::NewBuffersF, base::Unretained(this)),
144         true,
145         base::Bind(&MP4StreamParserTest::KeyNeededF, base::Unretained(this)),
146         base::Bind(&MP4StreamParserTest::NewSegmentF, base::Unretained(this)),
147         base::Bind(&MP4StreamParserTest::EndOfSegmentF,
148                    base::Unretained(this)),
149         LogCB());
150   }
151
152   bool ParseMP4File(const std::string& filename, int append_bytes) {
153     InitializeParser();
154
155     scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(filename);
156     EXPECT_TRUE(AppendDataInPieces(buffer->data(),
157                                    buffer->data_size(),
158                                    append_bytes));
159     return true;
160   }
161 };
162
163 TEST_F(MP4StreamParserTest, UnalignedAppend) {
164   // Test small, non-segment-aligned appends (small enough to exercise
165   // incremental append system)
166   ParseMP4File("bear-1280x720-av_frag.mp4", 512);
167 }
168
169 TEST_F(MP4StreamParserTest, BytewiseAppend) {
170   // Ensure no incremental errors occur when parsing
171   ParseMP4File("bear-1280x720-av_frag.mp4", 1);
172 }
173
174 TEST_F(MP4StreamParserTest, MultiFragmentAppend) {
175   // Large size ensures multiple fragments are appended in one call (size is
176   // larger than this particular test file)
177   ParseMP4File("bear-1280x720-av_frag.mp4", 768432);
178 }
179
180 TEST_F(MP4StreamParserTest, Flush) {
181   // Flush while reading sample data, then start a new stream.
182   InitializeParser();
183
184   scoped_refptr<DecoderBuffer> buffer =
185       ReadTestDataFile("bear-1280x720-av_frag.mp4");
186   EXPECT_TRUE(AppendDataInPieces(buffer->data(), 65536, 512));
187   parser_->Flush();
188   EXPECT_TRUE(AppendDataInPieces(buffer->data(),
189                                  buffer->data_size(),
190                                  512));
191 }
192
193 TEST_F(MP4StreamParserTest, Reinitialization) {
194   InitializeParser();
195
196   scoped_refptr<DecoderBuffer> buffer =
197       ReadTestDataFile("bear-1280x720-av_frag.mp4");
198   EXPECT_TRUE(AppendDataInPieces(buffer->data(),
199                                  buffer->data_size(),
200                                  512));
201   EXPECT_TRUE(AppendDataInPieces(buffer->data(),
202                                  buffer->data_size(),
203                                  512));
204 }
205
206 TEST_F(MP4StreamParserTest, MPEG2_AAC_LC) {
207   std::set<int> audio_object_types;
208   audio_object_types.insert(kISO_13818_7_AAC_LC);
209   parser_.reset(new MP4StreamParser(audio_object_types, false));
210   ParseMP4File("bear-mpeg2-aac-only_frag.mp4", 512);
211 }
212
213 // Test that a moov box is not always required after Flush() is called.
214 TEST_F(MP4StreamParserTest, NoMoovAfterFlush) {
215   InitializeParser();
216
217   scoped_refptr<DecoderBuffer> buffer =
218       ReadTestDataFile("bear-1280x720-av_frag.mp4");
219   EXPECT_TRUE(AppendDataInPieces(buffer->data(),
220                                  buffer->data_size(),
221                                  512));
222   parser_->Flush();
223
224   const int kFirstMoofOffset = 1307;
225   EXPECT_TRUE(AppendDataInPieces(buffer->data() + kFirstMoofOffset,
226                                  buffer->data_size() - kFirstMoofOffset,
227                                  512));
228 }
229
230 // Test an invalid file where there are encrypted samples, but
231 // SampleAuxiliaryInformation{Sizes|Offsets}Box (saiz|saio) are missing.
232 // The parser should fail instead of crash. See http://crbug.com/361347
233 TEST_F(MP4StreamParserTest, MissingSampleAuxInfo) {
234   InitializeParser();
235
236   scoped_refptr<DecoderBuffer> buffer =
237       ReadTestDataFile("bear-1280x720-a_frag-cenc_missing-saiz-saio.mp4");
238   EXPECT_FALSE(AppendDataInPieces(buffer->data(), buffer->data_size(), 512));
239 }
240
241 // Test a file where all video samples start with an Access Unit
242 // Delimiter (AUD) NALU.
243 TEST_F(MP4StreamParserTest, VideoSamplesStartWithAUDs) {
244   ParseMP4File("bear-1280x720-av_with-aud-nalus_frag.mp4", 512);
245 }
246
247 // TODO(strobe): Create and test media which uses CENC auxiliary info stored
248 // inside a private box
249
250 }  // namespace mp4
251 }  // namespace media