Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / media / formats / mp2t / mp2t_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/mp2t/mp2t_stream_parser.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21
22 namespace media {
23 namespace mp2t {
24
25 namespace {
26
27 bool IsMonotonic(const StreamParser::BufferQueue& buffers) {
28   if (buffers.empty())
29     return true;
30
31   StreamParser::BufferQueue::const_iterator it1 = buffers.begin();
32   StreamParser::BufferQueue::const_iterator it2 = ++it1;
33   for ( ; it2 != buffers.end(); ++it1, ++it2) {
34     if ((*it2)->GetDecodeTimestamp() < (*it1)->GetDecodeTimestamp())
35       return false;
36   }
37   return true;
38 }
39
40 bool IsAlmostEqual(DecodeTimestamp t0, DecodeTimestamp t1) {
41   base::TimeDelta kMaxDeviation = base::TimeDelta::FromMilliseconds(5);
42   base::TimeDelta diff = t1 - t0;
43   return (diff >= -kMaxDeviation && diff <= kMaxDeviation);
44 }
45
46 }  // namespace
47
48 class Mp2tStreamParserTest : public testing::Test {
49  public:
50   Mp2tStreamParserTest()
51       : segment_count_(0),
52         config_count_(0),
53         audio_frame_count_(0),
54         video_frame_count_(0),
55         has_video_(true),
56         audio_min_dts_(kNoDecodeTimestamp()),
57         audio_max_dts_(kNoDecodeTimestamp()),
58         video_min_dts_(kNoDecodeTimestamp()),
59         video_max_dts_(kNoDecodeTimestamp()) {
60     bool has_sbr = false;
61     parser_.reset(new Mp2tStreamParser(has_sbr));
62   }
63
64  protected:
65   scoped_ptr<Mp2tStreamParser> parser_;
66   int segment_count_;
67   int config_count_;
68   int audio_frame_count_;
69   int video_frame_count_;
70   bool has_video_;
71   DecodeTimestamp audio_min_dts_;
72   DecodeTimestamp audio_max_dts_;
73   DecodeTimestamp video_min_dts_;
74   DecodeTimestamp video_max_dts_;
75
76   void ResetStats() {
77     segment_count_ = 0;
78     config_count_ = 0;
79     audio_frame_count_ = 0;
80     video_frame_count_ = 0;
81     audio_min_dts_ = kNoDecodeTimestamp();
82     audio_max_dts_ = kNoDecodeTimestamp();
83     video_min_dts_ = kNoDecodeTimestamp();
84     video_max_dts_ = kNoDecodeTimestamp();
85   }
86
87   bool AppendData(const uint8* data, size_t length) {
88     return parser_->Parse(data, length);
89   }
90
91   bool AppendDataInPieces(const uint8* data, size_t length, size_t piece_size) {
92     const uint8* start = data;
93     const uint8* end = data + length;
94     while (start < end) {
95       size_t append_size = std::min(piece_size,
96                                     static_cast<size_t>(end - start));
97       if (!AppendData(start, append_size))
98         return false;
99       start += append_size;
100     }
101     return true;
102   }
103
104   void OnInit(bool init_ok,
105               const StreamParser::InitParameters& params) {
106     DVLOG(1) << "OnInit: ok=" << init_ok
107              << ", dur=" << params.duration.InMilliseconds()
108              << ", autoTimestampOffset=" << params.auto_update_timestamp_offset;
109   }
110
111   bool OnNewConfig(const AudioDecoderConfig& ac,
112                    const VideoDecoderConfig& vc,
113                    const StreamParser::TextTrackConfigMap& tc) {
114     DVLOG(1) << "OnNewConfig: audio=" << ac.IsValidConfig()
115              << ", video=" << vc.IsValidConfig();
116     config_count_++;
117     EXPECT_TRUE(ac.IsValidConfig());
118     EXPECT_EQ(vc.IsValidConfig(), has_video_);
119     return true;
120   }
121
122
123   void DumpBuffers(const std::string& label,
124                    const StreamParser::BufferQueue& buffers) {
125     DVLOG(2) << "DumpBuffers: " << label << " size " << buffers.size();
126     for (StreamParser::BufferQueue::const_iterator buf = buffers.begin();
127          buf != buffers.end(); buf++) {
128       DVLOG(3) << "  n=" << buf - buffers.begin()
129                << ", size=" << (*buf)->data_size()
130                << ", dur=" << (*buf)->duration().InMilliseconds();
131     }
132   }
133
134   bool OnNewBuffers(const StreamParser::BufferQueue& audio_buffers,
135                     const StreamParser::BufferQueue& video_buffers,
136                     const StreamParser::TextBufferQueueMap& text_map) {
137     EXPECT_GT(config_count_, 0);
138     DumpBuffers("audio_buffers", audio_buffers);
139     DumpBuffers("video_buffers", video_buffers);
140
141     // TODO(wolenetz/acolwell): Add text track support to more MSE parsers. See
142     // http://crbug.com/336926.
143     if (!text_map.empty())
144       return false;
145
146     // Verify monotonicity.
147     if (!IsMonotonic(video_buffers))
148       return false;
149     if (!IsMonotonic(audio_buffers))
150       return false;
151
152     if (!video_buffers.empty()) {
153       DecodeTimestamp first_dts = video_buffers.front()->GetDecodeTimestamp();
154       DecodeTimestamp last_dts = video_buffers.back()->GetDecodeTimestamp();
155       if (video_max_dts_ != kNoDecodeTimestamp() && first_dts < video_max_dts_)
156         return false;
157       if (video_min_dts_ == kNoDecodeTimestamp())
158         video_min_dts_ = first_dts;
159       video_max_dts_ = last_dts;
160     }
161     if (!audio_buffers.empty()) {
162       DecodeTimestamp first_dts = audio_buffers.front()->GetDecodeTimestamp();
163       DecodeTimestamp last_dts = audio_buffers.back()->GetDecodeTimestamp();
164       if (audio_max_dts_ != kNoDecodeTimestamp() && first_dts < audio_max_dts_)
165         return false;
166       if (audio_min_dts_ == kNoDecodeTimestamp())
167         audio_min_dts_ = first_dts;
168       audio_max_dts_ = last_dts;
169     }
170
171     audio_frame_count_ += audio_buffers.size();
172     video_frame_count_ += video_buffers.size();
173     return true;
174   }
175
176   void OnKeyNeeded(const std::string& type,
177                    const std::vector<uint8>& init_data) {
178     NOTREACHED() << "OnKeyNeeded not expected in the Mpeg2 TS parser";
179   }
180
181   void OnNewSegment() {
182     DVLOG(1) << "OnNewSegment";
183     segment_count_++;
184   }
185
186   void OnEndOfSegment() {
187     NOTREACHED() << "OnEndOfSegment not expected in the Mpeg2 TS parser";
188   }
189
190   void InitializeParser() {
191     parser_->Init(
192         base::Bind(&Mp2tStreamParserTest::OnInit,
193                    base::Unretained(this)),
194         base::Bind(&Mp2tStreamParserTest::OnNewConfig,
195                    base::Unretained(this)),
196         base::Bind(&Mp2tStreamParserTest::OnNewBuffers,
197                    base::Unretained(this)),
198         true,
199         base::Bind(&Mp2tStreamParserTest::OnKeyNeeded,
200                    base::Unretained(this)),
201         base::Bind(&Mp2tStreamParserTest::OnNewSegment,
202                    base::Unretained(this)),
203         base::Bind(&Mp2tStreamParserTest::OnEndOfSegment,
204                    base::Unretained(this)),
205         LogCB());
206   }
207
208   bool ParseMpeg2TsFile(const std::string& filename, int append_bytes) {
209     scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(filename);
210     EXPECT_TRUE(AppendDataInPieces(buffer->data(),
211                                    buffer->data_size(),
212                                    append_bytes));
213     return true;
214   }
215 };
216
217 TEST_F(Mp2tStreamParserTest, UnalignedAppend17) {
218   // Test small, non-segment-aligned appends.
219   InitializeParser();
220   ParseMpeg2TsFile("bear-1280x720.ts", 17);
221   parser_->Flush();
222   EXPECT_EQ(video_frame_count_, 82);
223   // This stream has no mid-stream configuration change.
224   EXPECT_EQ(config_count_, 1);
225   EXPECT_EQ(segment_count_, 1);
226 }
227
228 TEST_F(Mp2tStreamParserTest, UnalignedAppend512) {
229   // Test small, non-segment-aligned appends.
230   InitializeParser();
231   ParseMpeg2TsFile("bear-1280x720.ts", 512);
232   parser_->Flush();
233   EXPECT_EQ(video_frame_count_, 82);
234   // This stream has no mid-stream configuration change.
235   EXPECT_EQ(config_count_, 1);
236   EXPECT_EQ(segment_count_, 1);
237 }
238
239 TEST_F(Mp2tStreamParserTest, AppendAfterFlush512) {
240   InitializeParser();
241   ParseMpeg2TsFile("bear-1280x720.ts", 512);
242   parser_->Flush();
243   EXPECT_EQ(video_frame_count_, 82);
244   EXPECT_EQ(config_count_, 1);
245   EXPECT_EQ(segment_count_, 1);
246
247   ResetStats();
248   ParseMpeg2TsFile("bear-1280x720.ts", 512);
249   parser_->Flush();
250   EXPECT_EQ(video_frame_count_, 82);
251   EXPECT_EQ(config_count_, 1);
252   EXPECT_EQ(segment_count_, 1);
253 }
254
255 TEST_F(Mp2tStreamParserTest, TimestampWrapAround) {
256   // "bear-1280x720_ptswraparound.ts" has been transcoded
257   // from bear-1280x720.mp4 by applying a time offset of 95442s
258   // (close to 2^33 / 90000) which results in timestamps wrap around
259   // in the Mpeg2 TS stream.
260   InitializeParser();
261   ParseMpeg2TsFile("bear-1280x720_ptswraparound.ts", 512);
262   parser_->Flush();
263   EXPECT_EQ(video_frame_count_, 82);
264
265   EXPECT_TRUE(IsAlmostEqual(video_min_dts_,
266                             DecodeTimestamp::FromSecondsD(95443.376)));
267   EXPECT_TRUE(IsAlmostEqual(video_max_dts_,
268                             DecodeTimestamp::FromSecondsD(95446.079)));
269
270   // Note: for audio, AdtsStreamParser considers only the PTS (which is then
271   // used as the DTS).
272   // TODO(damienv): most of the time, audio streams just have PTS. Here, only
273   // the first PES packet has a DTS, all the other PES packets have PTS only.
274   // Reconsider the expected value for |audio_min_dts_| if DTS are used as part
275   // of the ADTS stream parser.
276   //
277   // Note: the last pts for audio is 95445.931 but this PES packet includes
278   // 9 ADTS frames with 1 AAC frame in each ADTS frame.
279   // So the PTS of the last AAC frame is:
280   // 95445.931 + 8 * (1024 / 44100) = 95446.117
281   EXPECT_TRUE(IsAlmostEqual(audio_min_dts_,
282                             DecodeTimestamp::FromSecondsD(95443.400)));
283   EXPECT_TRUE(IsAlmostEqual(audio_max_dts_,
284                             DecodeTimestamp::FromSecondsD(95446.117)));
285 }
286
287 TEST_F(Mp2tStreamParserTest, AudioInPrivateStream1) {
288   // Test small, non-segment-aligned appends.
289   InitializeParser();
290   has_video_ = false;
291   ParseMpeg2TsFile("bear_adts_in_private_stream_1.ts", 512);
292   parser_->Flush();
293   EXPECT_EQ(audio_frame_count_, 40);
294   EXPECT_EQ(video_frame_count_, 0);
295   // This stream has no mid-stream configuration change.
296   EXPECT_EQ(config_count_, 1);
297   EXPECT_EQ(segment_count_, 1);
298 }
299
300 }  // namespace mp2t
301 }  // namespace media