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