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 demuxer_->Stop(); 72 } 73 74 void CreateDemuxer(const std::string& name) { 75 CHECK(!demuxer_); 76 77 EXPECT_CALL(host_, AddBufferedTimeRange(_, _)).Times(AnyNumber()); 78 79 CreateDataSource(name); 80 81 Demuxer::NeedKeyCB need_key_cb = 82 base::Bind(&FFmpegDemuxerTest::NeedKeyCB, base::Unretained(this)); 83 84 demuxer_.reset(new FFmpegDemuxer(message_loop_.message_loop_proxy(), 85 data_source_.get(), 86 need_key_cb, 87 new MediaLog())); 88 } 89 90 MOCK_METHOD1(CheckPoint, void(int v)); 91 92 void InitializeDemuxerWithTimelineOffset(bool enable_text, 93 base::Time timeline_offset) { 94 EXPECT_CALL(host_, SetDuration(_)); 95 WaitableMessageLoopEvent event; 96 demuxer_->Initialize(&host_, event.GetPipelineStatusCB(), enable_text); 97 demuxer_->timeline_offset_ = timeline_offset; 98 event.RunAndWaitForStatus(PIPELINE_OK); 99 } 100 101 void InitializeDemuxerText(bool enable_text) { 102 InitializeDemuxerWithTimelineOffset(enable_text, base::Time()); 103 } 104 105 void InitializeDemuxer() { 106 InitializeDemuxerText(false); 107 } 108 109 MOCK_METHOD2(OnReadDoneCalled, void(int, int64)); 110 111 // Verifies that |buffer| has a specific |size| and |timestamp|. 112 // |location| simply indicates where the call to this function was made. 113 // This makes it easier to track down where test failures occur. 114 void OnReadDone(const tracked_objects::Location& location, 115 int size, 116 int64 timestamp_us, 117 base::TimeDelta discard_front_padding, 118 DemuxerStream::Status status, 119 const scoped_refptr<DecoderBuffer>& buffer) { 120 std::string location_str; 121 location.Write(true, false, &location_str); 122 location_str += "\n"; 123 SCOPED_TRACE(location_str); 124 EXPECT_EQ(status, DemuxerStream::kOk); 125 OnReadDoneCalled(size, timestamp_us); 126 EXPECT_TRUE(buffer.get() != NULL); 127 EXPECT_EQ(size, buffer->data_size()); 128 EXPECT_EQ(timestamp_us, buffer->timestamp().InMicroseconds()); 129 EXPECT_EQ(discard_front_padding, buffer->discard_padding().first); 130 DCHECK_EQ(&message_loop_, base::MessageLoop::current()); 131 message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); 132 } 133 134 DemuxerStream::ReadCB NewReadCB(const tracked_objects::Location& location, 135 int size, 136 int64 timestamp_us) { 137 EXPECT_CALL(*this, OnReadDoneCalled(size, timestamp_us)); 138 return base::Bind(&FFmpegDemuxerTest::OnReadDone, 139 base::Unretained(this), 140 location, 141 size, 142 timestamp_us, 143 base::TimeDelta()); 144 } 145 146 DemuxerStream::ReadCB NewReadCBWithCheckedDiscard( 147 const tracked_objects::Location& location, 148 int size, 149 int64 timestamp_us, 150 base::TimeDelta discard_front_padding) { 151 EXPECT_CALL(*this, OnReadDoneCalled(size, timestamp_us)); 152 return base::Bind(&FFmpegDemuxerTest::OnReadDone, 153 base::Unretained(this), 154 location, 155 size, 156 timestamp_us, 157 discard_front_padding); 158 } 159 160 // TODO(xhwang): This is a workaround of the issue that move-only parameters 161 // are not supported in mocked methods. Remove this when the issue is fixed 162 // (http://code.google.com/p/googletest/issues/detail?id=395) or when we use 163 // std::string instead of scoped_ptr<uint8[]> (http://crbug.com/130689). 164 MOCK_METHOD3(NeedKeyCBMock, void(const std::string& type, 165 const uint8* init_data, int init_data_size)); 166 void NeedKeyCB(const std::string& type, 167 const std::vector<uint8>& init_data) { 168 const uint8* init_data_ptr = init_data.empty() ? NULL : &init_data[0]; 169 NeedKeyCBMock(type, init_data_ptr, init_data.size()); 170 } 171 172 // Accessor to demuxer internals. 173 void set_duration_known(bool duration_known) { 174 demuxer_->duration_known_ = duration_known; 175 } 176 177 bool IsStreamStopped(DemuxerStream::Type type) { 178 DemuxerStream* stream = demuxer_->GetStream(type); 179 CHECK(stream); 180 return !static_cast<FFmpegDemuxerStream*>(stream)->demuxer_; 181 } 182 183 // Fixture members. 184 scoped_ptr<FileDataSource> data_source_; 185 scoped_ptr<FFmpegDemuxer> demuxer_; 186 StrictMock<MockDemuxerHost> host_; 187 base::MessageLoop message_loop_; 188 189 AVFormatContext* format_context() { 190 return demuxer_->glue_->format_context(); 191 } 192 193 int preferred_seeking_stream_index() const { 194 return demuxer_->preferred_stream_for_seeking_.first; 195 } 196 197 void ReadUntilEndOfStream(DemuxerStream* stream) { 198 bool got_eos_buffer = false; 199 const int kMaxBuffers = 170; 200 for (int i = 0; !got_eos_buffer && i < kMaxBuffers; i++) { 201 stream->Read(base::Bind(&EosOnReadDone, &got_eos_buffer)); 202 message_loop_.Run(); 203 } 204 205 EXPECT_TRUE(got_eos_buffer); 206 } 207 208 private: 209 void CreateDataSource(const std::string& name) { 210 CHECK(!data_source_); 211 212 base::FilePath file_path; 213 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &file_path)); 214 215 file_path = file_path.Append(FILE_PATH_LITERAL("media")) 216 .Append(FILE_PATH_LITERAL("test")) 217 .Append(FILE_PATH_LITERAL("data")) 218 .AppendASCII(name); 219 220 data_source_.reset(new FileDataSource()); 221 EXPECT_TRUE(data_source_->Initialize(file_path)); 222 } 223 224 DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest); 225}; 226 227TEST_F(FFmpegDemuxerTest, Initialize_OpenFails) { 228 // Simulate avformat_open_input() failing. 229 CreateDemuxer("ten_byte_file"); 230 WaitableMessageLoopEvent event; 231 demuxer_->Initialize(&host_, event.GetPipelineStatusCB(), true); 232 event.RunAndWaitForStatus(DEMUXER_ERROR_COULD_NOT_OPEN); 233} 234 235// TODO(acolwell): Uncomment this test when we discover a file that passes 236// avformat_open_input(), but has avformat_find_stream_info() fail. 237// 238//TEST_F(FFmpegDemuxerTest, Initialize_ParseFails) { 239// ("find_stream_info_fail.webm"); 240// demuxer_->Initialize( 241// &host_, NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_PARSE)); 242// message_loop_.RunUntilIdle(); 243//} 244 245TEST_F(FFmpegDemuxerTest, Initialize_NoStreams) { 246 // Open a file with no streams whatsoever. 247 CreateDemuxer("no_streams.webm"); 248 WaitableMessageLoopEvent event; 249 demuxer_->Initialize(&host_, event.GetPipelineStatusCB(), true); 250 event.RunAndWaitForStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); 251} 252 253TEST_F(FFmpegDemuxerTest, Initialize_NoAudioVideo) { 254 // Open a file containing streams but none of which are audio/video streams. 255 CreateDemuxer("no_audio_video.webm"); 256 WaitableMessageLoopEvent event; 257 demuxer_->Initialize(&host_, event.GetPipelineStatusCB(), true); 258 event.RunAndWaitForStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); 259} 260 261TEST_F(FFmpegDemuxerTest, Initialize_Successful) { 262 CreateDemuxer("bear-320x240.webm"); 263 InitializeDemuxer(); 264 265 // Video stream should be present. 266 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); 267 ASSERT_TRUE(stream); 268 EXPECT_EQ(DemuxerStream::VIDEO, stream->type()); 269 270 const VideoDecoderConfig& video_config = stream->video_decoder_config(); 271 EXPECT_EQ(kCodecVP8, video_config.codec()); 272 EXPECT_EQ(VideoFrame::YV12, video_config.format()); 273 EXPECT_EQ(320, video_config.coded_size().width()); 274 EXPECT_EQ(240, video_config.coded_size().height()); 275 EXPECT_EQ(0, video_config.visible_rect().x()); 276 EXPECT_EQ(0, video_config.visible_rect().y()); 277 EXPECT_EQ(320, video_config.visible_rect().width()); 278 EXPECT_EQ(240, video_config.visible_rect().height()); 279 EXPECT_EQ(320, video_config.natural_size().width()); 280 EXPECT_EQ(240, video_config.natural_size().height()); 281 EXPECT_FALSE(video_config.extra_data()); 282 EXPECT_EQ(0u, video_config.extra_data_size()); 283 284 // Audio stream should be present. 285 stream = demuxer_->GetStream(DemuxerStream::AUDIO); 286 ASSERT_TRUE(stream); 287 EXPECT_EQ(DemuxerStream::AUDIO, stream->type()); 288 289 const AudioDecoderConfig& audio_config = stream->audio_decoder_config(); 290 EXPECT_EQ(kCodecVorbis, audio_config.codec()); 291 EXPECT_EQ(32, audio_config.bits_per_channel()); 292 EXPECT_EQ(CHANNEL_LAYOUT_STEREO, audio_config.channel_layout()); 293 EXPECT_EQ(44100, audio_config.samples_per_second()); 294 EXPECT_EQ(kSampleFormatPlanarF32, audio_config.sample_format()); 295 EXPECT_TRUE(audio_config.extra_data()); 296 EXPECT_GT(audio_config.extra_data_size(), 0u); 297 298 // Unknown stream should never be present. 299 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN)); 300} 301 302TEST_F(FFmpegDemuxerTest, Initialize_Multitrack) { 303 // Open a file containing the following streams: 304 // Stream #0: Video (VP8) 305 // Stream #1: Audio (Vorbis) 306 // Stream #2: Subtitles (SRT) 307 // Stream #3: Video (Theora) 308 // Stream #4: Audio (16-bit signed little endian PCM) 309 // 310 // We should only pick the first audio/video streams we come across. 311 CreateDemuxer("bear-320x240-multitrack.webm"); 312 InitializeDemuxer(); 313 314 // Video stream should be VP8. 315 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); 316 ASSERT_TRUE(stream); 317 EXPECT_EQ(DemuxerStream::VIDEO, stream->type()); 318 EXPECT_EQ(kCodecVP8, stream->video_decoder_config().codec()); 319 320 // Audio stream should be Vorbis. 321 stream = demuxer_->GetStream(DemuxerStream::AUDIO); 322 ASSERT_TRUE(stream); 323 EXPECT_EQ(DemuxerStream::AUDIO, stream->type()); 324 EXPECT_EQ(kCodecVorbis, stream->audio_decoder_config().codec()); 325 326 // Unknown stream should never be present. 327 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN)); 328} 329 330TEST_F(FFmpegDemuxerTest, Initialize_MultitrackText) { 331 // Open a file containing the following streams: 332 // Stream #0: Video (VP8) 333 // Stream #1: Audio (Vorbis) 334 // Stream #2: Text (WebVTT) 335 336 CreateDemuxer("bear-vp8-webvtt.webm"); 337 DemuxerStream* text_stream = NULL; 338 EXPECT_CALL(host_, AddTextStream(_, _)) 339 .WillOnce(SaveArg<0>(&text_stream)); 340 InitializeDemuxerText(true); 341 ASSERT_TRUE(text_stream); 342 EXPECT_EQ(DemuxerStream::TEXT, text_stream->type()); 343 344 // Video stream should be VP8. 345 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); 346 ASSERT_TRUE(stream); 347 EXPECT_EQ(DemuxerStream::VIDEO, stream->type()); 348 EXPECT_EQ(kCodecVP8, stream->video_decoder_config().codec()); 349 350 // Audio stream should be Vorbis. 351 stream = demuxer_->GetStream(DemuxerStream::AUDIO); 352 ASSERT_TRUE(stream); 353 EXPECT_EQ(DemuxerStream::AUDIO, stream->type()); 354 EXPECT_EQ(kCodecVorbis, stream->audio_decoder_config().codec()); 355 356 // Unknown stream should never be present. 357 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN)); 358} 359 360TEST_F(FFmpegDemuxerTest, Initialize_Encrypted) { 361 EXPECT_CALL(*this, NeedKeyCBMock(kWebMEncryptInitDataType, NotNull(), 362 DecryptConfig::kDecryptionKeySize)) 363 .Times(Exactly(2)); 364 365 CreateDemuxer("bear-320x240-av_enc-av.webm"); 366 InitializeDemuxer(); 367} 368 369TEST_F(FFmpegDemuxerTest, Read_Audio) { 370 // We test that on a successful audio packet read. 371 CreateDemuxer("bear-320x240.webm"); 372 InitializeDemuxer(); 373 374 // Attempt a read from the audio stream and run the message loop until done. 375 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); 376 377 audio->Read(NewReadCB(FROM_HERE, 29, 0)); 378 message_loop_.Run(); 379 380 audio->Read(NewReadCB(FROM_HERE, 27, 3000)); 381 message_loop_.Run(); 382} 383 384TEST_F(FFmpegDemuxerTest, Read_Video) { 385 // We test that on a successful video packet read. 386 CreateDemuxer("bear-320x240.webm"); 387 InitializeDemuxer(); 388 389 // Attempt a read from the video stream and run the message loop until done. 390 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO); 391 392 video->Read(NewReadCB(FROM_HERE, 22084, 0)); 393 message_loop_.Run(); 394 395 video->Read(NewReadCB(FROM_HERE, 1057, 33000)); 396 message_loop_.Run(); 397} 398 399TEST_F(FFmpegDemuxerTest, Read_Text) { 400 // We test that on a successful text packet read. 401 CreateDemuxer("bear-vp8-webvtt.webm"); 402 DemuxerStream* text_stream = NULL; 403 EXPECT_CALL(host_, AddTextStream(_, _)) 404 .WillOnce(SaveArg<0>(&text_stream)); 405 InitializeDemuxerText(true); 406 ASSERT_TRUE(text_stream); 407 EXPECT_EQ(DemuxerStream::TEXT, text_stream->type()); 408 409 text_stream->Read(NewReadCB(FROM_HERE, 31, 0)); 410 message_loop_.Run(); 411 412 text_stream->Read(NewReadCB(FROM_HERE, 19, 500000)); 413 message_loop_.Run(); 414} 415 416TEST_F(FFmpegDemuxerTest, SeekInitialized_NoVideoStartTime) { 417 CreateDemuxer("audio-start-time-only.webm"); 418 InitializeDemuxer(); 419 EXPECT_EQ(0, preferred_seeking_stream_index()); 420} 421 422TEST_F(FFmpegDemuxerTest, Read_VideoPositiveStartTime) { 423 const int64 kTimelineOffsetMs = 1352550896000LL; 424 425 // Test the start time is the first timestamp of the video and audio stream. 426 CreateDemuxer("nonzero-start-time.webm"); 427 InitializeDemuxerWithTimelineOffset( 428 false, base::Time::FromJsTime(kTimelineOffsetMs)); 429 430 // Attempt a read from the video stream and run the message loop until done. 431 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO); 432 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); 433 434 const base::TimeDelta video_start_time = 435 base::TimeDelta::FromMicroseconds(400000); 436 const base::TimeDelta audio_start_time = 437 base::TimeDelta::FromMicroseconds(396000); 438 439 // Run the test twice with a seek in between. 440 for (int i = 0; i < 2; ++i) { 441 video->Read(NewReadCB(FROM_HERE, 5636, video_start_time.InMicroseconds())); 442 message_loop_.Run(); 443 audio->Read(NewReadCB(FROM_HERE, 165, audio_start_time.InMicroseconds())); 444 message_loop_.Run(); 445 446 // Verify that the start time is equal to the lowest timestamp (ie the 447 // audio). 448 EXPECT_EQ(audio_start_time, demuxer_->start_time()); 449 450 // Verify that the timeline offset has not been adjusted by the start time. 451 EXPECT_EQ(kTimelineOffsetMs, demuxer_->GetTimelineOffset().ToJavaTime()); 452 453 // Seek back to the beginning and repeat the test. 454 WaitableMessageLoopEvent event; 455 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB()); 456 event.RunAndWaitForStatus(PIPELINE_OK); 457 } 458} 459 460TEST_F(FFmpegDemuxerTest, Read_AudioNoStartTime) { 461 // FFmpeg does not set timestamps when demuxing wave files. Ensure that the 462 // demuxer sets a start time of zero in this case. 463 CreateDemuxer("sfx_s24le.wav"); 464 InitializeDemuxer(); 465 466 // Run the test twice with a seek in between. 467 for (int i = 0; i < 2; ++i) { 468 demuxer_->GetStream(DemuxerStream::AUDIO) 469 ->Read(NewReadCB(FROM_HERE, 4095, 0)); 470 message_loop_.Run(); 471 EXPECT_EQ(base::TimeDelta(), demuxer_->start_time()); 472 473 // Seek back to the beginning and repeat the test. 474 WaitableMessageLoopEvent event; 475 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB()); 476 event.RunAndWaitForStatus(PIPELINE_OK); 477 } 478} 479 480// TODO(dalecurtis): Test is disabled since FFmpeg does not currently guarantee 481// the order of demuxed packets in OGG containers. Re-enable once we decide to 482// either workaround it or attempt a fix upstream. See http://crbug.com/387996. 483TEST_F(FFmpegDemuxerTest, 484 DISABLED_Read_AudioNegativeStartTimeAndOggDiscard_Bear) { 485 // Many ogg files have negative starting timestamps, so ensure demuxing and 486 // seeking work correctly with a negative start time. 487 CreateDemuxer("bear.ogv"); 488 InitializeDemuxer(); 489 490 // Attempt a read from the video stream and run the message loop until done. 491 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO); 492 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); 493 494 // Run the test twice with a seek in between. 495 for (int i = 0; i < 2; ++i) { 496 audio->Read( 497 NewReadCBWithCheckedDiscard(FROM_HERE, 40, 0, kInfiniteDuration())); 498 message_loop_.Run(); 499 audio->Read( 500 NewReadCBWithCheckedDiscard(FROM_HERE, 41, 2903, kInfiniteDuration())); 501 message_loop_.Run(); 502 audio->Read(NewReadCBWithCheckedDiscard( 503 FROM_HERE, 173, 5805, base::TimeDelta::FromMicroseconds(10159))); 504 message_loop_.Run(); 505 506 audio->Read(NewReadCB(FROM_HERE, 148, 18866)); 507 message_loop_.Run(); 508 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-15964), 509 demuxer_->start_time()); 510 511 video->Read(NewReadCB(FROM_HERE, 5751, 0)); 512 message_loop_.Run(); 513 514 video->Read(NewReadCB(FROM_HERE, 846, 33367)); 515 message_loop_.Run(); 516 517 video->Read(NewReadCB(FROM_HERE, 1255, 66733)); 518 message_loop_.Run(); 519 520 // Seek back to the beginning and repeat the test. 521 WaitableMessageLoopEvent event; 522 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB()); 523 event.RunAndWaitForStatus(PIPELINE_OK); 524 } 525} 526 527// Same test above, but using sync2.ogv which has video stream muxed before the 528// audio stream, so seeking based only on start time will fail since ffmpeg is 529// essentially just seeking based on file position. 530TEST_F(FFmpegDemuxerTest, Read_AudioNegativeStartTimeAndOggDiscard_Sync) { 531 // Many ogg files have negative starting timestamps, so ensure demuxing and 532 // seeking work correctly with a negative start time. 533 CreateDemuxer("sync2.ogv"); 534 InitializeDemuxer(); 535 536 // Attempt a read from the video stream and run the message loop until done. 537 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO); 538 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); 539 540 // Run the test twice with a seek in between. 541 for (int i = 0; i < 2; ++i) { 542 audio->Read(NewReadCBWithCheckedDiscard( 543 FROM_HERE, 1, 0, base::TimeDelta::FromMicroseconds(2902))); 544 message_loop_.Run(); 545 546 audio->Read(NewReadCB(FROM_HERE, 1, 2902)); 547 message_loop_.Run(); 548 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-2902), 549 demuxer_->start_time()); 550 551 // Though the internal start time may be below zero, the exposed media time 552 // must always be greater than zero. 553 EXPECT_EQ(base::TimeDelta(), demuxer_->GetStartTime()); 554 555 video->Read(NewReadCB(FROM_HERE, 9997, 0)); 556 message_loop_.Run(); 557 558 video->Read(NewReadCB(FROM_HERE, 16, 33241)); 559 message_loop_.Run(); 560 561 video->Read(NewReadCB(FROM_HERE, 631, 66482)); 562 message_loop_.Run(); 563 564 // Seek back to the beginning and repeat the test. 565 WaitableMessageLoopEvent event; 566 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB()); 567 event.RunAndWaitForStatus(PIPELINE_OK); 568 } 569} 570 571TEST_F(FFmpegDemuxerTest, Read_EndOfStream) { 572 // Verify that end of stream buffers are created. 573 CreateDemuxer("bear-320x240.webm"); 574 InitializeDemuxer(); 575 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO)); 576} 577 578TEST_F(FFmpegDemuxerTest, Read_EndOfStreamText) { 579 // Verify that end of stream buffers are created. 580 CreateDemuxer("bear-vp8-webvtt.webm"); 581 DemuxerStream* text_stream = NULL; 582 EXPECT_CALL(host_, AddTextStream(_, _)) 583 .WillOnce(SaveArg<0>(&text_stream)); 584 InitializeDemuxerText(true); 585 ASSERT_TRUE(text_stream); 586 EXPECT_EQ(DemuxerStream::TEXT, text_stream->type()); 587 588 bool got_eos_buffer = false; 589 const int kMaxBuffers = 10; 590 for (int i = 0; !got_eos_buffer && i < kMaxBuffers; i++) { 591 text_stream->Read(base::Bind(&EosOnReadDone, &got_eos_buffer)); 592 message_loop_.Run(); 593 } 594 595 EXPECT_TRUE(got_eos_buffer); 596} 597 598TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration) { 599 // Verify that end of stream buffers are created. 600 CreateDemuxer("bear-320x240.webm"); 601 InitializeDemuxer(); 602 set_duration_known(false); 603 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(2767))); 604 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO)); 605 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::VIDEO)); 606} 607 608TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration_VideoOnly) { 609 // Verify that end of stream buffers are created. 610 CreateDemuxer("bear-320x240-video-only.webm"); 611 InitializeDemuxer(); 612 set_duration_known(false); 613 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(2703))); 614 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::VIDEO)); 615} 616 617TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration_AudioOnly) { 618 // Verify that end of stream buffers are created. 619 CreateDemuxer("bear-320x240-audio-only.webm"); 620 InitializeDemuxer(); 621 set_duration_known(false); 622 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(2767))); 623 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO)); 624} 625 626TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration_UnsupportedStream) { 627 // Verify that end of stream buffers are created and we don't crash 628 // if there are streams in the file that we don't support. 629 CreateDemuxer("vorbis_audio_wmv_video.mkv"); 630 InitializeDemuxer(); 631 set_duration_known(false); 632 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(1014))); 633 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO)); 634} 635 636TEST_F(FFmpegDemuxerTest, Seek) { 637 // We're testing that the demuxer frees all queued packets when it receives 638 // a Seek(). 639 CreateDemuxer("bear-320x240.webm"); 640 InitializeDemuxer(); 641 642 // Get our streams. 643 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO); 644 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); 645 ASSERT_TRUE(video); 646 ASSERT_TRUE(audio); 647 648 // Read a video packet and release it. 649 video->Read(NewReadCB(FROM_HERE, 22084, 0)); 650 message_loop_.Run(); 651 652 // Issue a simple forward seek, which should discard queued packets. 653 WaitableMessageLoopEvent event; 654 demuxer_->Seek(base::TimeDelta::FromMicroseconds(1000000), 655 event.GetPipelineStatusCB()); 656 event.RunAndWaitForStatus(PIPELINE_OK); 657 658 // Audio read #1. 659 audio->Read(NewReadCB(FROM_HERE, 145, 803000)); 660 message_loop_.Run(); 661 662 // Audio read #2. 663 audio->Read(NewReadCB(FROM_HERE, 148, 826000)); 664 message_loop_.Run(); 665 666 // Video read #1. 667 video->Read(NewReadCB(FROM_HERE, 5425, 801000)); 668 message_loop_.Run(); 669 670 // Video read #2. 671 video->Read(NewReadCB(FROM_HERE, 1906, 834000)); 672 message_loop_.Run(); 673} 674 675TEST_F(FFmpegDemuxerTest, SeekText) { 676 // We're testing that the demuxer frees all queued packets when it receives 677 // a Seek(). 678 CreateDemuxer("bear-vp8-webvtt.webm"); 679 DemuxerStream* text_stream = NULL; 680 EXPECT_CALL(host_, AddTextStream(_, _)) 681 .WillOnce(SaveArg<0>(&text_stream)); 682 InitializeDemuxerText(true); 683 ASSERT_TRUE(text_stream); 684 EXPECT_EQ(DemuxerStream::TEXT, text_stream->type()); 685 686 // Get our streams. 687 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO); 688 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); 689 ASSERT_TRUE(video); 690 ASSERT_TRUE(audio); 691 692 // Read a text packet and release it. 693 text_stream->Read(NewReadCB(FROM_HERE, 31, 0)); 694 message_loop_.Run(); 695 696 // Issue a simple forward seek, which should discard queued packets. 697 WaitableMessageLoopEvent event; 698 demuxer_->Seek(base::TimeDelta::FromMicroseconds(1000000), 699 event.GetPipelineStatusCB()); 700 event.RunAndWaitForStatus(PIPELINE_OK); 701 702 // Audio read #1. 703 audio->Read(NewReadCB(FROM_HERE, 145, 803000)); 704 message_loop_.Run(); 705 706 // Audio read #2. 707 audio->Read(NewReadCB(FROM_HERE, 148, 826000)); 708 message_loop_.Run(); 709 710 // Video read #1. 711 video->Read(NewReadCB(FROM_HERE, 5425, 801000)); 712 message_loop_.Run(); 713 714 // Video read #2. 715 video->Read(NewReadCB(FROM_HERE, 1906, 834000)); 716 message_loop_.Run(); 717 718 // Text read #1. 719 text_stream->Read(NewReadCB(FROM_HERE, 19, 500000)); 720 message_loop_.Run(); 721 722 // Text read #2. 723 text_stream->Read(NewReadCB(FROM_HERE, 19, 1000000)); 724 message_loop_.Run(); 725} 726 727class MockReadCB { 728 public: 729 MockReadCB() {} 730 ~MockReadCB() {} 731 732 MOCK_METHOD2(Run, void(DemuxerStream::Status status, 733 const scoped_refptr<DecoderBuffer>& buffer)); 734 private: 735 DISALLOW_COPY_AND_ASSIGN(MockReadCB); 736}; 737 738TEST_F(FFmpegDemuxerTest, Stop) { 739 // Tests that calling Read() on a stopped demuxer stream immediately deletes 740 // the callback. 741 CreateDemuxer("bear-320x240.webm"); 742 InitializeDemuxer(); 743 744 // Get our stream. 745 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); 746 ASSERT_TRUE(audio); 747 748 demuxer_->Stop(); 749 750 // Reads after being stopped are all EOS buffers. 751 StrictMock<MockReadCB> callback; 752 EXPECT_CALL(callback, Run(DemuxerStream::kOk, IsEndOfStreamBuffer())); 753 754 // Attempt the read... 755 audio->Read(base::Bind(&MockReadCB::Run, base::Unretained(&callback))); 756 message_loop_.RunUntilIdle(); 757 758 // Don't let the test call Stop() again. 759 demuxer_.reset(); 760} 761 762// Verify that seek works properly when the WebM cues data is at the start of 763// the file instead of at the end. 764TEST_F(FFmpegDemuxerTest, SeekWithCuesBeforeFirstCluster) { 765 CreateDemuxer("bear-320x240-cues-in-front.webm"); 766 InitializeDemuxer(); 767 768 // Get our streams. 769 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO); 770 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO); 771 ASSERT_TRUE(video); 772 ASSERT_TRUE(audio); 773 774 // Read a video packet and release it. 775 video->Read(NewReadCB(FROM_HERE, 22084, 0)); 776 message_loop_.Run(); 777 778 // Issue a simple forward seek, which should discard queued packets. 779 WaitableMessageLoopEvent event; 780 demuxer_->Seek(base::TimeDelta::FromMicroseconds(2500000), 781 event.GetPipelineStatusCB()); 782 event.RunAndWaitForStatus(PIPELINE_OK); 783 784 // Audio read #1. 785 audio->Read(NewReadCB(FROM_HERE, 40, 2403000)); 786 message_loop_.Run(); 787 788 // Audio read #2. 789 audio->Read(NewReadCB(FROM_HERE, 42, 2406000)); 790 message_loop_.Run(); 791 792 // Video read #1. 793 video->Read(NewReadCB(FROM_HERE, 5276, 2402000)); 794 message_loop_.Run(); 795 796 // Video read #2. 797 video->Read(NewReadCB(FROM_HERE, 1740, 2436000)); 798 message_loop_.Run(); 799} 800 801#if defined(USE_PROPRIETARY_CODECS) 802// Ensure ID3v1 tag reading is disabled. id3_test.mp3 has an ID3v1 tag with the 803// field "title" set to "sample for id3 test". 804TEST_F(FFmpegDemuxerTest, NoID3TagData) { 805 CreateDemuxer("id3_test.mp3"); 806 InitializeDemuxer(); 807 EXPECT_FALSE(av_dict_get(format_context()->metadata, "title", NULL, 0)); 808} 809#endif 810 811#if defined(USE_PROPRIETARY_CODECS) 812// Ensure MP3 files with large image/video based ID3 tags demux okay. FFmpeg 813// will hand us a video stream to the data which will likely be in a format we 814// don't accept as video; e.g. PNG. 815TEST_F(FFmpegDemuxerTest, Mp3WithVideoStreamID3TagData) { 816 CreateDemuxer("id3_png_test.mp3"); 817 InitializeDemuxer(); 818 819 // Ensure the expected streams are present. 820 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO)); 821 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO)); 822} 823#endif 824 825// Ensure a video with an unsupported audio track still results in the video 826// stream being demuxed. 827TEST_F(FFmpegDemuxerTest, UnsupportedAudioSupportedVideoDemux) { 828 CreateDemuxer("speex_audio_vorbis_video.ogv"); 829 InitializeDemuxer(); 830 831 // Ensure the expected streams are present. 832 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::VIDEO)); 833 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::AUDIO)); 834} 835 836// Ensure a video with an unsupported video track still results in the audio 837// stream being demuxed. 838TEST_F(FFmpegDemuxerTest, UnsupportedVideoSupportedAudioDemux) { 839 CreateDemuxer("vorbis_audio_wmv_video.mkv"); 840 InitializeDemuxer(); 841 842 // Ensure the expected streams are present. 843 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO)); 844 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO)); 845} 846 847#if defined(USE_PROPRIETARY_CODECS) 848// FFmpeg returns null data pointers when samples have zero size, leading to 849// mistakenly creating end of stream buffers http://crbug.com/169133 850TEST_F(FFmpegDemuxerTest, MP4_ZeroStszEntry) { 851 CreateDemuxer("bear-1280x720-zero-stsz-entry.mp4"); 852 InitializeDemuxer(); 853 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO)); 854} 855 856 857static void ValidateAnnexB(DemuxerStream* stream, 858 DemuxerStream::Status status, 859 const scoped_refptr<DecoderBuffer>& buffer) { 860 EXPECT_EQ(status, DemuxerStream::kOk); 861 862 if (buffer->end_of_stream()) { 863 base::MessageLoop::current()->PostTask( 864 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); 865 return; 866 } 867 868 std::vector<SubsampleEntry> subsamples; 869 870 if (buffer->decrypt_config()) 871 subsamples = buffer->decrypt_config()->subsamples(); 872 873 bool is_valid = 874 mp4::AVC::IsValidAnnexB(buffer->data(), buffer->data_size(), 875 subsamples); 876 EXPECT_TRUE(is_valid); 877 878 if (!is_valid) { 879 LOG(ERROR) << "Buffer contains invalid Annex B data."; 880 base::MessageLoop::current()->PostTask( 881 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure()); 882 return; 883 } 884 885 stream->Read(base::Bind(&ValidateAnnexB, stream)); 886}; 887 888TEST_F(FFmpegDemuxerTest, IsValidAnnexB) { 889 const char* files[] = { 890 "bear-1280x720-av_frag.mp4", 891 "bear-1280x720-av_with-aud-nalus_frag.mp4" 892 }; 893 894 for (size_t i = 0; i < arraysize(files); ++i) { 895 DVLOG(1) << "Testing " << files[i]; 896 CreateDemuxer(files[i]); 897 InitializeDemuxer(); 898 899 // Ensure the expected streams are present. 900 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); 901 ASSERT_TRUE(stream); 902 stream->EnableBitstreamConverter(); 903 904 stream->Read(base::Bind(&ValidateAnnexB, stream)); 905 message_loop_.Run(); 906 907 demuxer_->Stop(); 908 demuxer_.reset(); 909 data_source_.reset(); 910 } 911} 912 913TEST_F(FFmpegDemuxerTest, Rotate_Metadata_0) { 914 CreateDemuxer("bear_rotate_0.mp4"); 915 InitializeDemuxer(); 916 917 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); 918 ASSERT_TRUE(stream); 919 ASSERT_EQ(VIDEO_ROTATION_0, stream->video_rotation()); 920} 921 922TEST_F(FFmpegDemuxerTest, Rotate_Metadata_90) { 923 CreateDemuxer("bear_rotate_90.mp4"); 924 InitializeDemuxer(); 925 926 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); 927 ASSERT_TRUE(stream); 928 ASSERT_EQ(VIDEO_ROTATION_90, stream->video_rotation()); 929} 930 931TEST_F(FFmpegDemuxerTest, Rotate_Metadata_180) { 932 CreateDemuxer("bear_rotate_180.mp4"); 933 InitializeDemuxer(); 934 935 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); 936 ASSERT_TRUE(stream); 937 ASSERT_EQ(VIDEO_ROTATION_180, stream->video_rotation()); 938} 939 940TEST_F(FFmpegDemuxerTest, Rotate_Metadata_270) { 941 CreateDemuxer("bear_rotate_270.mp4"); 942 InitializeDemuxer(); 943 944 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO); 945 ASSERT_TRUE(stream); 946 ASSERT_EQ(VIDEO_ROTATION_270, stream->video_rotation()); 947} 948 949#endif 950 951} // namespace media 952