Disable view source for Developer Tools.
[chromium-blink-merge.git] / media / filters / ffmpeg_demuxer_unittest.cc
blobe498d66b5855d6ffe1d0efaa69d1005578f90d37
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/path_service.h"
12 #include "base/threading/thread.h"
13 #include "media/base/decrypt_config.h"
14 #include "media/base/media_log.h"
15 #include "media/base/mock_demuxer_host.h"
16 #include "media/base/test_helpers.h"
17 #include "media/ffmpeg/ffmpeg_common.h"
18 #include "media/filters/ffmpeg_demuxer.h"
19 #include "media/filters/file_data_source.h"
20 #include "media/webm/webm_crypto_helpers.h"
21 #include "testing/gtest/include/gtest/gtest.h"
23 using ::testing::AnyNumber;
24 using ::testing::DoAll;
25 using ::testing::Exactly;
26 using ::testing::InSequence;
27 using ::testing::Invoke;
28 using ::testing::NotNull;
29 using ::testing::Return;
30 using ::testing::SaveArg;
31 using ::testing::SetArgPointee;
32 using ::testing::StrictMock;
33 using ::testing::WithArgs;
34 using ::testing::_;
36 namespace media {
38 MATCHER(IsEndOfStreamBuffer,
39 std::string(negation ? "isn't" : "is") + " end of stream") {
40 return arg->end_of_stream();
43 static void EosOnReadDone(bool* got_eos_buffer,
44 DemuxerStream::Status status,
45 const scoped_refptr<DecoderBuffer>& buffer) {
46 base::MessageLoop::current()->PostTask(
47 FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
49 EXPECT_EQ(status, DemuxerStream::kOk);
50 if (buffer->end_of_stream()) {
51 *got_eos_buffer = true;
52 return;
55 EXPECT_TRUE(buffer->data());
56 EXPECT_GT(buffer->data_size(), 0);
57 *got_eos_buffer = false;
61 // Fixture class to facilitate writing tests. Takes care of setting up the
62 // FFmpeg, pipeline and filter host mocks.
63 class FFmpegDemuxerTest : public testing::Test {
64 protected:
65 FFmpegDemuxerTest() {}
67 virtual ~FFmpegDemuxerTest() {
68 if (demuxer_) {
69 WaitableMessageLoopEvent event;
70 demuxer_->Stop(event.GetClosure());
71 event.RunAndWait();
75 void CreateDemuxer(const std::string& name) {
76 CHECK(!demuxer_);
78 EXPECT_CALL(host_, SetTotalBytes(_)).Times(AnyNumber());
79 EXPECT_CALL(host_, AddBufferedByteRange(_, _)).Times(AnyNumber());
80 EXPECT_CALL(host_, AddBufferedTimeRange(_, _)).Times(AnyNumber());
82 CreateDataSource(name);
84 Demuxer::NeedKeyCB need_key_cb =
85 base::Bind(&FFmpegDemuxerTest::NeedKeyCB, base::Unretained(this));
87 demuxer_.reset(new FFmpegDemuxer(message_loop_.message_loop_proxy(),
88 data_source_.get(),
89 need_key_cb,
90 new MediaLog()));
93 MOCK_METHOD1(CheckPoint, void(int v));
95 void InitializeDemuxerText(bool enable_text) {
96 EXPECT_CALL(host_, SetDuration(_));
97 WaitableMessageLoopEvent event;
98 demuxer_->Initialize(&host_, event.GetPipelineStatusCB(), enable_text);
99 event.RunAndWaitForStatus(PIPELINE_OK);
102 void InitializeDemuxer() {
103 InitializeDemuxerText(false);
106 MOCK_METHOD2(OnReadDoneCalled, void(int, int64));
108 // Verifies that |buffer| has a specific |size| and |timestamp|.
109 // |location| simply indicates where the call to this function was made.
110 // This makes it easier to track down where test failures occur.
111 void OnReadDone(const tracked_objects::Location& location,
112 int size, int64 timestampInMicroseconds,
113 DemuxerStream::Status status,
114 const scoped_refptr<DecoderBuffer>& buffer) {
115 std::string location_str;
116 location.Write(true, false, &location_str);
117 location_str += "\n";
118 SCOPED_TRACE(location_str);
119 EXPECT_EQ(status, DemuxerStream::kOk);
120 OnReadDoneCalled(size, timestampInMicroseconds);
121 EXPECT_TRUE(buffer.get() != NULL);
122 EXPECT_EQ(size, buffer->data_size());
123 EXPECT_EQ(base::TimeDelta::FromMicroseconds(timestampInMicroseconds),
124 buffer->timestamp());
126 DCHECK_EQ(&message_loop_, base::MessageLoop::current());
127 message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
130 DemuxerStream::ReadCB NewReadCB(const tracked_objects::Location& location,
131 int size, int64 timestampInMicroseconds) {
132 EXPECT_CALL(*this, OnReadDoneCalled(size, timestampInMicroseconds));
133 return base::Bind(&FFmpegDemuxerTest::OnReadDone, base::Unretained(this),
134 location, size, timestampInMicroseconds);
137 // TODO(xhwang): This is a workaround of the issue that move-only parameters
138 // are not supported in mocked methods. Remove this when the issue is fixed
139 // (http://code.google.com/p/googletest/issues/detail?id=395) or when we use
140 // std::string instead of scoped_ptr<uint8[]> (http://crbug.com/130689).
141 MOCK_METHOD3(NeedKeyCBMock, void(const std::string& type,
142 const uint8* init_data, int init_data_size));
143 void NeedKeyCB(const std::string& type,
144 const std::vector<uint8>& init_data) {
145 const uint8* init_data_ptr = init_data.empty() ? NULL : &init_data[0];
146 NeedKeyCBMock(type, init_data_ptr, init_data.size());
149 // Accessor to demuxer internals.
150 void set_duration_known(bool duration_known) {
151 demuxer_->duration_known_ = duration_known;
154 bool IsStreamStopped(DemuxerStream::Type type) {
155 DemuxerStream* stream = demuxer_->GetStream(type);
156 CHECK(stream);
157 return !static_cast<FFmpegDemuxerStream*>(stream)->demuxer_;
160 // Fixture members.
161 scoped_ptr<FileDataSource> data_source_;
162 scoped_ptr<FFmpegDemuxer> demuxer_;
163 StrictMock<MockDemuxerHost> host_;
164 base::MessageLoop message_loop_;
166 AVFormatContext* format_context() {
167 return demuxer_->glue_->format_context();
170 void ReadUntilEndOfStream(DemuxerStream* stream) {
171 bool got_eos_buffer = false;
172 const int kMaxBuffers = 170;
173 for (int i = 0; !got_eos_buffer && i < kMaxBuffers; i++) {
174 stream->Read(base::Bind(&EosOnReadDone, &got_eos_buffer));
175 message_loop_.Run();
178 EXPECT_TRUE(got_eos_buffer);
181 private:
182 void CreateDataSource(const std::string& name) {
183 CHECK(!data_source_);
185 base::FilePath file_path;
186 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
188 file_path = file_path.Append(FILE_PATH_LITERAL("media"))
189 .Append(FILE_PATH_LITERAL("test"))
190 .Append(FILE_PATH_LITERAL("data"))
191 .AppendASCII(name);
193 data_source_.reset(new FileDataSource());
194 EXPECT_TRUE(data_source_->Initialize(file_path));
197 DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest);
200 TEST_F(FFmpegDemuxerTest, Initialize_OpenFails) {
201 // Simulate avformat_open_input() failing.
202 CreateDemuxer("ten_byte_file");
203 WaitableMessageLoopEvent event;
204 demuxer_->Initialize(&host_, event.GetPipelineStatusCB(), true);
205 event.RunAndWaitForStatus(DEMUXER_ERROR_COULD_NOT_OPEN);
208 // TODO(acolwell): Uncomment this test when we discover a file that passes
209 // avformat_open_input(), but has avformat_find_stream_info() fail.
211 //TEST_F(FFmpegDemuxerTest, Initialize_ParseFails) {
212 // ("find_stream_info_fail.webm");
213 // demuxer_->Initialize(
214 // &host_, NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_PARSE));
215 // message_loop_.RunUntilIdle();
218 TEST_F(FFmpegDemuxerTest, Initialize_NoStreams) {
219 // Open a file with no streams whatsoever.
220 CreateDemuxer("no_streams.webm");
221 WaitableMessageLoopEvent event;
222 demuxer_->Initialize(&host_, event.GetPipelineStatusCB(), true);
223 event.RunAndWaitForStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
226 TEST_F(FFmpegDemuxerTest, Initialize_NoAudioVideo) {
227 // Open a file containing streams but none of which are audio/video streams.
228 CreateDemuxer("no_audio_video.webm");
229 WaitableMessageLoopEvent event;
230 demuxer_->Initialize(&host_, event.GetPipelineStatusCB(), true);
231 event.RunAndWaitForStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
234 TEST_F(FFmpegDemuxerTest, Initialize_Successful) {
235 CreateDemuxer("bear-320x240.webm");
236 InitializeDemuxer();
238 // Video stream should be present.
239 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
240 ASSERT_TRUE(stream);
241 EXPECT_EQ(DemuxerStream::VIDEO, stream->type());
243 const VideoDecoderConfig& video_config = stream->video_decoder_config();
244 EXPECT_EQ(kCodecVP8, video_config.codec());
245 EXPECT_EQ(VideoFrame::YV12, video_config.format());
246 EXPECT_EQ(320, video_config.coded_size().width());
247 EXPECT_EQ(240, video_config.coded_size().height());
248 EXPECT_EQ(0, video_config.visible_rect().x());
249 EXPECT_EQ(0, video_config.visible_rect().y());
250 EXPECT_EQ(320, video_config.visible_rect().width());
251 EXPECT_EQ(240, video_config.visible_rect().height());
252 EXPECT_EQ(320, video_config.natural_size().width());
253 EXPECT_EQ(240, video_config.natural_size().height());
254 EXPECT_FALSE(video_config.extra_data());
255 EXPECT_EQ(0u, video_config.extra_data_size());
257 // Audio stream should be present.
258 stream = demuxer_->GetStream(DemuxerStream::AUDIO);
259 ASSERT_TRUE(stream);
260 EXPECT_EQ(DemuxerStream::AUDIO, stream->type());
262 const AudioDecoderConfig& audio_config = stream->audio_decoder_config();
263 EXPECT_EQ(kCodecVorbis, audio_config.codec());
264 EXPECT_EQ(32, audio_config.bits_per_channel());
265 EXPECT_EQ(CHANNEL_LAYOUT_STEREO, audio_config.channel_layout());
266 EXPECT_EQ(44100, audio_config.samples_per_second());
267 EXPECT_EQ(kSampleFormatPlanarF32, audio_config.sample_format());
268 EXPECT_TRUE(audio_config.extra_data());
269 EXPECT_GT(audio_config.extra_data_size(), 0u);
271 // Unknown stream should never be present.
272 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN));
275 TEST_F(FFmpegDemuxerTest, Initialize_Multitrack) {
276 // Open a file containing the following streams:
277 // Stream #0: Video (VP8)
278 // Stream #1: Audio (Vorbis)
279 // Stream #2: Subtitles (SRT)
280 // Stream #3: Video (Theora)
281 // Stream #4: Audio (16-bit signed little endian PCM)
283 // We should only pick the first audio/video streams we come across.
284 CreateDemuxer("bear-320x240-multitrack.webm");
285 InitializeDemuxer();
287 // Video stream should be VP8.
288 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
289 ASSERT_TRUE(stream);
290 EXPECT_EQ(DemuxerStream::VIDEO, stream->type());
291 EXPECT_EQ(kCodecVP8, stream->video_decoder_config().codec());
293 // Audio stream should be Vorbis.
294 stream = demuxer_->GetStream(DemuxerStream::AUDIO);
295 ASSERT_TRUE(stream);
296 EXPECT_EQ(DemuxerStream::AUDIO, stream->type());
297 EXPECT_EQ(kCodecVorbis, stream->audio_decoder_config().codec());
299 // Unknown stream should never be present.
300 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN));
303 TEST_F(FFmpegDemuxerTest, Initialize_MultitrackText) {
304 // Open a file containing the following streams:
305 // Stream #0: Video (VP8)
306 // Stream #1: Audio (Vorbis)
307 // Stream #2: Text (WebVTT)
309 CreateDemuxer("bear-vp8-webvtt.webm");
310 DemuxerStream* text_stream = NULL;
311 EXPECT_CALL(host_, AddTextStream(_, _))
312 .WillOnce(SaveArg<0>(&text_stream));
313 InitializeDemuxerText(true);
314 ASSERT_TRUE(text_stream);
315 EXPECT_EQ(DemuxerStream::TEXT, text_stream->type());
317 // Video stream should be VP8.
318 DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
319 ASSERT_TRUE(stream);
320 EXPECT_EQ(DemuxerStream::VIDEO, stream->type());
321 EXPECT_EQ(kCodecVP8, stream->video_decoder_config().codec());
323 // Audio stream should be Vorbis.
324 stream = demuxer_->GetStream(DemuxerStream::AUDIO);
325 ASSERT_TRUE(stream);
326 EXPECT_EQ(DemuxerStream::AUDIO, stream->type());
327 EXPECT_EQ(kCodecVorbis, stream->audio_decoder_config().codec());
329 // Unknown stream should never be present.
330 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN));
333 TEST_F(FFmpegDemuxerTest, Initialize_Encrypted) {
334 EXPECT_CALL(*this, NeedKeyCBMock(kWebMEncryptInitDataType, NotNull(),
335 DecryptConfig::kDecryptionKeySize))
336 .Times(Exactly(2));
338 CreateDemuxer("bear-320x240-av_enc-av.webm");
339 InitializeDemuxer();
342 TEST_F(FFmpegDemuxerTest, Read_Audio) {
343 // We test that on a successful audio packet read.
344 CreateDemuxer("bear-320x240.webm");
345 InitializeDemuxer();
347 // Attempt a read from the audio stream and run the message loop until done.
348 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
350 audio->Read(NewReadCB(FROM_HERE, 29, 0));
351 message_loop_.Run();
353 audio->Read(NewReadCB(FROM_HERE, 27, 3000));
354 message_loop_.Run();
357 TEST_F(FFmpegDemuxerTest, Read_Video) {
358 // We test that on a successful video packet read.
359 CreateDemuxer("bear-320x240.webm");
360 InitializeDemuxer();
362 // Attempt a read from the video stream and run the message loop until done.
363 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
365 video->Read(NewReadCB(FROM_HERE, 22084, 0));
366 message_loop_.Run();
368 video->Read(NewReadCB(FROM_HERE, 1057, 33000));
369 message_loop_.Run();
372 TEST_F(FFmpegDemuxerTest, Read_Text) {
373 // We test that on a successful text packet read.
374 CreateDemuxer("bear-vp8-webvtt.webm");
375 DemuxerStream* text_stream = NULL;
376 EXPECT_CALL(host_, AddTextStream(_, _))
377 .WillOnce(SaveArg<0>(&text_stream));
378 InitializeDemuxerText(true);
379 ASSERT_TRUE(text_stream);
380 EXPECT_EQ(DemuxerStream::TEXT, text_stream->type());
382 text_stream->Read(NewReadCB(FROM_HERE, 31, 0));
383 message_loop_.Run();
385 text_stream->Read(NewReadCB(FROM_HERE, 19, 500000));
386 message_loop_.Run();
389 TEST_F(FFmpegDemuxerTest, Read_VideoNonZeroStart) {
390 // Test the start time is the first timestamp of the video and audio stream.
391 CreateDemuxer("nonzero-start-time.webm");
392 InitializeDemuxer();
394 // Attempt a read from the video stream and run the message loop until done.
395 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
396 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
398 // Check first buffer in video stream.
399 video->Read(NewReadCB(FROM_HERE, 5636, 400000));
400 message_loop_.Run();
402 // Check first buffer in audio stream.
403 audio->Read(NewReadCB(FROM_HERE, 165, 396000));
404 message_loop_.Run();
406 // Verify that the start time is equal to the lowest timestamp (ie the audio).
407 EXPECT_EQ(demuxer_->GetStartTime().InMicroseconds(), 396000);
410 TEST_F(FFmpegDemuxerTest, Read_EndOfStream) {
411 // Verify that end of stream buffers are created.
412 CreateDemuxer("bear-320x240.webm");
413 InitializeDemuxer();
414 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO));
417 TEST_F(FFmpegDemuxerTest, Read_EndOfStreamText) {
418 // Verify that end of stream buffers are created.
419 CreateDemuxer("bear-vp8-webvtt.webm");
420 DemuxerStream* text_stream = NULL;
421 EXPECT_CALL(host_, AddTextStream(_, _))
422 .WillOnce(SaveArg<0>(&text_stream));
423 InitializeDemuxerText(true);
424 ASSERT_TRUE(text_stream);
425 EXPECT_EQ(DemuxerStream::TEXT, text_stream->type());
427 bool got_eos_buffer = false;
428 const int kMaxBuffers = 10;
429 for (int i = 0; !got_eos_buffer && i < kMaxBuffers; i++) {
430 text_stream->Read(base::Bind(&EosOnReadDone, &got_eos_buffer));
431 message_loop_.Run();
434 EXPECT_TRUE(got_eos_buffer);
437 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration) {
438 // Verify that end of stream buffers are created.
439 CreateDemuxer("bear-320x240.webm");
440 InitializeDemuxer();
441 set_duration_known(false);
442 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(2767)));
443 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO));
444 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::VIDEO));
447 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration_VideoOnly) {
448 // Verify that end of stream buffers are created.
449 CreateDemuxer("bear-320x240-video-only.webm");
450 InitializeDemuxer();
451 set_duration_known(false);
452 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(2703)));
453 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::VIDEO));
456 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration_AudioOnly) {
457 // Verify that end of stream buffers are created.
458 CreateDemuxer("bear-320x240-audio-only.webm");
459 InitializeDemuxer();
460 set_duration_known(false);
461 EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(2767)));
462 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO));
465 TEST_F(FFmpegDemuxerTest, Seek) {
466 // We're testing that the demuxer frees all queued packets when it receives
467 // a Seek().
468 CreateDemuxer("bear-320x240.webm");
469 InitializeDemuxer();
471 // Get our streams.
472 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
473 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
474 ASSERT_TRUE(video);
475 ASSERT_TRUE(audio);
477 // Read a video packet and release it.
478 video->Read(NewReadCB(FROM_HERE, 22084, 0));
479 message_loop_.Run();
481 // Issue a simple forward seek, which should discard queued packets.
482 WaitableMessageLoopEvent event;
483 demuxer_->Seek(base::TimeDelta::FromMicroseconds(1000000),
484 event.GetPipelineStatusCB());
485 event.RunAndWaitForStatus(PIPELINE_OK);
487 // Audio read #1.
488 audio->Read(NewReadCB(FROM_HERE, 145, 803000));
489 message_loop_.Run();
491 // Audio read #2.
492 audio->Read(NewReadCB(FROM_HERE, 148, 826000));
493 message_loop_.Run();
495 // Video read #1.
496 video->Read(NewReadCB(FROM_HERE, 5425, 801000));
497 message_loop_.Run();
499 // Video read #2.
500 video->Read(NewReadCB(FROM_HERE, 1906, 834000));
501 message_loop_.Run();
504 TEST_F(FFmpegDemuxerTest, SeekText) {
505 // We're testing that the demuxer frees all queued packets when it receives
506 // a Seek().
507 CreateDemuxer("bear-vp8-webvtt.webm");
508 DemuxerStream* text_stream = NULL;
509 EXPECT_CALL(host_, AddTextStream(_, _))
510 .WillOnce(SaveArg<0>(&text_stream));
511 InitializeDemuxerText(true);
512 ASSERT_TRUE(text_stream);
513 EXPECT_EQ(DemuxerStream::TEXT, text_stream->type());
515 // Get our streams.
516 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
517 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
518 ASSERT_TRUE(video);
519 ASSERT_TRUE(audio);
521 // Read a text packet and release it.
522 text_stream->Read(NewReadCB(FROM_HERE, 31, 0));
523 message_loop_.Run();
525 // Issue a simple forward seek, which should discard queued packets.
526 WaitableMessageLoopEvent event;
527 demuxer_->Seek(base::TimeDelta::FromMicroseconds(1000000),
528 event.GetPipelineStatusCB());
529 event.RunAndWaitForStatus(PIPELINE_OK);
531 // Audio read #1.
532 audio->Read(NewReadCB(FROM_HERE, 145, 803000));
533 message_loop_.Run();
535 // Audio read #2.
536 audio->Read(NewReadCB(FROM_HERE, 148, 826000));
537 message_loop_.Run();
539 // Video read #1.
540 video->Read(NewReadCB(FROM_HERE, 5425, 801000));
541 message_loop_.Run();
543 // Video read #2.
544 video->Read(NewReadCB(FROM_HERE, 1906, 834000));
545 message_loop_.Run();
547 // Text read #1.
548 text_stream->Read(NewReadCB(FROM_HERE, 19, 500000));
549 message_loop_.Run();
551 // Text read #2.
552 text_stream->Read(NewReadCB(FROM_HERE, 19, 1000000));
553 message_loop_.Run();
556 class MockReadCB {
557 public:
558 MockReadCB() {}
559 ~MockReadCB() {}
561 MOCK_METHOD2(Run, void(DemuxerStream::Status status,
562 const scoped_refptr<DecoderBuffer>& buffer));
563 private:
564 DISALLOW_COPY_AND_ASSIGN(MockReadCB);
567 TEST_F(FFmpegDemuxerTest, Stop) {
568 // Tests that calling Read() on a stopped demuxer stream immediately deletes
569 // the callback.
570 CreateDemuxer("bear-320x240.webm");
571 InitializeDemuxer();
573 // Get our stream.
574 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
575 ASSERT_TRUE(audio);
577 WaitableMessageLoopEvent event;
578 demuxer_->Stop(event.GetClosure());
579 event.RunAndWait();
581 // Reads after being stopped are all EOS buffers.
582 StrictMock<MockReadCB> callback;
583 EXPECT_CALL(callback, Run(DemuxerStream::kOk, IsEndOfStreamBuffer()));
585 // Attempt the read...
586 audio->Read(base::Bind(&MockReadCB::Run, base::Unretained(&callback)));
587 message_loop_.RunUntilIdle();
589 // Don't let the test call Stop() again.
590 demuxer_.reset();
593 TEST_F(FFmpegDemuxerTest, DisableAudioStream) {
594 // We are doing the following things here:
595 // 1. Initialize the demuxer with audio and video stream.
596 // 2. Send a "disable audio stream" message to the demuxer.
597 // 3. Demuxer will free audio packets even if audio stream was initialized.
598 CreateDemuxer("bear-320x240.webm");
599 InitializeDemuxer();
601 // Submit a "disable audio stream" message to the demuxer.
602 demuxer_->OnAudioRendererDisabled();
603 message_loop_.RunUntilIdle();
605 // Get our streams.
606 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
607 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
608 ASSERT_TRUE(video);
609 ASSERT_TRUE(audio);
611 // The audio stream should have been prematurely stopped.
612 EXPECT_FALSE(IsStreamStopped(DemuxerStream::VIDEO));
613 EXPECT_TRUE(IsStreamStopped(DemuxerStream::AUDIO));
615 // Attempt a read from the video stream: it should return valid data.
616 video->Read(NewReadCB(FROM_HERE, 22084, 0));
617 message_loop_.Run();
619 // Attempt a read from the audio stream: it should immediately return end of
620 // stream without requiring the message loop to read data.
621 bool got_eos_buffer = false;
622 audio->Read(base::Bind(&EosOnReadDone, &got_eos_buffer));
623 message_loop_.RunUntilIdle();
624 EXPECT_TRUE(got_eos_buffer);
627 // Verify that seek works properly when the WebM cues data is at the start of
628 // the file instead of at the end.
629 TEST_F(FFmpegDemuxerTest, SeekWithCuesBeforeFirstCluster) {
630 CreateDemuxer("bear-320x240-cues-in-front.webm");
631 InitializeDemuxer();
633 // Get our streams.
634 DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
635 DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
636 ASSERT_TRUE(video);
637 ASSERT_TRUE(audio);
639 // Read a video packet and release it.
640 video->Read(NewReadCB(FROM_HERE, 22084, 0));
641 message_loop_.Run();
643 // Issue a simple forward seek, which should discard queued packets.
644 WaitableMessageLoopEvent event;
645 demuxer_->Seek(base::TimeDelta::FromMicroseconds(2500000),
646 event.GetPipelineStatusCB());
647 event.RunAndWaitForStatus(PIPELINE_OK);
649 // Audio read #1.
650 audio->Read(NewReadCB(FROM_HERE, 40, 2403000));
651 message_loop_.Run();
653 // Audio read #2.
654 audio->Read(NewReadCB(FROM_HERE, 42, 2406000));
655 message_loop_.Run();
657 // Video read #1.
658 video->Read(NewReadCB(FROM_HERE, 5276, 2402000));
659 message_loop_.Run();
661 // Video read #2.
662 video->Read(NewReadCB(FROM_HERE, 1740, 2436000));
663 message_loop_.Run();
666 // Ensure ID3v1 tag reading is disabled. id3_test.mp3 has an ID3v1 tag with the
667 // field "title" set to "sample for id3 test".
668 TEST_F(FFmpegDemuxerTest, NoID3TagData) {
669 #if !defined(USE_PROPRIETARY_CODECS)
670 return;
671 #endif
672 CreateDemuxer("id3_test.mp3");
673 InitializeDemuxer();
674 EXPECT_FALSE(av_dict_get(format_context()->metadata, "title", NULL, 0));
677 // Ensure MP3 files with large image/video based ID3 tags demux okay. FFmpeg
678 // will hand us a video stream to the data which will likely be in a format we
679 // don't accept as video; e.g. PNG.
680 TEST_F(FFmpegDemuxerTest, Mp3WithVideoStreamID3TagData) {
681 #if !defined(USE_PROPRIETARY_CODECS)
682 return;
683 #endif
684 CreateDemuxer("id3_png_test.mp3");
685 InitializeDemuxer();
687 // Ensure the expected streams are present.
688 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO));
689 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO));
692 // Ensure a video with an unsupported audio track still results in the video
693 // stream being demuxed.
694 TEST_F(FFmpegDemuxerTest, UnsupportedAudioSupportedVideoDemux) {
695 CreateDemuxer("speex_audio_vorbis_video.ogv");
696 InitializeDemuxer();
698 // Ensure the expected streams are present.
699 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::VIDEO));
700 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::AUDIO));
703 // Ensure a video with an unsupported video track still results in the audio
704 // stream being demuxed.
705 TEST_F(FFmpegDemuxerTest, UnsupportedVideoSupportedAudioDemux) {
706 CreateDemuxer("vorbis_audio_wmv_video.mkv");
707 InitializeDemuxer();
709 // Ensure the expected streams are present.
710 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO));
711 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO));
714 // FFmpeg returns null data pointers when samples have zero size, leading to
715 // mistakenly creating end of stream buffers http://crbug.com/169133
716 TEST_F(FFmpegDemuxerTest, MP4_ZeroStszEntry) {
717 #if !defined(USE_PROPRIETARY_CODECS)
718 return;
719 #endif
720 CreateDemuxer("bear-1280x720-zero-stsz-entry.mp4");
721 InitializeDemuxer();
722 ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO));
725 } // namespace media