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