OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 <utility> | |
6 | |
7 #include "base/bind.h" | 5 #include "base/bind.h" |
8 #include "base/callback.h" | |
9 #include "base/callback_helpers.h" | |
10 #include "base/debug/stack_trace.h" | 6 #include "base/debug/stack_trace.h" |
11 #include "base/message_loop/message_loop.h" | 7 #include "base/message_loop/message_loop.h" |
12 #include "base/stl_util.h" | |
13 #include "base/strings/string_number_conversions.h" | 8 #include "base/strings/string_number_conversions.h" |
14 #include "base/strings/string_split.h" | 9 #include "base/strings/string_split.h" |
15 #include "base/strings/stringprintf.h" | 10 #include "base/strings/stringprintf.h" |
16 #include "base/synchronization/lock.h" | 11 #include "base/test/simple_test_tick_clock.h" |
17 #include "base/timer/timer.h" | |
18 #include "media/base/data_buffer.h" | |
19 #include "media/base/gmock_callback_support.h" | 12 #include "media/base/gmock_callback_support.h" |
20 #include "media/base/limits.h" | |
21 #include "media/base/mock_filters.h" | 13 #include "media/base/mock_filters.h" |
22 #include "media/base/test_helpers.h" | 14 #include "media/base/test_helpers.h" |
23 #include "media/base/video_frame.h" | 15 #include "media/filters/test_video_frame_scheduler.h" |
24 #include "media/filters/video_renderer_impl.h" | 16 #include "media/filters/video_renderer_impl.h" |
25 #include "testing/gtest/include/gtest/gtest.h" | 17 #include "testing/gtest/include/gtest/gtest.h" |
26 | 18 |
27 using ::testing::_; | 19 using ::testing::_; |
28 using ::testing::AnyNumber; | 20 using ::testing::AnyNumber; |
29 using ::testing::InSequence; | |
30 using ::testing::Invoke; | 21 using ::testing::Invoke; |
31 using ::testing::NiceMock; | 22 using ::testing::NiceMock; |
32 using ::testing::NotNull; | |
33 using ::testing::Return; | |
34 using ::testing::StrictMock; | |
35 | 23 |
36 namespace media { | 24 namespace media { |
37 | 25 |
38 MATCHER_P(HasTimestamp, ms, "") { | 26 static void AssignValue(bool* b, bool value) { |
39 *result_listener << "has timestamp " << arg->timestamp().InMilliseconds(); | 27 *b = value; |
40 return arg->timestamp().InMilliseconds() == ms; | |
41 } | 28 } |
42 | 29 |
43 // Arbitrary value. Has to be larger to cover any timestamp value used in tests. | |
44 static const int kVideoDurationInMs = 1000; | |
45 | |
46 class VideoRendererImplTest : public ::testing::Test { | 30 class VideoRendererImplTest : public ::testing::Test { |
47 public: | 31 public: |
48 VideoRendererImplTest() | 32 VideoRendererImplTest() |
49 : decoder_(new MockVideoDecoder()), | 33 : decoder_(new MockVideoDecoder()), |
50 demuxer_stream_(DemuxerStream::VIDEO) { | 34 scheduler_(new TestVideoFrameScheduler()), |
| 35 tick_clock_(new base::SimpleTestTickClock()), |
| 36 demuxer_stream_(DemuxerStream::VIDEO), |
| 37 max_time_(kNoTimestamp()), |
| 38 decoded_frames_(0), |
| 39 dropped_frames_(0), |
| 40 ended_cb_run_(false) { |
51 ScopedVector<VideoDecoder> decoders; | 41 ScopedVector<VideoDecoder> decoders; |
52 decoders.push_back(decoder_); | 42 decoders.push_back(decoder_); |
53 | 43 |
54 renderer_.reset( | 44 renderer_.reset( |
55 new VideoRendererImpl(message_loop_.message_loop_proxy(), | 45 new VideoRendererImpl(message_loop_.message_loop_proxy(), |
| 46 scoped_ptr<VideoFrameScheduler>(scheduler_), |
56 decoders.Pass(), | 47 decoders.Pass(), |
57 media::SetDecryptorReadyCB(), | 48 media::SetDecryptorReadyCB())); |
58 base::Bind(&StrictMock<MockDisplayCB>::Display, | 49 renderer_->SetTickClockForTesting(scoped_ptr<base::TickClock>(tick_clock_)); |
59 base::Unretained(&mock_display_cb_)), | |
60 true)); | |
61 | 50 |
62 demuxer_stream_.set_video_decoder_config(TestVideoConfig::Normal()); | 51 demuxer_stream_.set_video_decoder_config(TestVideoConfig::Normal()); |
63 | 52 |
64 // We expect these to be called but we don't care how/when. | 53 // We expect these to be called but we don't care how/when. |
65 EXPECT_CALL(demuxer_stream_, Read(_)) | 54 EXPECT_CALL(demuxer_stream_, Read(_)) |
66 .WillRepeatedly(RunCallback<0>(DemuxerStream::kOk, | 55 .WillRepeatedly(RunCallback<0>(DemuxerStream::kOk, |
67 DecoderBuffer::CreateEOSBuffer())); | 56 DecoderBuffer::CreateEOSBuffer())); |
68 EXPECT_CALL(*decoder_, Stop()) | 57 EXPECT_CALL(*decoder_, Stop()) |
69 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::StopRequested)); | 58 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::StopRequested)); |
70 EXPECT_CALL(statistics_cb_object_, OnStatistics(_)) | |
71 .Times(AnyNumber()); | |
72 EXPECT_CALL(*this, OnTimeUpdate(_)) | |
73 .Times(AnyNumber()); | |
74 } | 59 } |
75 | 60 |
76 virtual ~VideoRendererImplTest() {} | 61 virtual ~VideoRendererImplTest() {} |
77 | 62 |
78 // Callbacks passed into Initialize(). | |
79 MOCK_METHOD1(OnTimeUpdate, void(base::TimeDelta)); | |
80 | |
81 void Initialize() { | 63 void Initialize() { |
82 // Monitor decodes from the decoder. | 64 // Monitor decodes from the decoder. |
83 EXPECT_CALL(*decoder_, Decode(_, _)) | 65 EXPECT_CALL(*decoder_, Decode(_, _)) |
84 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::FrameRequested)); | 66 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::FrameRequested)); |
85 | 67 |
86 EXPECT_CALL(*decoder_, Reset(_)) | 68 EXPECT_CALL(*decoder_, Reset(_)) |
87 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::FlushRequested)); | 69 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::FlushRequested)); |
88 | 70 |
89 InSequence s; | |
90 | |
91 EXPECT_CALL(*decoder_, Initialize(_, _)) | 71 EXPECT_CALL(*decoder_, Initialize(_, _)) |
92 .WillOnce(RunCallback<1>(PIPELINE_OK)); | 72 .WillOnce(RunCallback<1>(PIPELINE_OK)); |
93 | 73 |
94 // Set playback rate before anything else happens. | 74 // Set playback rate before anything else happens. |
95 renderer_->SetPlaybackRate(1.0f); | 75 renderer_->SetPlaybackRate(1.0f); |
96 | 76 |
97 // Initialize, we shouldn't have any reads. | 77 // Initialize, we shouldn't have any reads. |
98 InitializeRenderer(PIPELINE_OK); | 78 InitializeRenderer(PIPELINE_OK); |
99 } | 79 } |
100 | 80 |
101 void InitializeRenderer(PipelineStatus expected) { | 81 void InitializeRenderer(PipelineStatus expected) { |
102 SCOPED_TRACE(base::StringPrintf("InitializeRenderer(%d)", expected)); | 82 SCOPED_TRACE(base::StringPrintf("InitializeRenderer(%d)", expected)); |
103 WaitableMessageLoopEvent event; | 83 WaitableMessageLoopEvent event; |
104 CallInitialize(event.GetPipelineStatusCB()); | 84 CallInitialize(event.GetPipelineStatusCB()); |
105 event.RunAndWaitForStatus(expected); | 85 event.RunAndWaitForStatus(expected); |
106 } | 86 } |
107 | 87 |
108 void CallInitialize(const PipelineStatusCB& status_cb) { | 88 void CallInitialize(const PipelineStatusCB& status_cb) { |
109 renderer_->Initialize( | 89 renderer_->Initialize( |
110 &demuxer_stream_, | 90 &demuxer_stream_, |
111 status_cb, | 91 status_cb, |
112 base::Bind(&MockStatisticsCB::OnStatistics, | 92 base::Bind(&VideoRendererImplTest::OnStatisticsUpdate, |
113 base::Unretained(&statistics_cb_object_)), | |
114 base::Bind(&VideoRendererImplTest::OnTimeUpdate, | |
115 base::Unretained(this)), | 93 base::Unretained(this)), |
116 ended_event_.GetClosure(), | 94 base::Bind(&VideoRendererImplTest::OnMaxTimeUpdate, |
| 95 base::Unretained(this)), |
| 96 base::Bind(&AssignValue, &ended_cb_run_, true), |
117 error_event_.GetPipelineStatusCB(), | 97 error_event_.GetPipelineStatusCB(), |
118 base::Bind(&VideoRendererImplTest::GetTime, base::Unretained(this)), | 98 base::Bind(&VideoRendererImplTest::time, base::Unretained(this)), |
119 base::Bind(&VideoRendererImplTest::GetDuration, | 99 base::Bind(&VideoRendererImplTest::duration, base::Unretained(this))); |
120 base::Unretained(this))); | |
121 } | 100 } |
122 | 101 |
123 void Play() { | 102 void Play() { |
124 SCOPED_TRACE("Play()"); | 103 SCOPED_TRACE("Play()"); |
125 WaitableMessageLoopEvent event; | 104 WaitableMessageLoopEvent event; |
126 renderer_->Play(event.GetClosure()); | 105 renderer_->Play(event.GetClosure()); |
127 event.RunAndWait(); | 106 event.RunAndWait(); |
128 } | 107 } |
129 | 108 |
130 void Preroll(int timestamp_ms, PipelineStatus expected) { | 109 void Preroll(int timestamp_ms, PipelineStatus expected) { |
(...skipping 83 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
214 | 193 |
215 CHECK(false) << "Unrecognized decoder buffer token: " << tokens[i]; | 194 CHECK(false) << "Unrecognized decoder buffer token: " << tokens[i]; |
216 } | 195 } |
217 } | 196 } |
218 | 197 |
219 void WaitForError(PipelineStatus expected) { | 198 void WaitForError(PipelineStatus expected) { |
220 SCOPED_TRACE(base::StringPrintf("WaitForError(%d)", expected)); | 199 SCOPED_TRACE(base::StringPrintf("WaitForError(%d)", expected)); |
221 error_event_.RunAndWaitForStatus(expected); | 200 error_event_.RunAndWaitForStatus(expected); |
222 } | 201 } |
223 | 202 |
224 void WaitForEnded() { | |
225 SCOPED_TRACE("WaitForEnded()"); | |
226 ended_event_.RunAndWait(); | |
227 } | |
228 | |
229 void WaitForPendingRead() { | |
230 SCOPED_TRACE("WaitForPendingRead()"); | |
231 if (!read_cb_.is_null()) | |
232 return; | |
233 | |
234 DCHECK(wait_for_pending_read_cb_.is_null()); | |
235 | |
236 WaitableMessageLoopEvent event; | |
237 wait_for_pending_read_cb_ = event.GetClosure(); | |
238 event.RunAndWait(); | |
239 | |
240 DCHECK(!read_cb_.is_null()); | |
241 DCHECK(wait_for_pending_read_cb_.is_null()); | |
242 } | |
243 | |
244 void SatisfyPendingRead() { | 203 void SatisfyPendingRead() { |
245 CHECK(!read_cb_.is_null()); | 204 CHECK(!read_cb_.is_null()); |
246 CHECK(!decode_results_.empty()); | 205 CHECK(!decode_results_.empty()); |
247 | 206 |
248 base::Closure closure = base::Bind( | 207 base::Closure closure = base::Bind( |
249 read_cb_, decode_results_.front().first, | 208 read_cb_, decode_results_.front().first, |
250 decode_results_.front().second); | 209 decode_results_.front().second); |
251 | 210 |
252 read_cb_.Reset(); | 211 read_cb_.Reset(); |
253 decode_results_.pop_front(); | 212 decode_results_.pop_front(); |
254 | 213 |
255 message_loop_.PostTask(FROM_HERE, closure); | 214 message_loop_.PostTask(FROM_HERE, closure); |
256 } | 215 } |
257 | 216 |
258 void AdvanceTimeInMs(int time_ms) { | 217 void DisplayFramesUpTo(int ms) { |
259 DCHECK_EQ(&message_loop_, base::MessageLoop::current()); | 218 scheduler_->DisplayFramesUpTo( |
260 base::AutoLock l(lock_); | 219 base::TimeTicks::FromInternalValue(ms * 1000)); |
261 time_ += base::TimeDelta::FromMilliseconds(time_ms); | 220 } |
262 DCHECK_LE(time_.InMicroseconds(), GetDuration().InMicroseconds()); | 221 |
| 222 void DropFramesUpTo(int ms) { |
| 223 scheduler_->DropFramesUpTo( |
| 224 base::TimeTicks::FromInternalValue(ms * 1000)); |
| 225 } |
| 226 |
| 227 // Returns a string representation of all scheduled frames' timestamps. |
| 228 // Timestamps are in milliseconds. |
| 229 // |
| 230 // Example: "0 10 20" |
| 231 std::string ScheduledFrameTimestamps() { |
| 232 std::string str; |
| 233 for (size_t i = 0; i < scheduler_->scheduled_frames().size(); ++i) { |
| 234 base::TimeDelta timestamp = |
| 235 scheduler_->scheduled_frames()[i].frame->timestamp(); |
| 236 |
| 237 if (i > 0) |
| 238 str += " "; |
| 239 str += base::Int64ToString(timestamp.InMilliseconds()); |
| 240 } |
| 241 return str; |
| 242 } |
| 243 |
| 244 // Returns a string representation of all scheduled frames' wall ticks. Ticks |
| 245 // are represented using their internal value. |
| 246 // |
| 247 // Example: "0 10000 20000" |
| 248 std::string ScheduledFrameWallTicks() { |
| 249 std::string str; |
| 250 for (size_t i = 0; i < scheduler_->scheduled_frames().size(); ++i) { |
| 251 base::TimeTicks wall_ticks = scheduler_->scheduled_frames()[i].wall_ticks; |
| 252 |
| 253 if (i > 0) |
| 254 str += " "; |
| 255 str += base::Int64ToString(wall_ticks.ToInternalValue()); |
| 256 } |
| 257 return str; |
| 258 } |
| 259 |
| 260 bool pending_read() const { return !read_cb_.is_null(); } |
| 261 base::TimeDelta time() const { return time_; } |
| 262 void set_time(base::TimeDelta time) { time_ = time; } |
| 263 base::TimeDelta max_time() const { return max_time_; } |
| 264 int decoded_frames() const { return decoded_frames_; } |
| 265 int dropped_frames() const { return dropped_frames_; } |
| 266 bool ended_cb_run() const { return ended_cb_run_; } |
| 267 |
| 268 base::TimeDelta duration() const { |
| 269 // Arbitrary value. Has to be large to cover any timestamp used in tests. |
| 270 return base::TimeDelta::FromMilliseconds(1000); |
263 } | 271 } |
264 | 272 |
265 protected: | 273 protected: |
266 // Fixture members. | 274 base::MessageLoop message_loop_; |
267 scoped_ptr<VideoRendererImpl> renderer_; | 275 scoped_ptr<VideoRendererImpl> renderer_; |
268 MockVideoDecoder* decoder_; // Owned by |renderer_|. | 276 MockVideoDecoder* decoder_; // Owned by |renderer_|. |
269 NiceMock<MockDemuxerStream> demuxer_stream_; | |
270 MockStatisticsCB statistics_cb_object_; | |
271 | |
272 // Use StrictMock<T> to catch missing/extra display callbacks. | |
273 class MockDisplayCB { | |
274 public: | |
275 MOCK_METHOD1(Display, void(const scoped_refptr<VideoFrame>&)); | |
276 }; | |
277 StrictMock<MockDisplayCB> mock_display_cb_; | |
278 | 277 |
279 private: | 278 private: |
280 base::TimeDelta GetTime() { | |
281 base::AutoLock l(lock_); | |
282 return time_; | |
283 } | |
284 | |
285 base::TimeDelta GetDuration() { | |
286 return base::TimeDelta::FromMilliseconds(kVideoDurationInMs); | |
287 } | |
288 | |
289 void FrameRequested(const scoped_refptr<DecoderBuffer>& buffer, | 279 void FrameRequested(const scoped_refptr<DecoderBuffer>& buffer, |
290 const VideoDecoder::DecodeCB& read_cb) { | 280 const VideoDecoder::DecodeCB& read_cb) { |
291 DCHECK_EQ(&message_loop_, base::MessageLoop::current()); | 281 DCHECK_EQ(&message_loop_, base::MessageLoop::current()); |
292 CHECK(read_cb_.is_null()); | 282 CHECK(read_cb_.is_null()); |
293 read_cb_ = read_cb; | 283 read_cb_ = read_cb; |
294 | 284 |
295 // Wake up WaitForPendingRead() if needed. | |
296 if (!wait_for_pending_read_cb_.is_null()) | |
297 base::ResetAndReturn(&wait_for_pending_read_cb_).Run(); | |
298 | |
299 if (decode_results_.empty()) | 285 if (decode_results_.empty()) |
300 return; | 286 return; |
301 | 287 |
302 SatisfyPendingRead(); | 288 SatisfyPendingRead(); |
303 } | 289 } |
304 | 290 |
305 void FlushRequested(const base::Closure& callback) { | 291 void FlushRequested(const base::Closure& callback) { |
306 DCHECK_EQ(&message_loop_, base::MessageLoop::current()); | 292 DCHECK_EQ(&message_loop_, base::MessageLoop::current()); |
307 decode_results_.clear(); | 293 decode_results_.clear(); |
308 if (!read_cb_.is_null()) { | 294 if (!read_cb_.is_null()) { |
309 QueueFrames("abort"); | 295 QueueFrames("abort"); |
310 SatisfyPendingRead(); | 296 SatisfyPendingRead(); |
311 } | 297 } |
312 | 298 |
313 message_loop_.PostTask(FROM_HERE, callback); | 299 message_loop_.PostTask(FROM_HERE, callback); |
314 } | 300 } |
315 | 301 |
316 void StopRequested() { | 302 void StopRequested() { |
317 DCHECK_EQ(&message_loop_, base::MessageLoop::current()); | 303 DCHECK_EQ(&message_loop_, base::MessageLoop::current()); |
318 decode_results_.clear(); | 304 decode_results_.clear(); |
319 if (!read_cb_.is_null()) { | 305 if (!read_cb_.is_null()) { |
320 QueueFrames("abort"); | 306 QueueFrames("abort"); |
321 SatisfyPendingRead(); | 307 SatisfyPendingRead(); |
322 } | 308 } |
323 } | 309 } |
324 | 310 |
325 base::MessageLoop message_loop_; | 311 void OnMaxTimeUpdate(base::TimeDelta max_time) { max_time_ = max_time; } |
326 | 312 |
327 // Used to protect |time_|. | 313 void OnStatisticsUpdate(const PipelineStatistics& stats) { |
328 base::Lock lock_; | 314 decoded_frames_ = stats.video_frames_decoded; |
329 base::TimeDelta time_; | 315 dropped_frames_ = stats.video_frames_dropped; |
| 316 } |
| 317 |
| 318 TestVideoFrameScheduler* scheduler_; // Owned by |renderer_|. |
| 319 base::SimpleTestTickClock* tick_clock_; // Owned by |renderer_|. |
| 320 NiceMock<MockDemuxerStream> demuxer_stream_; |
330 | 321 |
331 // Used for satisfying reads. | 322 // Used for satisfying reads. |
332 VideoDecoder::DecodeCB read_cb_; | 323 VideoDecoder::DecodeCB read_cb_; |
333 base::TimeDelta next_frame_timestamp_; | 324 base::TimeDelta next_frame_timestamp_; |
334 | 325 |
335 WaitableMessageLoopEvent error_event_; | 326 WaitableMessageLoopEvent error_event_; |
336 WaitableMessageLoopEvent ended_event_; | |
337 | |
338 // Run during FrameRequested() to unblock WaitForPendingRead(). | |
339 base::Closure wait_for_pending_read_cb_; | |
340 | 327 |
341 std::deque<std::pair< | 328 std::deque<std::pair< |
342 VideoDecoder::Status, scoped_refptr<VideoFrame> > > decode_results_; | 329 VideoDecoder::Status, scoped_refptr<VideoFrame> > > decode_results_; |
343 | 330 |
| 331 base::TimeDelta time_; |
| 332 base::TimeDelta max_time_; |
| 333 int decoded_frames_; |
| 334 int dropped_frames_; |
| 335 bool ended_cb_run_; |
| 336 |
344 DISALLOW_COPY_AND_ASSIGN(VideoRendererImplTest); | 337 DISALLOW_COPY_AND_ASSIGN(VideoRendererImplTest); |
345 }; | 338 }; |
346 | 339 |
347 TEST_F(VideoRendererImplTest, DoNothing) { | 340 TEST_F(VideoRendererImplTest, DoNothing) { |
348 // Test that creation and deletion doesn't depend on calls to Initialize() | 341 // Test that creation and deletion doesn't depend on calls to Initialize() |
349 // and/or Stop(). | 342 // and/or Stop(). |
350 } | 343 } |
351 | 344 |
352 TEST_F(VideoRendererImplTest, StopWithoutInitialize) { | 345 TEST_F(VideoRendererImplTest, StopWithoutInitialize) { |
353 Stop(); | 346 Stop(); |
354 } | 347 } |
355 | 348 |
356 TEST_F(VideoRendererImplTest, Initialize) { | 349 TEST_F(VideoRendererImplTest, Initialize) { |
357 Initialize(); | 350 Initialize(); |
358 Shutdown(); | 351 Shutdown(); |
359 } | 352 } |
360 | 353 |
361 TEST_F(VideoRendererImplTest, InitializeAndPreroll) { | |
362 Initialize(); | |
363 QueueFrames("0 10 20 30"); | |
364 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0))); | |
365 Preroll(0, PIPELINE_OK); | |
366 Shutdown(); | |
367 } | |
368 | |
369 static void ExpectNotCalled(PipelineStatus) { | 354 static void ExpectNotCalled(PipelineStatus) { |
370 base::debug::StackTrace stack; | 355 base::debug::StackTrace stack; |
371 ADD_FAILURE() << "Expected callback not to be called\n" << stack.ToString(); | 356 ADD_FAILURE() << "Expected callback not to be called\n" << stack.ToString(); |
372 } | 357 } |
373 | 358 |
374 TEST_F(VideoRendererImplTest, StopWhileInitializing) { | 359 TEST_F(VideoRendererImplTest, StopWhileInitializing) { |
375 EXPECT_CALL(*decoder_, Initialize(_, _)) | 360 EXPECT_CALL(*decoder_, Initialize(_, _)) |
376 .WillOnce(RunCallback<1>(PIPELINE_OK)); | 361 .WillOnce(RunCallback<1>(PIPELINE_OK)); |
377 CallInitialize(base::Bind(&ExpectNotCalled)); | 362 CallInitialize(base::Bind(&ExpectNotCalled)); |
378 Stop(); | 363 Stop(); |
379 | 364 |
380 // ~VideoRendererImpl() will CHECK() if we left anything initialized. | 365 // ~VideoRendererImpl() will CHECK() if we left anything initialized. |
381 } | 366 } |
382 | 367 |
383 TEST_F(VideoRendererImplTest, StopWhileFlushing) { | 368 TEST_F(VideoRendererImplTest, StopWhileFlushing) { |
384 Initialize(); | 369 Initialize(); |
385 Pause(); | 370 Pause(); |
386 renderer_->Flush(base::Bind(&ExpectNotCalled, PIPELINE_OK)); | 371 renderer_->Flush(base::Bind(&ExpectNotCalled, PIPELINE_OK)); |
387 Stop(); | 372 Stop(); |
388 | 373 |
389 // ~VideoRendererImpl() will CHECK() if we left anything initialized. | 374 // ~VideoRendererImpl() will CHECK() if we left anything initialized. |
390 } | 375 } |
391 | 376 |
392 TEST_F(VideoRendererImplTest, Play) { | 377 TEST_F(VideoRendererImplTest, PrerollSchedulesFirstFrame) { |
393 Initialize(); | 378 Initialize(); |
394 QueueFrames("0 10 20 30"); | 379 QueueFrames("0 10 20 30"); |
395 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0))); | |
396 Preroll(0, PIPELINE_OK); | 380 Preroll(0, PIPELINE_OK); |
397 Play(); | 381 |
| 382 EXPECT_EQ("0", ScheduledFrameTimestamps()); |
| 383 EXPECT_EQ("0", ScheduledFrameWallTicks()); |
| 384 |
398 Shutdown(); | 385 Shutdown(); |
399 } | 386 } |
400 | 387 |
401 TEST_F(VideoRendererImplTest, EndOfStream_ClipDuration) { | 388 TEST_F(VideoRendererImplTest, PlaySchedulesAllFrames) { |
402 Initialize(); | 389 Initialize(); |
403 QueueFrames("0 10 20 30"); | 390 QueueFrames("0 10 20 30"); |
404 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0))); | |
405 Preroll(0, PIPELINE_OK); | 391 Preroll(0, PIPELINE_OK); |
406 Play(); | 392 Play(); |
407 | 393 |
408 // Next frame has timestamp way past duration. Its timestamp will be adjusted | 394 EXPECT_EQ("0 10 20 30", ScheduledFrameTimestamps()); |
409 // to match the duration of the video. | 395 EXPECT_EQ("0 10000 20000 30000", ScheduledFrameWallTicks()); |
410 QueueFrames(base::IntToString(kVideoDurationInMs + 1000)); | |
411 | |
412 // Queue the end of stream frame and wait for the last frame to be rendered. | |
413 QueueFrames("eos"); | |
414 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(kVideoDurationInMs))); | |
415 AdvanceTimeInMs(kVideoDurationInMs); | |
416 WaitForEnded(); | |
417 | 396 |
418 Shutdown(); | 397 Shutdown(); |
419 } | 398 } |
| 399 |
| 400 TEST_F(VideoRendererImplTest, PauseResetsScheduledFrames) { |
| 401 Initialize(); |
| 402 QueueFrames("0 10 20 30"); |
| 403 Preroll(0, PIPELINE_OK); |
| 404 Play(); |
| 405 Pause(); |
| 406 |
| 407 EXPECT_EQ("", ScheduledFrameTimestamps()); |
| 408 |
| 409 Shutdown(); |
| 410 } |
| 411 |
| 412 TEST_F(VideoRendererImplTest, SetPlaybackRateReschedulesFrames) { |
| 413 Initialize(); |
| 414 QueueFrames("0 10 20 30"); |
| 415 Preroll(0, PIPELINE_OK); |
| 416 Play(); |
| 417 |
| 418 renderer_->SetPlaybackRate(2.0); |
| 419 |
| 420 // Wall times should be cut in half. |
| 421 EXPECT_EQ("0 10 20 30", ScheduledFrameTimestamps()); |
| 422 EXPECT_EQ("0 5000 10000 15000", ScheduledFrameWallTicks()); |
| 423 |
| 424 renderer_->SetPlaybackRate(0.5); |
| 425 |
| 426 // Wall times should be doubled. |
| 427 EXPECT_EQ("0 10 20 30", ScheduledFrameTimestamps()); |
| 428 EXPECT_EQ("0 20000 40000 60000", ScheduledFrameWallTicks()); |
| 429 |
| 430 Shutdown(); |
| 431 } |
| 432 |
| 433 TEST_F(VideoRendererImplTest, MediaTimeUsedToScheduleFrames) { |
| 434 Initialize(); |
| 435 QueueFrames("0 10 20 30"); |
| 436 Preroll(0, PIPELINE_OK); |
| 437 |
| 438 // Introduce an offset in the media time before playing. |
| 439 set_time(base::TimeDelta::FromMilliseconds(20)); |
| 440 |
| 441 Play(); |
| 442 |
| 443 // All newly scheduled frames should respect the media time. |
| 444 // The first frame is present due to prerolling. |
| 445 EXPECT_EQ("0 10 20 30", ScheduledFrameTimestamps()); |
| 446 EXPECT_EQ("0 -10000 0 10000", ScheduledFrameWallTicks()); |
| 447 |
| 448 Shutdown(); |
| 449 } |
| 450 |
| 451 TEST_F(VideoRendererImplTest, EndedWaitsForLastFrame) { |
| 452 Initialize(); |
| 453 QueueFrames("0 10 20 30 eos"); |
| 454 Preroll(0, PIPELINE_OK); |
| 455 Play(); |
| 456 |
| 457 // Display up to last frame. |
| 458 DisplayFramesUpTo(20); |
| 459 message_loop_.RunUntilIdle(); |
| 460 EXPECT_FALSE(ended_cb_run()); |
| 461 |
| 462 // Display last frame. |
| 463 DisplayFramesUpTo(30); |
| 464 message_loop_.RunUntilIdle(); |
| 465 EXPECT_TRUE(ended_cb_run()); |
| 466 |
| 467 Shutdown(); |
| 468 } |
| 469 |
| 470 TEST_F(VideoRendererImplTest, EndedWaitsForEndOfStream) { |
| 471 Initialize(); |
| 472 QueueFrames("0 10 20 30"); |
| 473 Preroll(0, PIPELINE_OK); |
| 474 Play(); |
| 475 |
| 476 // Display last frame. |
| 477 DisplayFramesUpTo(30); |
| 478 message_loop_.RunUntilIdle(); |
| 479 EXPECT_FALSE(ended_cb_run()); |
| 480 |
| 481 // Deliver end of stream. |
| 482 QueueFrames("eos"); |
| 483 SatisfyPendingRead(); |
| 484 message_loop_.RunUntilIdle(); |
| 485 EXPECT_TRUE(ended_cb_run()); |
| 486 |
| 487 Shutdown(); |
| 488 } |
| 489 |
| 490 TEST_F(VideoRendererImplTest, AdjustTimestampsPastDuration) { |
| 491 Initialize(); |
| 492 QueueFrames("0 10 20 30"); |
| 493 Preroll(0, PIPELINE_OK); |
| 494 Play(); |
| 495 |
| 496 // Last frame has timestamp way past duration. Its timestamp will be adjusted |
| 497 // to match the duration of the video. |
| 498 QueueFrames(base::IntToString((duration() * 10).InMilliseconds())); |
| 499 QueueFrames("eos"); |
| 500 |
| 501 DisplayFramesUpTo(30); |
| 502 message_loop_.RunUntilIdle(); |
| 503 |
| 504 EXPECT_EQ("1000", ScheduledFrameTimestamps()); |
| 505 |
| 506 Shutdown(); |
| 507 } |
| 508 |
| 509 TEST_F(VideoRendererImplTest, IncomingFramesUpdateMaxTime) { |
| 510 EXPECT_EQ(kNoTimestamp(), max_time()); |
| 511 |
| 512 Initialize(); |
| 513 QueueFrames("0 10 20 30"); |
| 514 Preroll(0, PIPELINE_OK); |
| 515 |
| 516 EXPECT_EQ(base::TimeDelta::FromMilliseconds(30), max_time()); |
| 517 |
| 518 Shutdown(); |
| 519 } |
| 520 |
| 521 TEST_F(VideoRendererImplTest, EndOfStreamSetsMaxTimeToDuration) { |
| 522 EXPECT_EQ(kNoTimestamp(), max_time()); |
| 523 |
| 524 Initialize(); |
| 525 QueueFrames("0 10 20 eos"); |
| 526 Preroll(0, PIPELINE_OK); |
| 527 |
| 528 EXPECT_EQ(duration(), max_time()); |
| 529 |
| 530 Shutdown(); |
| 531 } |
| 532 |
| 533 TEST_F(VideoRendererImplTest, DisplayedFramesIncrementStatistics) { |
| 534 Initialize(); |
| 535 QueueFrames("0 10 20 30"); |
| 536 Preroll(0, PIPELINE_OK); |
| 537 Play(); |
| 538 |
| 539 EXPECT_EQ(0, decoded_frames()); |
| 540 EXPECT_EQ(0, dropped_frames()); |
| 541 |
| 542 DisplayFramesUpTo(0); |
| 543 |
| 544 EXPECT_EQ(1, decoded_frames()); |
| 545 EXPECT_EQ(0, dropped_frames()); |
| 546 |
| 547 Shutdown(); |
| 548 } |
| 549 |
| 550 TEST_F(VideoRendererImplTest, DroppedFramesIncrementStatistics) { |
| 551 Initialize(); |
| 552 QueueFrames("0 10 20 30"); |
| 553 Preroll(0, PIPELINE_OK); |
| 554 Play(); |
| 555 |
| 556 EXPECT_EQ(0, decoded_frames()); |
| 557 EXPECT_EQ(0, dropped_frames()); |
| 558 |
| 559 DropFramesUpTo(0); |
| 560 |
| 561 EXPECT_EQ(1, decoded_frames()); |
| 562 EXPECT_EQ(1, dropped_frames()); |
| 563 |
| 564 Shutdown(); |
| 565 } |
420 | 566 |
421 TEST_F(VideoRendererImplTest, DecodeError_Playing) { | 567 TEST_F(VideoRendererImplTest, DecodeError_Playing) { |
422 Initialize(); | 568 Initialize(); |
423 QueueFrames("0 10 20 30"); | 569 QueueFrames("0 10 20 30"); |
424 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0))); | |
425 Preroll(0, PIPELINE_OK); | 570 Preroll(0, PIPELINE_OK); |
426 Play(); | 571 Play(); |
427 | 572 |
| 573 DisplayFramesUpTo(3); |
| 574 EXPECT_TRUE(pending_read()); |
| 575 |
428 QueueFrames("error"); | 576 QueueFrames("error"); |
429 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(10))); | 577 SatisfyPendingRead(); |
430 AdvanceTimeInMs(10); | |
431 WaitForError(PIPELINE_ERROR_DECODE); | 578 WaitForError(PIPELINE_ERROR_DECODE); |
432 Shutdown(); | 579 Shutdown(); |
433 } | 580 } |
434 | 581 |
435 TEST_F(VideoRendererImplTest, DecodeError_DuringPreroll) { | 582 TEST_F(VideoRendererImplTest, DecodeError_DuringPreroll) { |
436 Initialize(); | 583 Initialize(); |
437 QueueFrames("error"); | 584 QueueFrames("error"); |
438 Preroll(0, PIPELINE_ERROR_DECODE); | 585 Preroll(0, PIPELINE_ERROR_DECODE); |
439 Shutdown(); | 586 Shutdown(); |
440 } | 587 } |
441 | 588 |
442 TEST_F(VideoRendererImplTest, Preroll_Exact) { | 589 TEST_F(VideoRendererImplTest, Preroll_Exact) { |
443 Initialize(); | 590 Initialize(); |
444 QueueFrames("50 60 70 80 90"); | 591 QueueFrames("50 60 70 80 90"); |
445 | |
446 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(60))); | |
447 Preroll(60, PIPELINE_OK); | 592 Preroll(60, PIPELINE_OK); |
| 593 EXPECT_EQ("60", ScheduledFrameTimestamps()); |
448 Shutdown(); | 594 Shutdown(); |
449 } | 595 } |
450 | 596 |
451 TEST_F(VideoRendererImplTest, Preroll_RightBefore) { | 597 TEST_F(VideoRendererImplTest, Preroll_RightBefore) { |
452 Initialize(); | 598 Initialize(); |
453 QueueFrames("50 60 70 80 90"); | 599 QueueFrames("50 60 70 80 90"); |
454 | |
455 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(50))); | |
456 Preroll(59, PIPELINE_OK); | 600 Preroll(59, PIPELINE_OK); |
| 601 EXPECT_EQ("50", ScheduledFrameTimestamps()); |
457 Shutdown(); | 602 Shutdown(); |
458 } | 603 } |
459 | 604 |
460 TEST_F(VideoRendererImplTest, Preroll_RightAfter) { | 605 TEST_F(VideoRendererImplTest, Preroll_RightAfter) { |
461 Initialize(); | 606 Initialize(); |
462 QueueFrames("50 60 70 80 90"); | 607 QueueFrames("50 60 70 80 90"); |
463 | |
464 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(60))); | |
465 Preroll(61, PIPELINE_OK); | 608 Preroll(61, PIPELINE_OK); |
| 609 EXPECT_EQ("60", ScheduledFrameTimestamps()); |
466 Shutdown(); | 610 Shutdown(); |
467 } | 611 } |
468 | 612 |
469 TEST_F(VideoRendererImplTest, PlayAfterPreroll) { | 613 TEST_F(VideoRendererImplTest, PlayAfterPreroll) { |
470 Initialize(); | 614 Initialize(); |
471 QueueFrames("0 10 20 30"); | 615 QueueFrames("0 10 20 30"); |
472 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0))); | |
473 Preroll(0, PIPELINE_OK); | 616 Preroll(0, PIPELINE_OK); |
474 Play(); | 617 Play(); |
475 | 618 |
476 // Advance time past prerolled time to trigger a Read(). | 619 DisplayFramesUpTo(0); |
477 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(10))); | 620 EXPECT_TRUE(pending_read()); |
478 AdvanceTimeInMs(10); | 621 |
479 WaitForPendingRead(); | |
480 Shutdown(); | 622 Shutdown(); |
481 } | 623 } |
482 | 624 |
483 TEST_F(VideoRendererImplTest, Rebuffer) { | 625 TEST_F(VideoRendererImplTest, Rebuffer) { |
484 Initialize(); | 626 Initialize(); |
485 QueueFrames("0 10 20 30"); | 627 QueueFrames("0 10 20 30"); |
486 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0))); | |
487 Preroll(0, PIPELINE_OK); | 628 Preroll(0, PIPELINE_OK); |
488 Play(); | 629 Play(); |
489 | 630 |
490 // Advance time past prerolled time drain the ready frame queue. | 631 // Display all frames to empty frame buffer. |
491 AdvanceTimeInMs(50); | 632 DisplayFramesUpTo(30); |
492 WaitForPendingRead(); | 633 EXPECT_TRUE(pending_read()); |
493 | 634 |
494 // Simulate a Pause/Preroll/Play rebuffer sequence. | 635 // Simulate a Pause/Preroll/Play rebuffer sequence. |
495 Pause(); | 636 Pause(); |
496 | 637 |
497 WaitableMessageLoopEvent event; | 638 WaitableMessageLoopEvent event; |
498 renderer_->Preroll(kNoTimestamp(), | 639 renderer_->Preroll(kNoTimestamp(), |
499 event.GetPipelineStatusCB()); | 640 event.GetPipelineStatusCB()); |
500 | 641 |
501 // Queue enough frames to satisfy preroll. | 642 // Queue enough frames to satisfy preroll. |
502 QueueFrames("40 50 60 70"); | 643 QueueFrames("40 50 60 70"); |
503 SatisfyPendingRead(); | 644 SatisfyPendingRead(); |
| 645 event.RunAndWaitForStatus(PIPELINE_OK); |
504 | 646 |
505 // TODO(scherkus): We shouldn't display the next ready frame in a rebuffer | 647 // TODO(scherkus): We shouldn't display the next ready frame in a rebuffer |
506 // situation, see http://crbug.com/365516 | 648 // situation, see http://crbug.com/365516 |
507 EXPECT_CALL(mock_display_cb_, Display(_)); | 649 EXPECT_EQ("40", ScheduledFrameTimestamps()); |
508 | |
509 event.RunAndWaitForStatus(PIPELINE_OK); | |
510 | 650 |
511 Play(); | 651 Play(); |
512 | 652 |
513 Shutdown(); | 653 Shutdown(); |
514 } | 654 } |
515 | 655 |
516 TEST_F(VideoRendererImplTest, Rebuffer_AlreadyHaveEnoughFrames) { | 656 TEST_F(VideoRendererImplTest, Rebuffer_AlreadyHaveEnoughFrames) { |
517 Initialize(); | 657 Initialize(); |
518 QueueFrames("0 10 20 30"); | 658 QueueFrames("0 10 20 30"); |
519 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0))); | |
520 Preroll(0, PIPELINE_OK); | 659 Preroll(0, PIPELINE_OK); |
521 | |
522 // Queue an extra frame so that we'll have enough frames to satisfy | |
523 // preroll even after the first frame is painted. | |
524 QueueFrames("40"); | |
525 Play(); | 660 Play(); |
526 | 661 |
527 // Simulate a Pause/Preroll/Play rebuffer sequence. | 662 // Simulate a Pause/Preroll/Play rebuffer sequence. |
528 Pause(); | 663 Pause(); |
529 | 664 |
530 // TODO(scherkus): We shouldn't display the next ready frame in a rebuffer | |
531 // situation, see http://crbug.com/365516 | |
532 EXPECT_CALL(mock_display_cb_, Display(_)); | |
533 | |
534 WaitableMessageLoopEvent event; | 665 WaitableMessageLoopEvent event; |
535 renderer_->Preroll(kNoTimestamp(), | 666 renderer_->Preroll(kNoTimestamp(), |
536 event.GetPipelineStatusCB()); | 667 event.GetPipelineStatusCB()); |
| 668 event.RunAndWaitForStatus(PIPELINE_OK); |
537 | 669 |
538 event.RunAndWaitForStatus(PIPELINE_OK); | 670 // TODO(scherkus): We shouldn't display the next ready frame in a rebuffer |
| 671 // situation, see http://crbug.com/365516 |
| 672 EXPECT_EQ("0", ScheduledFrameTimestamps()); |
539 | 673 |
540 Play(); | 674 Play(); |
541 | 675 |
542 Shutdown(); | 676 Shutdown(); |
543 } | 677 } |
544 | 678 |
545 // Verify that a late decoder response doesn't break invariants in the renderer. | 679 // Verify that a late decoder response doesn't break invariants in the renderer. |
546 TEST_F(VideoRendererImplTest, StopDuringOutstandingRead) { | 680 TEST_F(VideoRendererImplTest, StopDuringOutstandingRead) { |
547 Initialize(); | 681 Initialize(); |
548 QueueFrames("0 10 20 30"); | 682 QueueFrames("0 10 20 30"); |
549 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0))); | |
550 Preroll(0, PIPELINE_OK); | 683 Preroll(0, PIPELINE_OK); |
551 Play(); | 684 Play(); |
552 | 685 |
553 // Advance time a bit to trigger a Read(). | 686 DisplayFramesUpTo(0); |
554 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(10))); | 687 EXPECT_TRUE(pending_read()); |
555 AdvanceTimeInMs(10); | |
556 WaitForPendingRead(); | |
557 | 688 |
558 WaitableMessageLoopEvent event; | 689 WaitableMessageLoopEvent event; |
559 renderer_->Stop(event.GetClosure()); | 690 renderer_->Stop(event.GetClosure()); |
560 event.RunAndWait(); | 691 event.RunAndWait(); |
561 } | 692 } |
562 | 693 |
563 TEST_F(VideoRendererImplTest, AbortPendingRead_Playing) { | 694 TEST_F(VideoRendererImplTest, AbortPendingRead_Playing) { |
564 Initialize(); | 695 Initialize(); |
565 QueueFrames("0 10 20 30"); | 696 QueueFrames("0 10 20 30"); |
566 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0))); | |
567 Preroll(0, PIPELINE_OK); | 697 Preroll(0, PIPELINE_OK); |
568 Play(); | 698 Play(); |
569 | 699 |
570 // Advance time a bit to trigger a Read(). | 700 DisplayFramesUpTo(0); |
571 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(10))); | 701 EXPECT_TRUE(pending_read()); |
572 AdvanceTimeInMs(10); | |
573 WaitForPendingRead(); | |
574 QueueFrames("abort"); | 702 QueueFrames("abort"); |
575 SatisfyPendingRead(); | 703 SatisfyPendingRead(); |
576 | 704 |
577 Pause(); | 705 Pause(); |
578 Flush(); | 706 Flush(); |
579 QueueFrames("60 70 80 90"); | 707 QueueFrames("60 70 80 90"); |
580 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(60))); | |
581 Preroll(60, PIPELINE_OK); | 708 Preroll(60, PIPELINE_OK); |
582 Shutdown(); | 709 Shutdown(); |
583 } | 710 } |
584 | 711 |
585 TEST_F(VideoRendererImplTest, AbortPendingRead_Flush) { | 712 TEST_F(VideoRendererImplTest, AbortPendingRead_Flush) { |
586 Initialize(); | 713 Initialize(); |
587 QueueFrames("0 10 20 30"); | 714 QueueFrames("0 10 20 30"); |
588 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0))); | |
589 Preroll(0, PIPELINE_OK); | 715 Preroll(0, PIPELINE_OK); |
590 Play(); | 716 Play(); |
591 | 717 |
592 // Advance time a bit to trigger a Read(). | 718 DisplayFramesUpTo(0); |
593 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(10))); | 719 EXPECT_TRUE(pending_read()); |
594 AdvanceTimeInMs(10); | |
595 WaitForPendingRead(); | |
596 | 720 |
597 Pause(); | 721 Pause(); |
598 Flush(); | 722 Flush(); |
599 Shutdown(); | 723 Shutdown(); |
600 } | 724 } |
601 | 725 |
602 TEST_F(VideoRendererImplTest, AbortPendingRead_Preroll) { | 726 TEST_F(VideoRendererImplTest, AbortPendingRead_Preroll) { |
603 Initialize(); | 727 Initialize(); |
604 QueueFrames("0 10 abort"); | 728 QueueFrames("0 10 abort"); |
605 EXPECT_CALL(mock_display_cb_, Display(HasTimestamp(0))); | |
606 Preroll(0, PIPELINE_OK); | 729 Preroll(0, PIPELINE_OK); |
607 Shutdown(); | 730 Shutdown(); |
608 } | 731 } |
609 | 732 |
610 TEST_F(VideoRendererImplTest, VideoDecoder_InitFailure) { | 733 TEST_F(VideoRendererImplTest, VideoDecoder_InitFailure) { |
611 InSequence s; | |
612 | |
613 EXPECT_CALL(*decoder_, Initialize(_, _)) | 734 EXPECT_CALL(*decoder_, Initialize(_, _)) |
614 .WillOnce(RunCallback<1>(DECODER_ERROR_NOT_SUPPORTED)); | 735 .WillOnce(RunCallback<1>(DECODER_ERROR_NOT_SUPPORTED)); |
615 InitializeRenderer(DECODER_ERROR_NOT_SUPPORTED); | 736 InitializeRenderer(DECODER_ERROR_NOT_SUPPORTED); |
616 | 737 |
617 Stop(); | 738 Stop(); |
618 } | 739 } |
619 | 740 |
620 } // namespace media | 741 } // namespace media |
OLD | NEW |