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 // Check first buffer in video stream. It should have been adjusted such
445 // that it starts 400ms after the first audio buffer.
449 (video_start_time
- audio_start_time
).InMicroseconds()));
452 // Since the audio buffer has a lower first timestamp, it should become
454 audio
->Read(NewReadCB(FROM_HERE
, 165, 0));
457 // Verify that the start time is equal to the lowest timestamp (ie the
459 EXPECT_EQ(audio_start_time
, demuxer_
->start_time());
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());
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
);
472 TEST_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");
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));
483 EXPECT_EQ(base::TimeDelta(), demuxer_
->start_time());
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
);
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.
495 TEST_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");
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
);
506 // Run the test twice with a seek in between.
507 for (int i
= 0; i
< 2; ++i
) {
509 NewReadCBWithCheckedDiscard(FROM_HERE
, 40, 0, kInfiniteDuration()));
512 NewReadCBWithCheckedDiscard(FROM_HERE
, 41, 2903, kInfiniteDuration()));
514 audio
->Read(NewReadCBWithCheckedDiscard(
515 FROM_HERE
, 173, 5805, base::TimeDelta::FromMicroseconds(10159)));
518 audio
->Read(NewReadCB(FROM_HERE
, 148, 18866));
520 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-15964),
521 demuxer_
->start_time());
523 video
->Read(NewReadCB(FROM_HERE
, 5751, 0));
526 video
->Read(NewReadCB(FROM_HERE
, 846, 33367));
529 video
->Read(NewReadCB(FROM_HERE
, 1255, 66733));
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
);
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.
542 TEST_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");
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
);
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)));
558 audio
->Read(NewReadCB(FROM_HERE
, 1, 2902));
560 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-2902),
561 demuxer_
->start_time());
563 video
->Read(NewReadCB(FROM_HERE
, 9997, 0));
566 video
->Read(NewReadCB(FROM_HERE
, 16, 33241));
569 video
->Read(NewReadCB(FROM_HERE
, 631, 66482));
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
);
579 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream
) {
580 // Verify that end of stream buffers are created.
581 CreateDemuxer("bear-320x240.webm");
583 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
586 TEST_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());
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
));
603 EXPECT_TRUE(got_eos_buffer
);
606 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream_NoDuration
) {
607 // Verify that end of stream buffers are created.
608 CreateDemuxer("bear-320x240.webm");
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
));
616 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream_NoDuration_VideoOnly
) {
617 // Verify that end of stream buffers are created.
618 CreateDemuxer("bear-320x240-video-only.webm");
620 set_duration_known(false);
621 EXPECT_CALL(host_
, SetDuration(base::TimeDelta::FromMilliseconds(2703)));
622 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::VIDEO
));
625 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream_NoDuration_AudioOnly
) {
626 // Verify that end of stream buffers are created.
627 CreateDemuxer("bear-320x240-audio-only.webm");
629 set_duration_known(false);
630 EXPECT_CALL(host_
, SetDuration(base::TimeDelta::FromMilliseconds(2767)));
631 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
634 TEST_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");
639 set_duration_known(false);
640 EXPECT_CALL(host_
, SetDuration(base::TimeDelta::FromMilliseconds(1014)));
641 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
644 TEST_F(FFmpegDemuxerTest
, Seek
) {
645 // We're testing that the demuxer frees all queued packets when it receives
647 CreateDemuxer("bear-320x240.webm");
651 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
652 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
656 // Read a video packet and release it.
657 video
->Read(NewReadCB(FROM_HERE
, 22084, 0));
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
);
667 audio
->Read(NewReadCB(FROM_HERE
, 145, 803000));
671 audio
->Read(NewReadCB(FROM_HERE
, 148, 826000));
675 video
->Read(NewReadCB(FROM_HERE
, 5425, 801000));
679 video
->Read(NewReadCB(FROM_HERE
, 1906, 834000));
683 TEST_F(FFmpegDemuxerTest
, SeekText
) {
684 // We're testing that the demuxer frees all queued packets when it receives
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());
695 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
696 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
700 // Read a text packet and release it.
701 text_stream
->Read(NewReadCB(FROM_HERE
, 31, 0));
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
);
711 audio
->Read(NewReadCB(FROM_HERE
, 145, 803000));
715 audio
->Read(NewReadCB(FROM_HERE
, 148, 826000));
719 video
->Read(NewReadCB(FROM_HERE
, 5425, 801000));
723 video
->Read(NewReadCB(FROM_HERE
, 1906, 834000));
727 text_stream
->Read(NewReadCB(FROM_HERE
, 19, 500000));
731 text_stream
->Read(NewReadCB(FROM_HERE
, 19, 1000000));
740 MOCK_METHOD2(Run
, void(DemuxerStream::Status status
,
741 const scoped_refptr
<DecoderBuffer
>& buffer
));
743 DISALLOW_COPY_AND_ASSIGN(MockReadCB
);
746 TEST_F(FFmpegDemuxerTest
, Stop
) {
747 // Tests that calling Read() on a stopped demuxer stream immediately deletes
749 CreateDemuxer("bear-320x240.webm");
753 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
756 WaitableMessageLoopEvent event
;
757 demuxer_
->Stop(event
.GetClosure());
760 // Reads after being stopped are all EOS buffers.
761 StrictMock
<MockReadCB
> callback
;
762 EXPECT_CALL(callback
, Run(DemuxerStream::kOk
, IsEndOfStreamBuffer()));
764 // Attempt the read...
765 audio
->Read(base::Bind(&MockReadCB::Run
, base::Unretained(&callback
)));
766 message_loop_
.RunUntilIdle();
768 // Don't let the test call Stop() again.
772 // Verify that seek works properly when the WebM cues data is at the start of
773 // the file instead of at the end.
774 TEST_F(FFmpegDemuxerTest
, SeekWithCuesBeforeFirstCluster
) {
775 CreateDemuxer("bear-320x240-cues-in-front.webm");
779 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
780 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
784 // Read a video packet and release it.
785 video
->Read(NewReadCB(FROM_HERE
, 22084, 0));
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
);
795 audio
->Read(NewReadCB(FROM_HERE
, 40, 2403000));
799 audio
->Read(NewReadCB(FROM_HERE
, 42, 2406000));
803 video
->Read(NewReadCB(FROM_HERE
, 5276, 2402000));
807 video
->Read(NewReadCB(FROM_HERE
, 1740, 2436000));
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".
814 TEST_F(FFmpegDemuxerTest
, NoID3TagData
) {
815 CreateDemuxer("id3_test.mp3");
817 EXPECT_FALSE(av_dict_get(format_context()->metadata
, "title", NULL
, 0));
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.
825 TEST_F(FFmpegDemuxerTest
, Mp3WithVideoStreamID3TagData
) {
826 CreateDemuxer("id3_png_test.mp3");
829 // Ensure the expected streams are present.
830 EXPECT_FALSE(demuxer_
->GetStream(DemuxerStream::VIDEO
));
831 EXPECT_TRUE(demuxer_
->GetStream(DemuxerStream::AUDIO
));
835 // Ensure a video with an unsupported audio track still results in the video
836 // stream being demuxed.
837 TEST_F(FFmpegDemuxerTest
, UnsupportedAudioSupportedVideoDemux
) {
838 CreateDemuxer("speex_audio_vorbis_video.ogv");
841 // Ensure the expected streams are present.
842 EXPECT_TRUE(demuxer_
->GetStream(DemuxerStream::VIDEO
));
843 EXPECT_FALSE(demuxer_
->GetStream(DemuxerStream::AUDIO
));
846 // Ensure a video with an unsupported video track still results in the audio
847 // stream being demuxed.
848 TEST_F(FFmpegDemuxerTest
, UnsupportedVideoSupportedAudioDemux
) {
849 CreateDemuxer("vorbis_audio_wmv_video.mkv");
852 // Ensure the expected streams are present.
853 EXPECT_FALSE(demuxer_
->GetStream(DemuxerStream::VIDEO
));
854 EXPECT_TRUE(demuxer_
->GetStream(DemuxerStream::AUDIO
));
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
860 TEST_F(FFmpegDemuxerTest
, MP4_ZeroStszEntry
) {
861 CreateDemuxer("bear-1280x720-zero-stsz-entry.mp4");
863 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
867 static void ValidateAnnexB(DemuxerStream
* stream
,
868 DemuxerStream::Status status
,
869 const scoped_refptr
<DecoderBuffer
>& buffer
) {
870 EXPECT_EQ(status
, DemuxerStream::kOk
);
872 if (buffer
->end_of_stream()) {
873 base::MessageLoop::current()->PostTask(
874 FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
879 mp4::AVC::IsValidAnnexB(buffer
->data(), buffer
->data_size());
880 EXPECT_TRUE(is_valid
);
883 LOG(ERROR
) << "Buffer contains invalid Annex B data.";
884 base::MessageLoop::current()->PostTask(
885 FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
889 stream
->Read(base::Bind(&ValidateAnnexB
, stream
));
892 TEST_F(FFmpegDemuxerTest
, IsValidAnnexB
) {
893 const char* files
[] = {
894 "bear-1280x720-av_frag.mp4",
895 "bear-1280x720-av_with-aud-nalus_frag.mp4"
898 for (size_t i
= 0; i
< arraysize(files
); ++i
) {
899 DVLOG(1) << "Testing " << files
[i
];
900 CreateDemuxer(files
[i
]);
903 // Ensure the expected streams are present.
904 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
906 stream
->EnableBitstreamConverter();
908 stream
->Read(base::Bind(&ValidateAnnexB
, stream
));
911 WaitableMessageLoopEvent event
;
912 demuxer_
->Stop(event
.GetClosure());
915 data_source_
.reset();
919 TEST_F(FFmpegDemuxerTest
, Rotate_Metadata_0
) {
920 CreateDemuxer("bear_rotate_0.mp4");
923 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
925 ASSERT_EQ(VIDEO_ROTATION_0
, stream
->video_rotation());
928 TEST_F(FFmpegDemuxerTest
, Rotate_Metadata_90
) {
929 CreateDemuxer("bear_rotate_90.mp4");
932 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
934 ASSERT_EQ(VIDEO_ROTATION_90
, stream
->video_rotation());
937 TEST_F(FFmpegDemuxerTest
, Rotate_Metadata_180
) {
938 CreateDemuxer("bear_rotate_180.mp4");
941 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
943 ASSERT_EQ(VIDEO_ROTATION_180
, stream
->video_rotation());
946 TEST_F(FFmpegDemuxerTest
, Rotate_Metadata_270
) {
947 CreateDemuxer("bear_rotate_270.mp4");
950 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
952 ASSERT_EQ(VIDEO_ROTATION_270
, stream
->video_rotation());