OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 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" | |
8 #include "base/path_service.h" | |
7 #include "base/threading/thread.h" | 9 #include "base/threading/thread.h" |
8 #include "media/base/filters.h" | 10 #include "media/base/filters.h" |
11 #include "media/base/media.h" | |
9 #include "media/base/mock_callback.h" | 12 #include "media/base/mock_callback.h" |
10 #include "media/base/mock_ffmpeg.h" | |
11 #include "media/base/mock_filter_host.h" | 13 #include "media/base/mock_filter_host.h" |
12 #include "media/base/mock_filters.h" | 14 #include "media/base/mock_filters.h" |
13 #include "media/base/mock_reader.h" | 15 #include "media/base/mock_reader.h" |
14 #include "media/ffmpeg/ffmpeg_common.h" | 16 #include "media/ffmpeg/ffmpeg_common.h" |
15 #include "media/filters/ffmpeg_demuxer.h" | 17 #include "media/filters/ffmpeg_demuxer.h" |
18 #include "media/filters/file_data_source.h" | |
16 #include "testing/gtest/include/gtest/gtest.h" | 19 #include "testing/gtest/include/gtest/gtest.h" |
17 | 20 |
18 using ::testing::AnyNumber; | 21 using ::testing::AnyNumber; |
19 using ::testing::DoAll; | 22 using ::testing::DoAll; |
20 using ::testing::InSequence; | 23 using ::testing::InSequence; |
21 using ::testing::Invoke; | 24 using ::testing::Invoke; |
22 using ::testing::NotNull; | 25 using ::testing::NotNull; |
23 using ::testing::Return; | 26 using ::testing::Return; |
24 using ::testing::SetArgumentPointee; | 27 using ::testing::SaveArg; |
28 using ::testing::SetArgPointee; | |
25 using ::testing::StrictMock; | 29 using ::testing::StrictMock; |
26 using ::testing::WithArgs; | 30 using ::testing::WithArgs; |
27 using ::testing::_; | 31 using ::testing::_; |
28 | 32 |
29 namespace media { | 33 namespace media { |
30 | 34 |
31 // Fixture class to facilitate writing tests. Takes care of setting up the | 35 // Fixture class to facilitate writing tests. Takes care of setting up the |
32 // FFmpeg, pipeline and filter host mocks. | 36 // FFmpeg, pipeline and filter host mocks. |
33 class FFmpegDemuxerTest : public testing::Test { | 37 class FFmpegDemuxerTest : public testing::Test { |
34 protected: | 38 protected: |
35 // These constants refer to the stream ordering inside AVFormatContext. We | |
36 // simulate media with a data stream, audio stream and video stream. Having | |
37 // the data stream first forces the audio and video streams to get remapped | |
38 // from indices {1,2} to {0,1} respectively, which covers an important test | |
39 // case. | |
40 enum AVStreamIndex { | |
41 AV_STREAM_DATA, | |
42 AV_STREAM_VIDEO, | |
43 AV_STREAM_AUDIO, | |
44 AV_STREAM_MAX, | |
45 }; | |
46 | |
47 // These constants refer to the stream ordering inside an initialized | |
48 // FFmpegDemuxer based on the ordering of the AVStreamIndex constants. | |
49 enum DemuxerStreamIndex { | |
50 DS_STREAM_VIDEO, | |
51 DS_STREAM_AUDIO, | |
52 DS_STREAM_MAX, | |
53 }; | |
54 | |
55 static const int kDurations[]; | |
56 static const int kChannels; | |
57 static const int kSampleRate; | |
58 static const int kWidth; | |
59 static const int kHeight; | |
60 | |
61 static const size_t kDataSize; | |
62 static const uint8 kAudioData[]; | |
63 static const uint8 kVideoData[]; | |
64 static const uint8* kNullData; | |
65 | 39 |
66 FFmpegDemuxerTest() { | 40 FFmpegDemuxerTest() { |
41 EXPECT_TRUE(InitializeMediaLibraryForTesting()); | |
42 | |
67 // Create an FFmpegDemuxer. | 43 // Create an FFmpegDemuxer. |
68 demuxer_ = new FFmpegDemuxer(&message_loop_); | 44 demuxer_ = new FFmpegDemuxer(&message_loop_); |
69 demuxer_->disable_first_seek_hack_for_testing(); | 45 demuxer_->disable_first_seek_hack_for_testing(); |
70 | 46 |
71 // Inject a filter host and message loop and prepare a data source. | 47 // Inject a filter host and message loop and prepare a data source. |
72 demuxer_->set_host(&host_); | 48 demuxer_->set_host(&host_); |
73 data_source_ = new StrictMock<MockDataSource>(); | |
74 | 49 |
75 EXPECT_CALL(*data_source_, Stop(NotNull())) | 50 EXPECT_CALL(host_, SetTotalBytes(_)).Times(AnyNumber()); |
76 .WillRepeatedly(Invoke(&RunStopFilterCallback)); | 51 EXPECT_CALL(host_, SetBufferedBytes(_)).Times(AnyNumber()); |
77 | 52 EXPECT_CALL(host_, SetCurrentReadPosition(_)) |
78 // Initialize FFmpeg fixtures. | 53 .WillRepeatedly(SaveArg<0>(¤t_read_position_)); |
79 memset(&format_context_, 0, sizeof(format_context_)); | |
80 memset(&input_format_, 0, sizeof(input_format_)); | |
81 memset(&streams_, 0, sizeof(streams_)); | |
82 memset(&codecs_, 0, sizeof(codecs_)); | |
83 | |
84 // Initialize AVCodecContext structures. | |
85 codecs_[AV_STREAM_DATA].codec_type = AVMEDIA_TYPE_DATA; | |
86 codecs_[AV_STREAM_DATA].codec_id = CODEC_ID_NONE; | |
87 | |
88 codecs_[AV_STREAM_VIDEO].codec_type = AVMEDIA_TYPE_VIDEO; | |
89 codecs_[AV_STREAM_VIDEO].codec_id = CODEC_ID_THEORA; | |
90 codecs_[AV_STREAM_VIDEO].width = kWidth; | |
91 codecs_[AV_STREAM_VIDEO].height = kHeight; | |
92 | |
93 codecs_[AV_STREAM_AUDIO].codec_type = AVMEDIA_TYPE_AUDIO; | |
94 codecs_[AV_STREAM_AUDIO].codec_id = CODEC_ID_VORBIS; | |
95 codecs_[AV_STREAM_AUDIO].channels = kChannels; | |
96 codecs_[AV_STREAM_AUDIO].sample_rate = kSampleRate; | |
97 | |
98 input_format_.name = "foo"; | |
99 format_context_.iformat = &input_format_; | |
100 | |
101 // Initialize AVStream and AVFormatContext structures. We set the time base | |
102 // of the streams such that duration is reported in microseconds. | |
103 format_context_.nb_streams = AV_STREAM_MAX; | |
104 format_context_.streams = new AVStream*[AV_STREAM_MAX]; | |
105 for (size_t i = 0; i < AV_STREAM_MAX; ++i) { | |
106 format_context_.streams[i] = &streams_[i]; | |
107 streams_[i].codec = &codecs_[i]; | |
108 streams_[i].duration = kDurations[i]; | |
109 streams_[i].time_base.den = 1 * base::Time::kMicrosecondsPerSecond; | |
110 streams_[i].time_base.num = 1; | |
111 } | |
112 } | 54 } |
113 | 55 |
114 virtual ~FFmpegDemuxerTest() { | 56 virtual ~FFmpegDemuxerTest() { |
115 // Call Stop() to shut down internal threads. | 57 // Call Stop() to shut down internal threads. |
116 demuxer_->Stop(NewExpectedCallback()); | 58 demuxer_->Stop(NewExpectedCallback()); |
117 | 59 |
118 // Finish up any remaining tasks. | 60 // Finish up any remaining tasks. |
119 message_loop_.RunAllPending(); | 61 message_loop_.RunAllPending(); |
120 // Release the reference to the demuxer. | 62 // Release the reference to the demuxer. |
121 demuxer_ = NULL; | 63 demuxer_ = NULL; |
122 | |
123 if (format_context_.streams) { | |
124 delete[] format_context_.streams; | |
125 format_context_.streams = NULL; | |
126 format_context_.nb_streams = 0; | |
127 } | |
128 } | 64 } |
129 | 65 |
130 // Sets up MockFFmpeg to allow FFmpegDemuxer to successfully initialize. | 66 scoped_refptr<DataSource> CreateDataSource(const std::string& name) { |
131 void InitializeDemuxerMocks() { | 67 FilePath file_path; |
132 EXPECT_CALL(mock_ffmpeg_, AVOpenInputFile(_, _, NULL, 0, NULL)) | 68 EXPECT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &file_path)); |
scherkus (not reviewing)
2011/08/11 01:26:29
can we use the ReadTestData functions here?
acolwell GONE FROM CHROMIUM
2011/08/11 23:54:40
No because we don't have an in-memory DataSource i
| |
133 .WillOnce(DoAll(SetArgumentPointee<0>(&format_context_), Return(0))); | 69 |
134 EXPECT_CALL(mock_ffmpeg_, AVFindStreamInfo(&format_context_)) | 70 file_path = file_path.Append(FILE_PATH_LITERAL("media")) |
135 .WillOnce(Return(0)); | 71 .Append(FILE_PATH_LITERAL("test")) |
136 EXPECT_CALL(mock_ffmpeg_, AVCloseInputFile(&format_context_)); | 72 .Append(FILE_PATH_LITERAL("data")) |
73 .AppendASCII(name); | |
74 | |
75 scoped_refptr<FileDataSource> data_source = new FileDataSource(); | |
76 | |
77 EXPECT_EQ(PIPELINE_OK, data_source->Initialize(file_path.MaybeAsASCII())); | |
78 | |
79 return data_source.get(); | |
137 } | 80 } |
138 | 81 |
139 // Initializes both MockFFmpeg and FFmpegDemuxer. | 82 MOCK_METHOD1(CheckPoint, void(int v)); |
140 void InitializeDemuxer() { | |
141 InitializeDemuxerMocks(); | |
142 | 83 |
143 // Since we ignore data streams, the duration should be equal to the longest | 84 // Initializes FFmpegDemuxer. |
144 // supported stream's duration (audio, in this case). | 85 void InitializeDemuxer(const scoped_refptr<DataSource>& data_source) { |
145 base::TimeDelta expected_duration = | 86 EXPECT_CALL(host_, SetDuration(_)); |
146 base::TimeDelta::FromMicroseconds(kDurations[AV_STREAM_AUDIO]); | 87 demuxer_->Initialize(data_source, NewExpectedStatusCB(PIPELINE_OK)); |
147 EXPECT_CALL(host_, SetDuration(expected_duration)); | 88 message_loop_.RunAllPending(); |
89 } | |
148 | 90 |
149 demuxer_->Initialize(data_source_.get(), | 91 void ValidateBuffer(const tracked_objects::Location& location, |
scherkus (not reviewing)
2011/08/11 01:26:29
docs? what does this do exactly?
acolwell GONE FROM CHROMIUM
2011/08/11 23:54:40
Done. It just makes sure the buffer has the expect
| |
150 NewExpectedStatusCB(PIPELINE_OK)); | 92 const scoped_refptr<Buffer>& buffer, |
151 message_loop_.RunAllPending(); | 93 size_t size, int64 timestampInMicroseconds) { |
94 std::string location_str; | |
95 location.Write(true, false, &location_str); | |
96 location_str += "\n"; | |
97 SCOPED_TRACE(location_str); | |
98 EXPECT_TRUE(buffer.get() != NULL); | |
99 EXPECT_EQ(size, buffer->GetDataSize()); | |
100 EXPECT_EQ(base::TimeDelta::FromMicroseconds(timestampInMicroseconds), | |
101 buffer->GetTimestamp()); | |
152 } | 102 } |
153 | 103 |
154 // Fixture members. | 104 // Fixture members. |
155 scoped_refptr<FFmpegDemuxer> demuxer_; | 105 scoped_refptr<FFmpegDemuxer> demuxer_; |
156 scoped_refptr<StrictMock<MockDataSource> > data_source_; | |
157 StrictMock<MockFilterHost> host_; | 106 StrictMock<MockFilterHost> host_; |
158 MessageLoop message_loop_; | 107 MessageLoop message_loop_; |
159 | 108 |
160 // FFmpeg fixtures. | 109 int64 current_read_position_; |
161 AVFormatContext format_context_; | |
162 AVInputFormat input_format_; | |
163 AVCodecContext codecs_[AV_STREAM_MAX]; | |
164 AVStream streams_[AV_STREAM_MAX]; | |
165 MockFFmpeg mock_ffmpeg_; | |
166 | 110 |
167 private: | 111 private: |
168 DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest); | 112 DISALLOW_COPY_AND_ASSIGN(FFmpegDemuxerTest); |
169 }; | 113 }; |
170 | 114 |
171 // These durations are picked so that the demuxer chooses the longest supported | |
172 // stream, which would be 30 in this case for the audio stream. | |
173 const int FFmpegDemuxerTest::kDurations[AV_STREAM_MAX] = {100, 20, 30}; | |
174 const int FFmpegDemuxerTest::kChannels = 2; | |
175 const int FFmpegDemuxerTest::kSampleRate = 44100; | |
176 const int FFmpegDemuxerTest::kWidth = 1280; | |
177 const int FFmpegDemuxerTest::kHeight = 720; | |
178 | |
179 const size_t FFmpegDemuxerTest::kDataSize = 4; | |
180 const uint8 FFmpegDemuxerTest::kAudioData[kDataSize] = {0, 1, 2, 3}; | |
181 const uint8 FFmpegDemuxerTest::kVideoData[kDataSize] = {4, 5, 6, 7}; | |
182 const uint8* FFmpegDemuxerTest::kNullData = NULL; | |
183 | |
184 TEST_F(FFmpegDemuxerTest, Initialize_OpenFails) { | 115 TEST_F(FFmpegDemuxerTest, Initialize_OpenFails) { |
185 // Simulate av_open_input_file() failing. | 116 // Simulate av_open_input_file() failing. |
186 EXPECT_CALL(mock_ffmpeg_, AVOpenInputFile(_, _, NULL, 0, NULL)) | 117 EXPECT_CALL(host_, SetCurrentReadPosition(_)); |
187 .WillOnce(Return(-1)); | 118 demuxer_->Initialize(CreateDataSource("ten_byte_file"), |
119 NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_OPEN)); | |
188 | 120 |
189 demuxer_->Initialize(data_source_.get(), | |
190 NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_OPEN)); | |
191 message_loop_.RunAllPending(); | 121 message_loop_.RunAllPending(); |
192 } | 122 } |
193 | 123 |
194 TEST_F(FFmpegDemuxerTest, Initialize_ParseFails) { | 124 // TODO(acolwell): Uncomment this test when we discover a file that passes |
195 // Simulate av_find_stream_info() failing. | 125 // av_open_input_file(), but has av_find_stream_info() fail. |
196 EXPECT_CALL(mock_ffmpeg_, AVOpenInputFile(_, _, NULL, 0, NULL)) | 126 // |
197 .WillOnce(DoAll(SetArgumentPointee<0>(&format_context_), Return(0))); | 127 //TEST_F(FFmpegDemuxerTest, Initialize_ParseFails) { |
198 EXPECT_CALL(mock_ffmpeg_, AVFindStreamInfo(&format_context_)) | 128 // demuxer_->Initialize( |
199 .WillOnce(Return(AVERROR(EIO))); | 129 // CreateDataSource("find_stream_info_fail.webm"), |
200 EXPECT_CALL(mock_ffmpeg_, AVCloseInputFile(&format_context_)); | 130 // NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_PARSE)); |
201 | 131 // message_loop_.RunAllPending(); |
202 demuxer_->Initialize( | 132 //} |
203 data_source_.get(), | |
204 NewExpectedStatusCB(DEMUXER_ERROR_COULD_NOT_PARSE)); | |
205 message_loop_.RunAllPending(); | |
206 } | |
207 | 133 |
208 TEST_F(FFmpegDemuxerTest, Initialize_NoStreams) { | 134 TEST_F(FFmpegDemuxerTest, Initialize_NoStreams) { |
209 // Simulate media with no parseable streams. | 135 // Open a file with no parseable streams. |
210 { | 136 EXPECT_CALL(host_, SetCurrentReadPosition(_)); |
211 SCOPED_TRACE(""); | |
212 InitializeDemuxerMocks(); | |
213 } | |
214 format_context_.nb_streams = 0; | |
215 | |
216 demuxer_->Initialize( | 137 demuxer_->Initialize( |
217 data_source_.get(), | 138 CreateDataSource("no_streams.webm"), |
218 NewExpectedStatusCB(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); | 139 NewExpectedStatusCB(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); |
219 message_loop_.RunAllPending(); | 140 message_loop_.RunAllPending(); |
220 } | 141 } |
221 | 142 |
222 TEST_F(FFmpegDemuxerTest, Initialize_DataStreamOnly) { | 143 // TODO(acolwell): Find a subtitle only file so we can uncomment this test. |
223 // Simulate media with a data stream but no audio or video streams. | 144 // |
224 { | 145 //TEST_F(FFmpegDemuxerTest, Initialize_DataStreamOnly) { |
225 SCOPED_TRACE(""); | 146 // demuxer_->Initialize( |
226 InitializeDemuxerMocks(); | 147 // CreateDataSource("subtitles_only.mp4"),, |
227 } | 148 // NewExpectedStatusCB(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); |
228 EXPECT_EQ(format_context_.streams[0], &streams_[AV_STREAM_DATA]); | 149 // message_loop_.RunAllPending(); |
229 format_context_.nb_streams = 1; | 150 //} |
230 | |
231 demuxer_->Initialize( | |
232 data_source_.get(), | |
233 NewExpectedStatusCB(DEMUXER_ERROR_NO_SUPPORTED_STREAMS)); | |
234 message_loop_.RunAllPending(); | |
235 } | |
236 | 151 |
237 TEST_F(FFmpegDemuxerTest, Initialize_Successful) { | 152 TEST_F(FFmpegDemuxerTest, Initialize_Successful) { |
238 { | 153 InitializeDemuxer(CreateDataSource("bear-320x240.webm")); |
239 SCOPED_TRACE(""); | |
240 InitializeDemuxer(); | |
241 } | |
242 | 154 |
243 // First stream should be video and support the FFmpegDemuxerStream interface. | 155 // First stream should be video and support the FFmpegDemuxerStream interface. |
244 scoped_refptr<DemuxerStream> stream = | 156 scoped_refptr<DemuxerStream> stream = |
245 demuxer_->GetStream(DemuxerStream::VIDEO); | 157 demuxer_->GetStream(DemuxerStream::VIDEO); |
246 ASSERT_TRUE(stream); | 158 ASSERT_TRUE(stream); |
247 EXPECT_EQ(DemuxerStream::VIDEO, stream->type()); | 159 EXPECT_EQ(DemuxerStream::VIDEO, stream->type()); |
248 EXPECT_EQ(&streams_[AV_STREAM_VIDEO], stream->GetAVStream()); | 160 ASSERT_TRUE(stream->GetAVStream()); |
249 | 161 |
250 // Other stream should be audio and support the FFmpegDemuxerStream interface. | 162 // Other stream should be audio and support the FFmpegDemuxerStream interface. |
251 stream = demuxer_->GetStream(DemuxerStream::AUDIO); | 163 stream = demuxer_->GetStream(DemuxerStream::AUDIO); |
252 ASSERT_TRUE(stream); | 164 ASSERT_TRUE(stream); |
253 EXPECT_EQ(DemuxerStream::AUDIO, stream->type()); | 165 EXPECT_EQ(DemuxerStream::AUDIO, stream->type()); |
254 EXPECT_EQ(&streams_[AV_STREAM_AUDIO], stream->GetAVStream()); | 166 ASSERT_TRUE(stream->GetAVStream()); |
255 } | 167 } |
256 | 168 |
257 TEST_F(FFmpegDemuxerTest, Read_DiscardUninteresting) { | 169 TEST_F(FFmpegDemuxerTest, Read_Audio) { |
258 // We test that on a successful audio packet read, that the packet is | 170 // We test that on a successful audio packet read. |
259 // duplicated (FFmpeg memory management safety), and a copy of it ends up in | 171 InitializeDemuxer(CreateDataSource("bear-320x240.webm")); |
260 // the DemuxerStream. | |
261 { | |
262 SCOPED_TRACE(""); | |
263 InitializeDemuxer(); | |
264 } | |
265 | |
266 // Ignore all AVFreePacket() calls. We check this elsewhere. | |
267 EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber()); | |
268 | |
269 // The demuxer will read a data packet which will get immediately freed, | |
270 // followed by a read error to end the reading. | |
271 InSequence s; | |
272 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) | |
273 .WillOnce(CreatePacketNoCount(AV_STREAM_DATA, kNullData, 0)); | |
274 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) | |
275 .WillOnce(Return(AVERROR(EIO))); | |
276 | 172 |
277 // Attempt a read from the audio stream and run the message loop until done. | 173 // Attempt a read from the audio stream and run the message loop until done. |
278 scoped_refptr<DemuxerStream> audio = | 174 scoped_refptr<DemuxerStream> audio = |
279 demuxer_->GetStream(DemuxerStream::AUDIO); | 175 demuxer_->GetStream(DemuxerStream::AUDIO); |
280 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); | 176 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); |
281 reader->Read(audio); | 177 reader->Read(audio); |
282 message_loop_.RunAllPending(); | 178 message_loop_.RunAllPending(); |
179 EXPECT_TRUE(reader->called()); | |
180 ValidateBuffer(FROM_HERE, reader->buffer(), 29, 0); | |
283 | 181 |
284 EXPECT_TRUE(reader->called()); | 182 reader->Reset(); |
285 ASSERT_TRUE(reader->buffer()); | |
286 EXPECT_TRUE(reader->buffer()->IsEndOfStream()); | |
287 } | |
288 | |
289 TEST_F(FFmpegDemuxerTest, Read_Audio) { | |
290 // We test that on a successful audio packet read, that the packet is | |
291 // duplicated (FFmpeg memory management safety), and a copy of it ends up in | |
292 // the DemuxerStream. | |
293 { | |
294 SCOPED_TRACE(""); | |
295 InitializeDemuxer(); | |
296 } | |
297 | |
298 // Ignore all AVFreePacket() calls. We check this via valgrind. | |
299 EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber()); | |
300 | |
301 // The demuxer will read a data packet which will get immediately freed, | |
302 // followed by reading an audio packet... | |
303 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) | |
304 .WillOnce(CreatePacketNoCount(AV_STREAM_AUDIO, kAudioData, kDataSize)); | |
305 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) | |
306 .WillOnce(Return(0)); | |
307 | |
308 // Attempt a read from the audio stream and run the message loop until done. | |
309 scoped_refptr<DemuxerStream> audio = | |
310 demuxer_->GetStream(DemuxerStream::AUDIO); | |
311 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); | |
312 reader->Read(audio); | 183 reader->Read(audio); |
313 message_loop_.RunAllPending(); | 184 message_loop_.RunAllPending(); |
314 | |
315 EXPECT_TRUE(reader->called()); | 185 EXPECT_TRUE(reader->called()); |
316 ASSERT_TRUE(reader->buffer()); | 186 ValidateBuffer(FROM_HERE, reader->buffer(), 27, 3000); |
317 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); | |
318 EXPECT_EQ(0, memcmp(kAudioData, reader->buffer()->GetData(), | |
319 reader->buffer()->GetDataSize())); | |
320 } | 187 } |
321 | 188 |
322 TEST_F(FFmpegDemuxerTest, Read_Video) { | 189 TEST_F(FFmpegDemuxerTest, Read_Video) { |
323 // We test that on a successful video packet read, that the packet is | 190 // We test that on a successful video packet read. |
324 // duplicated (FFmpeg memory management safety), and a copy of it ends up in | 191 InitializeDemuxer(CreateDataSource("bear-320x240.webm")); |
325 // the DemuxerStream. | |
326 { | |
327 SCOPED_TRACE(""); | |
328 InitializeDemuxer(); | |
329 } | |
330 | |
331 // Ignore all AVFreePacket() calls. We check this via valgrind. | |
332 EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber()); | |
333 | |
334 // Simulate a successful frame read. | |
335 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) | |
336 .WillOnce(CreatePacketNoCount(AV_STREAM_VIDEO, kVideoData, kDataSize)); | |
337 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) | |
338 .WillOnce(Return(0)); | |
339 | 192 |
340 // Attempt a read from the video stream and run the message loop until done. | 193 // Attempt a read from the video stream and run the message loop until done. |
341 scoped_refptr<DemuxerStream> video = | 194 scoped_refptr<DemuxerStream> video = |
342 demuxer_->GetStream(DemuxerStream::VIDEO); | 195 demuxer_->GetStream(DemuxerStream::VIDEO); |
343 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); | 196 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); |
197 | |
344 reader->Read(video); | 198 reader->Read(video); |
345 message_loop_.RunAllPending(); | 199 message_loop_.RunAllPending(); |
200 EXPECT_TRUE(reader->called()); | |
201 ValidateBuffer(FROM_HERE, reader->buffer(), 22084, 0); | |
346 | 202 |
203 reader->Reset(); | |
204 reader->Read(video); | |
205 message_loop_.RunAllPending(); | |
347 EXPECT_TRUE(reader->called()); | 206 EXPECT_TRUE(reader->called()); |
348 ASSERT_TRUE(reader->buffer()); | 207 ValidateBuffer(FROM_HERE, reader->buffer(), 1057, 33000); |
349 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); | |
350 EXPECT_EQ(0, memcmp(kVideoData, reader->buffer()->GetData(), | |
351 reader->buffer()->GetDataSize())); | |
352 } | 208 } |
353 | 209 |
354 TEST_F(FFmpegDemuxerTest, Read_VideoNonZeroStart) { | 210 TEST_F(FFmpegDemuxerTest, Read_VideoNonZeroStart) { |
355 // Test the start time is the first timestamp of the video and audio stream. | 211 // Test the start time is the first timestamp of the video and audio stream. |
356 const int64 kStartTime = 60000; | 212 InitializeDemuxer(CreateDataSource("nonzero-start-time.webm")); |
357 // Set the audio and video stream's first timestamp. | |
358 streams_[AV_STREAM_AUDIO].first_dts = kStartTime; | |
359 streams_[AV_STREAM_VIDEO].first_dts = kStartTime; | |
360 { | |
361 SCOPED_TRACE(""); | |
362 InitializeDemuxer(); | |
363 } | |
364 | |
365 // Ignore all AVFreePacket() calls. We check this via valgrind. | |
366 EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber()); | |
367 | 213 |
368 const base::TimeDelta kExpectedTimestamp = | 214 const base::TimeDelta kExpectedTimestamp = |
369 base::TimeDelta::FromMicroseconds(kStartTime); | 215 base::TimeDelta::FromMicroseconds(396000); |
370 | |
371 // Simulate a successful frame read. | |
372 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) | |
373 .WillOnce(CreatePacketTimeNoCount(AV_STREAM_VIDEO, | |
374 kVideoData, | |
375 kDataSize, | |
376 kStartTime)); | |
377 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) | |
378 .WillOnce(Return(0)); | |
379 | |
380 // Attempt a read from the video stream and run the message loop until done. | |
381 scoped_refptr<DemuxerStream> video = | |
382 demuxer_->GetStream(DemuxerStream::VIDEO); | |
383 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); | |
384 reader->Read(video); | |
385 message_loop_.RunAllPending(); | |
386 | |
387 EXPECT_TRUE(reader->called()); | |
388 ASSERT_TRUE(reader->buffer()); | |
389 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); | |
390 EXPECT_EQ(kExpectedTimestamp, reader->buffer()->GetTimestamp()); | |
391 EXPECT_EQ(0, memcmp(kVideoData, reader->buffer()->GetData(), | |
392 reader->buffer()->GetDataSize())); | |
393 | |
394 EXPECT_EQ(kExpectedTimestamp, demuxer_->GetStartTime()); | |
395 } | |
396 | |
397 TEST_F(FFmpegDemuxerTest, CheckMinStartTime) { | |
398 // Test the start time is minimum timestamp of all streams. | |
399 const int64 kAudioStartTime = 5000000; | |
400 const int64 kVideoStartTime = 5033000; | |
401 // Set the audio and video stream's first timestamp. | |
402 streams_[AV_STREAM_AUDIO].first_dts = kAudioStartTime; | |
403 streams_[AV_STREAM_VIDEO].first_dts = kVideoStartTime; | |
404 { | |
405 SCOPED_TRACE(""); | |
406 InitializeDemuxer(); | |
407 } | |
408 | |
409 // Ignore all AVFreePacket() calls. We check this via valgrind. | |
410 EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber()); | |
411 | |
412 // Expect all calls in sequence. | |
413 InSequence s; | |
414 | |
415 const base::TimeDelta kExpectedAudioTimestamp = | |
416 base::TimeDelta::FromMicroseconds(kAudioStartTime); | |
417 const base::TimeDelta kExpectedVideoTimestamp = | |
418 base::TimeDelta::FromMicroseconds(kVideoStartTime); | |
419 | |
420 // First read a video packet, then an audio packet. | |
421 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) | |
422 .WillOnce(CreatePacketTimeNoCount(AV_STREAM_AUDIO, | |
423 kAudioData, | |
424 kDataSize, | |
425 kAudioStartTime)); | |
426 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) | |
427 .WillOnce(Return(0)); | |
428 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) | |
429 .WillOnce(CreatePacketTimeNoCount(AV_STREAM_VIDEO, | |
430 kVideoData, | |
431 kDataSize, | |
432 kVideoStartTime)); | |
433 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) | |
434 .WillOnce(Return(0)); | |
435 | 216 |
436 // Attempt a read from the video stream and run the message loop until done. | 217 // Attempt a read from the video stream and run the message loop until done. |
437 scoped_refptr<DemuxerStream> video = | 218 scoped_refptr<DemuxerStream> video = |
438 demuxer_->GetStream(DemuxerStream::VIDEO); | 219 demuxer_->GetStream(DemuxerStream::VIDEO); |
439 scoped_refptr<DemuxerStream> audio = | 220 scoped_refptr<DemuxerStream> audio = |
440 demuxer_->GetStream(DemuxerStream::AUDIO); | 221 demuxer_->GetStream(DemuxerStream::AUDIO); |
441 ASSERT_TRUE(video); | 222 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); |
442 ASSERT_TRUE(audio); | |
443 | 223 |
444 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); | 224 // Check first buffer in video stream. |
445 reader->Read(video); | 225 reader->Read(video); |
446 message_loop_.RunAllPending(); | 226 message_loop_.RunAllPending(); |
227 EXPECT_TRUE(reader->called()); | |
228 ValidateBuffer(FROM_HERE, reader->buffer(), 5636, 400000); | |
229 const base::TimeDelta video_timestamp = reader->buffer()->GetTimestamp(); | |
447 | 230 |
448 EXPECT_TRUE(reader->called()); | 231 // Check first buffer in audio stream. |
449 ASSERT_TRUE(reader->buffer()); | |
450 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); | |
451 EXPECT_EQ(kExpectedVideoTimestamp, reader->buffer()->GetTimestamp()); | |
452 EXPECT_EQ(0, memcmp(kVideoData, reader->buffer()->GetData(), | |
453 reader->buffer()->GetDataSize())); | |
454 | |
455 EXPECT_EQ(kExpectedAudioTimestamp, demuxer_->GetStartTime()); | |
456 | |
457 reader->Reset(); | 232 reader->Reset(); |
458 reader->Read(audio); | 233 reader->Read(audio); |
459 message_loop_.RunAllPending(); | 234 message_loop_.RunAllPending(); |
460 EXPECT_TRUE(reader->called()); | 235 EXPECT_TRUE(reader->called()); |
461 ASSERT_TRUE(reader->buffer()); | 236 ValidateBuffer(FROM_HERE, reader->buffer(), 165, 396000); |
462 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); | 237 const base::TimeDelta audio_timestamp = reader->buffer()->GetTimestamp(); |
463 EXPECT_EQ(kExpectedAudioTimestamp, reader->buffer()->GetTimestamp()); | |
464 EXPECT_EQ(0, memcmp(kAudioData, reader->buffer()->GetData(), | |
465 reader->buffer()->GetDataSize())); | |
466 | 238 |
467 EXPECT_EQ(kExpectedAudioTimestamp, demuxer_->GetStartTime()); | 239 // Verify that the start time is equal to the lowest timestamp. |
240 EXPECT_EQ(std::min(audio_timestamp, video_timestamp), | |
241 demuxer_->GetStartTime()); | |
468 } | 242 } |
469 | 243 |
470 TEST_F(FFmpegDemuxerTest, Read_EndOfStream) { | 244 TEST_F(FFmpegDemuxerTest, Read_EndOfStream) { |
471 // On end of stream, a new, empty, AVPackets are created without any data for | 245 // Verify that end of stream buffers are created. |
472 // each stream and enqueued into the Buffer stream. Verify that these are | 246 InitializeDemuxer(CreateDataSource("bear-320x240.webm")); |
473 // indeed inserted. | |
474 { | |
475 SCOPED_TRACE(""); | |
476 InitializeDemuxer(); | |
477 } | |
478 | |
479 // Ignore all AVFreePacket() calls. We check this via valgrind. | |
480 EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber()); | |
481 | |
482 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) | |
483 .WillOnce(Return(AVERROR(EIO))); | |
484 | 247 |
485 // We should now expect an end of stream buffer. | 248 // We should now expect an end of stream buffer. |
486 scoped_refptr<DemuxerStream> audio = | 249 scoped_refptr<DemuxerStream> audio = |
487 demuxer_->GetStream(DemuxerStream::AUDIO); | 250 demuxer_->GetStream(DemuxerStream::AUDIO); |
488 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); | 251 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); |
489 reader->Read(audio); | 252 |
490 message_loop_.RunAllPending(); | 253 bool got_eos_buffer = false; |
491 EXPECT_TRUE(reader->called()); | 254 const int kMaxBuffers = 170; |
492 ASSERT_TRUE(reader->buffer()); | 255 for (int i = 0; !got_eos_buffer && i < kMaxBuffers; i++) { |
493 EXPECT_TRUE(reader->buffer()->IsEndOfStream()); | 256 reader->Read(audio); |
494 EXPECT_TRUE(reader->buffer()->GetData() == NULL); | 257 message_loop_.RunAllPending(); |
495 EXPECT_EQ(0u, reader->buffer()->GetDataSize()); | 258 EXPECT_TRUE(reader->called()); |
259 ASSERT_TRUE(reader->buffer()); | |
260 | |
261 if (reader->buffer()->IsEndOfStream()) { | |
262 got_eos_buffer = true; | |
263 EXPECT_TRUE(reader->buffer()->GetData() == NULL); | |
264 EXPECT_EQ(0u, reader->buffer()->GetDataSize()); | |
265 break; | |
266 } | |
267 | |
268 EXPECT_TRUE(reader->buffer()->GetData() != NULL); | |
269 EXPECT_GT(reader->buffer()->GetDataSize(), 0u); | |
270 reader->Reset(); | |
271 } | |
272 | |
273 EXPECT_TRUE(got_eos_buffer); | |
496 } | 274 } |
497 | 275 |
498 TEST_F(FFmpegDemuxerTest, Seek) { | 276 TEST_F(FFmpegDemuxerTest, Seek) { |
499 // We're testing that the demuxer frees all queued packets when it receives | 277 // We're testing that the demuxer frees all queued packets when it receives |
500 // a Seek(). | 278 // a Seek(). |
501 // | 279 InitializeDemuxer(CreateDataSource("bear-320x240.webm")); |
502 // Since we can't test which packets are being freed, we use check points to | |
503 // infer that the correct packets have been freed. | |
504 { | |
505 SCOPED_TRACE(""); | |
506 InitializeDemuxer(); | |
507 } | |
508 | 280 |
509 // Get our streams. | 281 // Get our streams. |
510 scoped_refptr<DemuxerStream> video = | 282 scoped_refptr<DemuxerStream> video = |
511 demuxer_->GetStream(DemuxerStream::VIDEO); | 283 demuxer_->GetStream(DemuxerStream::VIDEO); |
512 scoped_refptr<DemuxerStream> audio = | 284 scoped_refptr<DemuxerStream> audio = |
513 demuxer_->GetStream(DemuxerStream::AUDIO); | 285 demuxer_->GetStream(DemuxerStream::AUDIO); |
514 ASSERT_TRUE(video); | 286 ASSERT_TRUE(video); |
515 ASSERT_TRUE(audio); | 287 ASSERT_TRUE(audio); |
516 | 288 |
517 // Expected values. | |
518 const int64 kExpectedTimestamp = 1234; | |
519 const int64 kExpectedFlags = AVSEEK_FLAG_BACKWARD; | |
520 | |
521 // Ignore all AVFreePacket() calls. We check this via valgrind. | |
522 EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber()); | |
523 | |
524 // Expect all calls in sequence. | |
525 InSequence s; | |
526 | |
527 // First we'll read a video packet that causes two audio packets to be queued | |
528 // inside FFmpegDemuxer... | |
529 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) | |
530 .WillOnce(CreatePacketNoCount(AV_STREAM_AUDIO, kAudioData, kDataSize)); | |
531 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) | |
532 .WillOnce(Return(0)); | |
533 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) | |
534 .WillOnce(CreatePacketNoCount(AV_STREAM_AUDIO, kAudioData, kDataSize)); | |
535 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) | |
536 .WillOnce(Return(0)); | |
537 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) | |
538 .WillOnce(CreatePacketNoCount(AV_STREAM_VIDEO, kVideoData, kDataSize)); | |
539 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) | |
540 .WillOnce(Return(0)); | |
541 | |
542 EXPECT_CALL(mock_ffmpeg_, CheckPoint(1)); | |
543 | |
544 // ...then we'll expect a seek call... | |
545 EXPECT_CALL(mock_ffmpeg_, | |
546 AVSeekFrame(&format_context_, -1, kExpectedTimestamp, kExpectedFlags)) | |
547 .WillOnce(Return(0)); | |
548 | |
549 // ...then our callback will be executed... | |
550 FilterStatusCB seek_cb = NewExpectedStatusCB(PIPELINE_OK); | |
551 EXPECT_CALL(mock_ffmpeg_, CheckPoint(2)); | |
552 | |
553 // ...followed by two audio packet reads we'll trigger... | |
554 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) | |
555 .WillOnce(CreatePacketNoCount(AV_STREAM_AUDIO, kAudioData, kDataSize)); | |
556 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) | |
557 .WillOnce(Return(0)); | |
558 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) | |
559 .WillOnce(CreatePacketNoCount(AV_STREAM_AUDIO, kAudioData, kDataSize)); | |
560 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) | |
561 .WillOnce(Return(0)); | |
562 | |
563 // ...followed by two video packet reads... | |
564 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) | |
565 .WillOnce(CreatePacketNoCount(AV_STREAM_VIDEO, kVideoData, kDataSize)); | |
566 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) | |
567 .WillOnce(Return(0)); | |
568 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) | |
569 .WillOnce(CreatePacketNoCount(AV_STREAM_VIDEO, kVideoData, kDataSize)); | |
570 EXPECT_CALL(mock_ffmpeg_, AVDupPacket(_)) | |
571 .WillOnce(Return(0)); | |
572 | |
573 // ...and finally a sanity checkpoint to make sure everything was released. | |
574 EXPECT_CALL(mock_ffmpeg_, CheckPoint(3)); | |
575 | |
576 // Read a video packet and release it. | 289 // Read a video packet and release it. |
577 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); | 290 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); |
578 reader->Read(video); | 291 reader->Read(video); |
579 message_loop_.RunAllPending(); | 292 message_loop_.RunAllPending(); |
580 EXPECT_TRUE(reader->called()); | 293 EXPECT_TRUE(reader->called()); |
581 ASSERT_TRUE(reader->buffer()); | 294 ValidateBuffer(FROM_HERE, reader->buffer(), 22084, 0); |
582 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); | |
583 EXPECT_EQ(0, memcmp(kVideoData, reader->buffer()->GetData(), | |
584 reader->buffer()->GetDataSize())); | |
585 | 295 |
586 // Release the video packet and verify the other packets are still queued. | 296 // Release the video packet and verify the other packets are still queued. |
587 reader->Reset(); | 297 reader->Reset(); |
588 message_loop_.RunAllPending(); | 298 message_loop_.RunAllPending(); |
589 mock_ffmpeg_.CheckPoint(1); | |
590 | 299 |
591 // Issue a simple forward seek, which should discard queued packets. | 300 // Issue a simple forward seek, which should discard queued packets. |
592 demuxer_->Seek(base::TimeDelta::FromMicroseconds(kExpectedTimestamp), | 301 demuxer_->Seek(base::TimeDelta::FromMicroseconds(1000000), |
593 seek_cb); | 302 NewExpectedStatusCB(PIPELINE_OK)); |
594 message_loop_.RunAllPending(); | 303 message_loop_.RunAllPending(); |
595 mock_ffmpeg_.CheckPoint(2); | |
596 | 304 |
597 // Audio read #1. | 305 // Audio read #1. |
598 reader->Read(audio); | 306 reader->Read(audio); |
599 message_loop_.RunAllPending(); | 307 message_loop_.RunAllPending(); |
600 EXPECT_TRUE(reader->called()); | 308 EXPECT_TRUE(reader->called()); |
601 ASSERT_TRUE(reader->buffer()); | 309 ValidateBuffer(FROM_HERE, reader->buffer(), 145, 803000); |
602 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); | |
603 EXPECT_EQ(0, memcmp(kAudioData, reader->buffer()->GetData(), | |
604 reader->buffer()->GetDataSize())); | |
605 | 310 |
606 // Audio read #2. | 311 // Audio read #2. |
607 reader->Reset(); | 312 reader->Reset(); |
608 reader->Read(audio); | 313 reader->Read(audio); |
609 message_loop_.RunAllPending(); | 314 message_loop_.RunAllPending(); |
610 EXPECT_TRUE(reader->called()); | 315 EXPECT_TRUE(reader->called()); |
611 ASSERT_TRUE(reader->buffer()); | 316 ValidateBuffer(FROM_HERE, reader->buffer(), 148, 826000); |
612 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); | |
613 EXPECT_EQ(0, memcmp(kAudioData, reader->buffer()->GetData(), | |
614 reader->buffer()->GetDataSize())); | |
615 | 317 |
616 // Video read #1. | 318 // Video read #1. |
617 reader->Reset(); | 319 reader->Reset(); |
618 reader->Read(video); | 320 reader->Read(video); |
619 message_loop_.RunAllPending(); | 321 message_loop_.RunAllPending(); |
620 EXPECT_TRUE(reader->called()); | 322 EXPECT_TRUE(reader->called()); |
621 ASSERT_TRUE(reader->buffer()); | 323 ValidateBuffer(FROM_HERE, reader->buffer(), 5425, 801000); |
622 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); | |
623 EXPECT_EQ(0, memcmp(kVideoData, reader->buffer()->GetData(), | |
624 reader->buffer()->GetDataSize())); | |
625 | 324 |
626 // Video read #2. | 325 // Video read #2. |
627 reader->Reset(); | 326 reader->Reset(); |
628 reader->Read(video); | 327 reader->Read(video); |
629 message_loop_.RunAllPending(); | 328 message_loop_.RunAllPending(); |
630 EXPECT_TRUE(reader->called()); | 329 EXPECT_TRUE(reader->called()); |
631 ASSERT_TRUE(reader->buffer()); | 330 ValidateBuffer(FROM_HERE, reader->buffer(), 1906, 834000); |
632 ASSERT_EQ(kDataSize, reader->buffer()->GetDataSize()); | |
633 EXPECT_EQ(0, memcmp(kVideoData, reader->buffer()->GetData(), | |
634 reader->buffer()->GetDataSize())); | |
635 | 331 |
636 // Manually release the last reference to the buffer and verify it was freed. | 332 // Manually release the last reference to the buffer and verify it was freed. |
637 reader->Reset(); | 333 reader->Reset(); |
638 message_loop_.RunAllPending(); | 334 message_loop_.RunAllPending(); |
639 mock_ffmpeg_.CheckPoint(3); | |
640 } | 335 } |
641 | 336 |
642 // A mocked callback specialization for calling Read(). Since RunWithParams() | 337 // A mocked callback specialization for calling Read(). Since RunWithParams() |
643 // is mocked we don't need to pass in object or method pointers. | 338 // is mocked we don't need to pass in object or method pointers. |
644 class MockReadCallback : public base::RefCountedThreadSafe<MockReadCallback> { | 339 class MockReadCallback : public base::RefCountedThreadSafe<MockReadCallback> { |
645 public: | 340 public: |
646 MockReadCallback() {} | 341 MockReadCallback() {} |
647 | 342 |
648 virtual ~MockReadCallback() { | 343 virtual ~MockReadCallback() { |
649 OnDelete(); | 344 OnDelete(); |
650 } | 345 } |
651 | 346 |
652 MOCK_METHOD0(OnDelete, void()); | 347 MOCK_METHOD0(OnDelete, void()); |
653 MOCK_METHOD1(Run, void(Buffer* buffer)); | 348 MOCK_METHOD1(Run, void(Buffer* buffer)); |
654 | 349 |
655 private: | 350 private: |
656 DISALLOW_COPY_AND_ASSIGN(MockReadCallback); | 351 DISALLOW_COPY_AND_ASSIGN(MockReadCallback); |
657 }; | 352 }; |
658 | 353 |
659 TEST_F(FFmpegDemuxerTest, Stop) { | 354 TEST_F(FFmpegDemuxerTest, Stop) { |
660 // Tests that calling Read() on a stopped demuxer immediately deletes the | 355 // Tests that calling Read() on a stopped demuxer immediately deletes the |
661 // callback. | 356 // callback. |
662 { | 357 InitializeDemuxer(CreateDataSource("bear-320x240.webm")); |
663 SCOPED_TRACE(""); | |
664 InitializeDemuxer(); | |
665 } | |
666 | 358 |
667 // Get our stream. | 359 // Get our stream. |
668 scoped_refptr<DemuxerStream> audio = | 360 scoped_refptr<DemuxerStream> audio = |
669 demuxer_->GetStream(DemuxerStream::AUDIO); | 361 demuxer_->GetStream(DemuxerStream::AUDIO); |
670 ASSERT_TRUE(audio); | 362 ASSERT_TRUE(audio); |
671 | 363 |
672 // Stop the demuxer, overriding the default expectation to assert that | |
673 // data_source_ really is Stop()'d. | |
674 EXPECT_CALL(*data_source_, Stop(_)) | |
675 .WillOnce(Invoke(&RunStopFilterCallback)) | |
676 .RetiresOnSaturation(); | |
677 demuxer_->Stop(NewExpectedCallback()); | 364 demuxer_->Stop(NewExpectedCallback()); |
678 | 365 |
679 // Expect all calls in sequence. | 366 // Expect all calls in sequence. |
680 InSequence s; | 367 InSequence s; |
681 | 368 |
682 // Create our mocked callback. The Callback created by base::Bind() will take | 369 // Create our mocked callback. The Callback created by base::Bind() will take |
683 // ownership of this pointer. | 370 // ownership of this pointer. |
684 StrictMock<MockReadCallback>* callback = new StrictMock<MockReadCallback>(); | 371 StrictMock<MockReadCallback>* callback = new StrictMock<MockReadCallback>(); |
685 | 372 |
686 // The callback should be immediately deleted. We'll use a checkpoint to | 373 // The callback should be immediately deleted. We'll use a checkpoint to |
687 // verify that it has indeed been deleted. | 374 // verify that it has indeed been deleted. |
688 EXPECT_CALL(*callback, OnDelete()); | 375 EXPECT_CALL(*callback, OnDelete()); |
689 EXPECT_CALL(mock_ffmpeg_, CheckPoint(1)); | 376 EXPECT_CALL(*this, CheckPoint(1)); |
690 | 377 |
691 // Attempt the read... | 378 // Attempt the read... |
692 audio->Read(base::Bind(&MockReadCallback::Run, callback)); | 379 audio->Read(base::Bind(&MockReadCallback::Run, callback)); |
693 | 380 |
694 message_loop_.RunAllPending(); | 381 message_loop_.RunAllPending(); |
695 | 382 |
696 // ...and verify that |callback| was deleted. | 383 // ...and verify that |callback| was deleted. |
697 mock_ffmpeg_.CheckPoint(1); | 384 CheckPoint(1); |
698 } | 385 } |
699 | 386 |
700 TEST_F(FFmpegDemuxerTest, DisableAudioStream) { | 387 TEST_F(FFmpegDemuxerTest, DisableAudioStream) { |
701 // We are doing the following things here: | 388 // We are doing the following things here: |
702 // 1. Initialize the demuxer with audio and video stream. | 389 // 1. Initialize the demuxer with audio and video stream. |
703 // 2. Send a "disable audio stream" message to the demuxer. | 390 // 2. Send a "disable audio stream" message to the demuxer. |
704 // 3. Demuxer will free audio packets even if audio stream was initialized. | 391 // 3. Demuxer will free audio packets even if audio stream was initialized. |
705 { | 392 InitializeDemuxer(CreateDataSource("bear-320x240.webm")); |
706 SCOPED_TRACE(""); | |
707 InitializeDemuxer(); | |
708 } | |
709 | 393 |
710 // Submit a "disable audio stream" message to the demuxer. | 394 // Submit a "disable audio stream" message to the demuxer. |
711 demuxer_->OnAudioRendererDisabled(); | 395 demuxer_->OnAudioRendererDisabled(); |
712 message_loop_.RunAllPending(); | 396 message_loop_.RunAllPending(); |
713 | 397 |
714 // Ignore all AVFreePacket() calls. We check this via valgrind. | |
715 EXPECT_CALL(mock_ffmpeg_, AVFreePacket(_)).Times(AnyNumber()); | |
716 | |
717 // Expect all calls in sequence. | |
718 InSequence s; | |
719 | |
720 // The demuxer will read an audio packet which will get immediately freed. | |
721 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) | |
722 .WillOnce(CreatePacketNoCount(AV_STREAM_AUDIO, kNullData, 0)); | |
723 | |
724 // Then an end-of-stream packet is read. | |
725 EXPECT_CALL(mock_ffmpeg_, AVReadFrame(&format_context_, _)) | |
726 .WillOnce(Return(AVERROR(EIO))); | |
727 | |
728 // Get our streams. | 398 // Get our streams. |
729 scoped_refptr<DemuxerStream> video = | 399 scoped_refptr<DemuxerStream> video = |
730 demuxer_->GetStream(DemuxerStream::VIDEO); | 400 demuxer_->GetStream(DemuxerStream::VIDEO); |
401 scoped_refptr<DemuxerStream> audio = | |
402 demuxer_->GetStream(DemuxerStream::AUDIO); | |
731 ASSERT_TRUE(video); | 403 ASSERT_TRUE(video); |
404 ASSERT_TRUE(audio); | |
732 | 405 |
733 // Attempt a read from the video stream and run the message loop until done. | 406 // Attempt a read from the video stream and run the message loop until done. |
734 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); | 407 scoped_refptr<DemuxerStreamReader> reader(new DemuxerStreamReader()); |
735 reader->Read(video); | 408 reader->Read(video); |
736 message_loop_.RunAllPending(); | 409 message_loop_.RunAllPending(); |
410 EXPECT_TRUE(reader->called()); | |
411 ValidateBuffer(FROM_HERE, reader->buffer(), 22084, 0); | |
412 | |
413 reader->Reset(); | |
414 reader->Read(audio); | |
415 message_loop_.RunAllPending(); | |
416 EXPECT_TRUE(reader->called()); | |
417 EXPECT_TRUE(reader->buffer()->IsEndOfStream()); | |
737 } | 418 } |
738 | 419 |
739 class MockFFmpegDemuxer : public FFmpegDemuxer { | 420 class MockFFmpegDemuxer : public FFmpegDemuxer { |
740 public: | 421 public: |
741 explicit MockFFmpegDemuxer(MessageLoop* message_loop) | 422 explicit MockFFmpegDemuxer(MessageLoop* message_loop) |
742 : FFmpegDemuxer(message_loop) { | 423 : FFmpegDemuxer(message_loop) { |
743 } | 424 } |
744 virtual ~MockFFmpegDemuxer() {} | 425 virtual ~MockFFmpegDemuxer() {} |
745 | 426 |
746 MOCK_METHOD0(WaitForRead, size_t()); | 427 MOCK_METHOD0(WaitForRead, size_t()); |
747 MOCK_METHOD1(SignalReadCompleted, void(size_t size)); | 428 MOCK_METHOD1(SignalReadCompleted, void(size_t size)); |
748 | 429 |
749 private: | 430 private: |
750 DISALLOW_COPY_AND_ASSIGN(MockFFmpegDemuxer); | 431 DISALLOW_COPY_AND_ASSIGN(MockFFmpegDemuxer); |
751 }; | 432 }; |
752 | 433 |
753 // A gmock helper method to execute the callback and deletes it. | 434 // A gmock helper method to execute the callback and deletes it. |
754 void RunCallback(size_t size, DataSource::ReadCallback* callback) { | 435 void RunCallback(size_t size, DataSource::ReadCallback* callback) { |
755 DCHECK(callback); | 436 DCHECK(callback); |
756 callback->RunWithParams(Tuple1<size_t>(size)); | 437 callback->RunWithParams(Tuple1<size_t>(size)); |
757 delete callback; | 438 delete callback; |
758 } | 439 } |
759 | 440 |
760 TEST_F(FFmpegDemuxerTest, ProtocolRead) { | 441 TEST_F(FFmpegDemuxerTest, ProtocolRead) { |
442 scoped_refptr<StrictMock<MockDataSource> > data_source = | |
443 new StrictMock<MockDataSource>(); | |
444 | |
445 EXPECT_CALL(*data_source, Stop(NotNull())) | |
446 .WillRepeatedly(Invoke(&RunStopFilterCallback)); | |
447 | |
761 // Creates a demuxer. | 448 // Creates a demuxer. |
762 scoped_refptr<MockFFmpegDemuxer> demuxer( | 449 scoped_refptr<MockFFmpegDemuxer> demuxer( |
763 new MockFFmpegDemuxer(&message_loop_)); | 450 new MockFFmpegDemuxer(&message_loop_)); |
764 ASSERT_TRUE(demuxer); | 451 ASSERT_TRUE(demuxer); |
765 demuxer->set_host(&host_); | 452 demuxer->set_host(&host_); |
766 demuxer->data_source_ = data_source_; | 453 demuxer->data_source_ = data_source; |
767 | 454 |
768 uint8 kBuffer[1]; | 455 uint8 kBuffer[1]; |
769 InSequence s; | 456 InSequence s; |
770 // Actions taken in the first read. | 457 // Actions taken in the first read. |
771 EXPECT_CALL(*data_source_, GetSize(_)) | 458 EXPECT_CALL(*data_source, GetSize(_)) |
772 .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true))); | 459 .WillOnce(DoAll(SetArgPointee<0>(1024), Return(true))); |
773 EXPECT_CALL(*data_source_, Read(0, 512, kBuffer, NotNull())) | 460 EXPECT_CALL(*data_source, Read(0, 512, kBuffer, NotNull())) |
774 .WillOnce(WithArgs<1, 3>(Invoke(&RunCallback))); | 461 .WillOnce(WithArgs<1, 3>(Invoke(&RunCallback))); |
775 EXPECT_CALL(*demuxer, SignalReadCompleted(512)); | 462 EXPECT_CALL(*demuxer, SignalReadCompleted(512)); |
776 EXPECT_CALL(*demuxer, WaitForRead()) | 463 EXPECT_CALL(*demuxer, WaitForRead()) |
777 .WillOnce(Return(512)); | 464 .WillOnce(Return(512)); |
778 EXPECT_CALL(host_, SetCurrentReadPosition(512)); | 465 EXPECT_CALL(host_, SetCurrentReadPosition(512)); |
779 | 466 |
780 // Second read. | 467 // Second read. |
781 EXPECT_CALL(*data_source_, GetSize(_)) | 468 EXPECT_CALL(*data_source, GetSize(_)) |
782 .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true))); | 469 .WillOnce(DoAll(SetArgPointee<0>(1024), Return(true))); |
783 EXPECT_CALL(*data_source_, Read(512, 512, kBuffer, NotNull())) | 470 EXPECT_CALL(*data_source, Read(512, 512, kBuffer, NotNull())) |
784 .WillOnce(WithArgs<1, 3>(Invoke(&RunCallback))); | 471 .WillOnce(WithArgs<1, 3>(Invoke(&RunCallback))); |
785 EXPECT_CALL(*demuxer, SignalReadCompleted(512)); | 472 EXPECT_CALL(*demuxer, SignalReadCompleted(512)); |
786 EXPECT_CALL(*demuxer, WaitForRead()) | 473 EXPECT_CALL(*demuxer, WaitForRead()) |
787 .WillOnce(Return(512)); | 474 .WillOnce(Return(512)); |
788 EXPECT_CALL(host_, SetCurrentReadPosition(1024)); | 475 EXPECT_CALL(host_, SetCurrentReadPosition(1024)); |
789 | 476 |
790 // Third read will fail because it exceeds the file size. | 477 // Third read will fail because it exceeds the file size. |
791 EXPECT_CALL(*data_source_, GetSize(_)) | 478 EXPECT_CALL(*data_source, GetSize(_)) |
792 .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true))); | 479 .WillOnce(DoAll(SetArgPointee<0>(1024), Return(true))); |
793 | 480 |
794 // First read. | 481 // First read. |
795 EXPECT_EQ(512, demuxer->Read(512, kBuffer)); | 482 EXPECT_EQ(512, demuxer->Read(512, kBuffer)); |
796 int64 position; | 483 int64 position; |
797 EXPECT_TRUE(demuxer->GetPosition(&position)); | 484 EXPECT_TRUE(demuxer->GetPosition(&position)); |
798 EXPECT_EQ(512, position); | 485 EXPECT_EQ(512, position); |
799 | 486 |
800 // Second read. | 487 // Second read. |
801 EXPECT_EQ(512, demuxer->Read(512, kBuffer)); | 488 EXPECT_EQ(512, demuxer->Read(512, kBuffer)); |
802 EXPECT_TRUE(demuxer->GetPosition(&position)); | 489 EXPECT_TRUE(demuxer->GetPosition(&position)); |
803 EXPECT_EQ(1024, position); | 490 EXPECT_EQ(1024, position); |
804 | 491 |
805 // Third read will get an end-of-file error, which is represented as zero. | 492 // Third read will get an end-of-file error, which is represented as zero. |
806 EXPECT_EQ(0, demuxer->Read(512, kBuffer)); | 493 EXPECT_EQ(0, demuxer->Read(512, kBuffer)); |
807 | 494 |
808 // This read complete signal is generated when demuxer is stopped. | 495 // This read complete signal is generated when demuxer is stopped. |
809 EXPECT_CALL(*demuxer, SignalReadCompleted(DataSource::kReadError)); | 496 EXPECT_CALL(*demuxer, SignalReadCompleted(DataSource::kReadError)); |
810 demuxer->Stop(NewExpectedCallback()); | 497 demuxer->Stop(NewExpectedCallback()); |
811 message_loop_.RunAllPending(); | 498 message_loop_.RunAllPending(); |
812 } | 499 } |
813 | 500 |
814 TEST_F(FFmpegDemuxerTest, ProtocolGetSetPosition) { | 501 TEST_F(FFmpegDemuxerTest, ProtocolGetSetPosition) { |
815 { | 502 scoped_refptr<DataSource> data_source = CreateDataSource("bear-320x240.webm"); |
816 SCOPED_TRACE(""); | 503 InitializeDemuxer(data_source); |
817 InitializeDemuxer(); | |
818 } | |
819 | 504 |
820 InSequence s; | 505 InSequence s; |
821 | 506 |
822 EXPECT_CALL(*data_source_, GetSize(_)) | 507 int64 size; |
823 .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true))); | |
824 EXPECT_CALL(*data_source_, GetSize(_)) | |
825 .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true))); | |
826 EXPECT_CALL(*data_source_, GetSize(_)) | |
827 .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true))); | |
828 | |
829 int64 position; | 508 int64 position; |
509 EXPECT_TRUE(demuxer_->GetSize(&size)); | |
830 EXPECT_TRUE(demuxer_->GetPosition(&position)); | 510 EXPECT_TRUE(demuxer_->GetPosition(&position)); |
831 EXPECT_EQ(0, position); | 511 EXPECT_EQ(current_read_position_, position); |
832 | 512 |
833 EXPECT_TRUE(demuxer_->SetPosition(512)); | 513 EXPECT_TRUE(demuxer_->SetPosition(512)); |
834 EXPECT_FALSE(demuxer_->SetPosition(2048)); | 514 EXPECT_FALSE(demuxer_->SetPosition(size)); |
515 EXPECT_FALSE(demuxer_->SetPosition(size + 1)); | |
835 EXPECT_FALSE(demuxer_->SetPosition(-1)); | 516 EXPECT_FALSE(demuxer_->SetPosition(-1)); |
836 EXPECT_TRUE(demuxer_->GetPosition(&position)); | 517 EXPECT_TRUE(demuxer_->GetPosition(&position)); |
837 EXPECT_EQ(512, position); | 518 EXPECT_EQ(512, position); |
838 } | 519 } |
839 | 520 |
840 TEST_F(FFmpegDemuxerTest, ProtocolGetSize) { | 521 TEST_F(FFmpegDemuxerTest, ProtocolGetSize) { |
841 { | 522 scoped_refptr<DataSource> data_source = CreateDataSource("bear-320x240.webm"); |
842 SCOPED_TRACE(""); | 523 InitializeDemuxer(data_source); |
843 InitializeDemuxer(); | |
844 } | |
845 | 524 |
846 EXPECT_CALL(*data_source_, GetSize(_)) | 525 int64 data_source_size = 0; |
847 .WillOnce(DoAll(SetArgumentPointee<0>(1024), Return(true))); | 526 int64 demuxer_size = 0; |
848 | 527 EXPECT_TRUE(data_source->GetSize(&data_source_size)); |
849 int64 size; | 528 EXPECT_TRUE(demuxer_->GetSize(&demuxer_size)); |
850 EXPECT_TRUE(demuxer_->GetSize(&size)); | 529 EXPECT_NE(0, data_source_size); |
851 EXPECT_EQ(1024, size); | 530 EXPECT_EQ(data_source_size, demuxer_size); |
852 } | 531 } |
853 | 532 |
854 TEST_F(FFmpegDemuxerTest, ProtocolIsStreaming) { | 533 TEST_F(FFmpegDemuxerTest, ProtocolIsStreaming) { |
855 { | 534 scoped_refptr<DataSource> data_source = CreateDataSource("bear-320x240.webm"); |
856 SCOPED_TRACE(""); | 535 InitializeDemuxer(data_source); |
857 InitializeDemuxer(); | 536 |
858 } | 537 EXPECT_FALSE(data_source->IsStreaming()); |
859 EXPECT_CALL(*data_source_, IsStreaming()) | |
860 .WillOnce(Return(false)); | |
861 EXPECT_FALSE(demuxer_->IsStreaming()); | 538 EXPECT_FALSE(demuxer_->IsStreaming()); |
862 } | 539 } |
863 | 540 |
864 } // namespace media | 541 } // namespace media |
OLD | NEW |