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 "testing/gtest/include/gtest/gtest.h"
24 using ::testing::AnyNumber
;
25 using ::testing::DoAll
;
26 using ::testing::Exactly
;
27 using ::testing::InSequence
;
28 using ::testing::Invoke
;
29 using ::testing::NotNull
;
30 using ::testing::Return
;
31 using ::testing::SaveArg
;
32 using ::testing::SetArgPointee
;
33 using ::testing::StrictMock
;
34 using ::testing::WithArgs
;
39 MATCHER(IsEndOfStreamBuffer
,
40 std::string(negation
? "isn't" : "is") + " end of stream") {
41 return arg
->end_of_stream();
44 const uint8 kEncryptedMediaInitData
[] = {
45 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
46 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35,
49 static void EosOnReadDone(bool* got_eos_buffer
,
50 DemuxerStream::Status status
,
51 const scoped_refptr
<DecoderBuffer
>& buffer
) {
52 base::MessageLoop::current()->PostTask(
53 FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
55 EXPECT_EQ(status
, DemuxerStream::kOk
);
56 if (buffer
->end_of_stream()) {
57 *got_eos_buffer
= true;
61 EXPECT_TRUE(buffer
->data());
62 EXPECT_GT(buffer
->data_size(), 0);
63 *got_eos_buffer
= false;
67 // Fixture class to facilitate writing tests. Takes care of setting up the
68 // FFmpeg, pipeline and filter host mocks.
69 class FFmpegDemuxerTest
: public testing::Test
{
71 FFmpegDemuxerTest() {}
73 virtual ~FFmpegDemuxerTest() {
78 void CreateDemuxer(const std::string
& name
) {
81 EXPECT_CALL(host_
, AddBufferedTimeRange(_
, _
)).Times(AnyNumber());
83 CreateDataSource(name
);
85 Demuxer::EncryptedMediaInitDataCB encrypted_media_init_data_cb
= base::Bind(
86 &FFmpegDemuxerTest::OnEncryptedMediaInitData
, base::Unretained(this));
88 demuxer_
.reset(new FFmpegDemuxer(
89 message_loop_
.message_loop_proxy(), data_source_
.get(),
90 encrypted_media_init_data_cb
, new MediaLog()));
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 struct ReadExpectation
{
115 ReadExpectation(int size
,
117 const base::TimeDelta
& discard_front_padding
,
120 timestamp_us(timestamp_us
),
121 discard_front_padding(discard_front_padding
),
122 is_key_frame(is_key_frame
) {
127 base::TimeDelta discard_front_padding
;
131 // Verifies that |buffer| has a specific |size| and |timestamp|.
132 // |location| simply indicates where the call to this function was made.
133 // This makes it easier to track down where test failures occur.
134 void OnReadDone(const tracked_objects::Location
& location
,
135 const ReadExpectation
& read_expectation
,
136 DemuxerStream::Status status
,
137 const scoped_refptr
<DecoderBuffer
>& buffer
) {
138 std::string location_str
;
139 location
.Write(true, false, &location_str
);
140 location_str
+= "\n";
141 SCOPED_TRACE(location_str
);
142 EXPECT_EQ(status
, DemuxerStream::kOk
);
143 EXPECT_TRUE(buffer
.get() != NULL
);
144 EXPECT_EQ(read_expectation
.size
, buffer
->data_size());
145 EXPECT_EQ(read_expectation
.timestamp_us
,
146 buffer
->timestamp().InMicroseconds());
147 EXPECT_EQ(read_expectation
.discard_front_padding
,
148 buffer
->discard_padding().first
);
149 EXPECT_EQ(read_expectation
.is_key_frame
, buffer
->is_key_frame());
150 DCHECK_EQ(&message_loop_
, base::MessageLoop::current());
151 OnReadDoneCalled(read_expectation
.size
, read_expectation
.timestamp_us
);
152 message_loop_
.PostTask(FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
155 DemuxerStream::ReadCB
NewReadCB(const tracked_objects::Location
& location
,
159 return NewReadCBWithCheckedDiscard(location
,
166 DemuxerStream::ReadCB
NewReadCBWithCheckedDiscard(
167 const tracked_objects::Location
& location
,
170 base::TimeDelta discard_front_padding
,
172 EXPECT_CALL(*this, OnReadDoneCalled(size
, timestamp_us
));
174 struct ReadExpectation
read_expectation(size
,
176 discard_front_padding
,
179 return base::Bind(&FFmpegDemuxerTest::OnReadDone
,
180 base::Unretained(this),
185 MOCK_METHOD2(OnEncryptedMediaInitData
,
186 void(EmeInitDataType init_data_type
,
187 const std::vector
<uint8
>& init_data
));
189 // Accessor to demuxer internals.
190 void set_duration_known(bool duration_known
) {
191 demuxer_
->duration_known_
= duration_known
;
194 bool IsStreamStopped(DemuxerStream::Type type
) {
195 DemuxerStream
* stream
= demuxer_
->GetStream(type
);
197 return !static_cast<FFmpegDemuxerStream
*>(stream
)->demuxer_
;
201 scoped_ptr
<FileDataSource
> data_source_
;
202 scoped_ptr
<FFmpegDemuxer
> demuxer_
;
203 StrictMock
<MockDemuxerHost
> host_
;
204 base::MessageLoop message_loop_
;
206 AVFormatContext
* format_context() {
207 return demuxer_
->glue_
->format_context();
210 int preferred_seeking_stream_index() const {
211 return demuxer_
->preferred_stream_for_seeking_
.first
;
214 void ReadUntilEndOfStream(DemuxerStream
* stream
) {
215 bool got_eos_buffer
= false;
216 const int kMaxBuffers
= 170;
217 for (int i
= 0; !got_eos_buffer
&& i
< kMaxBuffers
; i
++) {
218 stream
->Read(base::Bind(&EosOnReadDone
, &got_eos_buffer
));
222 EXPECT_TRUE(got_eos_buffer
);
226 void CreateDataSource(const std::string
& name
) {
227 CHECK(!data_source_
);
229 base::FilePath file_path
;
230 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT
, &file_path
));
232 file_path
= file_path
.Append(FILE_PATH_LITERAL("media"))
233 .Append(FILE_PATH_LITERAL("test"))
234 .Append(FILE_PATH_LITERAL("data"))
237 data_source_
.reset(new FileDataSource());
238 EXPECT_TRUE(data_source_
->Initialize(file_path
));
241 DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest
);
244 TEST_F(FFmpegDemuxerTest
, Initialize_OpenFails
) {
245 // Simulate avformat_open_input() failing.
246 CreateDemuxer("ten_byte_file");
247 WaitableMessageLoopEvent event
;
248 demuxer_
->Initialize(&host_
, event
.GetPipelineStatusCB(), true);
249 event
.RunAndWaitForStatus(DEMUXER_ERROR_COULD_NOT_OPEN
);
252 // TODO(acolwell): Uncomment this test when we discover a file that passes
253 // avformat_open_input(), but has avformat_find_stream_info() fail.
255 //TEST_F(FFmpegDemuxerTest, Initialize_ParseFails) {
256 // ("find_stream_info_fail.webm");
257 // demuxer_->Initialize(
258 // &host_, NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_PARSE));
259 // message_loop_.RunUntilIdle();
262 TEST_F(FFmpegDemuxerTest
, Initialize_NoStreams
) {
263 // Open a file with no streams whatsoever.
264 CreateDemuxer("no_streams.webm");
265 WaitableMessageLoopEvent event
;
266 demuxer_
->Initialize(&host_
, event
.GetPipelineStatusCB(), true);
267 event
.RunAndWaitForStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS
);
270 TEST_F(FFmpegDemuxerTest
, Initialize_NoAudioVideo
) {
271 // Open a file containing streams but none of which are audio/video streams.
272 CreateDemuxer("no_audio_video.webm");
273 WaitableMessageLoopEvent event
;
274 demuxer_
->Initialize(&host_
, event
.GetPipelineStatusCB(), true);
275 event
.RunAndWaitForStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS
);
278 TEST_F(FFmpegDemuxerTest
, Initialize_Successful
) {
279 CreateDemuxer("bear-320x240.webm");
282 // Video stream should be present.
283 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
285 EXPECT_EQ(DemuxerStream::VIDEO
, stream
->type());
287 const VideoDecoderConfig
& video_config
= stream
->video_decoder_config();
288 EXPECT_EQ(kCodecVP8
, video_config
.codec());
289 EXPECT_EQ(VideoFrame::YV12
, video_config
.format());
290 EXPECT_EQ(320, video_config
.coded_size().width());
291 EXPECT_EQ(240, video_config
.coded_size().height());
292 EXPECT_EQ(0, video_config
.visible_rect().x());
293 EXPECT_EQ(0, video_config
.visible_rect().y());
294 EXPECT_EQ(320, video_config
.visible_rect().width());
295 EXPECT_EQ(240, video_config
.visible_rect().height());
296 EXPECT_EQ(320, video_config
.natural_size().width());
297 EXPECT_EQ(240, video_config
.natural_size().height());
298 EXPECT_FALSE(video_config
.extra_data());
299 EXPECT_EQ(0u, video_config
.extra_data_size());
301 // Audio stream should be present.
302 stream
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
304 EXPECT_EQ(DemuxerStream::AUDIO
, stream
->type());
306 const AudioDecoderConfig
& audio_config
= stream
->audio_decoder_config();
307 EXPECT_EQ(kCodecVorbis
, audio_config
.codec());
308 EXPECT_EQ(32, audio_config
.bits_per_channel());
309 EXPECT_EQ(CHANNEL_LAYOUT_STEREO
, audio_config
.channel_layout());
310 EXPECT_EQ(44100, audio_config
.samples_per_second());
311 EXPECT_EQ(kSampleFormatPlanarF32
, audio_config
.sample_format());
312 EXPECT_TRUE(audio_config
.extra_data());
313 EXPECT_GT(audio_config
.extra_data_size(), 0u);
315 // Unknown stream should never be present.
316 EXPECT_FALSE(demuxer_
->GetStream(DemuxerStream::UNKNOWN
));
319 TEST_F(FFmpegDemuxerTest
, Initialize_Multitrack
) {
320 // Open a file containing the following streams:
321 // Stream #0: Video (VP8)
322 // Stream #1: Audio (Vorbis)
323 // Stream #2: Subtitles (SRT)
324 // Stream #3: Video (Theora)
325 // Stream #4: Audio (16-bit signed little endian PCM)
327 // We should only pick the first audio/video streams we come across.
328 CreateDemuxer("bear-320x240-multitrack.webm");
331 // Video stream should be VP8.
332 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
334 EXPECT_EQ(DemuxerStream::VIDEO
, stream
->type());
335 EXPECT_EQ(kCodecVP8
, stream
->video_decoder_config().codec());
337 // Audio stream should be Vorbis.
338 stream
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
340 EXPECT_EQ(DemuxerStream::AUDIO
, stream
->type());
341 EXPECT_EQ(kCodecVorbis
, stream
->audio_decoder_config().codec());
343 // Unknown stream should never be present.
344 EXPECT_FALSE(demuxer_
->GetStream(DemuxerStream::UNKNOWN
));
347 TEST_F(FFmpegDemuxerTest
, Initialize_MultitrackText
) {
348 // Open a file containing the following streams:
349 // Stream #0: Video (VP8)
350 // Stream #1: Audio (Vorbis)
351 // Stream #2: Text (WebVTT)
353 CreateDemuxer("bear-vp8-webvtt.webm");
354 DemuxerStream
* text_stream
= NULL
;
355 EXPECT_CALL(host_
, AddTextStream(_
, _
))
356 .WillOnce(SaveArg
<0>(&text_stream
));
357 InitializeDemuxerText(true);
358 ASSERT_TRUE(text_stream
);
359 EXPECT_EQ(DemuxerStream::TEXT
, text_stream
->type());
361 // Video stream should be VP8.
362 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
364 EXPECT_EQ(DemuxerStream::VIDEO
, stream
->type());
365 EXPECT_EQ(kCodecVP8
, stream
->video_decoder_config().codec());
367 // Audio stream should be Vorbis.
368 stream
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
370 EXPECT_EQ(DemuxerStream::AUDIO
, stream
->type());
371 EXPECT_EQ(kCodecVorbis
, stream
->audio_decoder_config().codec());
373 // Unknown stream should never be present.
374 EXPECT_FALSE(demuxer_
->GetStream(DemuxerStream::UNKNOWN
));
377 TEST_F(FFmpegDemuxerTest
, Initialize_Encrypted
) {
379 OnEncryptedMediaInitData(
380 EmeInitDataType::WEBM
,
381 std::vector
<uint8
>(kEncryptedMediaInitData
,
382 kEncryptedMediaInitData
+
383 arraysize(kEncryptedMediaInitData
))))
386 CreateDemuxer("bear-320x240-av_enc-av.webm");
390 TEST_F(FFmpegDemuxerTest
, Read_Audio
) {
391 // We test that on a successful audio packet read.
392 CreateDemuxer("bear-320x240.webm");
395 // Attempt a read from the audio stream and run the message loop until done.
396 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
398 audio
->Read(NewReadCB(FROM_HERE
, 29, 0, true));
401 audio
->Read(NewReadCB(FROM_HERE
, 27, 3000, true));
405 TEST_F(FFmpegDemuxerTest
, Read_Video
) {
406 // We test that on a successful video packet read.
407 CreateDemuxer("bear-320x240.webm");
410 // Attempt a read from the video stream and run the message loop until done.
411 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
413 video
->Read(NewReadCB(FROM_HERE
, 22084, 0, true));
416 video
->Read(NewReadCB(FROM_HERE
, 1057, 33000, false));
420 TEST_F(FFmpegDemuxerTest
, Read_Text
) {
421 // We test that on a successful text packet read.
422 CreateDemuxer("bear-vp8-webvtt.webm");
423 DemuxerStream
* text_stream
= NULL
;
424 EXPECT_CALL(host_
, AddTextStream(_
, _
))
425 .WillOnce(SaveArg
<0>(&text_stream
));
426 InitializeDemuxerText(true);
427 ASSERT_TRUE(text_stream
);
428 EXPECT_EQ(DemuxerStream::TEXT
, text_stream
->type());
430 text_stream
->Read(NewReadCB(FROM_HERE
, 31, 0, true));
433 text_stream
->Read(NewReadCB(FROM_HERE
, 19, 500000, true));
437 TEST_F(FFmpegDemuxerTest
, SeekInitialized_NoVideoStartTime
) {
438 CreateDemuxer("audio-start-time-only.webm");
440 EXPECT_EQ(0, preferred_seeking_stream_index());
443 TEST_F(FFmpegDemuxerTest
, Read_VideoPositiveStartTime
) {
444 const int64 kTimelineOffsetMs
= 1352550896000LL;
446 // Test the start time is the first timestamp of the video and audio stream.
447 CreateDemuxer("nonzero-start-time.webm");
448 InitializeDemuxerWithTimelineOffset(
449 false, base::Time::FromJsTime(kTimelineOffsetMs
));
451 // Attempt a read from the video stream and run the message loop until done.
452 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
453 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
455 const base::TimeDelta video_start_time
=
456 base::TimeDelta::FromMicroseconds(400000);
457 const base::TimeDelta audio_start_time
=
458 base::TimeDelta::FromMicroseconds(396000);
460 // Run the test twice with a seek in between.
461 for (int i
= 0; i
< 2; ++i
) {
462 video
->Read(NewReadCB(FROM_HERE
, 5636, video_start_time
.InMicroseconds(),
465 audio
->Read(NewReadCB(FROM_HERE
, 165, audio_start_time
.InMicroseconds(),
469 // Verify that the start time is equal to the lowest timestamp (ie the
471 EXPECT_EQ(audio_start_time
, demuxer_
->start_time());
473 // Verify that the timeline offset has not been adjusted by the start time.
474 EXPECT_EQ(kTimelineOffsetMs
, demuxer_
->GetTimelineOffset().ToJavaTime());
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 TEST_F(FFmpegDemuxerTest
, Read_AudioNoStartTime
) {
484 // FFmpeg does not set timestamps when demuxing wave files. Ensure that the
485 // demuxer sets a start time of zero in this case.
486 CreateDemuxer("sfx_s24le.wav");
489 // Run the test twice with a seek in between.
490 for (int i
= 0; i
< 2; ++i
) {
491 demuxer_
->GetStream(DemuxerStream::AUDIO
)
492 ->Read(NewReadCB(FROM_HERE
, 4095, 0, true));
494 EXPECT_EQ(base::TimeDelta(), demuxer_
->start_time());
496 // Seek back to the beginning and repeat the test.
497 WaitableMessageLoopEvent event
;
498 demuxer_
->Seek(base::TimeDelta(), event
.GetPipelineStatusCB());
499 event
.RunAndWaitForStatus(PIPELINE_OK
);
503 // TODO(dalecurtis): Test is disabled since FFmpeg does not currently guarantee
504 // the order of demuxed packets in OGG containers. Re-enable and fix key frame
505 // expectations once we decide to either workaround it or attempt a fix
506 // upstream. See http://crbug.com/387996.
507 TEST_F(FFmpegDemuxerTest
,
508 DISABLED_Read_AudioNegativeStartTimeAndOggDiscard_Bear
) {
509 // Many ogg files have negative starting timestamps, so ensure demuxing and
510 // seeking work correctly with a negative start time.
511 CreateDemuxer("bear.ogv");
514 // Attempt a read from the video stream and run the message loop until done.
515 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
516 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
518 // Run the test twice with a seek in between.
519 for (int i
= 0; i
< 2; ++i
) {
521 NewReadCBWithCheckedDiscard(FROM_HERE
, 40, 0, kInfiniteDuration(),
525 NewReadCBWithCheckedDiscard(FROM_HERE
, 41, 2903, kInfiniteDuration(),
528 audio
->Read(NewReadCBWithCheckedDiscard(
529 FROM_HERE
, 173, 5805, base::TimeDelta::FromMicroseconds(10159), true));
532 audio
->Read(NewReadCB(FROM_HERE
, 148, 18866, true));
534 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-15964),
535 demuxer_
->start_time());
537 video
->Read(NewReadCB(FROM_HERE
, 5751, 0, true));
540 video
->Read(NewReadCB(FROM_HERE
, 846, 33367, true));
543 video
->Read(NewReadCB(FROM_HERE
, 1255, 66733, true));
546 // Seek back to the beginning and repeat the test.
547 WaitableMessageLoopEvent event
;
548 demuxer_
->Seek(base::TimeDelta(), event
.GetPipelineStatusCB());
549 event
.RunAndWaitForStatus(PIPELINE_OK
);
553 // Same test above, but using sync2.ogv which has video stream muxed before the
554 // audio stream, so seeking based only on start time will fail since ffmpeg is
555 // essentially just seeking based on file position.
556 TEST_F(FFmpegDemuxerTest
, Read_AudioNegativeStartTimeAndOggDiscard_Sync
) {
557 // Many ogg files have negative starting timestamps, so ensure demuxing and
558 // seeking work correctly with a negative start time.
559 CreateDemuxer("sync2.ogv");
562 // Attempt a read from the video stream and run the message loop until done.
563 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
564 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
566 // Run the test twice with a seek in between.
567 for (int i
= 0; i
< 2; ++i
) {
568 audio
->Read(NewReadCBWithCheckedDiscard(
569 FROM_HERE
, 1, 0, base::TimeDelta::FromMicroseconds(2902), true));
572 audio
->Read(NewReadCB(FROM_HERE
, 1, 2902, true));
574 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-2902),
575 demuxer_
->start_time());
577 // Though the internal start time may be below zero, the exposed media time
578 // must always be greater than zero.
579 EXPECT_EQ(base::TimeDelta(), demuxer_
->GetStartTime());
581 video
->Read(NewReadCB(FROM_HERE
, 9997, 0, true));
584 video
->Read(NewReadCB(FROM_HERE
, 16, 33241, false));
587 video
->Read(NewReadCB(FROM_HERE
, 631, 66482, false));
590 // Seek back to the beginning and repeat the test.
591 WaitableMessageLoopEvent event
;
592 demuxer_
->Seek(base::TimeDelta(), event
.GetPipelineStatusCB());
593 event
.RunAndWaitForStatus(PIPELINE_OK
);
597 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream
) {
598 // Verify that end of stream buffers are created.
599 CreateDemuxer("bear-320x240.webm");
601 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
604 TEST_F(FFmpegDemuxerTest
, Read_EndOfStreamText
) {
605 // Verify that end of stream buffers are created.
606 CreateDemuxer("bear-vp8-webvtt.webm");
607 DemuxerStream
* text_stream
= NULL
;
608 EXPECT_CALL(host_
, AddTextStream(_
, _
))
609 .WillOnce(SaveArg
<0>(&text_stream
));
610 InitializeDemuxerText(true);
611 ASSERT_TRUE(text_stream
);
612 EXPECT_EQ(DemuxerStream::TEXT
, text_stream
->type());
614 bool got_eos_buffer
= false;
615 const int kMaxBuffers
= 10;
616 for (int i
= 0; !got_eos_buffer
&& i
< kMaxBuffers
; i
++) {
617 text_stream
->Read(base::Bind(&EosOnReadDone
, &got_eos_buffer
));
621 EXPECT_TRUE(got_eos_buffer
);
624 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream_NoDuration
) {
625 // Verify that end of stream buffers are created.
626 CreateDemuxer("bear-320x240.webm");
628 set_duration_known(false);
629 EXPECT_CALL(host_
, SetDuration(base::TimeDelta::FromMilliseconds(2767)));
630 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
631 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::VIDEO
));
634 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream_NoDuration_VideoOnly
) {
635 // Verify that end of stream buffers are created.
636 CreateDemuxer("bear-320x240-video-only.webm");
638 set_duration_known(false);
639 EXPECT_CALL(host_
, SetDuration(base::TimeDelta::FromMilliseconds(2703)));
640 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::VIDEO
));
643 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream_NoDuration_AudioOnly
) {
644 // Verify that end of stream buffers are created.
645 CreateDemuxer("bear-320x240-audio-only.webm");
647 set_duration_known(false);
648 EXPECT_CALL(host_
, SetDuration(base::TimeDelta::FromMilliseconds(2767)));
649 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
652 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream_NoDuration_UnsupportedStream
) {
653 // Verify that end of stream buffers are created and we don't crash
654 // if there are streams in the file that we don't support.
655 CreateDemuxer("vorbis_audio_wmv_video.mkv");
657 set_duration_known(false);
658 EXPECT_CALL(host_
, SetDuration(base::TimeDelta::FromMilliseconds(1014)));
659 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
662 TEST_F(FFmpegDemuxerTest
, Seek
) {
663 // We're testing that the demuxer frees all queued packets when it receives
665 CreateDemuxer("bear-320x240.webm");
669 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
670 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
674 // Read a video packet and release it.
675 video
->Read(NewReadCB(FROM_HERE
, 22084, 0, true));
678 // Issue a simple forward seek, which should discard queued packets.
679 WaitableMessageLoopEvent event
;
680 demuxer_
->Seek(base::TimeDelta::FromMicroseconds(1000000),
681 event
.GetPipelineStatusCB());
682 event
.RunAndWaitForStatus(PIPELINE_OK
);
685 audio
->Read(NewReadCB(FROM_HERE
, 145, 803000, true));
689 audio
->Read(NewReadCB(FROM_HERE
, 148, 826000, true));
693 video
->Read(NewReadCB(FROM_HERE
, 5425, 801000, true));
697 video
->Read(NewReadCB(FROM_HERE
, 1906, 834000, false));
701 TEST_F(FFmpegDemuxerTest
, SeekText
) {
702 // We're testing that the demuxer frees all queued packets when it receives
704 CreateDemuxer("bear-vp8-webvtt.webm");
705 DemuxerStream
* text_stream
= NULL
;
706 EXPECT_CALL(host_
, AddTextStream(_
, _
))
707 .WillOnce(SaveArg
<0>(&text_stream
));
708 InitializeDemuxerText(true);
709 ASSERT_TRUE(text_stream
);
710 EXPECT_EQ(DemuxerStream::TEXT
, text_stream
->type());
713 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
714 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
718 // Read a text packet and release it.
719 text_stream
->Read(NewReadCB(FROM_HERE
, 31, 0, true));
722 // Issue a simple forward seek, which should discard queued packets.
723 WaitableMessageLoopEvent event
;
724 demuxer_
->Seek(base::TimeDelta::FromMicroseconds(1000000),
725 event
.GetPipelineStatusCB());
726 event
.RunAndWaitForStatus(PIPELINE_OK
);
729 audio
->Read(NewReadCB(FROM_HERE
, 145, 803000, true));
733 audio
->Read(NewReadCB(FROM_HERE
, 148, 826000, true));
737 video
->Read(NewReadCB(FROM_HERE
, 5425, 801000, true));
741 video
->Read(NewReadCB(FROM_HERE
, 1906, 834000, false));
745 text_stream
->Read(NewReadCB(FROM_HERE
, 19, 500000, true));
749 text_stream
->Read(NewReadCB(FROM_HERE
, 19, 1000000, true));
758 MOCK_METHOD2(Run
, void(DemuxerStream::Status status
,
759 const scoped_refptr
<DecoderBuffer
>& buffer
));
761 DISALLOW_COPY_AND_ASSIGN(MockReadCB
);
764 TEST_F(FFmpegDemuxerTest
, Stop
) {
765 // Tests that calling Read() on a stopped demuxer stream immediately deletes
767 CreateDemuxer("bear-320x240.webm");
771 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
776 // Reads after being stopped are all EOS buffers.
777 StrictMock
<MockReadCB
> callback
;
778 EXPECT_CALL(callback
, Run(DemuxerStream::kOk
, IsEndOfStreamBuffer()));
780 // Attempt the read...
781 audio
->Read(base::Bind(&MockReadCB::Run
, base::Unretained(&callback
)));
782 message_loop_
.RunUntilIdle();
784 // Don't let the test call Stop() again.
788 // Verify that seek works properly when the WebM cues data is at the start of
789 // the file instead of at the end.
790 TEST_F(FFmpegDemuxerTest
, SeekWithCuesBeforeFirstCluster
) {
791 CreateDemuxer("bear-320x240-cues-in-front.webm");
795 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
796 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
800 // Read a video packet and release it.
801 video
->Read(NewReadCB(FROM_HERE
, 22084, 0, true));
804 // Issue a simple forward seek, which should discard queued packets.
805 WaitableMessageLoopEvent event
;
806 demuxer_
->Seek(base::TimeDelta::FromMicroseconds(2500000),
807 event
.GetPipelineStatusCB());
808 event
.RunAndWaitForStatus(PIPELINE_OK
);
811 audio
->Read(NewReadCB(FROM_HERE
, 40, 2403000, true));
815 audio
->Read(NewReadCB(FROM_HERE
, 42, 2406000, true));
819 video
->Read(NewReadCB(FROM_HERE
, 5276, 2402000, true));
823 video
->Read(NewReadCB(FROM_HERE
, 1740, 2436000, false));
827 #if defined(USE_PROPRIETARY_CODECS)
828 // Ensure ID3v1 tag reading is disabled. id3_test.mp3 has an ID3v1 tag with the
829 // field "title" set to "sample for id3 test".
830 TEST_F(FFmpegDemuxerTest
, NoID3TagData
) {
831 CreateDemuxer("id3_test.mp3");
833 EXPECT_FALSE(av_dict_get(format_context()->metadata
, "title", NULL
, 0));
837 #if defined(USE_PROPRIETARY_CODECS)
838 // Ensure MP3 files with large image/video based ID3 tags demux okay. FFmpeg
839 // will hand us a video stream to the data which will likely be in a format we
840 // don't accept as video; e.g. PNG.
841 TEST_F(FFmpegDemuxerTest
, Mp3WithVideoStreamID3TagData
) {
842 CreateDemuxer("id3_png_test.mp3");
845 // Ensure the expected streams are present.
846 EXPECT_FALSE(demuxer_
->GetStream(DemuxerStream::VIDEO
));
847 EXPECT_TRUE(demuxer_
->GetStream(DemuxerStream::AUDIO
));
851 // Ensure a video with an unsupported audio track still results in the video
852 // stream being demuxed.
853 TEST_F(FFmpegDemuxerTest
, UnsupportedAudioSupportedVideoDemux
) {
854 CreateDemuxer("speex_audio_vorbis_video.ogv");
857 // Ensure the expected streams are present.
858 EXPECT_TRUE(demuxer_
->GetStream(DemuxerStream::VIDEO
));
859 EXPECT_FALSE(demuxer_
->GetStream(DemuxerStream::AUDIO
));
862 // Ensure a video with an unsupported video track still results in the audio
863 // stream being demuxed.
864 TEST_F(FFmpegDemuxerTest
, UnsupportedVideoSupportedAudioDemux
) {
865 CreateDemuxer("vorbis_audio_wmv_video.mkv");
868 // Ensure the expected streams are present.
869 EXPECT_FALSE(demuxer_
->GetStream(DemuxerStream::VIDEO
));
870 EXPECT_TRUE(demuxer_
->GetStream(DemuxerStream::AUDIO
));
873 #if defined(USE_PROPRIETARY_CODECS)
874 // FFmpeg returns null data pointers when samples have zero size, leading to
875 // mistakenly creating end of stream buffers http://crbug.com/169133
876 TEST_F(FFmpegDemuxerTest
, MP4_ZeroStszEntry
) {
877 CreateDemuxer("bear-1280x720-zero-stsz-entry.mp4");
879 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
883 static void ValidateAnnexB(DemuxerStream
* stream
,
884 DemuxerStream::Status status
,
885 const scoped_refptr
<DecoderBuffer
>& buffer
) {
886 EXPECT_EQ(status
, DemuxerStream::kOk
);
888 if (buffer
->end_of_stream()) {
889 base::MessageLoop::current()->PostTask(
890 FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
894 std::vector
<SubsampleEntry
> subsamples
;
896 if (buffer
->decrypt_config())
897 subsamples
= buffer
->decrypt_config()->subsamples();
900 mp4::AVC::IsValidAnnexB(buffer
->data(), buffer
->data_size(),
902 EXPECT_TRUE(is_valid
);
905 LOG(ERROR
) << "Buffer contains invalid Annex B data.";
906 base::MessageLoop::current()->PostTask(
907 FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
911 stream
->Read(base::Bind(&ValidateAnnexB
, stream
));
914 TEST_F(FFmpegDemuxerTest
, IsValidAnnexB
) {
915 const char* files
[] = {
916 "bear-1280x720-av_frag.mp4",
917 "bear-1280x720-av_with-aud-nalus_frag.mp4"
920 for (size_t i
= 0; i
< arraysize(files
); ++i
) {
921 DVLOG(1) << "Testing " << files
[i
];
922 CreateDemuxer(files
[i
]);
925 // Ensure the expected streams are present.
926 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
928 stream
->EnableBitstreamConverter();
930 stream
->Read(base::Bind(&ValidateAnnexB
, stream
));
935 data_source_
.reset();
939 TEST_F(FFmpegDemuxerTest
, Rotate_Metadata_0
) {
940 CreateDemuxer("bear_rotate_0.mp4");
943 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
945 ASSERT_EQ(VIDEO_ROTATION_0
, stream
->video_rotation());
948 TEST_F(FFmpegDemuxerTest
, Rotate_Metadata_90
) {
949 CreateDemuxer("bear_rotate_90.mp4");
952 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
954 ASSERT_EQ(VIDEO_ROTATION_90
, stream
->video_rotation());
957 TEST_F(FFmpegDemuxerTest
, Rotate_Metadata_180
) {
958 CreateDemuxer("bear_rotate_180.mp4");
961 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
963 ASSERT_EQ(VIDEO_ROTATION_180
, stream
->video_rotation());
966 TEST_F(FFmpegDemuxerTest
, Rotate_Metadata_270
) {
967 CreateDemuxer("bear_rotate_270.mp4");
970 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
972 ASSERT_EQ(VIDEO_ROTATION_270
, stream
->video_rotation());