| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <algorithm> | 5 #include <algorithm> |
| 6 #include <deque> | 6 #include <deque> |
| 7 #include <string> | 7 #include <string> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/file_path.h" | 10 #include "base/file_path.h" |
| 11 #include "base/file_util.h" | 11 #include "base/file_util.h" |
| 12 #include "base/path_service.h" | 12 #include "base/path_service.h" |
| 13 #include "base/threading/thread.h" | 13 #include "base/threading/thread.h" |
| 14 #include "media/base/mock_callback.h" | |
| 15 #include "media/base/mock_demuxer_host.h" | 14 #include "media/base/mock_demuxer_host.h" |
| 15 #include "media/base/test_helpers.h" |
| 16 #include "media/ffmpeg/ffmpeg_common.h" | 16 #include "media/ffmpeg/ffmpeg_common.h" |
| 17 #include "media/filters/ffmpeg_demuxer.h" | 17 #include "media/filters/ffmpeg_demuxer.h" |
| 18 #include "media/filters/file_data_source.h" | 18 #include "media/filters/file_data_source.h" |
| 19 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
| 20 | 20 |
| 21 using ::testing::AnyNumber; | 21 using ::testing::AnyNumber; |
| 22 using ::testing::DoAll; | 22 using ::testing::DoAll; |
| 23 using ::testing::InSequence; | 23 using ::testing::InSequence; |
| 24 using ::testing::Invoke; | 24 using ::testing::Invoke; |
| 25 using ::testing::Return; | 25 using ::testing::Return; |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 80 | 80 |
| 81 CreateDataSource(name); | 81 CreateDataSource(name); |
| 82 demuxer_ = new FFmpegDemuxer(message_loop_.message_loop_proxy(), | 82 demuxer_ = new FFmpegDemuxer(message_loop_.message_loop_proxy(), |
| 83 data_source_); | 83 data_source_); |
| 84 } | 84 } |
| 85 | 85 |
| 86 MOCK_METHOD1(CheckPoint, void(int v)); | 86 MOCK_METHOD1(CheckPoint, void(int v)); |
| 87 | 87 |
| 88 void InitializeDemuxer() { | 88 void InitializeDemuxer() { |
| 89 EXPECT_CALL(host_, SetDuration(_)); | 89 EXPECT_CALL(host_, SetDuration(_)); |
| 90 demuxer_->Initialize(&host_, NewStatusCB(PIPELINE_OK)); | 90 WaitableMessageLoopEvent event; |
| 91 message_loop_.Run(); | 91 demuxer_->Initialize(&host_, event.GetPipelineStatusCB()); |
| 92 event.RunAndWaitForStatus(PIPELINE_OK); |
| 92 } | 93 } |
| 93 | 94 |
| 94 MOCK_METHOD2(OnReadDoneCalled, void(int, int64)); | 95 MOCK_METHOD2(OnReadDoneCalled, void(int, int64)); |
| 95 | 96 |
| 96 // Verifies that |buffer| has a specific |size| and |timestamp|. | 97 // Verifies that |buffer| has a specific |size| and |timestamp|. |
| 97 // |location| simply indicates where the call to this function was made. | 98 // |location| simply indicates where the call to this function was made. |
| 98 // This makes it easier to track down where test failures occur. | 99 // This makes it easier to track down where test failures occur. |
| 99 void OnReadDone(const tracked_objects::Location& location, | 100 void OnReadDone(const tracked_objects::Location& location, |
| 100 int size, int64 timestampInMicroseconds, | 101 int size, int64 timestampInMicroseconds, |
| 101 DemuxerStream::Status status, | 102 DemuxerStream::Status status, |
| (...skipping 13 matching lines...) Expand all Loading... |
| 115 message_loop_.PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure()); | 116 message_loop_.PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure()); |
| 116 } | 117 } |
| 117 | 118 |
| 118 DemuxerStream::ReadCB NewReadCB(const tracked_objects::Location& location, | 119 DemuxerStream::ReadCB NewReadCB(const tracked_objects::Location& location, |
| 119 int size, int64 timestampInMicroseconds) { | 120 int size, int64 timestampInMicroseconds) { |
| 120 EXPECT_CALL(*this, OnReadDoneCalled(size, timestampInMicroseconds)); | 121 EXPECT_CALL(*this, OnReadDoneCalled(size, timestampInMicroseconds)); |
| 121 return base::Bind(&FFmpegDemuxerTest::OnReadDone, base::Unretained(this), | 122 return base::Bind(&FFmpegDemuxerTest::OnReadDone, base::Unretained(this), |
| 122 location, size, timestampInMicroseconds); | 123 location, size, timestampInMicroseconds); |
| 123 } | 124 } |
| 124 | 125 |
| 125 PipelineStatusCB NewStatusCB(PipelineStatus expected) { | |
| 126 return base::Bind(&FFmpegDemuxerTest::OnStatusDone, | |
| 127 base::Unretained(this), expected); | |
| 128 } | |
| 129 | |
| 130 void OnStatusDone(PipelineStatus expected, PipelineStatus status) { | |
| 131 EXPECT_EQ(expected, status); | |
| 132 | |
| 133 DCHECK_EQ(&message_loop_, MessageLoop::current()); | |
| 134 message_loop_.PostTask(FROM_HERE, MessageLoop::QuitWhenIdleClosure()); | |
| 135 } | |
| 136 | |
| 137 // Accessor to demuxer internals. | 126 // Accessor to demuxer internals. |
| 138 void set_duration_known(bool duration_known) { | 127 void set_duration_known(bool duration_known) { |
| 139 demuxer_->duration_known_ = duration_known; | 128 demuxer_->duration_known_ = duration_known; |
| 140 } | 129 } |
| 141 | 130 |
| 142 bool IsStreamStopped(DemuxerStream::Type type) { | 131 bool IsStreamStopped(DemuxerStream::Type type) { |
| 143 DemuxerStream* stream = demuxer_->GetStream(type); | 132 DemuxerStream* stream = demuxer_->GetStream(type); |
| 144 CHECK(stream); | 133 CHECK(stream); |
| 145 return static_cast<FFmpegDemuxerStream*>(stream)->stopped_; | 134 return static_cast<FFmpegDemuxerStream*>(stream)->stopped_; |
| 146 } | 135 } |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 185 data_source_ = new FileDataSource(); | 174 data_source_ = new FileDataSource(); |
| 186 EXPECT_TRUE(data_source_->Initialize(file_path)); | 175 EXPECT_TRUE(data_source_->Initialize(file_path)); |
| 187 } | 176 } |
| 188 | 177 |
| 189 DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest); | 178 DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest); |
| 190 }; | 179 }; |
| 191 | 180 |
| 192 TEST_F(FFmpegDemuxerTest, Initialize_OpenFails) { | 181 TEST_F(FFmpegDemuxerTest, Initialize_OpenFails) { |
| 193 // Simulate avformat_open_input() failing. | 182 // Simulate avformat_open_input() failing. |
| 194 CreateDemuxer("ten_byte_file"); | 183 CreateDemuxer("ten_byte_file"); |
| 195 demuxer_->Initialize(&host_, NewStatusCB(DEMUXER_ERROR_COULD_NOT_OPEN)); | 184 WaitableMessageLoopEvent event; |
| 196 message_loop_.Run(); | 185 demuxer_->Initialize(&host_, event.GetPipelineStatusCB()); |
| 186 event.RunAndWaitForStatus(DEMUXER_ERROR_COULD_NOT_OPEN); |
| 197 } | 187 } |
| 198 | 188 |
| 199 // TODO(acolwell): Uncomment this test when we discover a file that passes | 189 // TODO(acolwell): Uncomment this test when we discover a file that passes |
| 200 // avformat_open_input(), but has avformat_find_stream_info() fail. | 190 // avformat_open_input(), but has avformat_find_stream_info() fail. |
| 201 // | 191 // |
| 202 //TEST_F(FFmpegDemuxerTest, Initialize_ParseFails) { | 192 //TEST_F(FFmpegDemuxerTest, Initialize_ParseFails) { |
| 203 // ("find_stream_info_fail.webm"); | 193 // ("find_stream_info_fail.webm"); |
| 204 // demuxer_->Initialize( | 194 // demuxer_->Initialize( |
| 205 // &host_, NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_PARSE)); | 195 // &host_, NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_PARSE)); |
| 206 // message_loop_.RunUntilIdle(); | 196 // message_loop_.RunUntilIdle(); |
| 207 //} | 197 //} |
| 208 | 198 |
| 209 TEST_F(FFmpegDemuxerTest, Initialize_NoStreams) { | 199 TEST_F(FFmpegDemuxerTest, Initialize_NoStreams) { |
| 210 // Open a file with no streams whatsoever. | 200 // Open a file with no streams whatsoever. |
| 211 CreateDemuxer("no_streams.webm"); | 201 CreateDemuxer("no_streams.webm"); |
| 212 demuxer_->Initialize(&host_, NewStatusCB(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); | 202 WaitableMessageLoopEvent event; |
| 213 message_loop_.Run(); | 203 demuxer_->Initialize(&host_, event.GetPipelineStatusCB()); |
| 204 event.RunAndWaitForStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); |
| 214 } | 205 } |
| 215 | 206 |
| 216 TEST_F(FFmpegDemuxerTest, Initialize_NoAudioVideo) { | 207 TEST_F(FFmpegDemuxerTest, Initialize_NoAudioVideo) { |
| 217 // Open a file containing streams but none of which are audio/video streams. | 208 // Open a file containing streams but none of which are audio/video streams. |
| 218 CreateDemuxer("no_audio_video.webm"); | 209 CreateDemuxer("no_audio_video.webm"); |
| 219 demuxer_->Initialize(&host_, NewStatusCB(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); | 210 WaitableMessageLoopEvent event; |
| 220 message_loop_.Run(); | 211 demuxer_->Initialize(&host_, event.GetPipelineStatusCB()); |
| 212 event.RunAndWaitForStatus(DEMUXER_ERROR_NO_SUPPORTED_STREAMS); |
| 221 } | 213 } |
| 222 | 214 |
| 223 TEST_F(FFmpegDemuxerTest, Initialize_Successful) { | 215 TEST_F(FFmpegDemuxerTest, Initialize_Successful) { |
| 224 CreateDemuxer("bear-320x240.webm"); | 216 CreateDemuxer("bear-320x240.webm"); |
| 225 InitializeDemuxer(); | 217 InitializeDemuxer(); |
| 226 | 218 |
| 227 // Video stream should be present. | 219 // Video stream should be present. |
| 228 scoped_refptr<DemuxerStream> stream = | 220 scoped_refptr<DemuxerStream> stream = |
| 229 demuxer_->GetStream(DemuxerStream::VIDEO); | 221 demuxer_->GetStream(DemuxerStream::VIDEO); |
| 230 ASSERT_TRUE(stream); | 222 ASSERT_TRUE(stream); |
| (...skipping 142 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 373 scoped_refptr<DemuxerStream> audio = | 365 scoped_refptr<DemuxerStream> audio = |
| 374 demuxer_->GetStream(DemuxerStream::AUDIO); | 366 demuxer_->GetStream(DemuxerStream::AUDIO); |
| 375 ASSERT_TRUE(video); | 367 ASSERT_TRUE(video); |
| 376 ASSERT_TRUE(audio); | 368 ASSERT_TRUE(audio); |
| 377 | 369 |
| 378 // Read a video packet and release it. | 370 // Read a video packet and release it. |
| 379 video->Read(NewReadCB(FROM_HERE, 22084, 0)); | 371 video->Read(NewReadCB(FROM_HERE, 22084, 0)); |
| 380 message_loop_.Run(); | 372 message_loop_.Run(); |
| 381 | 373 |
| 382 // Issue a simple forward seek, which should discard queued packets. | 374 // Issue a simple forward seek, which should discard queued packets. |
| 375 WaitableMessageLoopEvent event; |
| 383 demuxer_->Seek(base::TimeDelta::FromMicroseconds(1000000), | 376 demuxer_->Seek(base::TimeDelta::FromMicroseconds(1000000), |
| 384 NewStatusCB(PIPELINE_OK)); | 377 event.GetPipelineStatusCB()); |
| 385 message_loop_.Run(); | 378 event.RunAndWaitForStatus(PIPELINE_OK); |
| 386 | 379 |
| 387 // Audio read #1. | 380 // Audio read #1. |
| 388 audio->Read(NewReadCB(FROM_HERE, 145, 803000)); | 381 audio->Read(NewReadCB(FROM_HERE, 145, 803000)); |
| 389 message_loop_.Run(); | 382 message_loop_.Run(); |
| 390 | 383 |
| 391 // Audio read #2. | 384 // Audio read #2. |
| 392 audio->Read(NewReadCB(FROM_HERE, 148, 826000)); | 385 audio->Read(NewReadCB(FROM_HERE, 148, 826000)); |
| 393 message_loop_.Run(); | 386 message_loop_.Run(); |
| 394 | 387 |
| 395 // Video read #1. | 388 // Video read #1. |
| (...skipping 150 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 546 scoped_refptr<DemuxerStream> audio = | 539 scoped_refptr<DemuxerStream> audio = |
| 547 demuxer_->GetStream(DemuxerStream::AUDIO); | 540 demuxer_->GetStream(DemuxerStream::AUDIO); |
| 548 ASSERT_TRUE(video); | 541 ASSERT_TRUE(video); |
| 549 ASSERT_TRUE(audio); | 542 ASSERT_TRUE(audio); |
| 550 | 543 |
| 551 // Read a video packet and release it. | 544 // Read a video packet and release it. |
| 552 video->Read(NewReadCB(FROM_HERE, 22084, 0)); | 545 video->Read(NewReadCB(FROM_HERE, 22084, 0)); |
| 553 message_loop_.Run(); | 546 message_loop_.Run(); |
| 554 | 547 |
| 555 // Issue a simple forward seek, which should discard queued packets. | 548 // Issue a simple forward seek, which should discard queued packets. |
| 549 WaitableMessageLoopEvent event; |
| 556 demuxer_->Seek(base::TimeDelta::FromMicroseconds(2500000), | 550 demuxer_->Seek(base::TimeDelta::FromMicroseconds(2500000), |
| 557 NewStatusCB(PIPELINE_OK)); | 551 event.GetPipelineStatusCB()); |
| 558 message_loop_.Run(); | 552 event.RunAndWaitForStatus(PIPELINE_OK); |
| 559 | 553 |
| 560 // Audio read #1. | 554 // Audio read #1. |
| 561 audio->Read(NewReadCB(FROM_HERE, 40, 2403000)); | 555 audio->Read(NewReadCB(FROM_HERE, 40, 2403000)); |
| 562 message_loop_.Run(); | 556 message_loop_.Run(); |
| 563 | 557 |
| 564 // Audio read #2. | 558 // Audio read #2. |
| 565 audio->Read(NewReadCB(FROM_HERE, 42, 2406000)); | 559 audio->Read(NewReadCB(FROM_HERE, 42, 2406000)); |
| 566 message_loop_.Run(); | 560 message_loop_.Run(); |
| 567 | 561 |
| 568 // Video read #1. | 562 // Video read #1. |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 616 TEST_F(FFmpegDemuxerTest, UnsupportedVideoSupportedAudioDemux) { | 610 TEST_F(FFmpegDemuxerTest, UnsupportedVideoSupportedAudioDemux) { |
| 617 CreateDemuxer("vorbis_audio_wmv_video.mkv"); | 611 CreateDemuxer("vorbis_audio_wmv_video.mkv"); |
| 618 InitializeDemuxer(); | 612 InitializeDemuxer(); |
| 619 | 613 |
| 620 // Ensure the expected streams are present. | 614 // Ensure the expected streams are present. |
| 621 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO)); | 615 EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::VIDEO)); |
| 622 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO)); | 616 EXPECT_TRUE(demuxer_->GetStream(DemuxerStream::AUDIO)); |
| 623 } | 617 } |
| 624 | 618 |
| 625 } // namespace media | 619 } // namespace media |
| OLD | NEW |