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.
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"
25 using ::testing::AnyNumber;
26 using ::testing::DoAll;
27 using ::testing::Exactly;
28 using ::testing::InSequence;
29 using ::testing::Invoke;
30 using ::testing::NotNull;
31 using ::testing::Return;
32 using ::testing::SaveArg;
33 using ::testing::SetArgPointee;
34 using ::testing::StrictMock;
35 using ::testing::WithArgs;
40 MATCHER(IsEndOfStreamBuffer,
41 std::string(negation ? "isn't" : "is") + " end of stream") {
42 return arg->end_of_stream();
45 static void EosOnReadDone(bool* got_eos_buffer,
46 DemuxerStream::Status status,
47 const scoped_refptr<DecoderBuffer>& buffer) {
48 base::MessageLoop::current()->PostTask(
49 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
51 EXPECT_EQ(status, DemuxerStream::kOk);
52 if (buffer->end_of_stream()) {
53 *got_eos_buffer = true;
57 EXPECT_TRUE(buffer->data());
58 EXPECT_GT(buffer->data_size(), 0);
59 *got_eos_buffer = false;
63 // Fixture class to facilitate writing tests. Takes care of setting up the
64 // FFmpeg, pipeline and filter host mocks.
65 class FFmpegDemuxerTest : public testing::Test {
67 FFmpegDemuxerTest() {}
69 virtual ~FFmpegDemuxerTest() {
71 WaitableMessageLoopEvent event;
72 demuxer_->Stop(event.GetClosure());
77 void CreateDemuxer(const std::string& name) {
80 EXPECT_CALL(host_, AddBufferedTimeRange(_, _)).Times(AnyNumber());
82 CreateDataSource(name);
84 Demuxer::NeedKeyCB need_key_cb =
85 base::Bind(&FFmpegDemuxerTest::NeedKeyCB, base::Unretained(this));
87 demuxer_.reset(new FFmpegDemuxer(message_loop_.message_loop_proxy(),
93 MOCK_METHOD1(CheckPoint, void(int v));
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);
104 void InitializeDemuxerText(bool enable_text) {
105 InitializeDemuxerWithTimelineOffset(enable_text, base::Time());
108 void InitializeDemuxer() {
109 InitializeDemuxerText(false);
112 MOCK_METHOD2(OnReadDoneCalled, void(int, int64));
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,
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());
137 DemuxerStream::ReadCB NewReadCB(const tracked_objects::Location& location,
139 int64 timestamp_us) {
140 EXPECT_CALL(*this, OnReadDoneCalled(size, timestamp_us));
141 return base::Bind(&FFmpegDemuxerTest::OnReadDone,
142 base::Unretained(this),
149 DemuxerStream::ReadCB NewReadCBWithCheckedDiscard(
150 const tracked_objects::Location& location,
153 base::TimeDelta discard_front_padding) {
154 EXPECT_CALL(*this, OnReadDoneCalled(size, timestamp_us));
155 return base::Bind(&FFmpegDemuxerTest::OnReadDone,
156 base::Unretained(this),
160 discard_front_padding);
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());
175 // Accessor to demuxer internals.
176 void set_duration_known(bool duration_known) {
177 demuxer_->duration_known_ = duration_known;
180 bool IsStreamStopped(DemuxerStream::Type type) {
181 DemuxerStream* stream = demuxer_->GetStream(type);
183 return !static_cast<FFmpegDemuxerStream*>(stream)->demuxer_;
187 scoped_ptr<FileDataSource> data_source_;
188 scoped_ptr<FFmpegDemuxer> demuxer_;
189 StrictMock<MockDemuxerHost> host_;
190 base::MessageLoop message_loop_;
192 AVFormatContext* format_context() {
193 return demuxer_->glue_->format_context();
196 int preferred_seeking_stream_index() const {
197 return demuxer_->preferred_stream_for_seeking_.first;
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));
208 EXPECT_TRUE(got_eos_buffer);
212 void CreateDataSource(const std::string& name) {
213 CHECK(!data_source_);
215 base::FilePath file_path;
216 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
218 file_path = file_path.Append(FILE_PATH_LITERAL("media"))
219 .Append(FILE_PATH_LITERAL("test"))
220 .Append(FILE_PATH_LITERAL("data"))
223 data_source_.reset(new FileDataSource());
224 EXPECT_TRUE(data_source_->Initialize(file_path));
227 DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest);
230 TEST_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);
238 // TODO(acolwell): Uncomment this test when we discover a file that passes
239 // avformat_open_input(), but has avformat_find_stream_info() fail.
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();
248 TEST_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);
256 TEST_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);
264 TEST_F(FFmpegDemuxerTest, Initialize_Successful) {
265 CreateDemuxer("bear-320x240.webm");
268 // Video stream should be present.
269 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
271 EXPECT_EQ(DemuxerStream::VIDEO, stream->type());
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());
287 // Audio stream should be present.
288 stream = demuxer_->GetStream(DemuxerStream::AUDIO);
290 EXPECT_EQ(DemuxerStream::AUDIO, stream->type());
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);
301 // Unknown stream should never be present.
302 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN));
305 TEST_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)
313 // We should only pick the first audio/video streams we come across.
314 CreateDemuxer("bear-320x240-multitrack.webm");
317 // Video stream should be VP8.
318 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
320 EXPECT_EQ(DemuxerStream::VIDEO, stream->type());
321 EXPECT_EQ(kCodecVP8, stream->video_decoder_config().codec());
323 // Audio stream should be Vorbis.
324 stream = demuxer_->GetStream(DemuxerStream::AUDIO);
326 EXPECT_EQ(DemuxerStream::AUDIO, stream->type());
327 EXPECT_EQ(kCodecVorbis, stream->audio_decoder_config().codec());
329 // Unknown stream should never be present.
330 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN));
333 TEST_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)
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());
347 // Video stream should be VP8.
348 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
350 EXPECT_EQ(DemuxerStream::VIDEO, stream->type());
351 EXPECT_EQ(kCodecVP8, stream->video_decoder_config().codec());
353 // Audio stream should be Vorbis.
354 stream = demuxer_->GetStream(DemuxerStream::AUDIO);
356 EXPECT_EQ(DemuxerStream::AUDIO, stream->type());
357 EXPECT_EQ(kCodecVorbis, stream->audio_decoder_config().codec());
359 // Unknown stream should never be present.
360 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN));
363 TEST_F(FFmpegDemuxerTest, Initialize_Encrypted) {
364 EXPECT_CALL(*this, NeedKeyCBMock(kWebMEncryptInitDataType, NotNull(),
365 DecryptConfig::kDecryptionKeySize))
368 CreateDemuxer("bear-320x240-av_enc-av.webm");
372 TEST_F(FFmpegDemuxerTest, Read_Audio) {
373 // We test that on a successful audio packet read.
374 CreateDemuxer("bear-320x240.webm");
377 // Attempt a read from the audio stream and run the message loop until done.
378 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
380 audio->Read(NewReadCB(FROM_HERE, 29, 0));
383 audio->Read(NewReadCB(FROM_HERE, 27, 3000));
387 TEST_F(FFmpegDemuxerTest, Read_Video) {
388 // We test that on a successful video packet read.
389 CreateDemuxer("bear-320x240.webm");
392 // Attempt a read from the video stream and run the message loop until done.
393 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
395 video->Read(NewReadCB(FROM_HERE, 22084, 0));
398 video->Read(NewReadCB(FROM_HERE, 1057, 33000));
402 TEST_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());
412 text_stream->Read(NewReadCB(FROM_HERE, 31, 0));
415 text_stream->Read(NewReadCB(FROM_HERE, 19, 500000));
419 TEST_F(FFmpegDemuxerTest, SeekInitialized_NoVideoStartTime) {
420 CreateDemuxer("audio-start-time-only.webm");
422 EXPECT_EQ(0, preferred_seeking_stream_index());
425 TEST_F(FFmpegDemuxerTest, Read_VideoPositiveStartTime) {
426 const int64 kTimelineOffsetMs = 1352550896000LL;
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));
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);
437 const base::TimeDelta video_start_time =
438 base::TimeDelta::FromMicroseconds(400000);
439 const base::TimeDelta audio_start_time =
440 base::TimeDelta::FromMicroseconds(396000);
442 // Run the test twice with a seek in between.
443 for (int i = 0; i < 2; ++i) {
444 video->Read(NewReadCB(FROM_HERE, 5636, video_start_time.InMicroseconds()));
446 audio->Read(NewReadCB(FROM_HERE, 165, audio_start_time.InMicroseconds()));
449 // Verify that the start time is equal to the lowest timestamp (ie the
451 EXPECT_EQ(audio_start_time, demuxer_->start_time());
453 // Verify that the timeline offset has been adjusted by the start time.
454 EXPECT_EQ(kTimelineOffsetMs + audio_start_time.InMilliseconds(),
455 demuxer_->GetTimelineOffset().ToJavaTime());
457 // Seek back to the beginning and repeat the test.
458 WaitableMessageLoopEvent event;
459 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB());
460 event.RunAndWaitForStatus(PIPELINE_OK);
464 TEST_F(FFmpegDemuxerTest, Read_AudioNoStartTime) {
465 // FFmpeg does not set timestamps when demuxing wave files. Ensure that the
466 // demuxer sets a start time of zero in this case.
467 CreateDemuxer("sfx_s24le.wav");
470 // Run the test twice with a seek in between.
471 for (int i = 0; i < 2; ++i) {
472 demuxer_->GetStream(DemuxerStream::AUDIO)
473 ->Read(NewReadCB(FROM_HERE, 4095, 0));
475 EXPECT_EQ(base::TimeDelta(), demuxer_->start_time());
477 // Seek back to the beginning and repeat the test.
478 WaitableMessageLoopEvent event;
479 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB());
480 event.RunAndWaitForStatus(PIPELINE_OK);
484 // TODO(dalecurtis): Test is disabled since FFmpeg does not currently guarantee
485 // the order of demuxed packets in OGG containers. Re-enable once we decide to
486 // either workaround it or attempt a fix upstream. See http://crbug.com/387996.
487 TEST_F(FFmpegDemuxerTest,
488 DISABLED_Read_AudioNegativeStartTimeAndOggDiscard_Bear) {
489 // Many ogg files have negative starting timestamps, so ensure demuxing and
490 // seeking work correctly with a negative start time.
491 CreateDemuxer("bear.ogv");
494 // Attempt a read from the video stream and run the message loop until done.
495 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
496 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
498 // Run the test twice with a seek in between.
499 for (int i = 0; i < 2; ++i) {
501 NewReadCBWithCheckedDiscard(FROM_HERE, 40, 0, kInfiniteDuration()));
504 NewReadCBWithCheckedDiscard(FROM_HERE, 41, 2903, kInfiniteDuration()));
506 audio->Read(NewReadCBWithCheckedDiscard(
507 FROM_HERE, 173, 5805, base::TimeDelta::FromMicroseconds(10159)));
510 audio->Read(NewReadCB(FROM_HERE, 148, 18866));
512 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-15964),
513 demuxer_->start_time());
515 video->Read(NewReadCB(FROM_HERE, 5751, 0));
518 video->Read(NewReadCB(FROM_HERE, 846, 33367));
521 video->Read(NewReadCB(FROM_HERE, 1255, 66733));
524 // Seek back to the beginning and repeat the test.
525 WaitableMessageLoopEvent event;
526 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB());
527 event.RunAndWaitForStatus(PIPELINE_OK);
531 // Same test above, but using sync2.ogv which has video stream muxed before the
532 // audio stream, so seeking based only on start time will fail since ffmpeg is
533 // essentially just seeking based on file position.
534 TEST_F(FFmpegDemuxerTest, Read_AudioNegativeStartTimeAndOggDiscard_Sync) {
535 // Many ogg files have negative starting timestamps, so ensure demuxing and
536 // seeking work correctly with a negative start time.
537 CreateDemuxer("sync2.ogv");
540 // Attempt a read from the video stream and run the message loop until done.
541 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
542 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
544 // Run the test twice with a seek in between.
545 for (int i = 0; i < 2; ++i) {
546 audio->Read(NewReadCBWithCheckedDiscard(
547 FROM_HERE, 1, 0, base::TimeDelta::FromMicroseconds(2902)));
550 audio->Read(NewReadCB(FROM_HERE, 1, 2902));
552 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-2902),
553 demuxer_->start_time());
555 video->Read(NewReadCB(FROM_HERE, 9997, 0));
558 video->Read(NewReadCB(FROM_HERE, 16, 33241));
561 video->Read(NewReadCB(FROM_HERE, 631, 66482));
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);
571 TEST_F(FFmpegDemuxerTest, Read_EndOfStream) {
572 // Verify that end of stream buffers are created.
573 CreateDemuxer("bear-320x240.webm");
575 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO));
578 TEST_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());
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));
595 EXPECT_TRUE(got_eos_buffer);
598 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration) {
599 // Verify that end of stream buffers are created.
600 CreateDemuxer("bear-320x240.webm");
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));
608 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration_VideoOnly) {
609 // Verify that end of stream buffers are created.
610 CreateDemuxer("bear-320x240-video-only.webm");
612 set_duration_known(false);
613 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(2703)));
614 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::VIDEO));
617 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration_AudioOnly) {
618 // Verify that end of stream buffers are created.
619 CreateDemuxer("bear-320x240-audio-only.webm");
621 set_duration_known(false);
622 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(2767)));
623 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO));
626 TEST_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");
631 set_duration_known(false);
632 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(1014)));
633 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO));
636 TEST_F(FFmpegDemuxerTest, Seek) {
637 // We're testing that the demuxer frees all queued packets when it receives
639 CreateDemuxer("bear-320x240.webm");
643 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
644 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
648 // Read a video packet and release it.
649 video->Read(NewReadCB(FROM_HERE, 22084, 0));
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);
659 audio->Read(NewReadCB(FROM_HERE, 145, 803000));
663 audio->Read(NewReadCB(FROM_HERE, 148, 826000));
667 video->Read(NewReadCB(FROM_HERE, 5425, 801000));
671 video->Read(NewReadCB(FROM_HERE, 1906, 834000));
675 TEST_F(FFmpegDemuxerTest, SeekText) {
676 // We're testing that the demuxer frees all queued packets when it receives
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());
687 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
688 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
692 // Read a text packet and release it.
693 text_stream->Read(NewReadCB(FROM_HERE, 31, 0));
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);
703 audio->Read(NewReadCB(FROM_HERE, 145, 803000));
707 audio->Read(NewReadCB(FROM_HERE, 148, 826000));
711 video->Read(NewReadCB(FROM_HERE, 5425, 801000));
715 video->Read(NewReadCB(FROM_HERE, 1906, 834000));
719 text_stream->Read(NewReadCB(FROM_HERE, 19, 500000));
723 text_stream->Read(NewReadCB(FROM_HERE, 19, 1000000));
732 MOCK_METHOD2(Run, void(DemuxerStream::Status status,
733 const scoped_refptr<DecoderBuffer>& buffer));
735 DISALLOW_COPY_AND_ASSIGN(MockReadCB);
738 TEST_F(FFmpegDemuxerTest, Stop) {
739 // Tests that calling Read() on a stopped demuxer stream immediately deletes
741 CreateDemuxer("bear-320x240.webm");
745 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
748 WaitableMessageLoopEvent event;
749 demuxer_->Stop(event.GetClosure());
752 // Reads after being stopped are all EOS buffers.
753 StrictMock<MockReadCB> callback;
754 EXPECT_CALL(callback, Run(DemuxerStream::kOk, IsEndOfStreamBuffer()));
756 // Attempt the read...
757 audio->Read(base::Bind(&MockReadCB::Run, base::Unretained(&callback)));
758 message_loop_.RunUntilIdle();
760 // Don't let the test call Stop() again.
764 // Verify that seek works properly when the WebM cues data is at the start of
765 // the file instead of at the end.
766 TEST_F(FFmpegDemuxerTest, SeekWithCuesBeforeFirstCluster) {
767 CreateDemuxer("bear-320x240-cues-in-front.webm");
771 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
772 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
776 // Read a video packet and release it.
777 video->Read(NewReadCB(FROM_HERE, 22084, 0));
780 // Issue a simple forward seek, which should discard queued packets.
781 WaitableMessageLoopEvent event;
782 demuxer_->Seek(base::TimeDelta::FromMicroseconds(2500000),
783 event.GetPipelineStatusCB());
784 event.RunAndWaitForStatus(PIPELINE_OK);
787 audio->Read(NewReadCB(FROM_HERE, 40, 2403000));
791 audio->Read(NewReadCB(FROM_HERE, 42, 2406000));
795 video->Read(NewReadCB(FROM_HERE, 5276, 2402000));
799 video->Read(NewReadCB(FROM_HERE, 1740, 2436000));
803 #if defined(USE_PROPRIETARY_CODECS)
804 // Ensure ID3v1 tag reading is disabled. id3_test.mp3 has an ID3v1 tag with the
805 // field "title" set to "sample for id3 test".
806 TEST_F(FFmpegDemuxerTest, NoID3TagData) {
807 CreateDemuxer("id3_test.mp3");
809 EXPECT_FALSE(av_dict_get(format_context()->metadata, "title", NULL, 0));
813 #if defined(USE_PROPRIETARY_CODECS)
814 // Ensure MP3 files with large image/video based ID3 tags demux okay. FFmpeg
815 // will hand us a video stream to the data which will likely be in a format we
816 // don't accept as video; e.g. PNG.
817 TEST_F(FFmpegDemuxerTest, Mp3WithVideoStreamID3TagData) {
818 CreateDemuxer("id3_png_test.mp3");
821 // Ensure the expected streams are present.
822 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO));
823 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO));
827 // Ensure a video with an unsupported audio track still results in the video
828 // stream being demuxed.
829 TEST_F(FFmpegDemuxerTest, UnsupportedAudioSupportedVideoDemux) {
830 CreateDemuxer("speex_audio_vorbis_video.ogv");
833 // Ensure the expected streams are present.
834 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::VIDEO));
835 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::AUDIO));
838 // Ensure a video with an unsupported video track still results in the audio
839 // stream being demuxed.
840 TEST_F(FFmpegDemuxerTest, UnsupportedVideoSupportedAudioDemux) {
841 CreateDemuxer("vorbis_audio_wmv_video.mkv");
844 // Ensure the expected streams are present.
845 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO));
846 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO));
849 #if defined(USE_PROPRIETARY_CODECS)
850 // FFmpeg returns null data pointers when samples have zero size, leading to
851 // mistakenly creating end of stream buffers http://crbug.com/169133
852 TEST_F(FFmpegDemuxerTest, MP4_ZeroStszEntry) {
853 CreateDemuxer("bear-1280x720-zero-stsz-entry.mp4");
855 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO));
859 static void ValidateAnnexB(DemuxerStream* stream,
860 DemuxerStream::Status status,
861 const scoped_refptr<DecoderBuffer>& buffer) {
862 EXPECT_EQ(status, DemuxerStream::kOk);
864 if (buffer->end_of_stream()) {
865 base::MessageLoop::current()->PostTask(
866 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
870 std::vector<SubsampleEntry> subsamples;
872 if (buffer->decrypt_config())
873 subsamples = buffer->decrypt_config()->subsamples();
876 mp4::AVC::IsValidAnnexB(buffer->data(), buffer->data_size(),
878 EXPECT_TRUE(is_valid);
881 LOG(ERROR) << "Buffer contains invalid Annex B data.";
882 base::MessageLoop::current()->PostTask(
883 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
887 stream->Read(base::Bind(&ValidateAnnexB, stream));
890 TEST_F(FFmpegDemuxerTest, IsValidAnnexB) {
891 const char* files[] = {
892 "bear-1280x720-av_frag.mp4",
893 "bear-1280x720-av_with-aud-nalus_frag.mp4"
896 for (size_t i = 0; i < arraysize(files); ++i) {
897 DVLOG(1) << "Testing " << files[i];
898 CreateDemuxer(files[i]);
901 // Ensure the expected streams are present.
902 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
904 stream->EnableBitstreamConverter();
906 stream->Read(base::Bind(&ValidateAnnexB, stream));
909 WaitableMessageLoopEvent event;
910 demuxer_->Stop(event.GetClosure());
913 data_source_.reset();
917 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_0) {
918 CreateDemuxer("bear_rotate_0.mp4");
921 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
923 ASSERT_EQ(VIDEO_ROTATION_0, stream->video_rotation());
926 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_90) {
927 CreateDemuxer("bear_rotate_90.mp4");
930 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
932 ASSERT_EQ(VIDEO_ROTATION_90, stream->video_rotation());
935 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_180) {
936 CreateDemuxer("bear_rotate_180.mp4");
939 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
941 ASSERT_EQ(VIDEO_ROTATION_180, stream->video_rotation());
944 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_270) {
945 CreateDemuxer("bear_rotate_270.mp4");
948 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
950 ASSERT_EQ(VIDEO_ROTATION_270, stream->video_rotation());