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 struct ReadExpectation
{
112 ReadExpectation(int size
,
114 const base::TimeDelta
& discard_front_padding
,
117 timestamp_us(timestamp_us
),
118 discard_front_padding(discard_front_padding
),
119 is_key_frame(is_key_frame
) {
124 base::TimeDelta discard_front_padding
;
128 // Verifies that |buffer| has a specific |size| and |timestamp|.
129 // |location| simply indicates where the call to this function was made.
130 // This makes it easier to track down where test failures occur.
131 void OnReadDone(const tracked_objects::Location
& location
,
132 const ReadExpectation
& read_expectation
,
133 DemuxerStream::Status status
,
134 const scoped_refptr
<DecoderBuffer
>& buffer
) {
135 std::string location_str
;
136 location
.Write(true, false, &location_str
);
137 location_str
+= "\n";
138 SCOPED_TRACE(location_str
);
139 EXPECT_EQ(status
, DemuxerStream::kOk
);
140 EXPECT_TRUE(buffer
.get() != NULL
);
141 EXPECT_EQ(read_expectation
.size
, buffer
->data_size());
142 EXPECT_EQ(read_expectation
.timestamp_us
,
143 buffer
->timestamp().InMicroseconds());
144 EXPECT_EQ(read_expectation
.discard_front_padding
,
145 buffer
->discard_padding().first
);
146 EXPECT_EQ(read_expectation
.is_key_frame
, buffer
->is_key_frame());
147 DCHECK_EQ(&message_loop_
, base::MessageLoop::current());
148 OnReadDoneCalled(read_expectation
.size
, read_expectation
.timestamp_us
);
149 message_loop_
.PostTask(FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
152 DemuxerStream::ReadCB
NewReadCB(const tracked_objects::Location
& location
,
156 return NewReadCBWithCheckedDiscard(location
,
163 DemuxerStream::ReadCB
NewReadCBWithCheckedDiscard(
164 const tracked_objects::Location
& location
,
167 base::TimeDelta discard_front_padding
,
169 EXPECT_CALL(*this, OnReadDoneCalled(size
, timestamp_us
));
171 struct ReadExpectation
read_expectation(size
,
173 discard_front_padding
,
176 return base::Bind(&FFmpegDemuxerTest::OnReadDone
,
177 base::Unretained(this),
182 // TODO(xhwang): This is a workaround of the issue that move-only parameters
183 // are not supported in mocked methods. Remove this when the issue is fixed
184 // (http://code.google.com/p/googletest/issues/detail?id=395) or when we use
185 // std::string instead of scoped_ptr<uint8[]> (http://crbug.com/130689).
186 MOCK_METHOD3(NeedKeyCBMock
, void(const std::string
& type
,
187 const uint8
* init_data
, int init_data_size
));
188 void NeedKeyCB(const std::string
& type
,
189 const std::vector
<uint8
>& init_data
) {
190 const uint8
* init_data_ptr
= init_data
.empty() ? NULL
: &init_data
[0];
191 NeedKeyCBMock(type
, init_data_ptr
, init_data
.size());
194 // Accessor to demuxer internals.
195 void set_duration_known(bool duration_known
) {
196 demuxer_
->duration_known_
= duration_known
;
199 bool IsStreamStopped(DemuxerStream::Type type
) {
200 DemuxerStream
* stream
= demuxer_
->GetStream(type
);
202 return !static_cast<FFmpegDemuxerStream
*>(stream
)->demuxer_
;
206 scoped_ptr
<FileDataSource
> data_source_
;
207 scoped_ptr
<FFmpegDemuxer
> demuxer_
;
208 StrictMock
<MockDemuxerHost
> host_
;
209 base::MessageLoop message_loop_
;
211 AVFormatContext
* format_context() {
212 return demuxer_
->glue_
->format_context();
215 int preferred_seeking_stream_index() const {
216 return demuxer_
->preferred_stream_for_seeking_
.first
;
219 void ReadUntilEndOfStream(DemuxerStream
* stream
) {
220 bool got_eos_buffer
= false;
221 const int kMaxBuffers
= 170;
222 for (int i
= 0; !got_eos_buffer
&& i
< kMaxBuffers
; i
++) {
223 stream
->Read(base::Bind(&EosOnReadDone
, &got_eos_buffer
));
227 EXPECT_TRUE(got_eos_buffer
);
231 void CreateDataSource(const std::string
& name
) {
232 CHECK(!data_source_
);
234 base::FilePath file_path
;
235 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT
, &file_path
));
237 file_path
= file_path
.Append(FILE_PATH_LITERAL("media"))
238 .Append(FILE_PATH_LITERAL("test"))
239 .Append(FILE_PATH_LITERAL("data"))
242 data_source_
.reset(new FileDataSource());
243 EXPECT_TRUE(data_source_
->Initialize(file_path
));
246 DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest
);
249 TEST_F(FFmpegDemuxerTest
, Initialize_OpenFails
) {
250 // Simulate avformat_open_input() failing.
251 CreateDemuxer("ten_byte_file");
252 WaitableMessageLoopEvent event
;
253 demuxer_
->Initialize(&host_
, event
.GetPipelineStatusCB(), true);
254 event
.RunAndWaitForStatus(DEMUXER_ERROR_COULD_NOT_OPEN
);
257 // TODO(acolwell): Uncomment this test when we discover a file that passes
258 // avformat_open_input(), but has avformat_find_stream_info() fail.
260 //TEST_F(FFmpegDemuxerTest, Initialize_ParseFails) {
261 // ("find_stream_info_fail.webm");
262 // demuxer_->Initialize(
263 // &host_, NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_PARSE));
264 // message_loop_.RunUntilIdle();
267 TEST_F(FFmpegDemuxerTest
, Initialize_NoStreams
) {
268 // Open a file with no streams whatsoever.
269 CreateDemuxer("no_streams.webm");
270 WaitableMessageLoopEvent event
;
271 demuxer_
->Initialize(&host_
, event
.GetPipelineStatusCB(), true);
272 event
.RunAndWaitForStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS
);
275 TEST_F(FFmpegDemuxerTest
, Initialize_NoAudioVideo
) {
276 // Open a file containing streams but none of which are audio/video streams.
277 CreateDemuxer("no_audio_video.webm");
278 WaitableMessageLoopEvent event
;
279 demuxer_
->Initialize(&host_
, event
.GetPipelineStatusCB(), true);
280 event
.RunAndWaitForStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS
);
283 TEST_F(FFmpegDemuxerTest
, Initialize_Successful
) {
284 CreateDemuxer("bear-320x240.webm");
287 // Video stream should be present.
288 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
290 EXPECT_EQ(DemuxerStream::VIDEO
, stream
->type());
292 const VideoDecoderConfig
& video_config
= stream
->video_decoder_config();
293 EXPECT_EQ(kCodecVP8
, video_config
.codec());
294 EXPECT_EQ(VideoFrame::YV12
, video_config
.format());
295 EXPECT_EQ(320, video_config
.coded_size().width());
296 EXPECT_EQ(240, video_config
.coded_size().height());
297 EXPECT_EQ(0, video_config
.visible_rect().x());
298 EXPECT_EQ(0, video_config
.visible_rect().y());
299 EXPECT_EQ(320, video_config
.visible_rect().width());
300 EXPECT_EQ(240, video_config
.visible_rect().height());
301 EXPECT_EQ(320, video_config
.natural_size().width());
302 EXPECT_EQ(240, video_config
.natural_size().height());
303 EXPECT_FALSE(video_config
.extra_data());
304 EXPECT_EQ(0u, video_config
.extra_data_size());
306 // Audio stream should be present.
307 stream
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
309 EXPECT_EQ(DemuxerStream::AUDIO
, stream
->type());
311 const AudioDecoderConfig
& audio_config
= stream
->audio_decoder_config();
312 EXPECT_EQ(kCodecVorbis
, audio_config
.codec());
313 EXPECT_EQ(32, audio_config
.bits_per_channel());
314 EXPECT_EQ(CHANNEL_LAYOUT_STEREO
, audio_config
.channel_layout());
315 EXPECT_EQ(44100, audio_config
.samples_per_second());
316 EXPECT_EQ(kSampleFormatPlanarF32
, audio_config
.sample_format());
317 EXPECT_TRUE(audio_config
.extra_data());
318 EXPECT_GT(audio_config
.extra_data_size(), 0u);
320 // Unknown stream should never be present.
321 EXPECT_FALSE(demuxer_
->GetStream(DemuxerStream::UNKNOWN
));
324 TEST_F(FFmpegDemuxerTest
, Initialize_Multitrack
) {
325 // Open a file containing the following streams:
326 // Stream #0: Video (VP8)
327 // Stream #1: Audio (Vorbis)
328 // Stream #2: Subtitles (SRT)
329 // Stream #3: Video (Theora)
330 // Stream #4: Audio (16-bit signed little endian PCM)
332 // We should only pick the first audio/video streams we come across.
333 CreateDemuxer("bear-320x240-multitrack.webm");
336 // Video stream should be VP8.
337 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
339 EXPECT_EQ(DemuxerStream::VIDEO
, stream
->type());
340 EXPECT_EQ(kCodecVP8
, stream
->video_decoder_config().codec());
342 // Audio stream should be Vorbis.
343 stream
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
345 EXPECT_EQ(DemuxerStream::AUDIO
, stream
->type());
346 EXPECT_EQ(kCodecVorbis
, stream
->audio_decoder_config().codec());
348 // Unknown stream should never be present.
349 EXPECT_FALSE(demuxer_
->GetStream(DemuxerStream::UNKNOWN
));
352 TEST_F(FFmpegDemuxerTest
, Initialize_MultitrackText
) {
353 // Open a file containing the following streams:
354 // Stream #0: Video (VP8)
355 // Stream #1: Audio (Vorbis)
356 // Stream #2: Text (WebVTT)
358 CreateDemuxer("bear-vp8-webvtt.webm");
359 DemuxerStream
* text_stream
= NULL
;
360 EXPECT_CALL(host_
, AddTextStream(_
, _
))
361 .WillOnce(SaveArg
<0>(&text_stream
));
362 InitializeDemuxerText(true);
363 ASSERT_TRUE(text_stream
);
364 EXPECT_EQ(DemuxerStream::TEXT
, text_stream
->type());
366 // Video stream should be VP8.
367 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
369 EXPECT_EQ(DemuxerStream::VIDEO
, stream
->type());
370 EXPECT_EQ(kCodecVP8
, stream
->video_decoder_config().codec());
372 // Audio stream should be Vorbis.
373 stream
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
375 EXPECT_EQ(DemuxerStream::AUDIO
, stream
->type());
376 EXPECT_EQ(kCodecVorbis
, stream
->audio_decoder_config().codec());
378 // Unknown stream should never be present.
379 EXPECT_FALSE(demuxer_
->GetStream(DemuxerStream::UNKNOWN
));
382 TEST_F(FFmpegDemuxerTest
, Initialize_Encrypted
) {
383 EXPECT_CALL(*this, NeedKeyCBMock(kWebMInitDataType
, NotNull(),
384 DecryptConfig::kDecryptionKeySize
))
387 CreateDemuxer("bear-320x240-av_enc-av.webm");
391 TEST_F(FFmpegDemuxerTest
, Read_Audio
) {
392 // We test that on a successful audio packet read.
393 CreateDemuxer("bear-320x240.webm");
396 // Attempt a read from the audio stream and run the message loop until done.
397 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
399 audio
->Read(NewReadCB(FROM_HERE
, 29, 0, true));
402 audio
->Read(NewReadCB(FROM_HERE
, 27, 3000, true));
406 TEST_F(FFmpegDemuxerTest
, Read_Video
) {
407 // We test that on a successful video packet read.
408 CreateDemuxer("bear-320x240.webm");
411 // Attempt a read from the video stream and run the message loop until done.
412 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
414 video
->Read(NewReadCB(FROM_HERE
, 22084, 0, true));
417 video
->Read(NewReadCB(FROM_HERE
, 1057, 33000, false));
421 TEST_F(FFmpegDemuxerTest
, Read_Text
) {
422 // We test that on a successful text packet read.
423 CreateDemuxer("bear-vp8-webvtt.webm");
424 DemuxerStream
* text_stream
= NULL
;
425 EXPECT_CALL(host_
, AddTextStream(_
, _
))
426 .WillOnce(SaveArg
<0>(&text_stream
));
427 InitializeDemuxerText(true);
428 ASSERT_TRUE(text_stream
);
429 EXPECT_EQ(DemuxerStream::TEXT
, text_stream
->type());
431 text_stream
->Read(NewReadCB(FROM_HERE
, 31, 0, true));
434 text_stream
->Read(NewReadCB(FROM_HERE
, 19, 500000, true));
438 TEST_F(FFmpegDemuxerTest
, SeekInitialized_NoVideoStartTime
) {
439 CreateDemuxer("audio-start-time-only.webm");
441 EXPECT_EQ(0, preferred_seeking_stream_index());
444 TEST_F(FFmpegDemuxerTest
, Read_VideoPositiveStartTime
) {
445 const int64 kTimelineOffsetMs
= 1352550896000LL;
447 // Test the start time is the first timestamp of the video and audio stream.
448 CreateDemuxer("nonzero-start-time.webm");
449 InitializeDemuxerWithTimelineOffset(
450 false, base::Time::FromJsTime(kTimelineOffsetMs
));
452 // Attempt a read from the video stream and run the message loop until done.
453 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
454 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
456 const base::TimeDelta video_start_time
=
457 base::TimeDelta::FromMicroseconds(400000);
458 const base::TimeDelta audio_start_time
=
459 base::TimeDelta::FromMicroseconds(396000);
461 // Run the test twice with a seek in between.
462 for (int i
= 0; i
< 2; ++i
) {
463 video
->Read(NewReadCB(FROM_HERE
, 5636, video_start_time
.InMicroseconds(),
466 audio
->Read(NewReadCB(FROM_HERE
, 165, audio_start_time
.InMicroseconds(),
470 // Verify that the start time is equal to the lowest timestamp (ie the
472 EXPECT_EQ(audio_start_time
, demuxer_
->start_time());
474 // Verify that the timeline offset has not been adjusted by the start time.
475 EXPECT_EQ(kTimelineOffsetMs
, demuxer_
->GetTimelineOffset().ToJavaTime());
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 TEST_F(FFmpegDemuxerTest
, Read_AudioNoStartTime
) {
485 // FFmpeg does not set timestamps when demuxing wave files. Ensure that the
486 // demuxer sets a start time of zero in this case.
487 CreateDemuxer("sfx_s24le.wav");
490 // Run the test twice with a seek in between.
491 for (int i
= 0; i
< 2; ++i
) {
492 demuxer_
->GetStream(DemuxerStream::AUDIO
)
493 ->Read(NewReadCB(FROM_HERE
, 4095, 0, true));
495 EXPECT_EQ(base::TimeDelta(), demuxer_
->start_time());
497 // Seek back to the beginning and repeat the test.
498 WaitableMessageLoopEvent event
;
499 demuxer_
->Seek(base::TimeDelta(), event
.GetPipelineStatusCB());
500 event
.RunAndWaitForStatus(PIPELINE_OK
);
504 // TODO(dalecurtis): Test is disabled since FFmpeg does not currently guarantee
505 // the order of demuxed packets in OGG containers. Re-enable and fix key frame
506 // expectations once we decide to either workaround it or attempt a fix
507 // upstream. See http://crbug.com/387996.
508 TEST_F(FFmpegDemuxerTest
,
509 DISABLED_Read_AudioNegativeStartTimeAndOggDiscard_Bear
) {
510 // Many ogg files have negative starting timestamps, so ensure demuxing and
511 // seeking work correctly with a negative start time.
512 CreateDemuxer("bear.ogv");
515 // Attempt a read from the video stream and run the message loop until done.
516 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
517 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
519 // Run the test twice with a seek in between.
520 for (int i
= 0; i
< 2; ++i
) {
522 NewReadCBWithCheckedDiscard(FROM_HERE
, 40, 0, kInfiniteDuration(),
526 NewReadCBWithCheckedDiscard(FROM_HERE
, 41, 2903, kInfiniteDuration(),
529 audio
->Read(NewReadCBWithCheckedDiscard(
530 FROM_HERE
, 173, 5805, base::TimeDelta::FromMicroseconds(10159), true));
533 audio
->Read(NewReadCB(FROM_HERE
, 148, 18866, true));
535 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-15964),
536 demuxer_
->start_time());
538 video
->Read(NewReadCB(FROM_HERE
, 5751, 0, true));
541 video
->Read(NewReadCB(FROM_HERE
, 846, 33367, true));
544 video
->Read(NewReadCB(FROM_HERE
, 1255, 66733, true));
547 // Seek back to the beginning and repeat the test.
548 WaitableMessageLoopEvent event
;
549 demuxer_
->Seek(base::TimeDelta(), event
.GetPipelineStatusCB());
550 event
.RunAndWaitForStatus(PIPELINE_OK
);
554 // Same test above, but using sync2.ogv which has video stream muxed before the
555 // audio stream, so seeking based only on start time will fail since ffmpeg is
556 // essentially just seeking based on file position.
557 TEST_F(FFmpegDemuxerTest
, Read_AudioNegativeStartTimeAndOggDiscard_Sync
) {
558 // Many ogg files have negative starting timestamps, so ensure demuxing and
559 // seeking work correctly with a negative start time.
560 CreateDemuxer("sync2.ogv");
563 // Attempt a read from the video stream and run the message loop until done.
564 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
565 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
567 // Run the test twice with a seek in between.
568 for (int i
= 0; i
< 2; ++i
) {
569 audio
->Read(NewReadCBWithCheckedDiscard(
570 FROM_HERE
, 1, 0, base::TimeDelta::FromMicroseconds(2902), true));
573 audio
->Read(NewReadCB(FROM_HERE
, 1, 2902, true));
575 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-2902),
576 demuxer_
->start_time());
578 // Though the internal start time may be below zero, the exposed media time
579 // must always be greater than zero.
580 EXPECT_EQ(base::TimeDelta(), demuxer_
->GetStartTime());
582 video
->Read(NewReadCB(FROM_HERE
, 9997, 0, true));
585 video
->Read(NewReadCB(FROM_HERE
, 16, 33241, false));
588 video
->Read(NewReadCB(FROM_HERE
, 631, 66482, false));
591 // Seek back to the beginning and repeat the test.
592 WaitableMessageLoopEvent event
;
593 demuxer_
->Seek(base::TimeDelta(), event
.GetPipelineStatusCB());
594 event
.RunAndWaitForStatus(PIPELINE_OK
);
598 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream
) {
599 // Verify that end of stream buffers are created.
600 CreateDemuxer("bear-320x240.webm");
602 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
605 TEST_F(FFmpegDemuxerTest
, Read_EndOfStreamText
) {
606 // Verify that end of stream buffers are created.
607 CreateDemuxer("bear-vp8-webvtt.webm");
608 DemuxerStream
* text_stream
= NULL
;
609 EXPECT_CALL(host_
, AddTextStream(_
, _
))
610 .WillOnce(SaveArg
<0>(&text_stream
));
611 InitializeDemuxerText(true);
612 ASSERT_TRUE(text_stream
);
613 EXPECT_EQ(DemuxerStream::TEXT
, text_stream
->type());
615 bool got_eos_buffer
= false;
616 const int kMaxBuffers
= 10;
617 for (int i
= 0; !got_eos_buffer
&& i
< kMaxBuffers
; i
++) {
618 text_stream
->Read(base::Bind(&EosOnReadDone
, &got_eos_buffer
));
622 EXPECT_TRUE(got_eos_buffer
);
625 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream_NoDuration
) {
626 // Verify that end of stream buffers are created.
627 CreateDemuxer("bear-320x240.webm");
629 set_duration_known(false);
630 EXPECT_CALL(host_
, SetDuration(base::TimeDelta::FromMilliseconds(2767)));
631 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
632 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::VIDEO
));
635 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream_NoDuration_VideoOnly
) {
636 // Verify that end of stream buffers are created.
637 CreateDemuxer("bear-320x240-video-only.webm");
639 set_duration_known(false);
640 EXPECT_CALL(host_
, SetDuration(base::TimeDelta::FromMilliseconds(2703)));
641 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::VIDEO
));
644 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream_NoDuration_AudioOnly
) {
645 // Verify that end of stream buffers are created.
646 CreateDemuxer("bear-320x240-audio-only.webm");
648 set_duration_known(false);
649 EXPECT_CALL(host_
, SetDuration(base::TimeDelta::FromMilliseconds(2767)));
650 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
653 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream_NoDuration_UnsupportedStream
) {
654 // Verify that end of stream buffers are created and we don't crash
655 // if there are streams in the file that we don't support.
656 CreateDemuxer("vorbis_audio_wmv_video.mkv");
658 set_duration_known(false);
659 EXPECT_CALL(host_
, SetDuration(base::TimeDelta::FromMilliseconds(1014)));
660 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
663 TEST_F(FFmpegDemuxerTest
, Seek
) {
664 // We're testing that the demuxer frees all queued packets when it receives
666 CreateDemuxer("bear-320x240.webm");
670 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
671 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
675 // Read a video packet and release it.
676 video
->Read(NewReadCB(FROM_HERE
, 22084, 0, true));
679 // Issue a simple forward seek, which should discard queued packets.
680 WaitableMessageLoopEvent event
;
681 demuxer_
->Seek(base::TimeDelta::FromMicroseconds(1000000),
682 event
.GetPipelineStatusCB());
683 event
.RunAndWaitForStatus(PIPELINE_OK
);
686 audio
->Read(NewReadCB(FROM_HERE
, 145, 803000, true));
690 audio
->Read(NewReadCB(FROM_HERE
, 148, 826000, true));
694 video
->Read(NewReadCB(FROM_HERE
, 5425, 801000, true));
698 video
->Read(NewReadCB(FROM_HERE
, 1906, 834000, false));
702 TEST_F(FFmpegDemuxerTest
, SeekText
) {
703 // We're testing that the demuxer frees all queued packets when it receives
705 CreateDemuxer("bear-vp8-webvtt.webm");
706 DemuxerStream
* text_stream
= NULL
;
707 EXPECT_CALL(host_
, AddTextStream(_
, _
))
708 .WillOnce(SaveArg
<0>(&text_stream
));
709 InitializeDemuxerText(true);
710 ASSERT_TRUE(text_stream
);
711 EXPECT_EQ(DemuxerStream::TEXT
, text_stream
->type());
714 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
715 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
719 // Read a text packet and release it.
720 text_stream
->Read(NewReadCB(FROM_HERE
, 31, 0, true));
723 // Issue a simple forward seek, which should discard queued packets.
724 WaitableMessageLoopEvent event
;
725 demuxer_
->Seek(base::TimeDelta::FromMicroseconds(1000000),
726 event
.GetPipelineStatusCB());
727 event
.RunAndWaitForStatus(PIPELINE_OK
);
730 audio
->Read(NewReadCB(FROM_HERE
, 145, 803000, true));
734 audio
->Read(NewReadCB(FROM_HERE
, 148, 826000, true));
738 video
->Read(NewReadCB(FROM_HERE
, 5425, 801000, true));
742 video
->Read(NewReadCB(FROM_HERE
, 1906, 834000, false));
746 text_stream
->Read(NewReadCB(FROM_HERE
, 19, 500000, true));
750 text_stream
->Read(NewReadCB(FROM_HERE
, 19, 1000000, true));
759 MOCK_METHOD2(Run
, void(DemuxerStream::Status status
,
760 const scoped_refptr
<DecoderBuffer
>& buffer
));
762 DISALLOW_COPY_AND_ASSIGN(MockReadCB
);
765 TEST_F(FFmpegDemuxerTest
, Stop
) {
766 // Tests that calling Read() on a stopped demuxer stream immediately deletes
768 CreateDemuxer("bear-320x240.webm");
772 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
777 // Reads after being stopped are all EOS buffers.
778 StrictMock
<MockReadCB
> callback
;
779 EXPECT_CALL(callback
, Run(DemuxerStream::kOk
, IsEndOfStreamBuffer()));
781 // Attempt the read...
782 audio
->Read(base::Bind(&MockReadCB::Run
, base::Unretained(&callback
)));
783 message_loop_
.RunUntilIdle();
785 // Don't let the test call Stop() again.
789 // Verify that seek works properly when the WebM cues data is at the start of
790 // the file instead of at the end.
791 TEST_F(FFmpegDemuxerTest
, SeekWithCuesBeforeFirstCluster
) {
792 CreateDemuxer("bear-320x240-cues-in-front.webm");
796 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
797 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
801 // Read a video packet and release it.
802 video
->Read(NewReadCB(FROM_HERE
, 22084, 0, true));
805 // Issue a simple forward seek, which should discard queued packets.
806 WaitableMessageLoopEvent event
;
807 demuxer_
->Seek(base::TimeDelta::FromMicroseconds(2500000),
808 event
.GetPipelineStatusCB());
809 event
.RunAndWaitForStatus(PIPELINE_OK
);
812 audio
->Read(NewReadCB(FROM_HERE
, 40, 2403000, true));
816 audio
->Read(NewReadCB(FROM_HERE
, 42, 2406000, true));
820 video
->Read(NewReadCB(FROM_HERE
, 5276, 2402000, true));
824 video
->Read(NewReadCB(FROM_HERE
, 1740, 2436000, false));
828 #if defined(USE_PROPRIETARY_CODECS)
829 // Ensure ID3v1 tag reading is disabled. id3_test.mp3 has an ID3v1 tag with the
830 // field "title" set to "sample for id3 test".
831 TEST_F(FFmpegDemuxerTest
, NoID3TagData
) {
832 CreateDemuxer("id3_test.mp3");
834 EXPECT_FALSE(av_dict_get(format_context()->metadata
, "title", NULL
, 0));
838 #if defined(USE_PROPRIETARY_CODECS)
839 // Ensure MP3 files with large image/video based ID3 tags demux okay. FFmpeg
840 // will hand us a video stream to the data which will likely be in a format we
841 // don't accept as video; e.g. PNG.
842 TEST_F(FFmpegDemuxerTest
, Mp3WithVideoStreamID3TagData
) {
843 CreateDemuxer("id3_png_test.mp3");
846 // Ensure the expected streams are present.
847 EXPECT_FALSE(demuxer_
->GetStream(DemuxerStream::VIDEO
));
848 EXPECT_TRUE(demuxer_
->GetStream(DemuxerStream::AUDIO
));
852 // Ensure a video with an unsupported audio track still results in the video
853 // stream being demuxed.
854 TEST_F(FFmpegDemuxerTest
, UnsupportedAudioSupportedVideoDemux
) {
855 CreateDemuxer("speex_audio_vorbis_video.ogv");
858 // Ensure the expected streams are present.
859 EXPECT_TRUE(demuxer_
->GetStream(DemuxerStream::VIDEO
));
860 EXPECT_FALSE(demuxer_
->GetStream(DemuxerStream::AUDIO
));
863 // Ensure a video with an unsupported video track still results in the audio
864 // stream being demuxed.
865 TEST_F(FFmpegDemuxerTest
, UnsupportedVideoSupportedAudioDemux
) {
866 CreateDemuxer("vorbis_audio_wmv_video.mkv");
869 // Ensure the expected streams are present.
870 EXPECT_FALSE(demuxer_
->GetStream(DemuxerStream::VIDEO
));
871 EXPECT_TRUE(demuxer_
->GetStream(DemuxerStream::AUDIO
));
874 #if defined(USE_PROPRIETARY_CODECS)
875 // FFmpeg returns null data pointers when samples have zero size, leading to
876 // mistakenly creating end of stream buffers http://crbug.com/169133
877 TEST_F(FFmpegDemuxerTest
, MP4_ZeroStszEntry
) {
878 CreateDemuxer("bear-1280x720-zero-stsz-entry.mp4");
880 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
884 static void ValidateAnnexB(DemuxerStream
* stream
,
885 DemuxerStream::Status status
,
886 const scoped_refptr
<DecoderBuffer
>& buffer
) {
887 EXPECT_EQ(status
, DemuxerStream::kOk
);
889 if (buffer
->end_of_stream()) {
890 base::MessageLoop::current()->PostTask(
891 FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
895 std::vector
<SubsampleEntry
> subsamples
;
897 if (buffer
->decrypt_config())
898 subsamples
= buffer
->decrypt_config()->subsamples();
901 mp4::AVC::IsValidAnnexB(buffer
->data(), buffer
->data_size(),
903 EXPECT_TRUE(is_valid
);
906 LOG(ERROR
) << "Buffer contains invalid Annex B data.";
907 base::MessageLoop::current()->PostTask(
908 FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
912 stream
->Read(base::Bind(&ValidateAnnexB
, stream
));
915 TEST_F(FFmpegDemuxerTest
, IsValidAnnexB
) {
916 const char* files
[] = {
917 "bear-1280x720-av_frag.mp4",
918 "bear-1280x720-av_with-aud-nalus_frag.mp4"
921 for (size_t i
= 0; i
< arraysize(files
); ++i
) {
922 DVLOG(1) << "Testing " << files
[i
];
923 CreateDemuxer(files
[i
]);
926 // Ensure the expected streams are present.
927 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
929 stream
->EnableBitstreamConverter();
931 stream
->Read(base::Bind(&ValidateAnnexB
, stream
));
936 data_source_
.reset();
940 TEST_F(FFmpegDemuxerTest
, Rotate_Metadata_0
) {
941 CreateDemuxer("bear_rotate_0.mp4");
944 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
946 ASSERT_EQ(VIDEO_ROTATION_0
, stream
->video_rotation());
949 TEST_F(FFmpegDemuxerTest
, Rotate_Metadata_90
) {
950 CreateDemuxer("bear_rotate_90.mp4");
953 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
955 ASSERT_EQ(VIDEO_ROTATION_90
, stream
->video_rotation());
958 TEST_F(FFmpegDemuxerTest
, Rotate_Metadata_180
) {
959 CreateDemuxer("bear_rotate_180.mp4");
962 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
964 ASSERT_EQ(VIDEO_ROTATION_180
, stream
->video_rotation());
967 TEST_F(FFmpegDemuxerTest
, Rotate_Metadata_270
) {
968 CreateDemuxer("bear_rotate_270.mp4");
971 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
973 ASSERT_EQ(VIDEO_ROTATION_270
, stream
->video_rotation());