1 // Copyright (c) 2012 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 <deque> 7 #include <string> 8 9 #include "base/bind.h" 10 #include "base/files/file_path.h" 11 #include "base/logging.h" 12 #include "base/path_service.h" 13 #include "base/threading/thread.h" 14 #include "media/base/decrypt_config.h" 15 #include "media/base/media_log.h" 16 #include "media/base/mock_demuxer_host.h" 17 #include "media/base/test_helpers.h" 18 #include "media/ffmpeg/ffmpeg_common.h" 19 #include "media/filters/ffmpeg_demuxer.h" 20 #include "media/filters/file_data_source.h" 21 #include "media/formats/mp4/avc.h" 22 #include "media/formats/webm/webm_crypto_helpers.h" 23 #include "testing/gtest/include/gtest/gtest.h" 24 25 using ::testing::AnyNumber; 26 using ::testing::DoAll; 27 using ::testing::Exactly; 28 using ::testing::InSequence; 29 using ::testing::Invoke; 30 using ::testing::NotNull; 31 using ::testing::Return; 32 using ::testing::SaveArg; 33 using ::testing::SetArgPointee; 34 using ::testing::StrictMock; 35 using ::testing::WithArgs; 36 using ::testing::_; 37 38 namespace media { 39 40 MATCHER(IsEndOfStreamBuffer, 41 std::string(negation ? "isn't" : "is") + " end of stream") { 42 return arg->end_of_stream(); 43 } 44 45 static void EosOnReadDone(bool* got_eos_buffer, 46 DemuxerStream::Status status, 47 const scoped_refptr<DecoderBuffer>& buffer) { 48 base::MessageLoop::current()->PostTask( 49 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); 50 51 EXPECT_EQ(status, DemuxerStream::kOk); 52 if (buffer->end_of_stream()) { 53 *got_eos_buffer = true; 54 return; 55 } 56 57 EXPECT_TRUE(buffer->data()); 58 EXPECT_GT(buffer->data_size(), 0); 59 *got_eos_buffer = false; 60 }; 61 62 63 // Fixture class to facilitate writing tests. Takes care of setting up the 64 // FFmpeg, pipeline and filter host mocks. 65 class FFmpegDemuxerTest : public testing::Test { 66 protected: 67 FFmpegDemuxerTest() {} 68 69 virtual ~FFmpegDemuxerTest() { 70 if (demuxer_) { 71 WaitableMessageLoopEvent event; 72 demuxer_->Stop(event.GetClosure()); 73 event.RunAndWait(); 74 } 75 } 76 77 void CreateDemuxer(const std::string& name) { 78 CHECK(!demuxer_); 79 80 EXPECT_CALL(host_, AddBufferedTimeRange(_, _)).Times(AnyNumber()); 81 82 CreateDataSource(name); 83 84 Demuxer::NeedKeyCB need_key_cb = 85 base::Bind(&FFmpegDemuxerTest::NeedKeyCB, base::Unretained(this)); 86 87 demuxer_.reset(new FFmpegDemuxer(message_loop_.message_loop_proxy(), 88 data_source_.get(), 89 need_key_cb, 90 new MediaLog())); 91 } 92 93 MOCK_METHOD1(CheckPoint, void(int v)); 94 95 void InitializeDemuxerText(bool enable_text) { 96 EXPECT_CALL(host_, SetDuration(_)); 97 WaitableMessageLoopEvent event; 98 demuxer_->Initialize(&host_, event.GetPipelineStatusCB(), enable_text); 99 event.RunAndWaitForStatus(PIPELINE_OK); 100 } 101 102 void InitializeDemuxer() { 103 InitializeDemuxerText(false); 104 } 105 106 MOCK_METHOD2(OnReadDoneCalled, void(int, int64)); 107 108 // Verifies that |buffer| has a specific |size| and |timestamp|. 109 // |location| simply indicates where the call to this function was made. 110 // This makes it easier to track down where test failures occur. 111 void OnReadDone(const tracked_objects::Location& location, 112 int size, int64 timestampInMicroseconds, 113 DemuxerStream::Status status, 114 const scoped_refptr<DecoderBuffer>& buffer) { 115 std::string location_str; 116 location.Write(true, false, &location_str); 117 location_str += "\n"; 118 SCOPED_TRACE(location_str); 119 EXPECT_EQ(status, DemuxerStream::kOk); 120 OnReadDoneCalled(size, timestampInMicroseconds); 121 EXPECT_TRUE(buffer.get() != NULL); 122 EXPECT_EQ(size, buffer->data_size()); 123 EXPECT_EQ(base::TimeDelta::FromMicroseconds(timestampInMicroseconds), 124 buffer->timestamp()); 125 126 DCHECK_EQ(&message_loop_, base::MessageLoop::current()); 127 message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); 128 } 129 130 DemuxerStream::ReadCB NewReadCB(const tracked_objects::Location& location, 131 int size, int64 timestampInMicroseconds) { 132 EXPECT_CALL(*this, OnReadDoneCalled(size, timestampInMicroseconds)); 133 return base::Bind(&FFmpegDemuxerTest::OnReadDone, base::Unretained(this), 134 location, size, timestampInMicroseconds); 135 } 136 137 // TODO(xhwang): This is a workaround of the issue that move-only parameters 138 // are not supported in mocked methods. Remove this when the issue is fixed 139 // (http://code.google.com/p/googletest/issues/detail?id=395) or when we use 140 // std::string instead of scoped_ptr<uint8[]> (http://crbug.com/130689). 141 MOCK_METHOD3(NeedKeyCBMock, void(const std::string& type, 142 const uint8* init_data, int init_data_size)); 143 void NeedKeyCB(const std::string& type, 144 const std::vector<uint8>& init_data) { 145 const uint8* init_data_ptr = init_data.empty() ? NULL : &init_data[0]; 146 NeedKeyCBMock(type, init_data_ptr, init_data.size()); 147 } 148 149 // Accessor to demuxer internals. 150 void set_duration_known(bool duration_known) { 151 demuxer_->duration_known_ = duration_known; 152 } 153 154 bool IsStreamStopped(DemuxerStream::Type type) { 155 DemuxerStream* stream = demuxer_->GetStream(type); 156 CHECK(stream); 157 return !static_cast<FFmpegDemuxerStream*>(stream)->demuxer_; 158 } 159 160 // Fixture members. 161 scoped_ptr<FileDataSource> data_source_; 162 scoped_ptr<FFmpegDemuxer> demuxer_; 163 StrictMock<MockDemuxerHost> host_; 164 base::MessageLoop message_loop_; 165 166 AVFormatContext* format_context() { 167 return demuxer_->glue_->format_context(); 168 } 169 170 void ReadUntilEndOfStream(DemuxerStream* stream) { 171 bool got_eos_buffer = false; 172 const int kMaxBuffers = 170; 173 for (int i = 0; !got_eos_buffer && i < kMaxBuffers; i++) { 174 stream->Read(base::Bind(&EosOnReadDone, &got_eos_buffer)); 175 message_loop_.Run(); 176 } 177 178 EXPECT_TRUE(got_eos_buffer); 179 } 180 181 private: 182 void CreateDataSource(const std::string& name) { 183 CHECK(!data_source_); 184 185 base::FilePath file_path; 186 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &file_path)); 187 188 file_path = file_path.Append(FILE_PATH_LITERAL("media")) 189 .Append(FILE_PATH_LITERAL("test")) 190 .Append(FILE_PATH_LITERAL("data")) 191 .AppendASCII(name); 192 193 data_source_.reset(new FileDataSource()); 194 EXPECT_TRUE(data_source_->Initialize(file_path)); 195 } 196 197 DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest); 198 }; 199 200 TEST_F(FFmpegDemuxerTest, Initialize_OpenFails) { 201 // Simulate avformat_open_input() failing. 202 CreateDemuxer("ten_byte_file"); 203 WaitableMessageLoopEvent event; 204 demuxer_->Initialize(&host_, event.GetPipelineStatusCB(), true); 205 event.RunAndWaitForStatus(DEMUXER_ERROR_COULD_NOT_OPEN); 206 } 207 208 // TODO(acolwell): Uncomment this test when we discover a file that passes 209 // avformat_open_input(), but has avformat_find_stream_info() fail. 210 // 211 //TEST_F(FFmpegDemuxerTest, Initialize_ParseFails) { 212 // ("find_stream_info_fail.webm"); 213 // demuxer_->Initialize( 214 // &host_, NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_PARSE)); 215 // message_loop_.RunUntilIdle(); 216 //} 217 218 TEST_F(FFmpegDemuxerTest, Initialize_NoStreams) { 219 // Open a file with no streams whatsoever. 220 CreateDemuxer("no_streams.webm"); 221 WaitableMessageLoopEvent event; 222 demuxer_->Initialize(&host_, event.GetPipelineStatusCB(), true); 223 event.RunAndWaitForStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); 224 } 225 226 TEST_F(FFmpegDemuxerTest, Initialize_NoAudioVideo) { 227 // Open a file containing streams but none of which are audio/video streams. 228 CreateDemuxer("no_audio_video.webm"); 229 WaitableMessageLoopEvent event; 230 demuxer_->Initialize(&host_, event.GetPipelineStatusCB(), true); 231 event.RunAndWaitForStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); 232 } 233 234 TEST_F(FFmpegDemuxerTest, Initialize_Successful) { 235 CreateDemuxer("bear-320x240.webm"); 236 InitializeDemuxer(); 237 238 // Video stream should be present. 239 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); 240 ASSERT_TRUE(stream); 241 EXPECT_EQ(DemuxerStream::VIDEO, stream->type()); 242 243 const VideoDecoderConfig& video_config = stream->video_decoder_config(); 244 EXPECT_EQ(kCodecVP8, video_config.codec()); 245 EXPECT_EQ(VideoFrame::YV12, video_config.format()); 246 EXPECT_EQ(320, video_config.coded_size().width()); 247 EXPECT_EQ(240, video_config.coded_size().height()); 248 EXPECT_EQ(0, video_config.visible_rect().x()); 249 EXPECT_EQ(0, video_config.visible_rect().y()); 250 EXPECT_EQ(320, video_config.visible_rect().width()); 251 EXPECT_EQ(240, video_config.visible_rect().height()); 252 EXPECT_EQ(320, video_config.natural_size().width()); 253 EXPECT_EQ(240, video_config.natural_size().height()); 254 EXPECT_FALSE(video_config.extra_data()); 255 EXPECT_EQ(0u, video_config.extra_data_size()); 256 257 // Audio stream should be present. 258 stream = demuxer_->GetStream(DemuxerStream::AUDIO); 259 ASSERT_TRUE(stream); 260 EXPECT_EQ(DemuxerStream::AUDIO, stream->type()); 261 262 const AudioDecoderConfig& audio_config = stream->audio_decoder_config(); 263 EXPECT_EQ(kCodecVorbis, audio_config.codec()); 264 EXPECT_EQ(32, audio_config.bits_per_channel()); 265 EXPECT_EQ(CHANNEL_LAYOUT_STEREO, audio_config.channel_layout()); 266 EXPECT_EQ(44100, audio_config.samples_per_second()); 267 EXPECT_EQ(kSampleFormatPlanarF32, audio_config.sample_format()); 268 EXPECT_TRUE(audio_config.extra_data()); 269 EXPECT_GT(audio_config.extra_data_size(), 0u); 270 271 // Unknown stream should never be present. 272 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN)); 273 } 274 275 TEST_F(FFmpegDemuxerTest, Initialize_Multitrack) { 276 // Open a file containing the following streams: 277 // Stream #0: Video (VP8) 278 // Stream #1: Audio (Vorbis) 279 // Stream #2: Subtitles (SRT) 280 // Stream #3: Video (Theora) 281 // Stream #4: Audio (16-bit signed little endian PCM) 282 // 283 // We should only pick the first audio/video streams we come across. 284 CreateDemuxer("bear-320x240-multitrack.webm"); 285 InitializeDemuxer(); 286 287 // Video stream should be VP8. 288 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); 289 ASSERT_TRUE(stream); 290 EXPECT_EQ(DemuxerStream::VIDEO, stream->type()); 291 EXPECT_EQ(kCodecVP8, stream->video_decoder_config().codec()); 292 293 // Audio stream should be Vorbis. 294 stream = demuxer_->GetStream(DemuxerStream::AUDIO); 295 ASSERT_TRUE(stream); 296 EXPECT_EQ(DemuxerStream::AUDIO, stream->type()); 297 EXPECT_EQ(kCodecVorbis, stream->audio_decoder_config().codec()); 298 299 // Unknown stream should never be present. 300 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN)); 301 } 302 303 TEST_F(FFmpegDemuxerTest, Initialize_MultitrackText) { 304 // Open a file containing the following streams: 305 // Stream #0: Video (VP8) 306 // Stream #1: Audio (Vorbis) 307 // Stream #2: Text (WebVTT) 308 309 CreateDemuxer("bear-vp8-webvtt.webm"); 310 DemuxerStream* text_stream = NULL; 311 EXPECT_CALL(host_, AddTextStream(_, _)) 312 .WillOnce(SaveArg<0>(&text_stream)); 313 InitializeDemuxerText(true); 314 ASSERT_TRUE(text_stream); 315 EXPECT_EQ(DemuxerStream::TEXT, text_stream->type()); 316 317 // Video stream should be VP8. 318 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); 319 ASSERT_TRUE(stream); 320 EXPECT_EQ(DemuxerStream::VIDEO, stream->type()); 321 EXPECT_EQ(kCodecVP8, stream->video_decoder_config().codec()); 322 323 // Audio stream should be Vorbis. 324 stream = demuxer_->GetStream(DemuxerStream::AUDIO); 325 ASSERT_TRUE(stream); 326 EXPECT_EQ(DemuxerStream::AUDIO, stream->type()); 327 EXPECT_EQ(kCodecVorbis, stream->audio_decoder_config().codec()); 328 329 // Unknown stream should never be present. 330 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN)); 331 } 332 333 TEST_F(FFmpegDemuxerTest, Initialize_Encrypted) { 334 EXPECT_CALL(*this, NeedKeyCBMock(kWebMEncryptInitDataType, NotNull(), 335 DecryptConfig::kDecryptionKeySize)) 336 .Times(Exactly(2)); 337 338 CreateDemuxer("bear-320x240-av_enc-av.webm"); 339 InitializeDemuxer(); 340 } 341 342 TEST_F(FFmpegDemuxerTest, Read_Audio) { 343 // We test that on a successful audio packet read. 344 CreateDemuxer("bear-320x240.webm"); 345 InitializeDemuxer(); 346 347 // Attempt a read from the audio stream and run the message loop until done. 348 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); 349 350 audio->Read(NewReadCB(FROM_HERE, 29, 0)); 351 message_loop_.Run(); 352 353 audio->Read(NewReadCB(FROM_HERE, 27, 3000)); 354 message_loop_.Run(); 355 } 356 357 TEST_F(FFmpegDemuxerTest, Read_Video) { 358 // We test that on a successful video packet read. 359 CreateDemuxer("bear-320x240.webm"); 360 InitializeDemuxer(); 361 362 // Attempt a read from the video stream and run the message loop until done. 363 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO); 364 365 video->Read(NewReadCB(FROM_HERE, 22084, 0)); 366 message_loop_.Run(); 367 368 video->Read(NewReadCB(FROM_HERE, 1057, 33000)); 369 message_loop_.Run(); 370 } 371 372 TEST_F(FFmpegDemuxerTest, Read_Text) { 373 // We test that on a successful text packet read. 374 CreateDemuxer("bear-vp8-webvtt.webm"); 375 DemuxerStream* text_stream = NULL; 376 EXPECT_CALL(host_, AddTextStream(_, _)) 377 .WillOnce(SaveArg<0>(&text_stream)); 378 InitializeDemuxerText(true); 379 ASSERT_TRUE(text_stream); 380 EXPECT_EQ(DemuxerStream::TEXT, text_stream->type()); 381 382 text_stream->Read(NewReadCB(FROM_HERE, 31, 0)); 383 message_loop_.Run(); 384 385 text_stream->Read(NewReadCB(FROM_HERE, 19, 500000)); 386 message_loop_.Run(); 387 } 388 389 TEST_F(FFmpegDemuxerTest, Read_VideoNonZeroStart) { 390 // Test the start time is the first timestamp of the video and audio stream. 391 CreateDemuxer("nonzero-start-time.webm"); 392 InitializeDemuxer(); 393 394 // Attempt a read from the video stream and run the message loop until done. 395 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO); 396 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); 397 398 // Check first buffer in video stream. 399 video->Read(NewReadCB(FROM_HERE, 5636, 400000)); 400 message_loop_.Run(); 401 402 // Check first buffer in audio stream. 403 audio->Read(NewReadCB(FROM_HERE, 165, 396000)); 404 message_loop_.Run(); 405 406 // Verify that the start time is equal to the lowest timestamp (ie the audio). 407 EXPECT_EQ(demuxer_->GetStartTime().InMicroseconds(), 396000); 408 } 409 410 TEST_F(FFmpegDemuxerTest, Read_EndOfStream) { 411 // Verify that end of stream buffers are created. 412 CreateDemuxer("bear-320x240.webm"); 413 InitializeDemuxer(); 414 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO)); 415 } 416 417 TEST_F(FFmpegDemuxerTest, Read_EndOfStreamText) { 418 // Verify that end of stream buffers are created. 419 CreateDemuxer("bear-vp8-webvtt.webm"); 420 DemuxerStream* text_stream = NULL; 421 EXPECT_CALL(host_, AddTextStream(_, _)) 422 .WillOnce(SaveArg<0>(&text_stream)); 423 InitializeDemuxerText(true); 424 ASSERT_TRUE(text_stream); 425 EXPECT_EQ(DemuxerStream::TEXT, text_stream->type()); 426 427 bool got_eos_buffer = false; 428 const int kMaxBuffers = 10; 429 for (int i = 0; !got_eos_buffer && i < kMaxBuffers; i++) { 430 text_stream->Read(base::Bind(&EosOnReadDone, &got_eos_buffer)); 431 message_loop_.Run(); 432 } 433 434 EXPECT_TRUE(got_eos_buffer); 435 } 436 437 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration) { 438 // Verify that end of stream buffers are created. 439 CreateDemuxer("bear-320x240.webm"); 440 InitializeDemuxer(); 441 set_duration_known(false); 442 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(2767))); 443 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO)); 444 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::VIDEO)); 445 } 446 447 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration_VideoOnly) { 448 // Verify that end of stream buffers are created. 449 CreateDemuxer("bear-320x240-video-only.webm"); 450 InitializeDemuxer(); 451 set_duration_known(false); 452 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(2703))); 453 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::VIDEO)); 454 } 455 456 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration_AudioOnly) { 457 // Verify that end of stream buffers are created. 458 CreateDemuxer("bear-320x240-audio-only.webm"); 459 InitializeDemuxer(); 460 set_duration_known(false); 461 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(2767))); 462 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO)); 463 } 464 465 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration_UnsupportedStream) { 466 // Verify that end of stream buffers are created and we don't crash 467 // if there are streams in the file that we don't support. 468 CreateDemuxer("vorbis_audio_wmv_video.mkv"); 469 InitializeDemuxer(); 470 set_duration_known(false); 471 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(1014))); 472 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO)); 473 } 474 475 TEST_F(FFmpegDemuxerTest, Seek) { 476 // We're testing that the demuxer frees all queued packets when it receives 477 // a Seek(). 478 CreateDemuxer("bear-320x240.webm"); 479 InitializeDemuxer(); 480 481 // Get our streams. 482 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO); 483 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); 484 ASSERT_TRUE(video); 485 ASSERT_TRUE(audio); 486 487 // Read a video packet and release it. 488 video->Read(NewReadCB(FROM_HERE, 22084, 0)); 489 message_loop_.Run(); 490 491 // Issue a simple forward seek, which should discard queued packets. 492 WaitableMessageLoopEvent event; 493 demuxer_->Seek(base::TimeDelta::FromMicroseconds(1000000), 494 event.GetPipelineStatusCB()); 495 event.RunAndWaitForStatus(PIPELINE_OK); 496 497 // Audio read #1. 498 audio->Read(NewReadCB(FROM_HERE, 145, 803000)); 499 message_loop_.Run(); 500 501 // Audio read #2. 502 audio->Read(NewReadCB(FROM_HERE, 148, 826000)); 503 message_loop_.Run(); 504 505 // Video read #1. 506 video->Read(NewReadCB(FROM_HERE, 5425, 801000)); 507 message_loop_.Run(); 508 509 // Video read #2. 510 video->Read(NewReadCB(FROM_HERE, 1906, 834000)); 511 message_loop_.Run(); 512 } 513 514 TEST_F(FFmpegDemuxerTest, SeekText) { 515 // We're testing that the demuxer frees all queued packets when it receives 516 // a Seek(). 517 CreateDemuxer("bear-vp8-webvtt.webm"); 518 DemuxerStream* text_stream = NULL; 519 EXPECT_CALL(host_, AddTextStream(_, _)) 520 .WillOnce(SaveArg<0>(&text_stream)); 521 InitializeDemuxerText(true); 522 ASSERT_TRUE(text_stream); 523 EXPECT_EQ(DemuxerStream::TEXT, text_stream->type()); 524 525 // Get our streams. 526 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO); 527 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); 528 ASSERT_TRUE(video); 529 ASSERT_TRUE(audio); 530 531 // Read a text packet and release it. 532 text_stream->Read(NewReadCB(FROM_HERE, 31, 0)); 533 message_loop_.Run(); 534 535 // Issue a simple forward seek, which should discard queued packets. 536 WaitableMessageLoopEvent event; 537 demuxer_->Seek(base::TimeDelta::FromMicroseconds(1000000), 538 event.GetPipelineStatusCB()); 539 event.RunAndWaitForStatus(PIPELINE_OK); 540 541 // Audio read #1. 542 audio->Read(NewReadCB(FROM_HERE, 145, 803000)); 543 message_loop_.Run(); 544 545 // Audio read #2. 546 audio->Read(NewReadCB(FROM_HERE, 148, 826000)); 547 message_loop_.Run(); 548 549 // Video read #1. 550 video->Read(NewReadCB(FROM_HERE, 5425, 801000)); 551 message_loop_.Run(); 552 553 // Video read #2. 554 video->Read(NewReadCB(FROM_HERE, 1906, 834000)); 555 message_loop_.Run(); 556 557 // Text read #1. 558 text_stream->Read(NewReadCB(FROM_HERE, 19, 500000)); 559 message_loop_.Run(); 560 561 // Text read #2. 562 text_stream->Read(NewReadCB(FROM_HERE, 19, 1000000)); 563 message_loop_.Run(); 564 } 565 566 class MockReadCB { 567 public: 568 MockReadCB() {} 569 ~MockReadCB() {} 570 571 MOCK_METHOD2(Run, void(DemuxerStream::Status status, 572 const scoped_refptr<DecoderBuffer>& buffer)); 573 private: 574 DISALLOW_COPY_AND_ASSIGN(MockReadCB); 575 }; 576 577 TEST_F(FFmpegDemuxerTest, Stop) { 578 // Tests that calling Read() on a stopped demuxer stream immediately deletes 579 // the callback. 580 CreateDemuxer("bear-320x240.webm"); 581 InitializeDemuxer(); 582 583 // Get our stream. 584 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); 585 ASSERT_TRUE(audio); 586 587 WaitableMessageLoopEvent event; 588 demuxer_->Stop(event.GetClosure()); 589 event.RunAndWait(); 590 591 // Reads after being stopped are all EOS buffers. 592 StrictMock<MockReadCB> callback; 593 EXPECT_CALL(callback, Run(DemuxerStream::kOk, IsEndOfStreamBuffer())); 594 595 // Attempt the read... 596 audio->Read(base::Bind(&MockReadCB::Run, base::Unretained(&callback))); 597 message_loop_.RunUntilIdle(); 598 599 // Don't let the test call Stop() again. 600 demuxer_.reset(); 601 } 602 603 // Verify that seek works properly when the WebM cues data is at the start of 604 // the file instead of at the end. 605 TEST_F(FFmpegDemuxerTest, SeekWithCuesBeforeFirstCluster) { 606 CreateDemuxer("bear-320x240-cues-in-front.webm"); 607 InitializeDemuxer(); 608 609 // Get our streams. 610 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO); 611 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); 612 ASSERT_TRUE(video); 613 ASSERT_TRUE(audio); 614 615 // Read a video packet and release it. 616 video->Read(NewReadCB(FROM_HERE, 22084, 0)); 617 message_loop_.Run(); 618 619 // Issue a simple forward seek, which should discard queued packets. 620 WaitableMessageLoopEvent event; 621 demuxer_->Seek(base::TimeDelta::FromMicroseconds(2500000), 622 event.GetPipelineStatusCB()); 623 event.RunAndWaitForStatus(PIPELINE_OK); 624 625 // Audio read #1. 626 audio->Read(NewReadCB(FROM_HERE, 40, 2403000)); 627 message_loop_.Run(); 628 629 // Audio read #2. 630 audio->Read(NewReadCB(FROM_HERE, 42, 2406000)); 631 message_loop_.Run(); 632 633 // Video read #1. 634 video->Read(NewReadCB(FROM_HERE, 5276, 2402000)); 635 message_loop_.Run(); 636 637 // Video read #2. 638 video->Read(NewReadCB(FROM_HERE, 1740, 2436000)); 639 message_loop_.Run(); 640 } 641 642 #if defined(USE_PROPRIETARY_CODECS) 643 // Ensure ID3v1 tag reading is disabled. id3_test.mp3 has an ID3v1 tag with the 644 // field "title" set to "sample for id3 test". 645 TEST_F(FFmpegDemuxerTest, NoID3TagData) { 646 CreateDemuxer("id3_test.mp3"); 647 InitializeDemuxer(); 648 EXPECT_FALSE(av_dict_get(format_context()->metadata, "title", NULL, 0)); 649 } 650 #endif 651 652 #if defined(USE_PROPRIETARY_CODECS) 653 // Ensure MP3 files with large image/video based ID3 tags demux okay. FFmpeg 654 // will hand us a video stream to the data which will likely be in a format we 655 // don't accept as video; e.g. PNG. 656 TEST_F(FFmpegDemuxerTest, Mp3WithVideoStreamID3TagData) { 657 CreateDemuxer("id3_png_test.mp3"); 658 InitializeDemuxer(); 659 660 // Ensure the expected streams are present. 661 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO)); 662 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO)); 663 } 664 #endif 665 666 // Ensure a video with an unsupported audio track still results in the video 667 // stream being demuxed. 668 TEST_F(FFmpegDemuxerTest, UnsupportedAudioSupportedVideoDemux) { 669 CreateDemuxer("speex_audio_vorbis_video.ogv"); 670 InitializeDemuxer(); 671 672 // Ensure the expected streams are present. 673 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::VIDEO)); 674 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::AUDIO)); 675 } 676 677 // Ensure a video with an unsupported video track still results in the audio 678 // stream being demuxed. 679 TEST_F(FFmpegDemuxerTest, UnsupportedVideoSupportedAudioDemux) { 680 CreateDemuxer("vorbis_audio_wmv_video.mkv"); 681 InitializeDemuxer(); 682 683 // Ensure the expected streams are present. 684 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO)); 685 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO)); 686 } 687 688 #if defined(USE_PROPRIETARY_CODECS) 689 // FFmpeg returns null data pointers when samples have zero size, leading to 690 // mistakenly creating end of stream buffers http://crbug.com/169133 691 TEST_F(FFmpegDemuxerTest, MP4_ZeroStszEntry) { 692 CreateDemuxer("bear-1280x720-zero-stsz-entry.mp4"); 693 InitializeDemuxer(); 694 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO)); 695 } 696 697 698 static void ValidateAnnexB(DemuxerStream* stream, 699 DemuxerStream::Status status, 700 const scoped_refptr<DecoderBuffer>& buffer) { 701 EXPECT_EQ(status, DemuxerStream::kOk); 702 703 if (buffer->end_of_stream()) { 704 base::MessageLoop::current()->PostTask( 705 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); 706 return; 707 } 708 709 bool is_valid = 710 mp4::AVC::IsValidAnnexB(buffer->data(), buffer->data_size()); 711 EXPECT_TRUE(is_valid); 712 713 if (!is_valid) { 714 LOG(ERROR) << "Buffer contains invalid Annex B data."; 715 base::MessageLoop::current()->PostTask( 716 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); 717 return; 718 } 719 720 stream->Read(base::Bind(&ValidateAnnexB, stream)); 721 }; 722 723 TEST_F(FFmpegDemuxerTest, IsValidAnnexB) { 724 const char* files[] = { 725 "bear-1280x720-av_frag.mp4", 726 "bear-1280x720-av_with-aud-nalus_frag.mp4" 727 }; 728 729 for (size_t i = 0; i < arraysize(files); ++i) { 730 DVLOG(1) << "Testing " << files[i]; 731 CreateDemuxer(files[i]); 732 InitializeDemuxer(); 733 734 // Ensure the expected streams are present. 735 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); 736 ASSERT_TRUE(stream); 737 stream->EnableBitstreamConverter(); 738 739 stream->Read(base::Bind(&ValidateAnnexB, stream)); 740 message_loop_.Run(); 741 742 WaitableMessageLoopEvent event; 743 demuxer_->Stop(event.GetClosure()); 744 event.RunAndWait(); 745 demuxer_.reset(); 746 data_source_.reset(); 747 } 748 } 749 750 #endif 751 752 } // namespace media 753