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 "base/bind.h" | 5 #include "base/bind.h" |
6 #include "base/message_loop.h" | 6 #include "base/message_loop.h" |
7 #include "media/base/filter_collection.h" | 7 #include "media/base/filter_collection.h" |
8 #include "media/base/media_log.h" | 8 #include "media/base/media_log.h" |
9 #include "media/base/message_loop_factory_impl.h" | 9 #include "media/base/message_loop_factory_impl.h" |
10 #include "media/base/pipeline.h" | 10 #include "media/base/pipeline.h" |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
97 // in the real AudioRendererImpl & SkCanvasVideoRenderer implementations used in | 97 // in the real AudioRendererImpl & SkCanvasVideoRenderer implementations used in |
98 // the browser. The renderers in this test don't actually write data to a | 98 // the browser. The renderers in this test don't actually write data to a |
99 // display or audio device. Both of these devices are simulated since they have | 99 // display or audio device. Both of these devices are simulated since they have |
100 // little effect on verifying pipeline behavior and allow tests to run faster | 100 // little effect on verifying pipeline behavior and allow tests to run faster |
101 // than real-time. | 101 // than real-time. |
102 class PipelineIntegrationTest : public testing::Test { | 102 class PipelineIntegrationTest : public testing::Test { |
103 public: | 103 public: |
104 PipelineIntegrationTest() | 104 PipelineIntegrationTest() |
105 : message_loop_factory_(new MessageLoopFactoryImpl()), | 105 : message_loop_factory_(new MessageLoopFactoryImpl()), |
106 pipeline_(new Pipeline(&message_loop_, new MediaLog())), | 106 pipeline_(new Pipeline(&message_loop_, new MediaLog())), |
107 ended_(false) { | 107 ended_(false), |
108 error_status_(PIPELINE_OK) { | |
Ami GONE FROM CHROMIUM
2012/01/31 19:06:54
since it can hold OK, s/error_/pipeline_/
acolwell GONE FROM CHROMIUM
2012/01/31 19:16:00
Done.
| |
108 EXPECT_CALL(*this, OnVideoRendererPaint()).Times(AnyNumber()); | 109 EXPECT_CALL(*this, OnVideoRendererPaint()).Times(AnyNumber()); |
109 EXPECT_CALL(*this, OnSetOpaque(true)).Times(AnyNumber()); | 110 EXPECT_CALL(*this, OnSetOpaque(true)).Times(AnyNumber()); |
110 } | 111 } |
111 | 112 |
112 virtual ~PipelineIntegrationTest() { | 113 virtual ~PipelineIntegrationTest() { |
113 if (!pipeline_->IsRunning()) | 114 if (!pipeline_->IsRunning()) |
114 return; | 115 return; |
115 | 116 |
116 Stop(); | 117 Stop(); |
117 } | 118 } |
118 | 119 |
119 void OnStatusCallback(PipelineStatus expected_status, | 120 void OnStatusCallback(PipelineStatus expected_status, |
120 PipelineStatus status) { | 121 PipelineStatus status) { |
121 EXPECT_EQ(status, expected_status); | 122 EXPECT_EQ(status, expected_status); |
123 error_status_ = status; | |
122 message_loop_.PostTask(FROM_HERE, MessageLoop::QuitClosure()); | 124 message_loop_.PostTask(FROM_HERE, MessageLoop::QuitClosure()); |
123 } | 125 } |
124 | 126 |
125 PipelineStatusCB QuitOnStatusCB(PipelineStatus expected_status) { | 127 PipelineStatusCB QuitOnStatusCB(PipelineStatus expected_status) { |
126 return base::Bind(&PipelineIntegrationTest::OnStatusCallback, | 128 return base::Bind(&PipelineIntegrationTest::OnStatusCallback, |
127 base::Unretained(this), | 129 base::Unretained(this), |
128 expected_status); | 130 expected_status); |
129 } | 131 } |
130 | 132 |
131 void OnEnded(PipelineStatus status) { | 133 void OnEnded(PipelineStatus status) { |
132 DCHECK_EQ(status, PIPELINE_OK); | 134 DCHECK_EQ(status, PIPELINE_OK); |
133 DCHECK(!ended_); | 135 DCHECK(!ended_); |
134 ended_ = true; | 136 ended_ = true; |
135 message_loop_.PostTask(FROM_HERE, MessageLoop::QuitClosure()); | 137 message_loop_.PostTask(FROM_HERE, MessageLoop::QuitClosure()); |
136 } | 138 } |
137 | 139 |
138 void WaitUntilOnEnded() { | 140 bool WaitUntilOnEnded() { |
139 if (!ended_) { | 141 if (ended_) |
140 message_loop_.Run(); | 142 return (error_status_ == PIPELINE_OK); |
141 DCHECK(ended_); | 143 message_loop_.Run(); |
142 } | 144 EXPECT_TRUE(ended_); |
145 return ended_ && (error_status_ == PIPELINE_OK); | |
143 } | 146 } |
144 | 147 |
145 MOCK_METHOD1(OnError, void(PipelineStatus)); | 148 void OnError(PipelineStatus status) { |
149 DCHECK_NE(status, PIPELINE_OK); | |
150 error_status_ = status; | |
151 message_loop_.PostTask(FROM_HERE, MessageLoop::QuitClosure()); | |
152 } | |
146 | 153 |
147 void Start(const std::string& url, PipelineStatus expected_status) { | 154 bool Start(const std::string& url, PipelineStatus expected_status) { |
148 pipeline_->Start( | 155 pipeline_->Start( |
149 CreateFilterCollection(url), | 156 CreateFilterCollection(url), |
150 url, | 157 url, |
151 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)), | 158 base::Bind(&PipelineIntegrationTest::OnEnded, base::Unretained(this)), |
152 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), | 159 base::Bind(&PipelineIntegrationTest::OnError, base::Unretained(this)), |
153 NetworkEventCB(), | 160 NetworkEventCB(), |
154 QuitOnStatusCB(expected_status)); | 161 QuitOnStatusCB(expected_status)); |
155 message_loop_.Run(); | 162 message_loop_.Run(); |
163 return (error_status_ == PIPELINE_OK); | |
156 } | 164 } |
157 | 165 |
158 void Play() { | 166 void Play() { |
159 pipeline_->SetPlaybackRate(1); | 167 pipeline_->SetPlaybackRate(1); |
160 } | 168 } |
161 | 169 |
162 void Pause() { | 170 void Pause() { |
163 pipeline_->SetPlaybackRate(0); | 171 pipeline_->SetPlaybackRate(0); |
164 } | 172 } |
165 | 173 |
166 void Seek(base::TimeDelta seek_time) { | 174 bool Seek(base::TimeDelta seek_time) { |
167 ended_ = false; | 175 ended_ = false; |
168 | 176 |
169 pipeline_->Seek(seek_time, QuitOnStatusCB(PIPELINE_OK)); | 177 pipeline_->Seek(seek_time, QuitOnStatusCB(PIPELINE_OK)); |
170 message_loop_.Run(); | 178 message_loop_.Run(); |
179 return (error_status_ == PIPELINE_OK); | |
171 } | 180 } |
172 | 181 |
173 void Stop() { | 182 void Stop() { |
174 DCHECK(pipeline_->IsRunning()); | 183 DCHECK(pipeline_->IsRunning()); |
175 pipeline_->Stop(QuitOnStatusCB(PIPELINE_OK)); | 184 pipeline_->Stop(QuitOnStatusCB(PIPELINE_OK)); |
176 message_loop_.Run(); | 185 message_loop_.Run(); |
177 } | 186 } |
178 | 187 |
179 void QuitAfterCurrentTimeTask(const base::TimeDelta& quit_time) { | 188 void QuitAfterCurrentTimeTask(const base::TimeDelta& quit_time) { |
180 if (pipeline_->GetCurrentTime() >= quit_time) { | 189 if (pipeline_->GetCurrentTime() >= quit_time || |
190 error_status_ != PIPELINE_OK) { | |
181 message_loop_.Quit(); | 191 message_loop_.Quit(); |
182 return; | 192 return; |
183 } | 193 } |
184 | 194 |
185 message_loop_.PostDelayedTask( | 195 message_loop_.PostDelayedTask( |
186 FROM_HERE, | 196 FROM_HERE, |
187 base::Bind(&PipelineIntegrationTest::QuitAfterCurrentTimeTask, | 197 base::Bind(&PipelineIntegrationTest::QuitAfterCurrentTimeTask, |
188 base::Unretained(this), quit_time), | 198 base::Unretained(this), quit_time), |
189 10); | 199 10); |
190 } | 200 } |
191 | 201 |
192 void WaitUntilCurrentTimeIsAfter(const base::TimeDelta& wait_time) { | 202 bool WaitUntilCurrentTimeIsAfter(const base::TimeDelta& wait_time) { |
193 DCHECK(pipeline_->IsRunning()); | 203 DCHECK(pipeline_->IsRunning()); |
194 DCHECK_GT(pipeline_->GetPlaybackRate(), 0); | 204 DCHECK_GT(pipeline_->GetPlaybackRate(), 0); |
195 DCHECK(wait_time <= pipeline_->GetMediaDuration()); | 205 DCHECK(wait_time <= pipeline_->GetMediaDuration()); |
196 | 206 |
197 message_loop_.PostDelayedTask( | 207 message_loop_.PostDelayedTask( |
198 FROM_HERE, | 208 FROM_HERE, |
199 base::Bind(&PipelineIntegrationTest::QuitAfterCurrentTimeTask, | 209 base::Bind(&PipelineIntegrationTest::QuitAfterCurrentTimeTask, |
200 base::Unretained(this), | 210 base::Unretained(this), |
201 wait_time), | 211 wait_time), |
202 10); | 212 10); |
203 message_loop_.Run(); | 213 message_loop_.Run(); |
214 return (error_status_ == PIPELINE_OK); | |
204 } | 215 } |
205 | 216 |
206 scoped_ptr<FilterCollection> CreateFilterCollection(const std::string& url) { | 217 scoped_ptr<FilterCollection> CreateFilterCollection(const std::string& url) { |
207 scoped_refptr<FileDataSource> data_source = new FileDataSource(); | 218 scoped_refptr<FileDataSource> data_source = new FileDataSource(); |
208 CHECK_EQ(PIPELINE_OK, data_source->Initialize(url)); | 219 CHECK_EQ(PIPELINE_OK, data_source->Initialize(url)); |
209 return CreateFilterCollection(scoped_ptr<DemuxerFactory>( | 220 return CreateFilterCollection(scoped_ptr<DemuxerFactory>( |
210 new FFmpegDemuxerFactory(data_source, &message_loop_))); | 221 new FFmpegDemuxerFactory(data_source, &message_loop_))); |
211 } | 222 } |
212 | 223 |
213 scoped_ptr<FilterCollection> CreateFilterCollection( | 224 scoped_ptr<FilterCollection> CreateFilterCollection( |
(...skipping 15 matching lines...) Expand all Loading... | |
229 base::Unretained(this)), | 240 base::Unretained(this)), |
230 base::Bind(&PipelineIntegrationTest::OnSetOpaque, | 241 base::Bind(&PipelineIntegrationTest::OnSetOpaque, |
231 base::Unretained(this)))); | 242 base::Unretained(this)))); |
232 collection->AddAudioRenderer(new NullAudioRenderer()); | 243 collection->AddAudioRenderer(new NullAudioRenderer()); |
233 return collection.Pass(); | 244 return collection.Pass(); |
234 } | 245 } |
235 | 246 |
236 // Verifies that seeking works properly for ChunkDemuxer when the | 247 // Verifies that seeking works properly for ChunkDemuxer when the |
237 // seek happens while there is a pending read on the ChunkDemuxer | 248 // seek happens while there is a pending read on the ChunkDemuxer |
238 // and no data is available. | 249 // and no data is available. |
239 void TestSeekDuringRead(const std::string& filename, | 250 bool TestSeekDuringRead(const std::string& filename, |
240 int initial_append_size, | 251 int initial_append_size, |
241 base::TimeDelta start_seek_time, | 252 base::TimeDelta start_seek_time, |
242 base::TimeDelta seek_time, | 253 base::TimeDelta seek_time, |
243 int seek_file_position, | 254 int seek_file_position, |
244 int seek_append_size) { | 255 int seek_append_size) { |
245 MockMediaSource source(filename, initial_append_size); | 256 MockMediaSource source(filename, initial_append_size); |
246 | 257 |
247 pipeline_->Start(CreateFilterCollection(&source), source.url(), | 258 pipeline_->Start(CreateFilterCollection(&source), source.url(), |
248 base::Bind(&PipelineIntegrationTest::OnEnded, | 259 base::Bind(&PipelineIntegrationTest::OnEnded, |
249 base::Unretained(this)), | 260 base::Unretained(this)), |
250 base::Bind(&PipelineIntegrationTest::OnError, | 261 base::Bind(&PipelineIntegrationTest::OnError, |
251 base::Unretained(this)), | 262 base::Unretained(this)), |
252 NetworkEventCB(), | 263 NetworkEventCB(), |
253 QuitOnStatusCB(PIPELINE_OK)); | 264 QuitOnStatusCB(PIPELINE_OK)); |
254 message_loop_.Run(); | 265 message_loop_.Run(); |
255 | 266 |
267 if (error_status_ != PIPELINE_OK) | |
268 return false; | |
269 | |
256 Play(); | 270 Play(); |
257 WaitUntilCurrentTimeIsAfter(start_seek_time); | 271 if (!WaitUntilCurrentTimeIsAfter(start_seek_time)) |
272 return false; | |
258 | 273 |
259 source.Seek(seek_file_position, seek_append_size); | 274 source.Seek(seek_file_position, seek_append_size); |
260 Seek(seek_time); | 275 if (!Seek(seek_time)) |
276 return false; | |
261 | 277 |
262 source.EndOfStream(); | 278 source.EndOfStream(); |
263 | 279 |
264 source.Abort(); | 280 source.Abort(); |
265 Stop(); | 281 Stop(); |
282 return true; | |
266 } | 283 } |
267 | 284 |
268 protected: | 285 protected: |
269 MessageLoop message_loop_; | 286 MessageLoop message_loop_; |
270 scoped_ptr<MessageLoopFactory> message_loop_factory_; | 287 scoped_ptr<MessageLoopFactory> message_loop_factory_; |
271 scoped_refptr<Pipeline> pipeline_; | 288 scoped_refptr<Pipeline> pipeline_; |
272 bool ended_; | 289 bool ended_; |
290 PipelineStatus error_status_; | |
273 | 291 |
274 private: | 292 private: |
275 MOCK_METHOD0(OnVideoRendererPaint, void()); | 293 MOCK_METHOD0(OnVideoRendererPaint, void()); |
276 MOCK_METHOD1(OnSetOpaque, void(bool)); | 294 MOCK_METHOD1(OnSetOpaque, void(bool)); |
277 }; | 295 }; |
278 | 296 |
279 | 297 |
280 TEST_F(PipelineIntegrationTest, BasicPlayback) { | 298 TEST_F(PipelineIntegrationTest, BasicPlayback) { |
281 Start(GetTestDataURL("bear-320x240.webm"), PIPELINE_OK); | 299 ASSERT_TRUE(Start(GetTestDataURL("bear-320x240.webm"), PIPELINE_OK)); |
282 | 300 |
283 Play(); | 301 Play(); |
284 | 302 |
285 WaitUntilOnEnded(); | 303 ASSERT_TRUE(WaitUntilOnEnded()); |
286 } | 304 } |
287 | 305 |
288 TEST_F(PipelineIntegrationTest, SeekWhilePaused) { | 306 TEST_F(PipelineIntegrationTest, SeekWhilePaused) { |
289 Start(GetTestDataURL("bear-320x240.webm"), PIPELINE_OK); | 307 ASSERT_TRUE(Start(GetTestDataURL("bear-320x240.webm"), PIPELINE_OK)); |
290 | 308 |
291 base::TimeDelta duration(pipeline_->GetMediaDuration()); | 309 base::TimeDelta duration(pipeline_->GetMediaDuration()); |
292 base::TimeDelta start_seek_time(duration / 4); | 310 base::TimeDelta start_seek_time(duration / 4); |
293 base::TimeDelta seek_time(duration * 3 / 4); | 311 base::TimeDelta seek_time(duration * 3 / 4); |
294 | 312 |
295 Play(); | 313 Play(); |
296 WaitUntilCurrentTimeIsAfter(start_seek_time); | 314 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time)); |
297 Pause(); | 315 Pause(); |
298 Seek(seek_time); | 316 ASSERT_TRUE(Seek(seek_time)); |
299 EXPECT_EQ(pipeline_->GetCurrentTime(), seek_time); | 317 EXPECT_EQ(pipeline_->GetCurrentTime(), seek_time); |
300 Play(); | 318 Play(); |
301 WaitUntilOnEnded(); | 319 ASSERT_TRUE(WaitUntilOnEnded()); |
302 | 320 |
303 // Make sure seeking after reaching the end works as expected. | 321 // Make sure seeking after reaching the end works as expected. |
304 Pause(); | 322 Pause(); |
305 Seek(seek_time); | 323 ASSERT_TRUE(Seek(seek_time)); |
306 EXPECT_EQ(pipeline_->GetCurrentTime(), seek_time); | 324 EXPECT_EQ(pipeline_->GetCurrentTime(), seek_time); |
307 Play(); | 325 Play(); |
308 WaitUntilOnEnded(); | 326 ASSERT_TRUE(WaitUntilOnEnded()); |
309 } | 327 } |
310 | 328 |
311 // TODO(acolwell): Fix flakiness http://crbug.com/109875 | 329 // TODO(acolwell): Fix flakiness http://crbug.com/109875 |
312 TEST_F(PipelineIntegrationTest, DISABLED_SeekWhilePlaying) { | 330 TEST_F(PipelineIntegrationTest, FLAKY_SeekWhilePlaying) { |
313 Start(GetTestDataURL("bear-320x240.webm"), PIPELINE_OK); | 331 ASSERT_TRUE(Start(GetTestDataURL("bear-320x240.webm"), PIPELINE_OK)); |
314 | 332 |
315 base::TimeDelta duration(pipeline_->GetMediaDuration()); | 333 base::TimeDelta duration(pipeline_->GetMediaDuration()); |
316 base::TimeDelta start_seek_time(duration / 4); | 334 base::TimeDelta start_seek_time(duration / 4); |
317 base::TimeDelta seek_time(duration * 3 / 4); | 335 base::TimeDelta seek_time(duration * 3 / 4); |
318 | 336 |
319 Play(); | 337 Play(); |
320 WaitUntilCurrentTimeIsAfter(start_seek_time); | 338 ASSERT_TRUE(WaitUntilCurrentTimeIsAfter(start_seek_time)); |
321 Seek(seek_time); | 339 ASSERT_TRUE(Seek(seek_time)); |
322 EXPECT_GE(pipeline_->GetCurrentTime(), seek_time); | 340 EXPECT_GE(pipeline_->GetCurrentTime(), seek_time); |
323 WaitUntilOnEnded(); | 341 ASSERT_TRUE(WaitUntilOnEnded()); |
324 | 342 |
325 // Make sure seeking after reaching the end works as expected. | 343 // Make sure seeking after reaching the end works as expected. |
326 Seek(seek_time); | 344 ASSERT_TRUE(Seek(seek_time)); |
327 EXPECT_GE(pipeline_->GetCurrentTime(), seek_time); | 345 EXPECT_GE(pipeline_->GetCurrentTime(), seek_time); |
328 WaitUntilOnEnded(); | 346 ASSERT_TRUE(WaitUntilOnEnded()); |
329 } | 347 } |
330 | 348 |
331 // Verify audio decoder & renderer can handle aborted demuxer reads. | 349 // Verify audio decoder & renderer can handle aborted demuxer reads. |
332 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_AudioOnly) { | 350 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_AudioOnly) { |
333 TestSeekDuringRead("bear-320x240-audio-only.webm", 8192, | 351 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-audio-only.webm", 8192, |
334 base::TimeDelta::FromMilliseconds(477), | 352 base::TimeDelta::FromMilliseconds(477), |
335 base::TimeDelta::FromMilliseconds(617), | 353 base::TimeDelta::FromMilliseconds(617), |
336 0x10CA, 19730); | 354 0x10CA, 19730)); |
337 } | 355 } |
338 | 356 |
339 // Verify video decoder & renderer can handle aborted demuxer reads. | 357 // Verify video decoder & renderer can handle aborted demuxer reads. |
340 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) { | 358 TEST_F(PipelineIntegrationTest, ChunkDemuxerAbortRead_VideoOnly) { |
341 TestSeekDuringRead("bear-320x240-video-only.webm", 32768, | 359 ASSERT_TRUE(TestSeekDuringRead("bear-320x240-video-only.webm", 32768, |
342 base::TimeDelta::FromMilliseconds(200), | 360 base::TimeDelta::FromMilliseconds(200), |
343 base::TimeDelta::FromMilliseconds(1668), | 361 base::TimeDelta::FromMilliseconds(1668), |
344 0x1C896, 65536); | 362 0x1C896, 65536)); |
345 } | 363 } |
346 | 364 |
347 } // namespace media | 365 } // namespace media |
OLD | NEW |