Upstream version 7.36.149.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/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"
24
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::_;
37
38 namespace media {
39
40 MATCHER(IsEndOfStreamBuffer,
41         std::string(negation ? "isn't" : "is") + " end of stream") {
42   return arg->end_of_stream();
43 }
44
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());
50
51   EXPECT_EQ(status, DemuxerStream::kOk);
52   if (buffer->end_of_stream()) {
53     *got_eos_buffer = true;
54     return;
55   }
56
57   EXPECT_TRUE(buffer->data());
58   EXPECT_GT(buffer->data_size(), 0);
59   *got_eos_buffer = false;
60 };
61
62
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() {}
68
69   virtual ~FFmpegDemuxerTest() {
70     if (demuxer_) {
71       WaitableMessageLoopEvent event;
72       demuxer_->Stop(event.GetClosure());
73       event.RunAndWait();
74     }
75   }
76
77   void CreateDemuxer(const std::string& name) {
78     CHECK(!demuxer_);
79
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 // Verify that seek works properly when the WebM cues data is at the start of
604 // the file instead of at the end.
605 TEST_F(FFmpegDemuxerTest, SeekWithCuesBeforeFirstCluster) {
606   CreateDemuxer("bear-320x240-cues-in-front.webm");
607   InitializeDemuxer();
608
609   // Get our streams.
610   DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
611   DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
612   ASSERT_TRUE(video);
613   ASSERT_TRUE(audio);
614
615   // Read a video packet and release it.
616   video->Read(NewReadCB(FROM_HERE, 22084, 0));
617   message_loop_.Run();
618
619   // Issue a simple forward seek, which should discard queued packets.
620   WaitableMessageLoopEvent event;
621   demuxer_->Seek(base::TimeDelta::FromMicroseconds(2500000),
622                  event.GetPipelineStatusCB());
623   event.RunAndWaitForStatus(PIPELINE_OK);
624
625   // Audio read #1.
626   audio->Read(NewReadCB(FROM_HERE, 40, 2403000));
627   message_loop_.Run();
628
629   // Audio read #2.
630   audio->Read(NewReadCB(FROM_HERE, 42, 2406000));
631   message_loop_.Run();
632
633   // Video read #1.
634   video->Read(NewReadCB(FROM_HERE, 5276, 2402000));
635   message_loop_.Run();
636
637   // Video read #2.
638   video->Read(NewReadCB(FROM_HERE, 1740, 2436000));
639   message_loop_.Run();
640 }
641
642 #if defined(USE_PROPRIETARY_CODECS)
643 // Ensure ID3v1 tag reading is disabled.  id3_test.mp3 has an ID3v1 tag with the
644 // field "title" set to "sample for id3 test".
645 TEST_F(FFmpegDemuxerTest, NoID3TagData) {
646   CreateDemuxer("id3_test.mp3");
647   InitializeDemuxer();
648   EXPECT_FALSE(av_dict_get(format_context()->metadata, "title", NULL, 0));
649 }
650 #endif
651
652 #if defined(USE_PROPRIETARY_CODECS)
653 // Ensure MP3 files with large image/video based ID3 tags demux okay.  FFmpeg
654 // will hand us a video stream to the data which will likely be in a format we
655 // don't accept as video; e.g. PNG.
656 TEST_F(FFmpegDemuxerTest, Mp3WithVideoStreamID3TagData) {
657   CreateDemuxer("id3_png_test.mp3");
658   InitializeDemuxer();
659
660   // Ensure the expected streams are present.
661   EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO));
662   EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO));
663 }
664 #endif
665
666 // Ensure a video with an unsupported audio track still results in the video
667 // stream being demuxed.
668 TEST_F(FFmpegDemuxerTest, UnsupportedAudioSupportedVideoDemux) {
669   CreateDemuxer("speex_audio_vorbis_video.ogv");
670   InitializeDemuxer();
671
672   // Ensure the expected streams are present.
673   EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::VIDEO));
674   EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::AUDIO));
675 }
676
677 // Ensure a video with an unsupported video track still results in the audio
678 // stream being demuxed.
679 TEST_F(FFmpegDemuxerTest, UnsupportedVideoSupportedAudioDemux) {
680   CreateDemuxer("vorbis_audio_wmv_video.mkv");
681   InitializeDemuxer();
682
683   // Ensure the expected streams are present.
684   EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO));
685   EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO));
686 }
687
688 #if defined(USE_PROPRIETARY_CODECS)
689 // FFmpeg returns null data pointers when samples have zero size, leading to
690 // mistakenly creating end of stream buffers http://crbug.com/169133
691 TEST_F(FFmpegDemuxerTest, MP4_ZeroStszEntry) {
692   CreateDemuxer("bear-1280x720-zero-stsz-entry.mp4");
693   InitializeDemuxer();
694   ReadUntilEndOfStream(demuxer_->GetStream(DemuxerStream::AUDIO));
695 }
696
697
698 static void ValidateAnnexB(DemuxerStream* stream,
699                            DemuxerStream::Status status,
700                            const scoped_refptr<DecoderBuffer>& buffer) {
701   EXPECT_EQ(status, DemuxerStream::kOk);
702
703   if (buffer->end_of_stream()) {
704     base::MessageLoop::current()->PostTask(
705         FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
706     return;
707   }
708
709   bool is_valid =
710       mp4::AVC::IsValidAnnexB(buffer->data(), buffer->data_size());
711   EXPECT_TRUE(is_valid);
712
713   if (!is_valid) {
714     LOG(ERROR) << "Buffer contains invalid Annex B data.";
715     base::MessageLoop::current()->PostTask(
716         FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
717     return;
718   }
719
720   stream->Read(base::Bind(&ValidateAnnexB, stream));
721 };
722
723 TEST_F(FFmpegDemuxerTest, IsValidAnnexB) {
724   const char* files[] = {
725     "bear-1280x720-av_frag.mp4",
726     "bear-1280x720-av_with-aud-nalus_frag.mp4"
727   };
728
729   for (size_t i = 0; i < arraysize(files); ++i) {
730     DVLOG(1) << "Testing " << files[i];
731     CreateDemuxer(files[i]);
732     InitializeDemuxer();
733
734     // Ensure the expected streams are present.
735     DemuxerStream* stream = demuxer_->GetStream(DemuxerStream::VIDEO);
736     ASSERT_TRUE(stream);
737     stream->EnableBitstreamConverter();
738
739     stream->Read(base::Bind(&ValidateAnnexB, stream));
740     message_loop_.Run();
741
742     WaitableMessageLoopEvent event;
743     demuxer_->Stop(event.GetClosure());
744     event.RunAndWait();
745     demuxer_.reset();
746     data_source_.reset();
747   }
748 }
749
750 #endif
751
752 }  // namespace media