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