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