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() {
74 void CreateDemuxer(const std::string& name) {
77 EXPECT_CALL(host_, AddBufferedTimeRange(_, _)).Times(AnyNumber());
79 CreateDataSource(name);
81 Demuxer::NeedKeyCB need_key_cb =
82 base::Bind(&FFmpegDemuxerTest::NeedKeyCB, base::Unretained(this));
84 demuxer_.reset(new FFmpegDemuxer(message_loop_.message_loop_proxy(),
90 MOCK_METHOD1(CheckPoint, void(int v));
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);
101 void InitializeDemuxerText(bool enable_text) {
102 InitializeDemuxerWithTimelineOffset(enable_text, base::Time());
105 void InitializeDemuxer() {
106 InitializeDemuxerText(false);
109 MOCK_METHOD2(OnReadDoneCalled, void(int, int64));
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,
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());
134 DemuxerStream::ReadCB NewReadCB(const tracked_objects::Location& location,
136 int64 timestamp_us) {
137 EXPECT_CALL(*this, OnReadDoneCalled(size, timestamp_us));
138 return base::Bind(&FFmpegDemuxerTest::OnReadDone,
139 base::Unretained(this),
146 DemuxerStream::ReadCB NewReadCBWithCheckedDiscard(
147 const tracked_objects::Location& location,
150 base::TimeDelta discard_front_padding) {
151 EXPECT_CALL(*this, OnReadDoneCalled(size, timestamp_us));
152 return base::Bind(&FFmpegDemuxerTest::OnReadDone,
153 base::Unretained(this),
157 discard_front_padding);
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());
172 // Accessor to demuxer internals.
173 void set_duration_known(bool duration_known) {
174 demuxer_->duration_known_ = duration_known;
177 bool IsStreamStopped(DemuxerStream::Type type) {
178 DemuxerStream* stream = demuxer_->GetStream(type);
180 return !static_cast<FFmpegDemuxerStream*>(stream)->demuxer_;
184 scoped_ptr<FileDataSource> data_source_;
185 scoped_ptr<FFmpegDemuxer> demuxer_;
186 StrictMock<MockDemuxerHost> host_;
187 base::MessageLoop message_loop_;
189 AVFormatContext* format_context() {
190 return demuxer_->glue_->format_context();
193 int preferred_seeking_stream_index() const {
194 return demuxer_->preferred_stream_for_seeking_.first;
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));
205 EXPECT_TRUE(got_eos_buffer);
209 void CreateDataSource(const std::string& name) {
210 CHECK(!data_source_);
212 base::FilePath file_path;
213 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
215 file_path = file_path.Append(FILE_PATH_LITERAL("media"))
216 .Append(FILE_PATH_LITERAL("test"))
217 .Append(FILE_PATH_LITERAL("data"))
220 data_source_.reset(new FileDataSource());
221 EXPECT_TRUE(data_source_->Initialize(file_path));
224 DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest);
227 TEST_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);
235 // TODO(acolwell): Uncomment this test when we discover a file that passes
236 // avformat_open_input(), but has avformat_find_stream_info() fail.
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();
245 TEST_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);
253 TEST_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);
261 TEST_F(FFmpegDemuxerTest, Initialize_Successful) {
262 CreateDemuxer("bear-320x240.webm");
265 // Video stream should be present.
266 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
268 EXPECT_EQ(DemuxerStream::VIDEO, stream->type());
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());
284 // Audio stream should be present.
285 stream = demuxer_->GetStream(DemuxerStream::AUDIO);
287 EXPECT_EQ(DemuxerStream::AUDIO, stream->type());
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);
298 // Unknown stream should never be present.
299 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN));
302 TEST_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)
310 // We should only pick the first audio/video streams we come across.
311 CreateDemuxer("bear-320x240-multitrack.webm");
314 // Video stream should be VP8.
315 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
317 EXPECT_EQ(DemuxerStream::VIDEO, stream->type());
318 EXPECT_EQ(kCodecVP8, stream->video_decoder_config().codec());
320 // Audio stream should be Vorbis.
321 stream = demuxer_->GetStream(DemuxerStream::AUDIO);
323 EXPECT_EQ(DemuxerStream::AUDIO, stream->type());
324 EXPECT_EQ(kCodecVorbis, stream->audio_decoder_config().codec());
326 // Unknown stream should never be present.
327 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN));
330 TEST_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)
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());
344 // Video stream should be VP8.
345 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
347 EXPECT_EQ(DemuxerStream::VIDEO, stream->type());
348 EXPECT_EQ(kCodecVP8, stream->video_decoder_config().codec());
350 // Audio stream should be Vorbis.
351 stream = demuxer_->GetStream(DemuxerStream::AUDIO);
353 EXPECT_EQ(DemuxerStream::AUDIO, stream->type());
354 EXPECT_EQ(kCodecVorbis, stream->audio_decoder_config().codec());
356 // Unknown stream should never be present.
357 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN));
360 TEST_F(FFmpegDemuxerTest, Initialize_Encrypted) {
361 EXPECT_CALL(*this, NeedKeyCBMock(kWebMEncryptInitDataType, NotNull(),
362 DecryptConfig::kDecryptionKeySize))
365 CreateDemuxer("bear-320x240-av_enc-av.webm");
369 TEST_F(FFmpegDemuxerTest, Read_Audio) {
370 // We test that on a successful audio packet read.
371 CreateDemuxer("bear-320x240.webm");
374 // Attempt a read from the audio stream and run the message loop until done.
375 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
377 audio->Read(NewReadCB(FROM_HERE, 29, 0));
380 audio->Read(NewReadCB(FROM_HERE, 27, 3000));
384 TEST_F(FFmpegDemuxerTest, Read_Video) {
385 // We test that on a successful video packet read.
386 CreateDemuxer("bear-320x240.webm");
389 // Attempt a read from the video stream and run the message loop until done.
390 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
392 video->Read(NewReadCB(FROM_HERE, 22084, 0));
395 video->Read(NewReadCB(FROM_HERE, 1057, 33000));
399 TEST_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());
409 text_stream->Read(NewReadCB(FROM_HERE, 31, 0));
412 text_stream->Read(NewReadCB(FROM_HERE, 19, 500000));
416 TEST_F(FFmpegDemuxerTest, SeekInitialized_NoVideoStartTime) {
417 CreateDemuxer("audio-start-time-only.webm");
419 EXPECT_EQ(0, preferred_seeking_stream_index());
422 TEST_F(FFmpegDemuxerTest, Read_VideoPositiveStartTime) {
423 const int64 kTimelineOffsetMs = 1352550896000LL;
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));
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);
434 const base::TimeDelta video_start_time =
435 base::TimeDelta::FromMicroseconds(400000);
436 const base::TimeDelta audio_start_time =
437 base::TimeDelta::FromMicroseconds(396000);
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()));
443 audio->Read(NewReadCB(FROM_HERE, 165, audio_start_time.InMicroseconds()));
446 // Verify that the start time is equal to the lowest timestamp (ie the
448 EXPECT_EQ(audio_start_time, demuxer_->start_time());
450 // Verify that the timeline offset has not been adjusted by the start time.
451 EXPECT_EQ(kTimelineOffsetMs, demuxer_->GetTimelineOffset().ToJavaTime());
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);
460 TEST_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");
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));
471 EXPECT_EQ(base::TimeDelta(), demuxer_->start_time());
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);
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.
483 TEST_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");
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);
494 // Run the test twice with a seek in between.
495 for (int i = 0; i < 2; ++i) {
497 NewReadCBWithCheckedDiscard(FROM_HERE, 40, 0, kInfiniteDuration()));
500 NewReadCBWithCheckedDiscard(FROM_HERE, 41, 2903, kInfiniteDuration()));
502 audio->Read(NewReadCBWithCheckedDiscard(
503 FROM_HERE, 173, 5805, base::TimeDelta::FromMicroseconds(10159)));
506 audio->Read(NewReadCB(FROM_HERE, 148, 18866));
508 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-15964),
509 demuxer_->start_time());
511 video->Read(NewReadCB(FROM_HERE, 5751, 0));
514 video->Read(NewReadCB(FROM_HERE, 846, 33367));
517 video->Read(NewReadCB(FROM_HERE, 1255, 66733));
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);
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.
530 TEST_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");
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);
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)));
546 audio->Read(NewReadCB(FROM_HERE, 1, 2902));
548 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-2902),
549 demuxer_->start_time());
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());
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);
750 // Reads after being stopped are all EOS buffers.
751 StrictMock<MockReadCB> callback;
752 EXPECT_CALL(callback, Run(DemuxerStream::kOk, IsEndOfStreamBuffer()));
754 // Attempt the read...
755 audio->Read(base::Bind(&MockReadCB::Run, base::Unretained(&callback)));
756 message_loop_.RunUntilIdle();
758 // Don't let the test call Stop() again.
762 // Verify that seek works properly when the WebM cues data is at the start of
763 // the file instead of at the end.
764 TEST_F(FFmpegDemuxerTest, SeekWithCuesBeforeFirstCluster) {
765 CreateDemuxer("bear-320x240-cues-in-front.webm");
769 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
770 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
774 // Read a video packet and release it.
775 video->Read(NewReadCB(FROM_HERE, 22084, 0));
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);
785 audio->Read(NewReadCB(FROM_HERE, 40, 2403000));
789 audio->Read(NewReadCB(FROM_HERE, 42, 2406000));
793 video->Read(NewReadCB(FROM_HERE, 5276, 2402000));
797 video->Read(NewReadCB(FROM_HERE, 1740, 2436000));
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".
804 TEST_F(FFmpegDemuxerTest, NoID3TagData) {
805 CreateDemuxer("id3_test.mp3");
807 EXPECT_FALSE(av_dict_get(format_context()->metadata, "title", NULL, 0));
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.
815 TEST_F(FFmpegDemuxerTest, Mp3WithVideoStreamID3TagData) {
816 CreateDemuxer("id3_png_test.mp3");
819 // Ensure the expected streams are present.
820 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO));
821 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO));
825 // Ensure a video with an unsupported audio track still results in the video
826 // stream being demuxed.
827 TEST_F(FFmpegDemuxerTest, UnsupportedAudioSupportedVideoDemux) {
828 CreateDemuxer("speex_audio_vorbis_video.ogv");
831 // Ensure the expected streams are present.
832 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::VIDEO));
833 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::AUDIO));
836 // Ensure a video with an unsupported video track still results in the audio
837 // stream being demuxed.
838 TEST_F(FFmpegDemuxerTest, UnsupportedVideoSupportedAudioDemux) {
839 CreateDemuxer("vorbis_audio_wmv_video.mkv");
842 // Ensure the expected streams are present.
843 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO));
844 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO));
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
850 TEST_F(FFmpegDemuxerTest, MP4_ZeroStszEntry) {
851 CreateDemuxer("bear-1280x720-zero-stsz-entry.mp4");
853 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO));
857 static void ValidateAnnexB(DemuxerStream* stream,
858 DemuxerStream::Status status,
859 const scoped_refptr<DecoderBuffer>& buffer) {
860 EXPECT_EQ(status, DemuxerStream::kOk);
862 if (buffer->end_of_stream()) {
863 base::MessageLoop::current()->PostTask(
864 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
868 std::vector<SubsampleEntry> subsamples;
870 if (buffer->decrypt_config())
871 subsamples = buffer->decrypt_config()->subsamples();
874 mp4::AVC::IsValidAnnexB(buffer->data(), buffer->data_size(),
876 EXPECT_TRUE(is_valid);
879 LOG(ERROR) << "Buffer contains invalid Annex B data.";
880 base::MessageLoop::current()->PostTask(
881 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
885 stream->Read(base::Bind(&ValidateAnnexB, stream));
888 TEST_F(FFmpegDemuxerTest, IsValidAnnexB) {
889 const char* files[] = {
890 "bear-1280x720-av_frag.mp4",
891 "bear-1280x720-av_with-aud-nalus_frag.mp4"
894 for (size_t i = 0; i < arraysize(files); ++i) {
895 DVLOG(1) << "Testing " << files[i];
896 CreateDemuxer(files[i]);
899 // Ensure the expected streams are present.
900 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
902 stream->EnableBitstreamConverter();
904 stream->Read(base::Bind(&ValidateAnnexB, stream));
909 data_source_.reset();
913 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_0) {
914 CreateDemuxer("bear_rotate_0.mp4");
917 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
919 ASSERT_EQ(VIDEO_ROTATION_0, stream->video_rotation());
922 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_90) {
923 CreateDemuxer("bear_rotate_90.mp4");
926 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
928 ASSERT_EQ(VIDEO_ROTATION_90, stream->video_rotation());
931 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_180) {
932 CreateDemuxer("bear_rotate_180.mp4");
935 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
937 ASSERT_EQ(VIDEO_ROTATION_180, stream->video_rotation());
940 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_270) {
941 CreateDemuxer("bear_rotate_270.mp4");
944 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
946 ASSERT_EQ(VIDEO_ROTATION_270, stream->video_rotation());