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