ffmpeg_demuxer_unittest.cc revision 0de6073388f4e2780db8536178b129cd8f6ab386
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 25using ::testing::AnyNumber; 26using ::testing::DoAll; 27using ::testing::Exactly; 28using ::testing::InSequence; 29using ::testing::Invoke; 30using ::testing::NotNull; 31using ::testing::Return; 32using ::testing::SaveArg; 33using ::testing::SetArgPointee; 34using ::testing::StrictMock; 35using ::testing::WithArgs; 36using ::testing::_; 37 38namespace media { 39 40MATCHER(IsEndOfStreamBuffer, 41 std::string(negation ? "isn't" : "is") + " end of stream") { 42 return arg->end_of_stream(); 43} 44 45static 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. 65class 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 200TEST_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 218TEST_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 226TEST_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 234TEST_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 275TEST_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 303TEST_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 333TEST_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 342TEST_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 357TEST_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 372TEST_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 389TEST_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 410TEST_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 417TEST_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 437TEST_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 447TEST_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 456TEST_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 465TEST_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 475TEST_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 514TEST_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 566class 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 577TEST_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. 605TEST_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". 645TEST_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. 656TEST_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. 668TEST_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. 679TEST_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 691TEST_F(FFmpegDemuxerTest, MP4_ZeroStszEntry) { 692 CreateDemuxer("bear-1280x720-zero-stsz-entry.mp4"); 693 InitializeDemuxer(); 694 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO)); 695} 696 697 698static 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 723TEST_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