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