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