| 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 <deque> | 5 #include <deque> |
| 6 | 6 |
| 7 #include "base/file_path.h" | 7 #include "base/file_path.h" |
| 8 #include "base/file_util.h" |
| 8 #include "base/path_service.h" | 9 #include "base/path_service.h" |
| 9 #include "base/threading/thread.h" | 10 #include "base/threading/thread.h" |
| 10 #include "media/base/filters.h" | 11 #include "media/base/filters.h" |
| 11 #include "media/base/mock_callback.h" | 12 #include "media/base/mock_callback.h" |
| 12 #include "media/base/mock_demuxer_host.h" | 13 #include "media/base/mock_demuxer_host.h" |
| 13 #include "media/base/mock_filters.h" | 14 #include "media/base/mock_filters.h" |
| 14 #include "media/base/mock_reader.h" | 15 #include "media/base/mock_reader.h" |
| 15 #include "media/ffmpeg/ffmpeg_common.h" | 16 #include "media/ffmpeg/ffmpeg_common.h" |
| 16 #include "media/filters/ffmpeg_demuxer.h" | 17 #include "media/filters/ffmpeg_demuxer.h" |
| 17 #include "media/filters/file_data_source.h" | 18 #include "media/filters/file_data_source.h" |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 EXPECT_CALL(host_, SetTotalBytes(_)).Times(AnyNumber()); | 66 EXPECT_CALL(host_, SetTotalBytes(_)).Times(AnyNumber()); |
| 66 EXPECT_CALL(host_, SetBufferedBytes(_)).Times(AnyNumber()); | 67 EXPECT_CALL(host_, SetBufferedBytes(_)).Times(AnyNumber()); |
| 67 EXPECT_CALL(host_, SetCurrentReadPosition(_)) | 68 EXPECT_CALL(host_, SetCurrentReadPosition(_)) |
| 68 .WillRepeatedly(SaveArg<0>(¤t_read_position_)); | 69 .WillRepeatedly(SaveArg<0>(¤t_read_position_)); |
| 69 | 70 |
| 70 CreateDataSource(name, disable_file_size); | 71 CreateDataSource(name, disable_file_size); |
| 71 | 72 |
| 72 // Create an FFmpegDemuxer with local data source. | 73 // Create an FFmpegDemuxer with local data source. |
| 73 demuxer_ = new FFmpegDemuxer(&message_loop_, data_source_, true); | 74 demuxer_ = new FFmpegDemuxer(&message_loop_, data_source_, true); |
| 74 demuxer_->disable_first_seek_hack_for_testing(); | 75 demuxer_->disable_first_seek_hack_for_testing(); |
| 75 | |
| 76 // Inject a filter host and message loop and prepare a data source. | |
| 77 demuxer_->set_host(&host_); | |
| 78 } | 76 } |
| 79 | 77 |
| 80 MOCK_METHOD1(CheckPoint, void(int v)); | 78 MOCK_METHOD1(CheckPoint, void(int v)); |
| 81 | 79 |
| 82 void InitializeDemuxer() { | 80 void InitializeDemuxer() { |
| 83 EXPECT_CALL(host_, SetDuration(_)); | 81 EXPECT_CALL(host_, SetDuration(_)); |
| 84 demuxer_->Initialize(NewExpectedStatusCB(PIPELINE_OK)); | 82 demuxer_->Initialize(&host_, NewExpectedStatusCB(PIPELINE_OK)); |
| 85 message_loop_.RunAllPending(); | 83 message_loop_.RunAllPending(); |
| 86 } | 84 } |
| 87 | 85 |
| 88 // Verifies that |buffer| has a specific |size| and |timestamp|. | 86 // Verifies that |buffer| has a specific |size| and |timestamp|. |
| 89 // |location| simply indicates where the call to this function was made. | 87 // |location| simply indicates where the call to this function was made. |
| 90 // This makes it easier to track down where test failures occur. | 88 // This makes it easier to track down where test failures occur. |
| 91 void ValidateBuffer(const tracked_objects::Location& location, | 89 void ValidateBuffer(const tracked_objects::Location& location, |
| 92 const scoped_refptr<Buffer>& buffer, | 90 const scoped_refptr<Buffer>& buffer, |
| 93 int size, int64 timestampInMicroseconds) { | 91 int size, int64 timestampInMicroseconds) { |
| 94 std::string location_str; | 92 std::string location_str; |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 142 EXPECT_EQ(PIPELINE_OK, data_source_->Initialize(file_path.MaybeAsASCII())); | 140 EXPECT_EQ(PIPELINE_OK, data_source_->Initialize(file_path.MaybeAsASCII())); |
| 143 } | 141 } |
| 144 | 142 |
| 145 DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest); | 143 DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest); |
| 146 }; | 144 }; |
| 147 | 145 |
| 148 TEST_F(FFmpegDemuxerTest, Initialize_OpenFails) { | 146 TEST_F(FFmpegDemuxerTest, Initialize_OpenFails) { |
| 149 // Simulate avformat_open_input() failing. | 147 // Simulate avformat_open_input() failing. |
| 150 CreateDemuxer("ten_byte_file"), | 148 CreateDemuxer("ten_byte_file"), |
| 151 EXPECT_CALL(host_, SetCurrentReadPosition(_)); | 149 EXPECT_CALL(host_, SetCurrentReadPosition(_)); |
| 152 demuxer_->Initialize(NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_OPEN)); | 150 demuxer_->Initialize( |
| 151 &host_, NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_OPEN)); |
| 153 | 152 |
| 154 message_loop_.RunAllPending(); | 153 message_loop_.RunAllPending(); |
| 155 } | 154 } |
| 156 | 155 |
| 157 // TODO(acolwell): Uncomment this test when we discover a file that passes | 156 // TODO(acolwell): Uncomment this test when we discover a file that passes |
| 158 // avformat_open_input(), but has avformat_find_stream_info() fail. | 157 // avformat_open_input(), but has avformat_find_stream_info() fail. |
| 159 // | 158 // |
| 160 //TEST_F(FFmpegDemuxerTest, Initialize_ParseFails) { | 159 //TEST_F(FFmpegDemuxerTest, Initialize_ParseFails) { |
| 161 // CreateDemuxer("find_stream_info_fail.webm"); | 160 // CreateDemuxer("find_stream_info_fail.webm"); |
| 162 // demuxer_->Initialize( | 161 // demuxer_->Initialize( |
| 163 // NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_PARSE)); | 162 // &host_, NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_PARSE)); |
| 164 // message_loop_.RunAllPending(); | 163 // message_loop_.RunAllPending(); |
| 165 //} | 164 //} |
| 166 | 165 |
| 167 TEST_F(FFmpegDemuxerTest, Initialize_NoStreams) { | 166 TEST_F(FFmpegDemuxerTest, Initialize_NoStreams) { |
| 168 // Open a file with no streams whatsoever. | 167 // Open a file with no streams whatsoever. |
| 169 CreateDemuxer("no_streams.webm"); | 168 CreateDemuxer("no_streams.webm"); |
| 170 EXPECT_CALL(host_, SetCurrentReadPosition(_)); | 169 EXPECT_CALL(host_, SetCurrentReadPosition(_)); |
| 171 demuxer_->Initialize( | 170 demuxer_->Initialize( |
| 172 NewExpectedStatusCB(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); | 171 &host_, NewExpectedStatusCB(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); |
| 173 message_loop_.RunAllPending(); | 172 message_loop_.RunAllPending(); |
| 174 } | 173 } |
| 175 | 174 |
| 176 TEST_F(FFmpegDemuxerTest, Initialize_NoAudioVideo) { | 175 TEST_F(FFmpegDemuxerTest, Initialize_NoAudioVideo) { |
| 177 // Open a file containing streams but none of which are audio/video streams. | 176 // Open a file containing streams but none of which are audio/video streams. |
| 178 CreateDemuxer("no_audio_video.webm"); | 177 CreateDemuxer("no_audio_video.webm"); |
| 179 demuxer_->Initialize( | 178 demuxer_->Initialize( |
| 180 NewExpectedStatusCB(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); | 179 &host_, NewExpectedStatusCB(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); |
| 181 message_loop_.RunAllPending(); | 180 message_loop_.RunAllPending(); |
| 182 } | 181 } |
| 183 | 182 |
| 184 TEST_F(FFmpegDemuxerTest, Initialize_Successful) { | 183 TEST_F(FFmpegDemuxerTest, Initialize_Successful) { |
| 185 CreateDemuxer("bear-320x240.webm"); | 184 CreateDemuxer("bear-320x240.webm"); |
| 186 InitializeDemuxer(); | 185 InitializeDemuxer(); |
| 187 | 186 |
| 188 // Video stream should be present. | 187 // Video stream should be present. |
| 189 scoped_refptr<DemuxerStream> stream = | 188 scoped_refptr<DemuxerStream> stream = |
| 190 demuxer_->GetStream(DemuxerStream::VIDEO); | 189 demuxer_->GetStream(DemuxerStream::VIDEO); |
| (...skipping 360 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 551 ValidateBuffer(FROM_HERE, reader->buffer(), 22084, 0); | 550 ValidateBuffer(FROM_HERE, reader->buffer(), 22084, 0); |
| 552 | 551 |
| 553 // Attempt a read from the audio stream: it should immediately return end of | 552 // Attempt a read from the audio stream: it should immediately return end of |
| 554 // stream without requiring the message loop to read data. | 553 // stream without requiring the message loop to read data. |
| 555 reader->Reset(); | 554 reader->Reset(); |
| 556 reader->Read(audio); | 555 reader->Read(audio); |
| 557 ASSERT_TRUE(reader->called()); | 556 ASSERT_TRUE(reader->called()); |
| 558 EXPECT_TRUE(reader->buffer()->IsEndOfStream()); | 557 EXPECT_TRUE(reader->buffer()->IsEndOfStream()); |
| 559 } | 558 } |
| 560 | 559 |
| 561 class MockFFmpegDemuxer : public FFmpegDemuxer { | 560 TEST_F(FFmpegDemuxerTest, ProtocolRead) { |
| 562 public: | 561 CreateDemuxer("bear-320x240.webm"); |
| 563 MockFFmpegDemuxer(MessageLoop* message_loop, | 562 InitializeDemuxer(); |
| 564 const scoped_refptr<DataSource>& data_source) | |
| 565 : FFmpegDemuxer(message_loop, data_source, true) { | |
| 566 } | |
| 567 virtual ~MockFFmpegDemuxer() {} | |
| 568 | 563 |
| 569 MOCK_METHOD0(WaitForRead, int()); | 564 // Set read head to zero as Initialize() will have parsed a bit of the file. |
| 570 MOCK_METHOD1(SignalReadCompleted, void(int size)); | 565 int64 position = 0; |
| 566 EXPECT_TRUE(demuxer_->SetPosition(0)); |
| 567 EXPECT_TRUE(demuxer_->GetPosition(&position)); |
| 568 EXPECT_EQ(0, position); |
| 571 | 569 |
| 572 private: | 570 // Read 32 bytes from offset zero and verify position. |
| 573 DISALLOW_COPY_AND_ASSIGN(MockFFmpegDemuxer); | 571 uint8 buffer[32]; |
| 574 }; | 572 EXPECT_EQ(32u, demuxer_->Read(32, buffer)); |
| 573 EXPECT_EQ(32, current_read_position_); |
| 574 EXPECT_TRUE(demuxer_->GetPosition(&position)); |
| 575 EXPECT_EQ(32, position); |
| 575 | 576 |
| 576 // A gmock helper method to execute the callback and deletes it. | 577 // Read an additional 32 bytes and verify position. |
| 577 void RunCallback(int size, const DataSource::ReadCB& callback) { | 578 EXPECT_EQ(32u, demuxer_->Read(32, buffer)); |
| 578 DCHECK(!callback.is_null()); | 579 EXPECT_EQ(64, current_read_position_); |
| 579 callback.Run(size); | 580 EXPECT_TRUE(demuxer_->GetPosition(&position)); |
| 580 } | 581 EXPECT_EQ(64, position); |
| 581 | 582 |
| 582 TEST_F(FFmpegDemuxerTest, ProtocolRead) { | 583 // Seek to end and read until EOF. |
| 583 scoped_refptr<StrictMock<MockDataSource> > data_source = | 584 int64 size = 0; |
| 584 new StrictMock<MockDataSource>(); | 585 EXPECT_TRUE(demuxer_->GetSize(&size)); |
| 586 EXPECT_TRUE(demuxer_->SetPosition(size - 48)); |
| 587 EXPECT_EQ(32u, demuxer_->Read(32, buffer)); |
| 588 EXPECT_EQ(size - 16, current_read_position_); |
| 589 EXPECT_TRUE(demuxer_->GetPosition(&position)); |
| 590 EXPECT_EQ(size - 16, position); |
| 585 | 591 |
| 586 EXPECT_CALL(*data_source, Stop(_)) | 592 EXPECT_EQ(16u, demuxer_->Read(32, buffer)); |
| 587 .WillRepeatedly(Invoke(&RunStopFilterCallback)); | 593 EXPECT_EQ(size, current_read_position_); |
| 594 EXPECT_TRUE(demuxer_->GetPosition(&position)); |
| 595 EXPECT_EQ(size, position); |
| 588 | 596 |
| 589 // Creates a demuxer. | 597 EXPECT_EQ(0u, demuxer_->Read(32, buffer)); |
| 590 scoped_refptr<MockFFmpegDemuxer> demuxer( | 598 EXPECT_EQ(size, current_read_position_); |
| 591 new MockFFmpegDemuxer(&message_loop_, data_source)); | 599 EXPECT_TRUE(demuxer_->GetPosition(&position)); |
| 592 demuxer->set_host(&host_); | 600 EXPECT_EQ(size, position); |
| 593 | 601 |
| 594 uint8 kBuffer[1]; | 602 demuxer_->Stop(NewExpectedClosure()); |
| 595 InSequence s; | |
| 596 // Actions taken in the first read. | |
| 597 EXPECT_CALL(*data_source, GetSize(_)) | |
| 598 .WillOnce(DoAll(SetArgPointee<0>(1024), Return(true))); | |
| 599 EXPECT_CALL(*data_source, Read(0, 512, kBuffer, _)) | |
| 600 .WillOnce(WithArgs<1, 3>(Invoke(&RunCallback))); | |
| 601 EXPECT_CALL(*demuxer, SignalReadCompleted(512)); | |
| 602 EXPECT_CALL(*demuxer, WaitForRead()) | |
| 603 .WillOnce(Return(512)); | |
| 604 EXPECT_CALL(host_, SetCurrentReadPosition(512)); | |
| 605 | |
| 606 // Second read. | |
| 607 EXPECT_CALL(*data_source, GetSize(_)) | |
| 608 .WillOnce(DoAll(SetArgPointee<0>(1024), Return(true))); | |
| 609 EXPECT_CALL(*data_source, Read(512, 512, kBuffer, _)) | |
| 610 .WillOnce(WithArgs<1, 3>(Invoke(&RunCallback))); | |
| 611 EXPECT_CALL(*demuxer, SignalReadCompleted(512)); | |
| 612 EXPECT_CALL(*demuxer, WaitForRead()) | |
| 613 .WillOnce(Return(512)); | |
| 614 EXPECT_CALL(host_, SetCurrentReadPosition(1024)); | |
| 615 | |
| 616 // Third read will fail because it exceeds the file size. | |
| 617 EXPECT_CALL(*data_source, GetSize(_)) | |
| 618 .WillOnce(DoAll(SetArgPointee<0>(1024), Return(true))); | |
| 619 | |
| 620 // First read. | |
| 621 EXPECT_EQ(512u, demuxer->Read(512, kBuffer)); | |
| 622 int64 position; | |
| 623 EXPECT_TRUE(demuxer->GetPosition(&position)); | |
| 624 EXPECT_EQ(512, position); | |
| 625 | |
| 626 // Second read. | |
| 627 EXPECT_EQ(512u, demuxer->Read(512, kBuffer)); | |
| 628 EXPECT_TRUE(demuxer->GetPosition(&position)); | |
| 629 EXPECT_EQ(1024, position); | |
| 630 | |
| 631 // Third read will get an end-of-file error, which is represented as zero. | |
| 632 EXPECT_EQ(0u, demuxer->Read(512, kBuffer)); | |
| 633 | |
| 634 // This read complete signal is generated when demuxer is stopped. | |
| 635 EXPECT_CALL(*demuxer, SignalReadCompleted(DataSource::kReadError)); | |
| 636 demuxer->Stop(NewExpectedClosure()); | |
| 637 message_loop_.RunAllPending(); | 603 message_loop_.RunAllPending(); |
| 638 } | 604 } |
| 639 | 605 |
| 640 TEST_F(FFmpegDemuxerTest, GetBitrate_SetInContainer) { | 606 TEST_F(FFmpegDemuxerTest, GetBitrate_SetInContainer) { |
| 641 EXPECT_TRUE(VideoHasValidBitrate("bear.ogv", false)); | 607 EXPECT_TRUE(VideoHasValidBitrate("bear.ogv", false)); |
| 642 } | 608 } |
| 643 | 609 |
| 644 TEST_F(FFmpegDemuxerTest, GetBitrate_UnsetInContainer_KnownSize) { | 610 TEST_F(FFmpegDemuxerTest, GetBitrate_UnsetInContainer_KnownSize) { |
| 645 EXPECT_TRUE(VideoHasValidBitrate("bear-320x240.webm", false)); | 611 EXPECT_TRUE(VideoHasValidBitrate("bear-320x240.webm", false)); |
| 646 } | 612 } |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 749 message_loop_.RunAllPending(); | 715 message_loop_.RunAllPending(); |
| 750 EXPECT_TRUE(reader->called()); | 716 EXPECT_TRUE(reader->called()); |
| 751 ValidateBuffer(FROM_HERE, reader->buffer(), 1740, 2436000); | 717 ValidateBuffer(FROM_HERE, reader->buffer(), 1740, 2436000); |
| 752 | 718 |
| 753 // Manually release the last reference to the buffer and verify it was freed. | 719 // Manually release the last reference to the buffer and verify it was freed. |
| 754 reader->Reset(); | 720 reader->Reset(); |
| 755 message_loop_.RunAllPending(); | 721 message_loop_.RunAllPending(); |
| 756 } | 722 } |
| 757 | 723 |
| 758 } // namespace media | 724 } // namespace media |
| OLD | NEW |