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.
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"
27 bool IsMonotonic(const StreamParser::BufferQueue& buffers) {
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())
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);
48 class Mp2tStreamParserTest : public testing::Test {
50 Mp2tStreamParserTest()
53 audio_frame_count_(0),
54 video_frame_count_(0),
56 audio_min_dts_(kNoDecodeTimestamp()),
57 audio_max_dts_(kNoDecodeTimestamp()),
58 video_min_dts_(kNoDecodeTimestamp()),
59 video_max_dts_(kNoDecodeTimestamp()) {
61 parser_.reset(new Mp2tStreamParser(has_sbr));
65 scoped_ptr<Mp2tStreamParser> parser_;
68 int audio_frame_count_;
69 int video_frame_count_;
71 DecodeTimestamp audio_min_dts_;
72 DecodeTimestamp audio_max_dts_;
73 DecodeTimestamp video_min_dts_;
74 DecodeTimestamp video_max_dts_;
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();
87 bool AppendData(const uint8* data, size_t length) {
88 return parser_->Parse(data, length);
91 bool AppendDataInPieces(const uint8* data, size_t length, size_t piece_size) {
92 const uint8* start = data;
93 const uint8* end = data + length;
95 size_t append_size = std::min(piece_size,
96 static_cast<size_t>(end - start));
97 if (!AppendData(start, append_size))
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;
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();
117 EXPECT_TRUE(ac.IsValidConfig());
118 EXPECT_EQ(vc.IsValidConfig(), has_video_);
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();
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);
141 // TODO(wolenetz/acolwell): Add text track support to more MSE parsers. See
142 // http://crbug.com/336926.
143 if (!text_map.empty())
146 // Verify monotonicity.
147 if (!IsMonotonic(video_buffers))
149 if (!IsMonotonic(audio_buffers))
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_)
157 if (video_min_dts_ == kNoDecodeTimestamp())
158 video_min_dts_ = first_dts;
159 video_max_dts_ = last_dts;
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_)
166 if (audio_min_dts_ == kNoDecodeTimestamp())
167 audio_min_dts_ = first_dts;
168 audio_max_dts_ = last_dts;
171 audio_frame_count_ += audio_buffers.size();
172 video_frame_count_ += video_buffers.size();
176 void OnKeyNeeded(const std::string& type,
177 const std::vector<uint8>& init_data) {
178 NOTREACHED() << "OnKeyNeeded not expected in the Mpeg2 TS parser";
181 void OnNewSegment() {
182 DVLOG(1) << "OnNewSegment";
186 void OnEndOfSegment() {
187 NOTREACHED() << "OnEndOfSegment not expected in the Mpeg2 TS parser";
190 void InitializeParser() {
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)),
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)),
208 bool ParseMpeg2TsFile(const std::string& filename, int append_bytes) {
209 scoped_refptr<DecoderBuffer> buffer = ReadTestDataFile(filename);
210 EXPECT_TRUE(AppendDataInPieces(buffer->data(),
217 TEST_F(Mp2tStreamParserTest, UnalignedAppend17) {
218 // Test small, non-segment-aligned appends.
220 ParseMpeg2TsFile("bear-1280x720.ts", 17);
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);
228 TEST_F(Mp2tStreamParserTest, UnalignedAppend512) {
229 // Test small, non-segment-aligned appends.
231 ParseMpeg2TsFile("bear-1280x720.ts", 512);
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);
239 TEST_F(Mp2tStreamParserTest, AppendAfterFlush512) {
241 ParseMpeg2TsFile("bear-1280x720.ts", 512);
243 EXPECT_EQ(video_frame_count_, 82);
244 EXPECT_EQ(config_count_, 1);
245 EXPECT_EQ(segment_count_, 1);
248 ParseMpeg2TsFile("bear-1280x720.ts", 512);
250 EXPECT_EQ(video_frame_count_, 82);
251 EXPECT_EQ(config_count_, 1);
252 EXPECT_EQ(segment_count_, 1);
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.
261 ParseMpeg2TsFile("bear-1280x720_ptswraparound.ts", 512);
263 EXPECT_EQ(video_frame_count_, 82);
265 EXPECT_TRUE(IsAlmostEqual(video_min_dts_,
266 DecodeTimestamp::FromSecondsD(95443.376)));
267 EXPECT_TRUE(IsAlmostEqual(video_max_dts_,
268 DecodeTimestamp::FromSecondsD(95446.079)));
270 // Note: for audio, AdtsStreamParser considers only the PTS (which is then
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.
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)));
287 TEST_F(Mp2tStreamParserTest, AudioInPrivateStream1) {
288 // Test small, non-segment-aligned appends.
291 ParseMpeg2TsFile("bear_adts_in_private_stream_1.ts", 512);
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);