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(const StreamParser::InitParameters
& params
) {
105 DVLOG(1) << "OnInit: dur=" << params
.duration
.InMilliseconds()
106 << ", autoTimestampOffset=" << params
.auto_update_timestamp_offset
;
109 bool OnNewConfig(const AudioDecoderConfig
& ac
,
110 const VideoDecoderConfig
& vc
,
111 const StreamParser::TextTrackConfigMap
& tc
) {
112 DVLOG(1) << "OnNewConfig: audio=" << ac
.IsValidConfig()
113 << ", video=" << vc
.IsValidConfig();
115 EXPECT_TRUE(ac
.IsValidConfig());
116 EXPECT_EQ(vc
.IsValidConfig(), has_video_
);
121 void DumpBuffers(const std::string
& label
,
122 const StreamParser::BufferQueue
& buffers
) {
123 DVLOG(2) << "DumpBuffers: " << label
<< " size " << buffers
.size();
124 for (StreamParser::BufferQueue::const_iterator buf
= buffers
.begin();
125 buf
!= buffers
.end(); buf
++) {
126 DVLOG(3) << " n=" << buf
- buffers
.begin()
127 << ", size=" << (*buf
)->data_size()
128 << ", dur=" << (*buf
)->duration().InMilliseconds();
132 bool OnNewBuffers(const StreamParser::BufferQueue
& audio_buffers
,
133 const StreamParser::BufferQueue
& video_buffers
,
134 const StreamParser::TextBufferQueueMap
& text_map
) {
135 EXPECT_GT(config_count_
, 0);
136 DumpBuffers("audio_buffers", audio_buffers
);
137 DumpBuffers("video_buffers", video_buffers
);
139 // TODO(wolenetz/acolwell): Add text track support to more MSE parsers. See
140 // http://crbug.com/336926.
141 if (!text_map
.empty())
144 // Verify monotonicity.
145 if (!IsMonotonic(video_buffers
))
147 if (!IsMonotonic(audio_buffers
))
150 if (!video_buffers
.empty()) {
151 DecodeTimestamp first_dts
= video_buffers
.front()->GetDecodeTimestamp();
152 DecodeTimestamp last_dts
= video_buffers
.back()->GetDecodeTimestamp();
153 if (video_max_dts_
!= kNoDecodeTimestamp() && first_dts
< video_max_dts_
)
155 if (video_min_dts_
== kNoDecodeTimestamp())
156 video_min_dts_
= first_dts
;
157 video_max_dts_
= last_dts
;
159 if (!audio_buffers
.empty()) {
160 DecodeTimestamp first_dts
= audio_buffers
.front()->GetDecodeTimestamp();
161 DecodeTimestamp last_dts
= audio_buffers
.back()->GetDecodeTimestamp();
162 if (audio_max_dts_
!= kNoDecodeTimestamp() && first_dts
< audio_max_dts_
)
164 if (audio_min_dts_
== kNoDecodeTimestamp())
165 audio_min_dts_
= first_dts
;
166 audio_max_dts_
= last_dts
;
169 audio_frame_count_
+= audio_buffers
.size();
170 video_frame_count_
+= video_buffers
.size();
174 void OnKeyNeeded(EmeInitDataType type
, const std::vector
<uint8
>& init_data
) {
175 NOTREACHED() << "OnKeyNeeded not expected in the Mpeg2 TS parser";
178 void OnNewSegment() {
179 DVLOG(1) << "OnNewSegment";
183 void OnEndOfSegment() {
184 NOTREACHED() << "OnEndOfSegment not expected in the Mpeg2 TS parser";
187 void InitializeParser() {
189 base::Bind(&Mp2tStreamParserTest::OnInit
, base::Unretained(this)),
190 base::Bind(&Mp2tStreamParserTest::OnNewConfig
, base::Unretained(this)),
191 base::Bind(&Mp2tStreamParserTest::OnNewBuffers
, base::Unretained(this)),
193 base::Bind(&Mp2tStreamParserTest::OnKeyNeeded
, base::Unretained(this)),
194 base::Bind(&Mp2tStreamParserTest::OnNewSegment
, base::Unretained(this)),
195 base::Bind(&Mp2tStreamParserTest::OnEndOfSegment
,
196 base::Unretained(this)),
200 bool ParseMpeg2TsFile(const std::string
& filename
, int append_bytes
) {
201 scoped_refptr
<DecoderBuffer
> buffer
= ReadTestDataFile(filename
);
202 EXPECT_TRUE(AppendDataInPieces(buffer
->data(),
209 TEST_F(Mp2tStreamParserTest
, UnalignedAppend17
) {
210 // Test small, non-segment-aligned appends.
212 ParseMpeg2TsFile("bear-1280x720.ts", 17);
214 EXPECT_EQ(video_frame_count_
, 82);
215 // This stream has no mid-stream configuration change.
216 EXPECT_EQ(config_count_
, 1);
217 EXPECT_EQ(segment_count_
, 1);
220 TEST_F(Mp2tStreamParserTest
, UnalignedAppend512
) {
221 // Test small, non-segment-aligned appends.
223 ParseMpeg2TsFile("bear-1280x720.ts", 512);
225 EXPECT_EQ(video_frame_count_
, 82);
226 // This stream has no mid-stream configuration change.
227 EXPECT_EQ(config_count_
, 1);
228 EXPECT_EQ(segment_count_
, 1);
231 TEST_F(Mp2tStreamParserTest
, AppendAfterFlush512
) {
233 ParseMpeg2TsFile("bear-1280x720.ts", 512);
235 EXPECT_EQ(video_frame_count_
, 82);
236 EXPECT_EQ(config_count_
, 1);
237 EXPECT_EQ(segment_count_
, 1);
240 ParseMpeg2TsFile("bear-1280x720.ts", 512);
242 EXPECT_EQ(video_frame_count_
, 82);
243 EXPECT_EQ(config_count_
, 1);
244 EXPECT_EQ(segment_count_
, 1);
247 TEST_F(Mp2tStreamParserTest
, TimestampWrapAround
) {
248 // "bear-1280x720_ptswraparound.ts" has been transcoded
249 // from bear-1280x720.mp4 by applying a time offset of 95442s
250 // (close to 2^33 / 90000) which results in timestamps wrap around
251 // in the Mpeg2 TS stream.
253 ParseMpeg2TsFile("bear-1280x720_ptswraparound.ts", 512);
255 EXPECT_EQ(video_frame_count_
, 82);
257 EXPECT_TRUE(IsAlmostEqual(video_min_dts_
,
258 DecodeTimestamp::FromSecondsD(95443.376)));
259 EXPECT_TRUE(IsAlmostEqual(video_max_dts_
,
260 DecodeTimestamp::FromSecondsD(95446.079)));
262 // Note: for audio, AdtsStreamParser considers only the PTS (which is then
264 // TODO(damienv): most of the time, audio streams just have PTS. Here, only
265 // the first PES packet has a DTS, all the other PES packets have PTS only.
266 // Reconsider the expected value for |audio_min_dts_| if DTS are used as part
267 // of the ADTS stream parser.
269 // Note: the last pts for audio is 95445.931 but this PES packet includes
270 // 9 ADTS frames with 1 AAC frame in each ADTS frame.
271 // So the PTS of the last AAC frame is:
272 // 95445.931 + 8 * (1024 / 44100) = 95446.117
273 EXPECT_TRUE(IsAlmostEqual(audio_min_dts_
,
274 DecodeTimestamp::FromSecondsD(95443.400)));
275 EXPECT_TRUE(IsAlmostEqual(audio_max_dts_
,
276 DecodeTimestamp::FromSecondsD(95446.117)));
279 TEST_F(Mp2tStreamParserTest
, AudioInPrivateStream1
) {
280 // Test small, non-segment-aligned appends.
283 ParseMpeg2TsFile("bear_adts_in_private_stream_1.ts", 512);
285 EXPECT_EQ(audio_frame_count_
, 40);
286 EXPECT_EQ(video_frame_count_
, 0);
287 // This stream has no mid-stream configuration change.
288 EXPECT_EQ(config_count_
, 1);
289 EXPECT_EQ(segment_count_
, 1);