- add sources.
[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/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     demuxer_.reset(new FFmpegDemuxer(message_loop_.message_loop_proxy(),
87                                      data_source_.get(),
88                                      need_key_cb,
89                                      new MediaLog()));
90   }
91
92   MOCK_METHOD1(CheckPoint, void(int v));
93
94   void InitializeDemuxer() {
95     EXPECT_CALL(host_, SetDuration(_));
96     WaitableMessageLoopEvent event;
97     demuxer_->Initialize(&host_, event.GetPipelineStatusCB());
98     event.RunAndWaitForStatus(PIPELINE_OK);
99   }
100
101   MOCK_METHOD2(OnReadDoneCalled, void(int, int64));
102
103   // Verifies that |buffer| has a specific |size| and |timestamp|.
104   // |location| simply indicates where the call to this function was made.
105   // This makes it easier to track down where test failures occur.
106   void OnReadDone(const tracked_objects::Location& location,
107                   int size, int64 timestampInMicroseconds,
108                   DemuxerStream::Status status,
109                   const scoped_refptr<DecoderBuffer>& buffer) {
110     std::string location_str;
111     location.Write(true, false, &location_str);
112     location_str += "\n";
113     SCOPED_TRACE(location_str);
114     EXPECT_EQ(status, DemuxerStream::kOk);
115     OnReadDoneCalled(size, timestampInMicroseconds);
116     EXPECT_TRUE(buffer.get() != NULL);
117     EXPECT_EQ(size, buffer->data_size());
118     EXPECT_EQ(base::TimeDelta::FromMicroseconds(timestampInMicroseconds),
119               buffer->timestamp());
120
121     DCHECK_EQ(&message_loop_, base::MessageLoop::current());
122     message_loop_.PostTask(FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
123   }
124
125   DemuxerStream::ReadCB NewReadCB(const tracked_objects::Location& location,
126                                   int size, int64 timestampInMicroseconds) {
127     EXPECT_CALL(*this, OnReadDoneCalled(size, timestampInMicroseconds));
128     return base::Bind(&FFmpegDemuxerTest::OnReadDone, base::Unretained(this),
129                       location, size, timestampInMicroseconds);
130   }
131
132   // TODO(xhwang): This is a workaround of the issue that move-only parameters
133   // are not supported in mocked methods. Remove this when the issue is fixed
134   // (http://code.google.com/p/googletest/issues/detail?id=395) or when we use
135   // std::string instead of scoped_ptr<uint8[]> (http://crbug.com/130689).
136   MOCK_METHOD3(NeedKeyCBMock, void(const std::string& type,
137                                    const uint8* init_data, int init_data_size));
138   void NeedKeyCB(const std::string& type,
139                  const std::vector<uint8>& init_data) {
140     const uint8* init_data_ptr = init_data.empty() ? NULL : &init_data[0];
141     NeedKeyCBMock(type, init_data_ptr, init_data.size());
142   }
143
144   // Accessor to demuxer internals.
145   void set_duration_known(bool duration_known) {
146     demuxer_->duration_known_ = duration_known;
147   }
148
149   bool IsStreamStopped(DemuxerStream::Type type) {
150     DemuxerStream* stream = demuxer_->GetStream(type);
151     CHECK(stream);
152     return !static_cast<FFmpegDemuxerStream*>(stream)->demuxer_;
153   }
154
155   // Fixture members.
156   scoped_ptr<FileDataSource> data_source_;
157   scoped_ptr<FFmpegDemuxer> demuxer_;
158   StrictMock<MockDemuxerHost> host_;
159   base::MessageLoop message_loop_;
160
161   AVFormatContext* format_context() {
162     return demuxer_->glue_->format_context();
163   }
164
165   void ReadUntilEndOfStream() {
166     // We should expect an end of stream buffer.
167     DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
168
169     bool got_eos_buffer = false;
170     const int kMaxBuffers = 170;
171     for (int i = 0; !got_eos_buffer && i < kMaxBuffers; i++) {
172       audio->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
198 TEST_F(FFmpegDemuxerTest, Initialize_OpenFails) {
199   // Simulate avformat_open_input() failing.
200   CreateDemuxer("ten_byte_file");
201   WaitableMessageLoopEvent event;
202   demuxer_->Initialize(&host_, event.GetPipelineStatusCB());
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
216 TEST_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());
221   event.RunAndWaitForStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
222 }
223
224 TEST_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());
229   event.RunAndWaitForStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS);
230 }
231
232 TEST_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
273 TEST_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
301 TEST_F(FFmpegDemuxerTest, Initialize_Encrypted) {
302   EXPECT_CALL(*this, NeedKeyCBMock(kWebMEncryptInitDataType, NotNull(),
303                                    DecryptConfig::kDecryptionKeySize))
304       .Times(Exactly(2));
305
306   CreateDemuxer("bear-320x240-av_enc-av.webm");
307   InitializeDemuxer();
308 }
309
310 TEST_F(FFmpegDemuxerTest, Read_Audio) {
311   // We test that on a successful audio packet read.
312   CreateDemuxer("bear-320x240.webm");
313   InitializeDemuxer();
314
315   // Attempt a read from the audio stream and run the message loop until done.
316   DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
317
318   audio->Read(NewReadCB(FROM_HERE, 29, 0));
319   message_loop_.Run();
320
321   audio->Read(NewReadCB(FROM_HERE, 27, 3000));
322   message_loop_.Run();
323 }
324
325 TEST_F(FFmpegDemuxerTest, Read_Video) {
326   // We test that on a successful video packet read.
327   CreateDemuxer("bear-320x240.webm");
328   InitializeDemuxer();
329
330   // Attempt a read from the video stream and run the message loop until done.
331   DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
332
333   video->Read(NewReadCB(FROM_HERE, 22084, 0));
334   message_loop_.Run();
335
336   video->Read(NewReadCB(FROM_HERE, 1057, 33000));
337   message_loop_.Run();
338 }
339
340 TEST_F(FFmpegDemuxerTest, Read_VideoNonZeroStart) {
341   // Test the start time is the first timestamp of the video and audio stream.
342   CreateDemuxer("nonzero-start-time.webm");
343   InitializeDemuxer();
344
345   // Attempt a read from the video stream and run the message loop until done.
346   DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
347   DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
348
349   // Check first buffer in video stream.
350   video->Read(NewReadCB(FROM_HERE, 5636, 400000));
351   message_loop_.Run();
352
353   // Check first buffer in audio stream.
354   audio->Read(NewReadCB(FROM_HERE, 165, 396000));
355   message_loop_.Run();
356
357   // Verify that the start time is equal to the lowest timestamp (ie the audio).
358   EXPECT_EQ(demuxer_->GetStartTime().InMicroseconds(), 396000);
359 }
360
361 TEST_F(FFmpegDemuxerTest, Read_EndOfStream) {
362   // Verify that end of stream buffers are created.
363   CreateDemuxer("bear-320x240.webm");
364   InitializeDemuxer();
365   ReadUntilEndOfStream();
366 }
367
368 TEST_F(FFmpegDemuxerTest, Read_EndOfStream_NoDuration) {
369   // Verify that end of stream buffers are created.
370   CreateDemuxer("bear-320x240.webm");
371   InitializeDemuxer();
372   set_duration_known(false);
373   EXPECT_CALL(host_, SetDuration(_));
374   ReadUntilEndOfStream();
375 }
376
377 TEST_F(FFmpegDemuxerTest, Seek) {
378   // We're testing that the demuxer frees all queued packets when it receives
379   // a Seek().
380   CreateDemuxer("bear-320x240.webm");
381   InitializeDemuxer();
382
383   // Get our streams.
384   DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
385   DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
386   ASSERT_TRUE(video);
387   ASSERT_TRUE(audio);
388
389   // Read a video packet and release it.
390   video->Read(NewReadCB(FROM_HERE, 22084, 0));
391   message_loop_.Run();
392
393   // Issue a simple forward seek, which should discard queued packets.
394   WaitableMessageLoopEvent event;
395   demuxer_->Seek(base::TimeDelta::FromMicroseconds(1000000),
396                  event.GetPipelineStatusCB());
397   event.RunAndWaitForStatus(PIPELINE_OK);
398
399   // Audio read #1.
400   audio->Read(NewReadCB(FROM_HERE, 145, 803000));
401   message_loop_.Run();
402
403   // Audio read #2.
404   audio->Read(NewReadCB(FROM_HERE, 148, 826000));
405   message_loop_.Run();
406
407   // Video read #1.
408   video->Read(NewReadCB(FROM_HERE, 5425, 801000));
409   message_loop_.Run();
410
411   // Video read #2.
412   video->Read(NewReadCB(FROM_HERE, 1906, 834000));
413   message_loop_.Run();
414 }
415
416 class MockReadCB {
417  public:
418   MockReadCB() {}
419   ~MockReadCB() {}
420
421   MOCK_METHOD2(Run, void(DemuxerStream::Status status,
422                          const scoped_refptr<DecoderBuffer>& buffer));
423  private:
424   DISALLOW_COPY_AND_ASSIGN(MockReadCB);
425 };
426
427 TEST_F(FFmpegDemuxerTest, Stop) {
428   // Tests that calling Read() on a stopped demuxer stream immediately deletes
429   // the callback.
430   CreateDemuxer("bear-320x240.webm");
431   InitializeDemuxer();
432
433   // Get our stream.
434   DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
435   ASSERT_TRUE(audio);
436
437   WaitableMessageLoopEvent event;
438   demuxer_->Stop(event.GetClosure());
439   event.RunAndWait();
440
441   // Reads after being stopped are all EOS buffers.
442   StrictMock<MockReadCB> callback;
443   EXPECT_CALL(callback, Run(DemuxerStream::kOk, IsEndOfStreamBuffer()));
444
445   // Attempt the read...
446   audio->Read(base::Bind(&MockReadCB::Run, base::Unretained(&callback)));
447   message_loop_.RunUntilIdle();
448
449   // Don't let the test call Stop() again.
450   demuxer_.reset();
451 }
452
453 TEST_F(FFmpegDemuxerTest, DisableAudioStream) {
454   // We are doing the following things here:
455   // 1. Initialize the demuxer with audio and video stream.
456   // 2. Send a "disable audio stream" message to the demuxer.
457   // 3. Demuxer will free audio packets even if audio stream was initialized.
458   CreateDemuxer("bear-320x240.webm");
459   InitializeDemuxer();
460
461   // Submit a "disable audio stream" message to the demuxer.
462   demuxer_->OnAudioRendererDisabled();
463   message_loop_.RunUntilIdle();
464
465   // Get our streams.
466   DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
467   DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
468   ASSERT_TRUE(video);
469   ASSERT_TRUE(audio);
470
471   // The audio stream should have been prematurely stopped.
472   EXPECT_FALSE(IsStreamStopped(DemuxerStream::VIDEO));
473   EXPECT_TRUE(IsStreamStopped(DemuxerStream::AUDIO));
474
475   // Attempt a read from the video stream: it should return valid data.
476   video->Read(NewReadCB(FROM_HERE, 22084, 0));
477   message_loop_.Run();
478
479   // Attempt a read from the audio stream: it should immediately return end of
480   // stream without requiring the message loop to read data.
481   bool got_eos_buffer = false;
482   audio->Read(base::Bind(&EosOnReadDone, &got_eos_buffer));
483   message_loop_.RunUntilIdle();
484   EXPECT_TRUE(got_eos_buffer);
485 }
486
487 // Verify that seek works properly when the WebM cues data is at the start of
488 // the file instead of at the end.
489 TEST_F(FFmpegDemuxerTest, SeekWithCuesBeforeFirstCluster) {
490   CreateDemuxer("bear-320x240-cues-in-front.webm");
491   InitializeDemuxer();
492
493   // Get our streams.
494   DemuxerStream* video = demuxer_->GetStream(DemuxerStream::VIDEO);
495   DemuxerStream* audio = demuxer_->GetStream(DemuxerStream::AUDIO);
496   ASSERT_TRUE(video);
497   ASSERT_TRUE(audio);
498
499   // Read a video packet and release it.
500   video->Read(NewReadCB(FROM_HERE, 22084, 0));
501   message_loop_.Run();
502
503   // Issue a simple forward seek, which should discard queued packets.
504   WaitableMessageLoopEvent event;
505   demuxer_->Seek(base::TimeDelta::FromMicroseconds(2500000),
506                  event.GetPipelineStatusCB());
507   event.RunAndWaitForStatus(PIPELINE_OK);
508
509   // Audio read #1.
510   audio->Read(NewReadCB(FROM_HERE, 40, 2403000));
511   message_loop_.Run();
512
513   // Audio read #2.
514   audio->Read(NewReadCB(FROM_HERE, 42, 2406000));
515   message_loop_.Run();
516
517   // Video read #1.
518   video->Read(NewReadCB(FROM_HERE, 5276, 2402000));
519   message_loop_.Run();
520
521   // Video read #2.
522   video->Read(NewReadCB(FROM_HERE, 1740, 2436000));
523   message_loop_.Run();
524 }
525
526 // Ensure ID3v1 tag reading is disabled.  id3_test.mp3 has an ID3v1 tag with the
527 // field "title" set to "sample for id3 test".
528 TEST_F(FFmpegDemuxerTest, NoID3TagData) {
529 #if !defined(USE_PROPRIETARY_CODECS)
530   return;
531 #endif
532   CreateDemuxer("id3_test.mp3");
533   InitializeDemuxer();
534   EXPECT_FALSE(av_dict_get(format_context()->metadata, "title", NULL, 0));
535 }
536
537 // Ensure MP3 files with large image/video based ID3 tags demux okay.  FFmpeg
538 // will hand us a video stream to the data which will likely be in a format we
539 // don't accept as video; e.g. PNG.
540 TEST_F(FFmpegDemuxerTest, Mp3WithVideoStreamID3TagData) {
541 #if !defined(USE_PROPRIETARY_CODECS)
542   return;
543 #endif
544   CreateDemuxer("id3_png_test.mp3");
545   InitializeDemuxer();
546
547   // Ensure the expected streams are present.
548   EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO));
549   EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO));
550 }
551
552 // Ensure a video with an unsupported audio track still results in the video
553 // stream being demuxed.
554 TEST_F(FFmpegDemuxerTest, UnsupportedAudioSupportedVideoDemux) {
555   CreateDemuxer("speex_audio_vorbis_video.ogv");
556   InitializeDemuxer();
557
558   // Ensure the expected streams are present.
559   EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::VIDEO));
560   EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::AUDIO));
561 }
562
563 // Ensure a video with an unsupported video track still results in the audio
564 // stream being demuxed.
565 TEST_F(FFmpegDemuxerTest, UnsupportedVideoSupportedAudioDemux) {
566   CreateDemuxer("vorbis_audio_wmv_video.mkv");
567   InitializeDemuxer();
568
569   // Ensure the expected streams are present.
570   EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO));
571   EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO));
572 }
573
574 // FFmpeg returns null data pointers when samples have zero size, leading to
575 // mistakenly creating end of stream buffers http://crbug.com/169133
576 TEST_F(FFmpegDemuxerTest, MP4_ZeroStszEntry) {
577 #if !defined(USE_PROPRIETARY_CODECS)
578   return;
579 #endif
580   CreateDemuxer("bear-1280x720-zero-stsz-entry.mp4");
581   InitializeDemuxer();
582   ReadUntilEndOfStream();
583 }
584
585 }  // namespace media