Roll src/third_party/skia e784db4:fa5e68e
[chromium-blink-merge.git] / media / filters / ffmpeg_demuxer_unittest.cc
blob961ae83daa0ddffb7ded44a2c119372a65a3deca
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.
5 #include <algorithm>
6 #include <deque>
7 #include <string>
9 #include "base/bind.h"
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;
35 using ::testing::_;
37 namespace media {
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;
58 return;
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 {
70 protected:
71 FFmpegDemuxerTest() {}
73 virtual ~FFmpegDemuxerTest() {
74 if (demuxer_)
75 demuxer_->Stop();
78 void CreateDemuxer(const std::string& name) {
79 CHECK(!demuxer_);
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,
116 int64 timestamp_us,
117 const base::TimeDelta& discard_front_padding,
118 bool is_key_frame)
119 : size(size),
120 timestamp_us(timestamp_us),
121 discard_front_padding(discard_front_padding),
122 is_key_frame(is_key_frame) {
125 int size;
126 int64 timestamp_us;
127 base::TimeDelta discard_front_padding;
128 bool is_key_frame;
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,
156 int size,
157 int64 timestamp_us,
158 bool is_key_frame) {
159 return NewReadCBWithCheckedDiscard(location,
160 size,
161 timestamp_us,
162 base::TimeDelta(),
163 is_key_frame);
166 DemuxerStream::ReadCB NewReadCBWithCheckedDiscard(
167 const tracked_objects::Location& location,
168 int size,
169 int64 timestamp_us,
170 base::TimeDelta discard_front_padding,
171 bool is_key_frame) {
172 EXPECT_CALL(*this, OnReadDoneCalled(size, timestamp_us));
174 struct ReadExpectation read_expectation(size,
175 timestamp_us,
176 discard_front_padding,
177 is_key_frame);
179 return base::Bind(&FFmpegDemuxerTest::OnReadDone,
180 base::Unretained(this),
181 location,
182 read_expectation);
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);
196 CHECK(stream);
197 return !static_cast<FFmpegDemuxerStream*>(stream)->demuxer_;
200 // Fixture members.
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));
219 message_loop_.Run();
222 EXPECT_TRUE(got_eos_buffer);
225 private:
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"))
235 .AppendASCII(name);
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");
280 InitializeDemuxer();
282 // Video stream should be present.
283 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
284 ASSERT_TRUE(stream);
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);
303 ASSERT_TRUE(stream);
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");
329 InitializeDemuxer();
331 // Video stream should be VP8.
332 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
333 ASSERT_TRUE(stream);
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);
339 ASSERT_TRUE(stream);
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);
363 ASSERT_TRUE(stream);
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);
369 ASSERT_TRUE(stream);
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) {
378 EXPECT_CALL(*this,
379 OnEncryptedMediaInitData(
380 EmeInitDataType::WEBM,
381 std::vector<uint8>(kEncryptedMediaInitData,
382 kEncryptedMediaInitData +
383 arraysize(kEncryptedMediaInitData))))
384 .Times(Exactly(2));
386 CreateDemuxer("bear-320x240-av_enc-av.webm");
387 InitializeDemuxer();
390 TEST_F(FFmpegDemuxerTest, Read_Audio) {
391 // We test that on a successful audio packet read.
392 CreateDemuxer("bear-320x240.webm");
393 InitializeDemuxer();
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));
399 message_loop_.Run();
401 audio->Read(NewReadCB(FROM_HERE, 27, 3000, true));
402 message_loop_.Run();
405 TEST_F(FFmpegDemuxerTest, Read_Video) {
406 // We test that on a successful video packet read.
407 CreateDemuxer("bear-320x240.webm");
408 InitializeDemuxer();
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));
414 message_loop_.Run();
416 video->Read(NewReadCB(FROM_HERE, 1057, 33000, false));
417 message_loop_.Run();
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));
431 message_loop_.Run();
433 text_stream->Read(NewReadCB(FROM_HERE, 19, 500000, true));
434 message_loop_.Run();
437 TEST_F(FFmpegDemuxerTest, SeekInitialized_NoVideoStartTime) {
438 CreateDemuxer("audio-start-time-only.webm");
439 InitializeDemuxer();
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(),
463 true));
464 message_loop_.Run();
465 audio->Read(NewReadCB(FROM_HERE, 165, audio_start_time.InMicroseconds(),
466 true));
467 message_loop_.Run();
469 // Verify that the start time is equal to the lowest timestamp (ie the
470 // audio).
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");
487 InitializeDemuxer();
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));
493 message_loop_.Run();
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");
512 InitializeDemuxer();
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) {
520 audio->Read(
521 NewReadCBWithCheckedDiscard(FROM_HERE, 40, 0, kInfiniteDuration(),
522 true));
523 message_loop_.Run();
524 audio->Read(
525 NewReadCBWithCheckedDiscard(FROM_HERE, 41, 2903, kInfiniteDuration(),
526 true));
527 message_loop_.Run();
528 audio->Read(NewReadCBWithCheckedDiscard(
529 FROM_HERE, 173, 5805, base::TimeDelta::FromMicroseconds(10159), true));
530 message_loop_.Run();
532 audio->Read(NewReadCB(FROM_HERE, 148, 18866, true));
533 message_loop_.Run();
534 EXPECT_EQ(base::TimeDelta::FromMicroseconds(-15964),
535 demuxer_->start_time());
537 video->Read(NewReadCB(FROM_HERE, 5751, 0, true));
538 message_loop_.Run();
540 video->Read(NewReadCB(FROM_HERE, 846, 33367, true));
541 message_loop_.Run();
543 video->Read(NewReadCB(FROM_HERE, 1255, 66733, true));
544 message_loop_.Run();
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");
560 InitializeDemuxer();
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));
570 message_loop_.Run();
572 audio->Read(NewReadCB(FROM_HERE, 1, 2902, true));
573 message_loop_.Run();
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));
582 message_loop_.Run();
584 video->Read(NewReadCB(FROM_HERE, 16, 33241, false));
585 message_loop_.Run();
587 video->Read(NewReadCB(FROM_HERE, 631, 66482, false));
588 message_loop_.Run();
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");
600 InitializeDemuxer();
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));
618 message_loop_.Run();
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");
627 InitializeDemuxer();
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");
637 InitializeDemuxer();
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");
646 InitializeDemuxer();
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");
656 InitializeDemuxer();
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
664 // a Seek().
665 CreateDemuxer("bear-320x240.webm");
666 InitializeDemuxer();
668 // Get our streams.
669 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
670 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
671 ASSERT_TRUE(video);
672 ASSERT_TRUE(audio);
674 // Read a video packet and release it.
675 video->Read(NewReadCB(FROM_HERE, 22084, 0, true));
676 message_loop_.Run();
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);
684 // Audio read #1.
685 audio->Read(NewReadCB(FROM_HERE, 145, 803000, true));
686 message_loop_.Run();
688 // Audio read #2.
689 audio->Read(NewReadCB(FROM_HERE, 148, 826000, true));
690 message_loop_.Run();
692 // Video read #1.
693 video->Read(NewReadCB(FROM_HERE, 5425, 801000, true));
694 message_loop_.Run();
696 // Video read #2.
697 video->Read(NewReadCB(FROM_HERE, 1906, 834000, false));
698 message_loop_.Run();
701 TEST_F(FFmpegDemuxerTest, SeekText) {
702 // We're testing that the demuxer frees all queued packets when it receives
703 // a Seek().
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());
712 // Get our streams.
713 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
714 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
715 ASSERT_TRUE(video);
716 ASSERT_TRUE(audio);
718 // Read a text packet and release it.
719 text_stream->Read(NewReadCB(FROM_HERE, 31, 0, true));
720 message_loop_.Run();
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);
728 // Audio read #1.
729 audio->Read(NewReadCB(FROM_HERE, 145, 803000, true));
730 message_loop_.Run();
732 // Audio read #2.
733 audio->Read(NewReadCB(FROM_HERE, 148, 826000, true));
734 message_loop_.Run();
736 // Video read #1.
737 video->Read(NewReadCB(FROM_HERE, 5425, 801000, true));
738 message_loop_.Run();
740 // Video read #2.
741 video->Read(NewReadCB(FROM_HERE, 1906, 834000, false));
742 message_loop_.Run();
744 // Text read #1.
745 text_stream->Read(NewReadCB(FROM_HERE, 19, 500000, true));
746 message_loop_.Run();
748 // Text read #2.
749 text_stream->Read(NewReadCB(FROM_HERE, 19, 1000000, true));
750 message_loop_.Run();
753 class MockReadCB {
754 public:
755 MockReadCB() {}
756 ~MockReadCB() {}
758 MOCK_METHOD2(Run, void(DemuxerStream::Status status,
759 const scoped_refptr<DecoderBuffer>& buffer));
760 private:
761 DISALLOW_COPY_AND_ASSIGN(MockReadCB);
764 TEST_F(FFmpegDemuxerTest, Stop) {
765 // Tests that calling Read() on a stopped demuxer stream immediately deletes
766 // the callback.
767 CreateDemuxer("bear-320x240.webm");
768 InitializeDemuxer();
770 // Get our stream.
771 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
772 ASSERT_TRUE(audio);
774 demuxer_->Stop();
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.
785 demuxer_.reset();
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");
792 InitializeDemuxer();
794 // Get our streams.
795 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
796 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
797 ASSERT_TRUE(video);
798 ASSERT_TRUE(audio);
800 // Read a video packet and release it.
801 video->Read(NewReadCB(FROM_HERE, 22084, 0, true));
802 message_loop_.Run();
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);
810 // Audio read #1.
811 audio->Read(NewReadCB(FROM_HERE, 40, 2403000, true));
812 message_loop_.Run();
814 // Audio read #2.
815 audio->Read(NewReadCB(FROM_HERE, 42, 2406000, true));
816 message_loop_.Run();
818 // Video read #1.
819 video->Read(NewReadCB(FROM_HERE, 5276, 2402000, true));
820 message_loop_.Run();
822 // Video read #2.
823 video->Read(NewReadCB(FROM_HERE, 1740, 2436000, false));
824 message_loop_.Run();
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");
832 InitializeDemuxer();
833 EXPECT_FALSE(av_dict_get(format_context()->metadata, "title", NULL, 0));
835 #endif
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");
843 InitializeDemuxer();
845 // Ensure the expected streams are present.
846 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO));
847 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO));
849 #endif
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");
855 InitializeDemuxer();
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");
866 InitializeDemuxer();
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");
878 InitializeDemuxer();
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());
891 return;
894 std::vector<SubsampleEntry> subsamples;
896 if (buffer->decrypt_config())
897 subsamples = buffer->decrypt_config()->subsamples();
899 bool is_valid =
900 mp4::AVC::IsValidAnnexB(buffer->data(), buffer->data_size(),
901 subsamples);
902 EXPECT_TRUE(is_valid);
904 if (!is_valid) {
905 LOG(ERROR) << "Buffer contains invalid Annex B data.";
906 base::MessageLoop::current()->PostTask(
907 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
908 return;
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]);
923 InitializeDemuxer();
925 // Ensure the expected streams are present.
926 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
927 ASSERT_TRUE(stream);
928 stream->EnableBitstreamConverter();
930 stream->Read(base::Bind(&ValidateAnnexB, stream));
931 message_loop_.Run();
933 demuxer_->Stop();
934 demuxer_.reset();
935 data_source_.reset();
939 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_0) {
940 CreateDemuxer("bear_rotate_0.mp4");
941 InitializeDemuxer();
943 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
944 ASSERT_TRUE(stream);
945 ASSERT_EQ(VIDEO_ROTATION_0, stream->video_rotation());
948 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_90) {
949 CreateDemuxer("bear_rotate_90.mp4");
950 InitializeDemuxer();
952 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
953 ASSERT_TRUE(stream);
954 ASSERT_EQ(VIDEO_ROTATION_90, stream->video_rotation());
957 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_180) {
958 CreateDemuxer("bear_rotate_180.mp4");
959 InitializeDemuxer();
961 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
962 ASSERT_TRUE(stream);
963 ASSERT_EQ(VIDEO_ROTATION_180, stream->video_rotation());
966 TEST_F(FFmpegDemuxerTest, Rotate_Metadata_270) {
967 CreateDemuxer("bear_rotate_270.mp4");
968 InitializeDemuxer();
970 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
971 ASSERT_TRUE(stream);
972 ASSERT_EQ(VIDEO_ROTATION_270, stream->video_rotation());
975 #endif
977 } // namespace media