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_
.task_runner(), 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(PIXEL_FORMAT_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 // Similar to the test above, but using an opus clip with a large amount of
598 // pre-skip, which ffmpeg encodes as negative timestamps.
599 TEST_F(FFmpegDemuxerTest
, Read_AudioNegativeStartTimeAndOpusDiscard_Sync
) {
600 CreateDemuxer("opus-trimming-video-test.webm");
603 // Attempt a read from the video stream and run the message loop until done.
604 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
605 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
606 EXPECT_EQ(audio
->audio_decoder_config().codec_delay(), 65535);
608 // Packet size to timestamp (in microseconds) mapping for the first N packets
609 // which should be fully discarded.
610 static const int kTestExpectations
[][2] = {
611 {635, 0}, {594, 120000}, {597, 240000}, {591, 360000},
612 {582, 480000}, {583, 600000}, {592, 720000}, {567, 840000},
613 {579, 960000}, {572, 1080000}, {583, 1200000}};
615 // Run the test twice with a seek in between.
616 for (int i
= 0; i
< 2; ++i
) {
617 for (size_t j
= 0; j
< arraysize(kTestExpectations
); ++j
) {
618 audio
->Read(NewReadCB(FROM_HERE
, kTestExpectations
[j
][0],
619 kTestExpectations
[j
][1], true));
623 // Though the internal start time may be below zero, the exposed media time
624 // must always be greater than zero.
625 EXPECT_EQ(base::TimeDelta(), demuxer_
->GetStartTime());
627 video
->Read(NewReadCB(FROM_HERE
, 16009, 0, true));
630 video
->Read(NewReadCB(FROM_HERE
, 2715, 1000, false));
633 video
->Read(NewReadCB(FROM_HERE
, 427, 33000, false));
636 // Seek back to the beginning and repeat the test.
637 WaitableMessageLoopEvent event
;
638 demuxer_
->Seek(base::TimeDelta(), event
.GetPipelineStatusCB());
639 event
.RunAndWaitForStatus(PIPELINE_OK
);
643 // Similar to the test above, but using sfx-opus.ogg, which has a much smaller
644 // amount of discard padding and no |start_time| set on the AVStream.
645 TEST_F(FFmpegDemuxerTest
, Read_AudioNegativeStartTimeAndOpusSfxDiscard_Sync
) {
646 CreateDemuxer("sfx-opus.ogg");
649 // Attempt a read from the video stream and run the message loop until done.
650 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
651 EXPECT_EQ(audio
->audio_decoder_config().codec_delay(), 312);
653 // Run the test twice with a seek in between.
654 for (int i
= 0; i
< 2; ++i
) {
655 audio
->Read(NewReadCB(FROM_HERE
, 314, 0, true));
658 audio
->Read(NewReadCB(FROM_HERE
, 244, 20000, true));
661 // Though the internal start time may be below zero, the exposed media time
662 // must always be greater than zero.
663 EXPECT_EQ(base::TimeDelta(), demuxer_
->GetStartTime());
665 // Seek back to the beginning and repeat the test.
666 WaitableMessageLoopEvent event
;
667 demuxer_
->Seek(base::TimeDelta(), event
.GetPipelineStatusCB());
668 event
.RunAndWaitForStatus(PIPELINE_OK
);
672 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream
) {
673 // Verify that end of stream buffers are created.
674 CreateDemuxer("bear-320x240.webm");
676 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
679 TEST_F(FFmpegDemuxerTest
, Read_EndOfStreamText
) {
680 // Verify that end of stream buffers are created.
681 CreateDemuxer("bear-vp8-webvtt.webm");
682 DemuxerStream
* text_stream
= NULL
;
683 EXPECT_CALL(host_
, AddTextStream(_
, _
))
684 .WillOnce(SaveArg
<0>(&text_stream
));
685 InitializeDemuxerText(true);
686 ASSERT_TRUE(text_stream
);
687 EXPECT_EQ(DemuxerStream::TEXT
, text_stream
->type());
689 bool got_eos_buffer
= false;
690 const int kMaxBuffers
= 10;
691 for (int i
= 0; !got_eos_buffer
&& i
< kMaxBuffers
; i
++) {
692 text_stream
->Read(base::Bind(&EosOnReadDone
, &got_eos_buffer
));
696 EXPECT_TRUE(got_eos_buffer
);
699 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream_NoDuration
) {
700 // Verify that end of stream buffers are created.
701 CreateDemuxer("bear-320x240.webm");
703 set_duration_known(false);
704 EXPECT_CALL(host_
, SetDuration(base::TimeDelta::FromMilliseconds(2767)));
705 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
706 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::VIDEO
));
709 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream_NoDuration_VideoOnly
) {
710 // Verify that end of stream buffers are created.
711 CreateDemuxer("bear-320x240-video-only.webm");
713 set_duration_known(false);
714 EXPECT_CALL(host_
, SetDuration(base::TimeDelta::FromMilliseconds(2736)));
715 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::VIDEO
));
718 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream_NoDuration_AudioOnly
) {
719 // Verify that end of stream buffers are created.
720 CreateDemuxer("bear-320x240-audio-only.webm");
722 set_duration_known(false);
723 EXPECT_CALL(host_
, SetDuration(base::TimeDelta::FromMilliseconds(2767)));
724 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
727 TEST_F(FFmpegDemuxerTest
, Read_EndOfStream_NoDuration_UnsupportedStream
) {
728 // Verify that end of stream buffers are created and we don't crash
729 // if there are streams in the file that we don't support.
730 CreateDemuxer("vorbis_audio_wmv_video.mkv");
732 set_duration_known(false);
733 EXPECT_CALL(host_
, SetDuration(base::TimeDelta::FromMilliseconds(1014)));
734 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
737 TEST_F(FFmpegDemuxerTest
, Seek
) {
738 // We're testing that the demuxer frees all queued packets when it receives
740 CreateDemuxer("bear-320x240.webm");
744 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
745 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
749 // Read a video packet and release it.
750 video
->Read(NewReadCB(FROM_HERE
, 22084, 0, true));
753 // Issue a simple forward seek, which should discard queued packets.
754 WaitableMessageLoopEvent event
;
755 demuxer_
->Seek(base::TimeDelta::FromMicroseconds(1000000),
756 event
.GetPipelineStatusCB());
757 event
.RunAndWaitForStatus(PIPELINE_OK
);
760 audio
->Read(NewReadCB(FROM_HERE
, 145, 803000, true));
764 audio
->Read(NewReadCB(FROM_HERE
, 148, 826000, true));
768 video
->Read(NewReadCB(FROM_HERE
, 5425, 801000, true));
772 video
->Read(NewReadCB(FROM_HERE
, 1906, 834000, false));
776 TEST_F(FFmpegDemuxerTest
, SeekText
) {
777 // We're testing that the demuxer frees all queued packets when it receives
779 CreateDemuxer("bear-vp8-webvtt.webm");
780 DemuxerStream
* text_stream
= NULL
;
781 EXPECT_CALL(host_
, AddTextStream(_
, _
))
782 .WillOnce(SaveArg
<0>(&text_stream
));
783 InitializeDemuxerText(true);
784 ASSERT_TRUE(text_stream
);
785 EXPECT_EQ(DemuxerStream::TEXT
, text_stream
->type());
788 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
789 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
793 // Read a text packet and release it.
794 text_stream
->Read(NewReadCB(FROM_HERE
, 31, 0, true));
797 // Issue a simple forward seek, which should discard queued packets.
798 WaitableMessageLoopEvent event
;
799 demuxer_
->Seek(base::TimeDelta::FromMicroseconds(1000000),
800 event
.GetPipelineStatusCB());
801 event
.RunAndWaitForStatus(PIPELINE_OK
);
804 audio
->Read(NewReadCB(FROM_HERE
, 145, 803000, true));
808 audio
->Read(NewReadCB(FROM_HERE
, 148, 826000, true));
812 video
->Read(NewReadCB(FROM_HERE
, 5425, 801000, true));
816 video
->Read(NewReadCB(FROM_HERE
, 1906, 834000, false));
820 text_stream
->Read(NewReadCB(FROM_HERE
, 19, 500000, true));
824 text_stream
->Read(NewReadCB(FROM_HERE
, 19, 1000000, true));
833 MOCK_METHOD2(Run
, void(DemuxerStream::Status status
,
834 const scoped_refptr
<DecoderBuffer
>& buffer
));
836 DISALLOW_COPY_AND_ASSIGN(MockReadCB
);
839 TEST_F(FFmpegDemuxerTest
, Stop
) {
840 // Tests that calling Read() on a stopped demuxer stream immediately deletes
842 CreateDemuxer("bear-320x240.webm");
846 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
851 // Reads after being stopped are all EOS buffers.
852 StrictMock
<MockReadCB
> callback
;
853 EXPECT_CALL(callback
, Run(DemuxerStream::kOk
, IsEndOfStreamBuffer()));
855 // Attempt the read...
856 audio
->Read(base::Bind(&MockReadCB::Run
, base::Unretained(&callback
)));
857 message_loop_
.RunUntilIdle();
859 // Don't let the test call Stop() again.
863 // Verify that seek works properly when the WebM cues data is at the start of
864 // the file instead of at the end.
865 TEST_F(FFmpegDemuxerTest
, SeekWithCuesBeforeFirstCluster
) {
866 CreateDemuxer("bear-320x240-cues-in-front.webm");
870 DemuxerStream
* video
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
871 DemuxerStream
* audio
= demuxer_
->GetStream(DemuxerStream::AUDIO
);
875 // Read a video packet and release it.
876 video
->Read(NewReadCB(FROM_HERE
, 22084, 0, true));
879 // Issue a simple forward seek, which should discard queued packets.
880 WaitableMessageLoopEvent event
;
881 demuxer_
->Seek(base::TimeDelta::FromMicroseconds(2500000),
882 event
.GetPipelineStatusCB());
883 event
.RunAndWaitForStatus(PIPELINE_OK
);
886 audio
->Read(NewReadCB(FROM_HERE
, 40, 2403000, true));
890 audio
->Read(NewReadCB(FROM_HERE
, 42, 2406000, true));
894 video
->Read(NewReadCB(FROM_HERE
, 5276, 2402000, true));
898 video
->Read(NewReadCB(FROM_HERE
, 1740, 2436000, false));
902 #if defined(USE_PROPRIETARY_CODECS)
903 // Ensure ID3v1 tag reading is disabled. id3_test.mp3 has an ID3v1 tag with the
904 // field "title" set to "sample for id3 test".
905 TEST_F(FFmpegDemuxerTest
, NoID3TagData
) {
906 CreateDemuxer("id3_test.mp3");
908 EXPECT_FALSE(av_dict_get(format_context()->metadata
, "title", NULL
, 0));
912 #if defined(USE_PROPRIETARY_CODECS)
913 // Ensure MP3 files with large image/video based ID3 tags demux okay. FFmpeg
914 // will hand us a video stream to the data which will likely be in a format we
915 // don't accept as video; e.g. PNG.
916 TEST_F(FFmpegDemuxerTest
, Mp3WithVideoStreamID3TagData
) {
917 CreateDemuxer("id3_png_test.mp3");
920 // Ensure the expected streams are present.
921 EXPECT_FALSE(demuxer_
->GetStream(DemuxerStream::VIDEO
));
922 EXPECT_TRUE(demuxer_
->GetStream(DemuxerStream::AUDIO
));
926 // Ensure a video with an unsupported audio track still results in the video
927 // stream being demuxed.
928 TEST_F(FFmpegDemuxerTest
, UnsupportedAudioSupportedVideoDemux
) {
929 CreateDemuxer("speex_audio_vorbis_video.ogv");
932 // Ensure the expected streams are present.
933 EXPECT_TRUE(demuxer_
->GetStream(DemuxerStream::VIDEO
));
934 EXPECT_FALSE(demuxer_
->GetStream(DemuxerStream::AUDIO
));
937 // Ensure a video with an unsupported video track still results in the audio
938 // stream being demuxed.
939 TEST_F(FFmpegDemuxerTest
, UnsupportedVideoSupportedAudioDemux
) {
940 CreateDemuxer("vorbis_audio_wmv_video.mkv");
943 // Ensure the expected streams are present.
944 EXPECT_FALSE(demuxer_
->GetStream(DemuxerStream::VIDEO
));
945 EXPECT_TRUE(demuxer_
->GetStream(DemuxerStream::AUDIO
));
948 #if defined(USE_PROPRIETARY_CODECS)
949 // FFmpeg returns null data pointers when samples have zero size, leading to
950 // mistakenly creating end of stream buffers http://crbug.com/169133
951 TEST_F(FFmpegDemuxerTest
, MP4_ZeroStszEntry
) {
952 CreateDemuxer("bear-1280x720-zero-stsz-entry.mp4");
954 ReadUntilEndOfStream(demuxer_
->GetStream(DemuxerStream::AUDIO
));
958 static void ValidateAnnexB(DemuxerStream
* stream
,
959 DemuxerStream::Status status
,
960 const scoped_refptr
<DecoderBuffer
>& buffer
) {
961 EXPECT_EQ(status
, DemuxerStream::kOk
);
963 if (buffer
->end_of_stream()) {
964 base::MessageLoop::current()->PostTask(
965 FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
969 std::vector
<SubsampleEntry
> subsamples
;
971 if (buffer
->decrypt_config())
972 subsamples
= buffer
->decrypt_config()->subsamples();
975 mp4::AVC::IsValidAnnexB(buffer
->data(), buffer
->data_size(),
977 EXPECT_TRUE(is_valid
);
980 LOG(ERROR
) << "Buffer contains invalid Annex B data.";
981 base::MessageLoop::current()->PostTask(
982 FROM_HERE
, base::MessageLoop::QuitWhenIdleClosure());
986 stream
->Read(base::Bind(&ValidateAnnexB
, stream
));
989 TEST_F(FFmpegDemuxerTest
, IsValidAnnexB
) {
990 const char* files
[] = {
991 "bear-1280x720-av_frag.mp4",
992 "bear-1280x720-av_with-aud-nalus_frag.mp4"
995 for (size_t i
= 0; i
< arraysize(files
); ++i
) {
996 DVLOG(1) << "Testing " << files
[i
];
997 CreateDemuxer(files
[i
]);
1000 // Ensure the expected streams are present.
1001 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
1002 ASSERT_TRUE(stream
);
1003 stream
->EnableBitstreamConverter();
1005 stream
->Read(base::Bind(&ValidateAnnexB
, stream
));
1006 message_loop_
.Run();
1010 data_source_
.reset();
1014 TEST_F(FFmpegDemuxerTest
, Rotate_Metadata_0
) {
1015 CreateDemuxer("bear_rotate_0.mp4");
1016 InitializeDemuxer();
1018 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
1019 ASSERT_TRUE(stream
);
1020 ASSERT_EQ(VIDEO_ROTATION_0
, stream
->video_rotation());
1023 TEST_F(FFmpegDemuxerTest
, Rotate_Metadata_90
) {
1024 CreateDemuxer("bear_rotate_90.mp4");
1025 InitializeDemuxer();
1027 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
1028 ASSERT_TRUE(stream
);
1029 ASSERT_EQ(VIDEO_ROTATION_90
, stream
->video_rotation());
1032 TEST_F(FFmpegDemuxerTest
, Rotate_Metadata_180
) {
1033 CreateDemuxer("bear_rotate_180.mp4");
1034 InitializeDemuxer();
1036 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
1037 ASSERT_TRUE(stream
);
1038 ASSERT_EQ(VIDEO_ROTATION_180
, stream
->video_rotation());
1041 TEST_F(FFmpegDemuxerTest
, Rotate_Metadata_270
) {
1042 CreateDemuxer("bear_rotate_270.mp4");
1043 InitializeDemuxer();
1045 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
1046 ASSERT_TRUE(stream
);
1047 ASSERT_EQ(VIDEO_ROTATION_270
, stream
->video_rotation());
1050 TEST_F(FFmpegDemuxerTest
, NaturalSizeWithoutPASP
) {
1051 CreateDemuxer("bear-640x360-non_square_pixel-without_pasp.mp4");
1052 InitializeDemuxer();
1054 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
1055 ASSERT_TRUE(stream
);
1057 const VideoDecoderConfig
& video_config
= stream
->video_decoder_config();
1058 EXPECT_EQ(gfx::Size(638, 360), video_config
.natural_size());
1061 TEST_F(FFmpegDemuxerTest
, NaturalSizeWithPASP
) {
1062 CreateDemuxer("bear-640x360-non_square_pixel-with_pasp.mp4");
1063 InitializeDemuxer();
1065 DemuxerStream
* stream
= demuxer_
->GetStream(DemuxerStream::VIDEO
);
1066 ASSERT_TRUE(stream
);
1068 const VideoDecoderConfig
& video_config
= stream
->video_decoder_config();
1069 EXPECT_EQ(gfx::Size(638, 360), video_config
.natural_size());
1074 } // namespace media