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 not been adjusted by the start time.
454 EXPECT_EQ(kTimelineOffsetMs, demuxer_->GetTimelineOffset().ToJavaTime());
456 // Seek back to the beginning and repeat the test.
457 WaitableMessageLoopEvent event;
458 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB());
459 event.RunAndWaitForStatus(PIPELINE_OK);
463 TEST_F(FFmpegDemuxerTest, Read_AudioNoStartTime) {
464 // FFmpeg does not set timestamps when demuxing wave files. Ensure that the
465 // demuxer sets a start time of zero in this case.
466 CreateDemuxer("sfx_s24le.wav");
469 // Run the test twice with a seek in between.
470 for (int i = 0; i < 2; ++i) {
471 demuxer_->GetStream(DemuxerStream::AUDIO)
472 ->Read(NewReadCB(FROM_HERE, 4095, 0));
474 EXPECT_EQ(base::TimeDelta(), demuxer_->start_time());
476 // Seek back to the beginning and repeat the test.
477 WaitableMessageLoopEvent event;
478 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB());
479 event.RunAndWaitForStatus(PIPELINE_OK);
483 // TODO(dalecurtis): Test is disabled since FFmpeg does not currently guarantee
484 // the order of demuxed packets in OGG containers. Re-enable once we decide to
485 // either workaround it or attempt a fix upstream. See http://crbug.com/387996.
486 TEST_F(FFmpegDemuxerTest,
487 DISABLED_Read_AudioNegativeStartTimeAndOggDiscard_Bear) {
488 // Many ogg files have negative starting timestamps, so ensure demuxing and
489 // seeking work correctly with a negative start time.
490 CreateDemuxer("bear.ogv");
493 // Attempt a read from the video stream and run the message loop until done.
494 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
495 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
497 // Run the test twice with a seek in between.
498 for (int i = 0; i < 2; ++i) {
500 NewReadCBWithCheckedDiscard(FROM_HERE, 40, 0, kInfiniteDuration()));
503 NewReadCBWithCheckedDiscard(FROM_HERE, 41, 2903, kInfiniteDuration()));
505 audio->Read(NewReadCBWithCheckedDiscard(
506 FROM_HERE, 173, 5805, base::TimeDelta::FromMicroseconds(10159)));
509 audio->Read(NewReadCB(FROM_HERE, 148, 18866));
511 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-15964),
512 demuxer_->start_time());
514 video->Read(NewReadCB(FROM_HERE, 5751, 0));
517 video->Read(NewReadCB(FROM_HERE, 846, 33367));
520 video->Read(NewReadCB(FROM_HERE, 1255, 66733));
523 // Seek back to the beginning and repeat the test.
524 WaitableMessageLoopEvent event;
525 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB());
526 event.RunAndWaitForStatus(PIPELINE_OK);
530 // Same test above, but using sync2.ogv which has video stream muxed before the
531 // audio stream, so seeking based only on start time will fail since ffmpeg is
532 // essentially just seeking based on file position.
533 TEST_F(FFmpegDemuxerTest, Read_AudioNegativeStartTimeAndOggDiscard_Sync) {
534 // Many ogg files have negative starting timestamps, so ensure demuxing and
535 // seeking work correctly with a negative start time.
536 CreateDemuxer("sync2.ogv");
539 // Attempt a read from the video stream and run the message loop until done.
540 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
541 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
543 // Run the test twice with a seek in between.
544 for (int i = 0; i < 2; ++i) {
545 audio->Read(NewReadCBWithCheckedDiscard(
546 FROM_HERE, 1, 0, base::TimeDelta::FromMicroseconds(2902)));
549 audio->Read(NewReadCB(FROM_HERE, 1, 2902));
551 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-2902),
552 demuxer_->start_time());
554 // Though the internal start time may be below zero, the exposed media time
555 // must always be greater than zero.
556 EXPECT_EQ(base::TimeDelta(), demuxer_->GetStartTime());
558 video->Read(NewReadCB(FROM_HERE, 9997, 0));
561 video->Read(NewReadCB(FROM_HERE, 16, 33241));
564 video->Read(NewReadCB(FROM_HERE, 631, 66482));
567 // Seek back to the beginning and repeat the test.
568 WaitableMessageLoopEvent event;
569 demuxer_->Seek(base::TimeDelta(), event.GetPipelineStatusCB());
570 event.RunAndWaitForStatus(PIPELINE_OK);
574 TEST_F(FFmpegDemuxerTest, Read_EndOfStream) {
575 // Verify that end of stream buffers are created.
576 CreateDemuxer("bear-320x240.webm");
578 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO));
581 TEST_F(FFmpegDemuxerTest, Read_EndOfStreamText) {
582 // Verify that end of stream buffers are created.
583 CreateDemuxer("bear-vp8-webvtt.webm");
584 DemuxerStream* text_stream = NULL;
585 EXPECT_CALL(host_, AddTextStream(_, _))
586 .WillOnce(SaveArg<0>(&text_stream));
587 InitializeDemuxerText(true);
588 ASSERT_TRUE(text_stream);
589 EXPECT_EQ(DemuxerStream::TEXT, text_stream->type());
591 bool got_eos_buffer = false;
592 const int kMaxBuffers = 10;
593 for (int i = 0; !got_eos_buffer && i < kMaxBuffers; i++) {
594 text_stream->Read(base::Bind(&EosOnReadDone, &got_eos_buffer));
598 EXPECT_TRUE(got_eos_buffer);
601 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration) {
602 // Verify that end of stream buffers are created.
603 CreateDemuxer("bear-320x240.webm");
605 set_duration_known(false);
606 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(2767)));
607 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO));
608 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::VIDEO));
611 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration_VideoOnly) {
612 // Verify that end of stream buffers are created.
613 CreateDemuxer("bear-320x240-video-only.webm");
615 set_duration_known(false);
616 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(2703)));
617 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::VIDEO));
620 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration_AudioOnly) {
621 // Verify that end of stream buffers are created.
622 CreateDemuxer("bear-320x240-audio-only.webm");
624 set_duration_known(false);
625 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(2767)));
626 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO));
629 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration_UnsupportedStream) {
630 // Verify that end of stream buffers are created and we don't crash
631 // if there are streams in the file that we don't support.
632 CreateDemuxer("vorbis_audio_wmv_video.mkv");
634 set_duration_known(false);
635 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(1014)));
636 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO));
639 TEST_F(FFmpegDemuxerTest, Seek) {
640 // We're testing that the demuxer frees all queued packets when it receives
642 CreateDemuxer("bear-320x240.webm");
646 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
647 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
651 // Read a video packet and release it.
652 video->Read(NewReadCB(FROM_HERE, 22084, 0));
655 // Issue a simple forward seek, which should discard queued packets.
656 WaitableMessageLoopEvent event;
657 demuxer_->Seek(base::TimeDelta::FromMicroseconds(1000000),
658 event.GetPipelineStatusCB());
659 event.RunAndWaitForStatus(PIPELINE_OK);
662 audio->Read(NewReadCB(FROM_HERE, 145, 803000));
666 audio->Read(NewReadCB(FROM_HERE, 148, 826000));
670 video->Read(NewReadCB(FROM_HERE, 5425, 801000));
674 video->Read(NewReadCB(FROM_HERE, 1906, 834000));
678 TEST_F(FFmpegDemuxerTest, SeekText) {
679 // We're testing that the demuxer frees all queued packets when it receives
681 CreateDemuxer("bear-vp8-webvtt.webm");
682 DemuxerStream* text_stream = NULL;
683 EXPECT_CALL(host_, AddTextStream(_, _))
684 .WillOnce(SaveArg<0>(&text_stream));
685 InitializeDemuxerText(true);
686 ASSERT_TRUE(text_stream);
687 EXPECT_EQ(DemuxerStream::TEXT, text_stream->type());
690 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
691 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
695 // Read a text packet and release it.
696 text_stream->Read(NewReadCB(FROM_HERE, 31, 0));
699 // Issue a simple forward seek, which should discard queued packets.
700 WaitableMessageLoopEvent event;
701 demuxer_->Seek(base::TimeDelta::FromMicroseconds(1000000),
702 event.GetPipelineStatusCB());
703 event.RunAndWaitForStatus(PIPELINE_OK);
706 audio->Read(NewReadCB(FROM_HERE, 145, 803000));
710 audio->Read(NewReadCB(FROM_HERE, 148, 826000));
714 video->Read(NewReadCB(FROM_HERE, 5425, 801000));
718 video->Read(NewReadCB(FROM_HERE, 1906, 834000));
722 text_stream->Read(NewReadCB(FROM_HERE, 19, 500000));
726 text_stream->Read(NewReadCB(FROM_HERE, 19, 1000000));
735 MOCK_METHOD2(Run, void(DemuxerStream::Status status,
736 const scoped_refptr<DecoderBuffer>& buffer));
738 DISALLOW_COPY_AND_ASSIGN(MockReadCB);
741 TEST_F(FFmpegDemuxerTest, Stop) {
742 // Tests that calling Read() on a stopped demuxer stream immediately deletes
744 CreateDemuxer("bear-320x240.webm");
748 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
751 WaitableMessageLoopEvent event;
752 demuxer_->Stop(event.GetClosure());
755 // Reads after being stopped are all EOS buffers.
756 StrictMock<MockReadCB> callback;
757 EXPECT_CALL(callback, Run(DemuxerStream::kOk, IsEndOfStreamBuffer()));
759 // Attempt the read...
760 audio->Read(base::Bind(&MockReadCB::Run, base::Unretained(&callback)));
761 message_loop_.RunUntilIdle();
763 // Don't let the test call Stop() again.
767 // Verify that seek works properly when the WebM cues data is at the start of
768 // the file instead of at the end.
769 TEST_F(FFmpegDemuxerTest, SeekWithCuesBeforeFirstCluster) {
770 CreateDemuxer("bear-320x240-cues-in-front.webm");
774 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
775 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
779 // Read a video packet and release it.
780 video->Read(NewReadCB(FROM_HERE, 22084, 0));
783 // Issue a simple forward seek, which should discard queued packets.
784 WaitableMessageLoopEvent event;
785 demuxer_->Seek(base::TimeDelta::FromMicroseconds(2500000),
786 event.GetPipelineStatusCB());
787 event.RunAndWaitForStatus(PIPELINE_OK);
790 audio->Read(NewReadCB(FROM_HERE, 40, 2403000));
794 audio->Read(NewReadCB(FROM_HERE, 42, 2406000));
798 video->Read(NewReadCB(FROM_HERE, 5276, 2402000));
802 video->Read(NewReadCB(FROM_HERE, 1740, 2436000));
806 #if defined(USE_PROPRIETARY_CODECS)
807 // Ensure ID3v1 tag reading is disabled. id3_test.mp3 has an ID3v1 tag with the
808 // field "title" set to "sample for id3 test".
809 TEST_F(FFmpegDemuxerTest, NoID3TagData) {
810 CreateDemuxer("id3_test.mp3");
812 EXPECT_FALSE(av_dict_get(format_context()->metadata, "title", NULL, 0));
816 #if defined(USE_PROPRIETARY_CODECS)
817 // Ensure MP3 files with large image/video based ID3 tags demux okay. FFmpeg
818 // will hand us a video stream to the data which will likely be in a format we
819 // don't accept as video; e.g. PNG.
820 TEST_F(FFmpegDemuxerTest, Mp3WithVideoStreamID3TagData) {
821 CreateDemuxer("id3_png_test.mp3");
824 // Ensure the expected streams are present.
825 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO));
826 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO));
830 // Ensure a video with an unsupported audio track still results in the video
831 // stream being demuxed.
832 TEST_F(FFmpegDemuxerTest, UnsupportedAudioSupportedVideoDemux) {
833 CreateDemuxer("speex_audio_vorbis_video.ogv");
836 // Ensure the expected streams are present.
837 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::VIDEO));
838 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::AUDIO));
841 // Ensure a video with an unsupported video track still results in the audio
842 // stream being demuxed.
843 TEST_F(FFmpegDemuxerTest, UnsupportedVideoSupportedAudioDemux) {
844 CreateDemuxer("vorbis_audio_wmv_video.mkv");
847 // Ensure the expected streams are present.
848 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO));
849 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO));
852 #if defined(USE_PROPRIETARY_CODECS)
853 // FFmpeg returns null data pointers when samples have zero size, leading to
854 // mistakenly creating end of stream buffers http://crbug.com/169133
855 TEST_F(FFmpegDemuxerTest, MP4_ZeroStszEntry) {
856 CreateDemuxer("bear-1280x720-zero-stsz-entry.mp4");
858 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO));
862 static void ValidateAnnexB(DemuxerStream* stream,
863 DemuxerStream::Status status,
864 const scoped_refptr<DecoderBuffer>& buffer) {
865 EXPECT_EQ(status, DemuxerStream::kOk);
867 if (buffer->end_of_stream()) {
868 base::MessageLoop::current()->PostTask(
869 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
873 std::vector<SubsampleEntry> subsamples;
875 if (buffer->decrypt_config())
876 subsamples = buffer->decrypt_config()->subsamples();
879 mp4::AVC::IsValidAnnexB(buffer->data(), buffer->data_size(),
881 EXPECT_TRUE(is_valid);
884 LOG(ERROR) << "Buffer contains invalid Annex B data.";
885 base::MessageLoop::current()->PostTask(
886 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
890 stream->Read(base::Bind(&ValidateAnnexB, stream));
893 TEST_F(FFmpegDemuxerTest, IsValidAnnexB) {
894 const char* files[] = {
895 "bear-1280x720-av_frag.mp4",
896 "bear-1280x720-av_with-aud-nalus_frag.mp4"
899 for (size_t i = 0; i < arraysize(files); ++i) {
900 DVLOG(1) << "Testing " << files[i];
901 CreateDemuxer(files[i]);
904 // Ensure the expected streams are present.
905 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
907 stream->EnableBitstreamConverter();
909 stream->Read(base::Bind(&ValidateAnnexB, stream));
912 WaitableMessageLoopEvent event;
913 demuxer_->Stop(event.GetClosure());
916 data_source_.reset();
920 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_0) {
921 CreateDemuxer("bear_rotate_0.mp4");
924 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
926 ASSERT_EQ(VIDEO_ROTATION_0, stream->video_rotation());
929 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_90) {
930 CreateDemuxer("bear_rotate_90.mp4");
933 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
935 ASSERT_EQ(VIDEO_ROTATION_90, stream->video_rotation());
938 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_180) {
939 CreateDemuxer("bear_rotate_180.mp4");
942 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
944 ASSERT_EQ(VIDEO_ROTATION_180, stream->video_rotation());
947 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_270) {
948 CreateDemuxer("bear_rotate_270.mp4");
951 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
953 ASSERT_EQ(VIDEO_ROTATION_270, stream->video_rotation());