Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1565)

Side by Side Diff: media/filters/pipeline_integration_test.cc

Issue 9309004: Fix PipelineIntegrationTest so it can't hang on decoder errors. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698