Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / media / filters / ffmpeg_demuxer_unittest.cc
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.
4
5 #include <algorithm>
6 #include <deque>
7 #include <string>
8
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/formats/webm/webm_crypto_helpers.h"
21 #include "testing/gtest/include/gtest/gtest.h"
22
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::_;
35
36 namespace media {
37
38 MATCHER(IsEndOfStreamBuffer,
39         std::string(negation ? "isn't" : "is") + " end of stream") {
40   return arg->end_of_stream();
41 }
42
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());
48
49   EXPECT_EQ(status, DemuxerStream::kOk);
50   if (buffer->end_of_stream()) {
51     *got_eos_buffer = true;
52     return;
53   }
54
55   EXPECT_TRUE(buffer->data());
56   EXPECT_GT(buffer->data_size(), 0);
57   *got_eos_buffer = false;
58 };
59
60
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() {}
66
67   virtual ~FFmpegDemuxerTest() {
68     if (demuxer_) {
69       WaitableMessageLoopEvent event;
70       demuxer_->Stop(event.GetClosure());
71       event.RunAndWait();
72     }
73   }
74
75   void CreateDemuxer(const std::string& name) {
76     CHECK(!demuxer_);
77
78     EXPECT_CALL(host_, SetTotalBytes(_)).Times(AnyNumber());
79     EXPECT_CALL(host_, AddBufferedByteRange(_, _)).Times(AnyNumber());
80     EXPECT_CALL(host_, AddBufferedTimeRange(_, _)).Times(AnyNumber());
81
82     CreateDataSource(name);
83
84     Demuxer::NeedKeyCB need_key_cb =
85         base::Bind(&FFmpegDemuxerTest::NeedKeyCB, base::Unretained(this));
86
87     demuxer_.reset(new FFmpegDemuxer(message_loop_.message_loop_proxy(),
88                                      data_source_.get(),
89                                      need_key_cb,
90                                      new MediaLog()));
91   }
92
93   MOCK_METHOD1(CheckPoint, void(int v));
94
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);
100   }
101
102   void InitializeDemuxer() {
103     InitializeDemuxerText(false);
104   }
105
106   MOCK_METHOD2(OnReadDoneCalled, void(int, int64));
107
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());
125
126     DCHECK_EQ(&message_loop_, base::MessageLoop::current());
127     message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
128   }
129
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);
135   }
136
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());
147   }
148
149   // Accessor to demuxer internals.
150   void set_duration_known(bool duration_known) {
151     demuxer_->duration_known_ = duration_known;
152   }
153
154   bool IsStreamStopped(DemuxerStream::Type type) {
155     DemuxerStream* stream = demuxer_->GetStream(type);
156     CHECK(stream);
157     return !static_cast<FFmpegDemuxerStream*>(stream)->demuxer_;
158   }
159
160   // Fixture members.
161   scoped_ptr<FileDataSource> data_source_;
162   scoped_ptr<FFmpegDemuxer> demuxer_;
163   StrictMock<MockDemuxerHost> host_;
164   base::MessageLoop message_loop_;
165
166   AVFormatContext* format_context() {
167     return demuxer_->glue_->format_context();
168   }
169
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();
176     }
177
178     EXPECT_TRUE(got_eos_buffer);
179   }
180
181  private:
182   void CreateDataSource(const std::string& name) {
183     CHECK(!data_source_);
184
185     base::FilePath file_path;
186     EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &file_path));
187
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);
192
193     data_source_.reset(new FileDataSource());
194     EXPECT_TRUE(data_source_->Initialize(file_path));
195   }
196
197   DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest);
198 };
199
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);
206 }
207
208 // TODO(acolwell): Uncomment this test when we discover a file that passes
209 // avformat_open_input(), but has avformat_find_stream_info() fail.
210 //
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();
216 //}
217
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);
224 }
225
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);
232 }
233
234 TEST_F(FFmpegDemuxerTest, Initialize_Successful) {
235   CreateDemuxer("bear-320x240.webm");
236   InitializeDemuxer();
237
238   // Video stream should be present.
239   DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
240   ASSERT_TRUE(stream);
241   EXPECT_EQ(DemuxerStream::VIDEO, stream->type());
242
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());
256
257   // Audio stream should be present.
258   stream = demuxer_->GetStream(DemuxerStream::AUDIO);
259   ASSERT_TRUE(stream);
260   EXPECT_EQ(DemuxerStream::AUDIO, stream->type());
261
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);
270
271   // Unknown stream should never be present.
272   EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN));
273 }
274
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)
282   //
283   // We should only pick the first audio/video streams we come across.
284   CreateDemuxer("bear-320x240-multitrack.webm");
285   InitializeDemuxer();
286
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());
292
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());
298
299   // Unknown stream should never be present.
300   EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN));
301 }
302
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)
308
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());
316
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());
322
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());
328
329   // Unknown stream should never be present.
330   EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN));
331 }
332
333 TEST_F(FFmpegDemuxerTest, Initialize_Encrypted) {
334   EXPECT_CALL(*this, NeedKeyCBMock(kWebMEncryptInitDataType, NotNull(),
335                                    DecryptConfig::kDecryptionKeySize))
336       .Times(Exactly(2));
337
338   CreateDemuxer("bear-320x240-av_enc-av.webm");
339   InitializeDemuxer();
340 }
341
342 TEST_F(FFmpegDemuxerTest, Read_Audio) {
343   // We test that on a successful audio packet read.
344   CreateDemuxer("bear-320x240.webm");
345   InitializeDemuxer();
346
347   // Attempt a read from the audio stream and run the message loop until done.
348   DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
349
350   audio->Read(NewReadCB(FROM_HERE, 29, 0));
351   message_loop_.Run();
352
353   audio->Read(NewReadCB(FROM_HERE, 27, 3000));
354   message_loop_.Run();
355 }
356
357 TEST_F(FFmpegDemuxerTest, Read_Video) {
358   // We test that on a successful video packet read.
359   CreateDemuxer("bear-320x240.webm");
360   InitializeDemuxer();
361
362   // Attempt a read from the video stream and run the message loop until done.
363   DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
364
365   video->Read(NewReadCB(FROM_HERE, 22084, 0));
366   message_loop_.Run();
367
368   video->Read(NewReadCB(FROM_HERE, 1057, 33000));
369   message_loop_.Run();
370 }
371
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());
381
382   text_stream->Read(NewReadCB(FROM_HERE, 31, 0));
383   message_loop_.Run();
384
385   text_stream->Read(NewReadCB(FROM_HERE, 19, 500000));
386   message_loop_.Run();
387 }
388
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();
393
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);
397
398   // Check first buffer in video stream.
399   video->Read(NewReadCB(FROM_HERE, 5636, 400000));
400   message_loop_.Run();
401
402   // Check first buffer in audio stream.
403   audio->Read(NewReadCB(FROM_HERE, 165, 396000));
404   message_loop_.Run();
405
406   // Verify that the start time is equal to the lowest timestamp (ie the audio).
407   EXPECT_EQ(demuxer_->GetStartTime().InMicroseconds(), 396000);
408 }
409
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));
415 }
416
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());
426
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();
432   }
433
434   EXPECT_TRUE(got_eos_buffer);
435 }
436
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));
445 }
446
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));
454 }
455
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));
463 }
464
465 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration_UnsupportedStream) {
466   // Verify that end of stream buffers are created and we don't crash
467   // if there are streams in the file that we don't support.
468   CreateDemuxer("vorbis_audio_wmv_video.mkv");
469   InitializeDemuxer();
470   set_duration_known(false);
471   EXPECT_CALL(host_, SetDuration(base::TimeDelta::FromMilliseconds(1014)));
472   ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO));
473 }
474
475 TEST_F(FFmpegDemuxerTest, Seek) {
476   // We're testing that the demuxer frees all queued packets when it receives
477   // a Seek().
478   CreateDemuxer("bear-320x240.webm");
479   InitializeDemuxer();
480
481   // Get our streams.
482   DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
483   DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
484   ASSERT_TRUE(video);
485   ASSERT_TRUE(audio);
486
487   // Read a video packet and release it.
488   video->Read(NewReadCB(FROM_HERE, 22084, 0));
489   message_loop_.Run();
490
491   // Issue a simple forward seek, which should discard queued packets.
492   WaitableMessageLoopEvent event;
493   demuxer_->Seek(base::TimeDelta::FromMicroseconds(1000000),
494                  event.GetPipelineStatusCB());
495   event.RunAndWaitForStatus(PIPELINE_OK);
496
497   // Audio read #1.
498   audio->Read(NewReadCB(FROM_HERE, 145, 803000));
499   message_loop_.Run();
500
501   // Audio read #2.
502   audio->Read(NewReadCB(FROM_HERE, 148, 826000));
503   message_loop_.Run();
504
505   // Video read #1.
506   video->Read(NewReadCB(FROM_HERE, 5425, 801000));
507   message_loop_.Run();
508
509   // Video read #2.
510   video->Read(NewReadCB(FROM_HERE, 1906, 834000));
511   message_loop_.Run();
512 }
513
514 TEST_F(FFmpegDemuxerTest, SeekText) {
515   // We're testing that the demuxer frees all queued packets when it receives
516   // a Seek().
517   CreateDemuxer("bear-vp8-webvtt.webm");
518   DemuxerStream* text_stream = NULL;
519   EXPECT_CALL(host_, AddTextStream(_, _))
520       .WillOnce(SaveArg<0>(&text_stream));
521   InitializeDemuxerText(true);
522   ASSERT_TRUE(text_stream);
523   EXPECT_EQ(DemuxerStream::TEXT, text_stream->type());
524
525   // Get our streams.
526   DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
527   DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
528   ASSERT_TRUE(video);
529   ASSERT_TRUE(audio);
530
531   // Read a text packet and release it.
532   text_stream->Read(NewReadCB(FROM_HERE, 31, 0));
533   message_loop_.Run();
534
535   // Issue a simple forward seek, which should discard queued packets.
536   WaitableMessageLoopEvent event;
537   demuxer_->Seek(base::TimeDelta::FromMicroseconds(1000000),
538                  event.GetPipelineStatusCB());
539   event.RunAndWaitForStatus(PIPELINE_OK);
540
541   // Audio read #1.
542   audio->Read(NewReadCB(FROM_HERE, 145, 803000));
543   message_loop_.Run();
544
545   // Audio read #2.
546   audio->Read(NewReadCB(FROM_HERE, 148, 826000));
547   message_loop_.Run();
548
549   // Video read #1.
550   video->Read(NewReadCB(FROM_HERE, 5425, 801000));
551   message_loop_.Run();
552
553   // Video read #2.
554   video->Read(NewReadCB(FROM_HERE, 1906, 834000));
555   message_loop_.Run();
556
557   // Text read #1.
558   text_stream->Read(NewReadCB(FROM_HERE, 19, 500000));
559   message_loop_.Run();
560
561   // Text read #2.
562   text_stream->Read(NewReadCB(FROM_HERE, 19, 1000000));
563   message_loop_.Run();
564 }
565
566 class MockReadCB {
567  public:
568   MockReadCB() {}
569   ~MockReadCB() {}
570
571   MOCK_METHOD2(Run, void(DemuxerStream::Status status,
572                          const scoped_refptr<DecoderBuffer>& buffer));
573  private:
574   DISALLOW_COPY_AND_ASSIGN(MockReadCB);
575 };
576
577 TEST_F(FFmpegDemuxerTest, Stop) {
578   // Tests that calling Read() on a stopped demuxer stream immediately deletes
579   // the callback.
580   CreateDemuxer("bear-320x240.webm");
581   InitializeDemuxer();
582
583   // Get our stream.
584   DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
585   ASSERT_TRUE(audio);
586
587   WaitableMessageLoopEvent event;
588   demuxer_->Stop(event.GetClosure());
589   event.RunAndWait();
590
591   // Reads after being stopped are all EOS buffers.
592   StrictMock<MockReadCB> callback;
593   EXPECT_CALL(callback, Run(DemuxerStream::kOk, IsEndOfStreamBuffer()));
594
595   // Attempt the read...
596   audio->Read(base::Bind(&MockReadCB::Run, base::Unretained(&callback)));
597   message_loop_.RunUntilIdle();
598
599   // Don't let the test call Stop() again.
600   demuxer_.reset();
601 }
602
603 TEST_F(FFmpegDemuxerTest, DisableAudioStream) {
604   // We are doing the following things here:
605   // 1. Initialize the demuxer with audio and video stream.
606   // 2. Send a "disable audio stream" message to the demuxer.
607   // 3. Demuxer will free audio packets even if audio stream was initialized.
608   CreateDemuxer("bear-320x240.webm");
609   InitializeDemuxer();
610
611   // Submit a "disable audio stream" message to the demuxer.
612   demuxer_->OnAudioRendererDisabled();
613   message_loop_.RunUntilIdle();
614
615   // Get our streams.
616   DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
617   DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
618   ASSERT_TRUE(video);
619   ASSERT_TRUE(audio);
620
621   // The audio stream should have been prematurely stopped.
622   EXPECT_FALSE(IsStreamStopped(DemuxerStream::VIDEO));
623   EXPECT_TRUE(IsStreamStopped(DemuxerStream::AUDIO));
624
625   // Attempt a read from the video stream: it should return valid data.
626   video->Read(NewReadCB(FROM_HERE, 22084, 0));
627   message_loop_.Run();
628
629   // Attempt a read from the audio stream: it should immediately return end of
630   // stream without requiring the message loop to read data.
631   bool got_eos_buffer = false;
632   audio->Read(base::Bind(&EosOnReadDone, &got_eos_buffer));
633   message_loop_.RunUntilIdle();
634   EXPECT_TRUE(got_eos_buffer);
635 }
636
637 // Verify that seek works properly when the WebM cues data is at the start of
638 // the file instead of at the end.
639 TEST_F(FFmpegDemuxerTest, SeekWithCuesBeforeFirstCluster) {
640   CreateDemuxer("bear-320x240-cues-in-front.webm");
641   InitializeDemuxer();
642
643   // Get our streams.
644   DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
645   DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
646   ASSERT_TRUE(video);
647   ASSERT_TRUE(audio);
648
649   // Read a video packet and release it.
650   video->Read(NewReadCB(FROM_HERE, 22084, 0));
651   message_loop_.Run();
652
653   // Issue a simple forward seek, which should discard queued packets.
654   WaitableMessageLoopEvent event;
655   demuxer_->Seek(base::TimeDelta::FromMicroseconds(2500000),
656                  event.GetPipelineStatusCB());
657   event.RunAndWaitForStatus(PIPELINE_OK);
658
659   // Audio read #1.
660   audio->Read(NewReadCB(FROM_HERE, 40, 2403000));
661   message_loop_.Run();
662
663   // Audio read #2.
664   audio->Read(NewReadCB(FROM_HERE, 42, 2406000));
665   message_loop_.Run();
666
667   // Video read #1.
668   video->Read(NewReadCB(FROM_HERE, 5276, 2402000));
669   message_loop_.Run();
670
671   // Video read #2.
672   video->Read(NewReadCB(FROM_HERE, 1740, 2436000));
673   message_loop_.Run();
674 }
675
676 // Ensure ID3v1 tag reading is disabled.  id3_test.mp3 has an ID3v1 tag with the
677 // field "title" set to "sample for id3 test".
678 TEST_F(FFmpegDemuxerTest, NoID3TagData) {
679 #if !defined(USE_PROPRIETARY_CODECS)
680   return;
681 #endif
682   CreateDemuxer("id3_test.mp3");
683   InitializeDemuxer();
684   EXPECT_FALSE(av_dict_get(format_context()->metadata, "title", NULL, 0));
685 }
686
687 // Ensure MP3 files with large image/video based ID3 tags demux okay.  FFmpeg
688 // will hand us a video stream to the data which will likely be in a format we
689 // don't accept as video; e.g. PNG.
690 TEST_F(FFmpegDemuxerTest, Mp3WithVideoStreamID3TagData) {
691 #if !defined(USE_PROPRIETARY_CODECS)
692   return;
693 #endif
694   CreateDemuxer("id3_png_test.mp3");
695   InitializeDemuxer();
696
697   // Ensure the expected streams are present.
698   EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO));
699   EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO));
700 }
701
702 // Ensure a video with an unsupported audio track still results in the video
703 // stream being demuxed.
704 TEST_F(FFmpegDemuxerTest, UnsupportedAudioSupportedVideoDemux) {
705   CreateDemuxer("speex_audio_vorbis_video.ogv");
706   InitializeDemuxer();
707
708   // Ensure the expected streams are present.
709   EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::VIDEO));
710   EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::AUDIO));
711 }
712
713 // Ensure a video with an unsupported video track still results in the audio
714 // stream being demuxed.
715 TEST_F(FFmpegDemuxerTest, UnsupportedVideoSupportedAudioDemux) {
716   CreateDemuxer("vorbis_audio_wmv_video.mkv");
717   InitializeDemuxer();
718
719   // Ensure the expected streams are present.
720   EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO));
721   EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO));
722 }
723
724 // FFmpeg returns null data pointers when samples have zero size, leading to
725 // mistakenly creating end of stream buffers http://crbug.com/169133
726 TEST_F(FFmpegDemuxerTest, MP4_ZeroStszEntry) {
727 #if !defined(USE_PROPRIETARY_CODECS)
728   return;
729 #endif
730   CreateDemuxer("bear-1280x720-zero-stsz-entry.mp4");
731   InitializeDemuxer();
732   ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO));
733 }
734
735 }  // namespace media