Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / media / renderers / video_renderer_impl_unittest.cc
blob86f767f606b661dff9c1b7b3ee7875d2f9830b12
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
3 // found in the LICENSE file.
5 #include <utility>
7 #include "base/bind.h"
8 #include "base/callback.h"
9 #include "base/callback_helpers.h"
10 #include "base/debug/stack_trace.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/stl_util.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_split.h"
15 #include "base/strings/stringprintf.h"
16 #include "base/synchronization/lock.h"
17 #include "base/test/simple_test_tick_clock.h"
18 #include "media/base/data_buffer.h"
19 #include "media/base/gmock_callback_support.h"
20 #include "media/base/limits.h"
21 #include "media/base/mock_filters.h"
22 #include "media/base/test_helpers.h"
23 #include "media/base/video_frame.h"
24 #include "media/renderers/video_renderer_impl.h"
25 #include "testing/gtest/include/gtest/gtest.h"
27 using ::testing::_;
28 using ::testing::AnyNumber;
29 using ::testing::Invoke;
30 using ::testing::Mock;
31 using ::testing::NiceMock;
32 using ::testing::Return;
33 using ::testing::SaveArg;
34 using ::testing::StrictMock;
36 namespace media {
38 ACTION_P(RunClosure, closure) {
39 closure.Run();
42 MATCHER_P(HasTimestamp, ms, "") {
43 *result_listener << "has timestamp " << arg->timestamp().InMilliseconds();
44 return arg->timestamp().InMilliseconds() == ms;
47 class VideoRendererImplTest : public ::testing::Test {
48 public:
49 VideoRendererImplTest()
50 : tick_clock_(new base::SimpleTestTickClock()),
51 decoder_(new MockVideoDecoder()),
52 demuxer_stream_(DemuxerStream::VIDEO) {
53 ScopedVector<VideoDecoder> decoders;
54 decoders.push_back(decoder_);
56 renderer_.reset(new VideoRendererImpl(message_loop_.message_loop_proxy(),
57 &mock_cb_,
58 decoders.Pass(), true,
59 new MediaLog()));
60 renderer_->SetTickClockForTesting(scoped_ptr<base::TickClock>(tick_clock_));
62 // Start wallclock time at a non-zero value.
63 AdvanceWallclockTimeInMs(12345);
65 demuxer_stream_.set_video_decoder_config(TestVideoConfig::Normal());
67 // We expect these to be called but we don't care how/when.
68 EXPECT_CALL(demuxer_stream_, Read(_)).WillRepeatedly(
69 RunCallback<0>(DemuxerStream::kOk,
70 scoped_refptr<DecoderBuffer>(new DecoderBuffer(0))));
73 virtual ~VideoRendererImplTest() {}
75 void Initialize() {
76 InitializeWithLowDelay(false);
79 void InitializeWithLowDelay(bool low_delay) {
80 // Monitor decodes from the decoder.
81 EXPECT_CALL(*decoder_, Decode(_, _))
82 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::DecodeRequested));
84 EXPECT_CALL(*decoder_, Reset(_))
85 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::FlushRequested));
87 // Initialize, we shouldn't have any reads.
88 InitializeRenderer(PIPELINE_OK, low_delay);
91 void InitializeRenderer(PipelineStatus expected, bool low_delay) {
92 SCOPED_TRACE(base::StringPrintf("InitializeRenderer(%d)", expected));
93 WaitableMessageLoopEvent event;
94 CallInitialize(event.GetPipelineStatusCB(), low_delay, expected);
95 event.RunAndWaitForStatus(expected);
98 void CallInitialize(const PipelineStatusCB& status_cb,
99 bool low_delay,
100 PipelineStatus decoder_status) {
101 if (low_delay)
102 demuxer_stream_.set_liveness(DemuxerStream::LIVENESS_LIVE);
103 EXPECT_CALL(*decoder_, Initialize(_, _, _, _)).WillOnce(
104 DoAll(SaveArg<3>(&output_cb_), RunCallback<2>(decoder_status)));
105 EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
106 renderer_->Initialize(
107 &demuxer_stream_, status_cb, media::SetDecryptorReadyCB(),
108 base::Bind(&VideoRendererImplTest::OnStatisticsUpdate,
109 base::Unretained(this)),
110 base::Bind(&StrictMock<MockCB>::BufferingStateChange,
111 base::Unretained(&mock_cb_)),
112 ended_event_.GetClosure(), error_event_.GetPipelineStatusCB(),
113 base::Bind(&VideoRendererImplTest::GetWallClockTime,
114 base::Unretained(this)),
115 base::Bind(&VideoRendererImplTest::OnWaitingForDecryptionKey,
116 base::Unretained(this)));
119 void StartPlayingFrom(int milliseconds) {
120 SCOPED_TRACE(base::StringPrintf("StartPlayingFrom(%d)", milliseconds));
121 renderer_->StartPlayingFrom(
122 base::TimeDelta::FromMilliseconds(milliseconds));
123 message_loop_.RunUntilIdle();
126 void Flush() {
127 SCOPED_TRACE("Flush()");
128 WaitableMessageLoopEvent event;
129 renderer_->Flush(event.GetClosure());
130 event.RunAndWait();
133 void Destroy() {
134 SCOPED_TRACE("Destroy()");
135 renderer_.reset();
136 message_loop_.RunUntilIdle();
139 // Parses a string representation of video frames and generates corresponding
140 // VideoFrame objects in |decode_results_|.
142 // Syntax:
143 // nn - Queue a decoder buffer with timestamp nn * 1000us
144 // abort - Queue an aborted read
145 // error - Queue a decoder error
147 // Examples:
148 // A clip that is four frames long: "0 10 20 30"
149 // A clip that has a decode error: "60 70 error"
150 void QueueFrames(const std::string& str) {
151 std::vector<std::string> tokens;
152 base::SplitString(str, ' ', &tokens);
153 for (size_t i = 0; i < tokens.size(); ++i) {
154 if (tokens[i] == "abort") {
155 scoped_refptr<VideoFrame> null_frame;
156 decode_results_.push_back(
157 std::make_pair(VideoDecoder::kAborted, null_frame));
158 continue;
161 if (tokens[i] == "error") {
162 scoped_refptr<VideoFrame> null_frame;
163 decode_results_.push_back(
164 std::make_pair(VideoDecoder::kDecodeError, null_frame));
165 continue;
168 int timestamp_in_ms = 0;
169 if (base::StringToInt(tokens[i], &timestamp_in_ms)) {
170 gfx::Size natural_size = TestVideoConfig::NormalCodedSize();
171 scoped_refptr<VideoFrame> frame = VideoFrame::CreateFrame(
172 VideoFrame::YV12,
173 natural_size,
174 gfx::Rect(natural_size),
175 natural_size,
176 base::TimeDelta::FromMilliseconds(timestamp_in_ms));
177 decode_results_.push_back(std::make_pair(VideoDecoder::kOk, frame));
178 continue;
181 CHECK(false) << "Unrecognized decoder buffer token: " << tokens[i];
185 bool IsReadPending() {
186 return !decode_cb_.is_null();
189 void WaitForError(PipelineStatus expected) {
190 SCOPED_TRACE(base::StringPrintf("WaitForError(%d)", expected));
191 error_event_.RunAndWaitForStatus(expected);
194 void WaitForEnded() {
195 SCOPED_TRACE("WaitForEnded()");
196 ended_event_.RunAndWait();
199 void WaitForPendingRead() {
200 SCOPED_TRACE("WaitForPendingRead()");
201 if (!decode_cb_.is_null())
202 return;
204 DCHECK(wait_for_pending_decode_cb_.is_null());
206 WaitableMessageLoopEvent event;
207 wait_for_pending_decode_cb_ = event.GetClosure();
208 event.RunAndWait();
210 DCHECK(!decode_cb_.is_null());
211 DCHECK(wait_for_pending_decode_cb_.is_null());
214 void SatisfyPendingRead() {
215 CHECK(!decode_cb_.is_null());
216 CHECK(!decode_results_.empty());
218 // Post tasks for OutputCB and DecodeCB.
219 scoped_refptr<VideoFrame> frame = decode_results_.front().second;
220 if (frame.get())
221 message_loop_.PostTask(FROM_HERE, base::Bind(output_cb_, frame));
222 message_loop_.PostTask(
223 FROM_HERE, base::Bind(base::ResetAndReturn(&decode_cb_),
224 decode_results_.front().first));
225 decode_results_.pop_front();
228 void SatisfyPendingReadWithEndOfStream() {
229 DCHECK(!decode_cb_.is_null());
231 // Return EOS buffer to trigger EOS frame.
232 EXPECT_CALL(demuxer_stream_, Read(_))
233 .WillOnce(RunCallback<0>(DemuxerStream::kOk,
234 DecoderBuffer::CreateEOSBuffer()));
236 // Satify pending |decode_cb_| to trigger a new DemuxerStream::Read().
237 message_loop_.PostTask(
238 FROM_HERE,
239 base::Bind(base::ResetAndReturn(&decode_cb_), VideoDecoder::kOk));
241 WaitForPendingRead();
243 message_loop_.PostTask(
244 FROM_HERE,
245 base::Bind(base::ResetAndReturn(&decode_cb_), VideoDecoder::kOk));
248 void AdvanceWallclockTimeInMs(int time_ms) {
249 DCHECK_EQ(&message_loop_, base::MessageLoop::current());
250 base::AutoLock l(lock_);
251 tick_clock_->Advance(base::TimeDelta::FromMilliseconds(time_ms));
254 void AdvanceTimeInMs(int time_ms) {
255 DCHECK_EQ(&message_loop_, base::MessageLoop::current());
256 base::AutoLock l(lock_);
257 time_ += base::TimeDelta::FromMilliseconds(time_ms);
260 protected:
261 // Fixture members.
262 scoped_ptr<VideoRendererImpl> renderer_;
263 base::SimpleTestTickClock* tick_clock_; // Owned by |renderer_|.
264 MockVideoDecoder* decoder_; // Owned by |renderer_|.
265 NiceMock<MockDemuxerStream> demuxer_stream_;
267 // Use StrictMock<T> to catch missing/extra callbacks.
268 // TODO(dalecurtis): Mocks won't be useful for the new rendering path, we'll
269 // need fake callback generators like we have for the audio path.
270 // http://crbug.com/473424
271 class MockCB : public VideoRendererSink {
272 public:
273 MOCK_METHOD1(Start, void(VideoRendererSink::RenderCallback*));
274 MOCK_METHOD0(Stop, void());
275 MOCK_METHOD1(PaintFrameUsingOldRenderingPath,
276 void(const scoped_refptr<VideoFrame>&));
277 MOCK_METHOD1(BufferingStateChange, void(BufferingState));
279 StrictMock<MockCB> mock_cb_;
281 private:
282 base::TimeTicks GetWallClockTime(base::TimeDelta time) {
283 base::AutoLock l(lock_);
284 return tick_clock_->NowTicks() + (time - time_);
287 void DecodeRequested(const scoped_refptr<DecoderBuffer>& buffer,
288 const VideoDecoder::DecodeCB& decode_cb) {
289 DCHECK_EQ(&message_loop_, base::MessageLoop::current());
290 CHECK(decode_cb_.is_null());
291 decode_cb_ = decode_cb;
293 // Wake up WaitForPendingRead() if needed.
294 if (!wait_for_pending_decode_cb_.is_null())
295 base::ResetAndReturn(&wait_for_pending_decode_cb_).Run();
297 if (decode_results_.empty())
298 return;
300 SatisfyPendingRead();
303 void FlushRequested(const base::Closure& callback) {
304 DCHECK_EQ(&message_loop_, base::MessageLoop::current());
305 decode_results_.clear();
306 if (!decode_cb_.is_null()) {
307 QueueFrames("abort");
308 SatisfyPendingRead();
311 message_loop_.PostTask(FROM_HERE, callback);
314 void OnStatisticsUpdate(const PipelineStatistics& stats) {}
316 MOCK_METHOD0(OnWaitingForDecryptionKey, void(void));
318 base::MessageLoop message_loop_;
320 // Used to protect |time_|.
321 base::Lock lock_;
322 base::TimeDelta time_;
324 // Used for satisfying reads.
325 VideoDecoder::OutputCB output_cb_;
326 VideoDecoder::DecodeCB decode_cb_;
327 base::TimeDelta next_frame_timestamp_;
329 WaitableMessageLoopEvent error_event_;
330 WaitableMessageLoopEvent ended_event_;
332 // Run during DecodeRequested() to unblock WaitForPendingRead().
333 base::Closure wait_for_pending_decode_cb_;
335 std::deque<std::pair<
336 VideoDecoder::Status, scoped_refptr<VideoFrame> > > decode_results_;
338 DISALLOW_COPY_AND_ASSIGN(VideoRendererImplTest);
341 TEST_F(VideoRendererImplTest, DoNothing) {
342 // Test that creation and deletion doesn't depend on calls to Initialize()
343 // and/or Destroy().
346 TEST_F(VideoRendererImplTest, DestroyWithoutInitialize) {
347 Destroy();
350 TEST_F(VideoRendererImplTest, Initialize) {
351 Initialize();
352 Destroy();
355 TEST_F(VideoRendererImplTest, InitializeAndStartPlayingFrom) {
356 Initialize();
357 QueueFrames("0 10 20 30");
358 EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0)));
359 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
360 StartPlayingFrom(0);
361 Destroy();
364 TEST_F(VideoRendererImplTest, DestroyWhileInitializing) {
365 CallInitialize(NewExpectedStatusCB(PIPELINE_ERROR_ABORT), false, PIPELINE_OK);
366 Destroy();
369 TEST_F(VideoRendererImplTest, DestroyWhileFlushing) {
370 Initialize();
371 QueueFrames("0 10 20 30");
372 EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0)));
373 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
374 StartPlayingFrom(0);
375 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING));
376 renderer_->Flush(NewExpectedClosure());
377 Destroy();
380 TEST_F(VideoRendererImplTest, Play) {
381 Initialize();
382 QueueFrames("0 10 20 30");
383 EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0)));
384 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
385 StartPlayingFrom(0);
386 Destroy();
389 TEST_F(VideoRendererImplTest, FlushWithNothingBuffered) {
390 Initialize();
391 StartPlayingFrom(0);
393 // We shouldn't expect a buffering state change since we never reached
394 // BUFFERING_HAVE_ENOUGH.
395 Flush();
396 Destroy();
399 TEST_F(VideoRendererImplTest, DecodeError_Playing) {
400 Initialize();
401 QueueFrames("0 10 20 30");
402 EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0)));
403 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
404 StartPlayingFrom(0);
406 QueueFrames("error");
407 SatisfyPendingRead();
408 WaitForError(PIPELINE_ERROR_DECODE);
409 Destroy();
412 TEST_F(VideoRendererImplTest, DecodeError_DuringStartPlayingFrom) {
413 Initialize();
414 QueueFrames("error");
415 StartPlayingFrom(0);
416 Destroy();
419 TEST_F(VideoRendererImplTest, StartPlayingFrom_Exact) {
420 Initialize();
421 QueueFrames("50 60 70 80 90");
423 EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(60)));
424 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
425 StartPlayingFrom(60);
426 Destroy();
429 TEST_F(VideoRendererImplTest, StartPlayingFrom_RightBefore) {
430 Initialize();
431 QueueFrames("50 60 70 80 90");
433 EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(50)));
434 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
435 StartPlayingFrom(59);
436 Destroy();
439 TEST_F(VideoRendererImplTest, StartPlayingFrom_RightAfter) {
440 Initialize();
441 QueueFrames("50 60 70 80 90");
443 EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(60)));
444 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
445 StartPlayingFrom(61);
446 Destroy();
449 TEST_F(VideoRendererImplTest, StartPlayingFrom_LowDelay) {
450 // In low-delay mode only one frame is required to finish preroll.
451 InitializeWithLowDelay(true);
452 QueueFrames("0");
454 // Expect some amount of have enough/nothing due to only requiring one frame.
455 EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0)));
456 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH))
457 .Times(AnyNumber());
458 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING))
459 .Times(AnyNumber());
460 StartPlayingFrom(0);
462 QueueFrames("10");
463 SatisfyPendingRead();
465 WaitableMessageLoopEvent event;
466 EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(10)))
467 .WillOnce(RunClosure(event.GetClosure()));
468 AdvanceTimeInMs(10);
469 event.RunAndWait();
471 Destroy();
474 // Verify that a late decoder response doesn't break invariants in the renderer.
475 TEST_F(VideoRendererImplTest, DestroyDuringOutstandingRead) {
476 Initialize();
477 QueueFrames("0 10 20 30");
478 EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0)));
479 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH));
480 StartPlayingFrom(0);
482 // Check that there is an outstanding Read() request.
483 EXPECT_TRUE(IsReadPending());
485 Destroy();
488 TEST_F(VideoRendererImplTest, VideoDecoder_InitFailure) {
489 InitializeRenderer(DECODER_ERROR_NOT_SUPPORTED, false);
490 Destroy();
493 TEST_F(VideoRendererImplTest, Underflow) {
494 Initialize();
495 QueueFrames("0 10 20 30");
498 WaitableMessageLoopEvent event;
499 EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(0)));
500 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH))
501 .WillOnce(RunClosure(event.GetClosure()));
502 StartPlayingFrom(0);
503 event.RunAndWait();
504 Mock::VerifyAndClearExpectations(&mock_cb_);
507 // Advance time slightly, but enough to exceed the duration of the last frame.
508 // Frames should be dropped and we should NOT signal having nothing.
510 SCOPED_TRACE("Waiting for frame drops");
511 WaitableMessageLoopEvent event;
512 EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(10)))
513 .Times(0);
514 EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(20)))
515 .Times(0);
516 EXPECT_CALL(mock_cb_, PaintFrameUsingOldRenderingPath(HasTimestamp(30)))
517 .WillOnce(RunClosure(event.GetClosure()));
518 AdvanceTimeInMs(31);
519 event.RunAndWait();
520 Mock::VerifyAndClearExpectations(&mock_cb_);
523 // Advance time more. Now we should signal having nothing. And put
524 // the last frame up for display.
526 SCOPED_TRACE("Waiting for BUFFERING_HAVE_NOTHING");
527 WaitableMessageLoopEvent event;
528 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_NOTHING))
529 .WillOnce(RunClosure(event.GetClosure()));
530 AdvanceWallclockTimeInMs(9);
531 event.RunAndWait();
532 Mock::VerifyAndClearExpectations(&mock_cb_);
535 // Receiving end of stream should signal having enough.
537 SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH");
538 WaitableMessageLoopEvent event;
539 EXPECT_CALL(mock_cb_, BufferingStateChange(BUFFERING_HAVE_ENOUGH))
540 .WillOnce(RunClosure(event.GetClosure()));
541 SatisfyPendingReadWithEndOfStream();
542 event.RunAndWait();
545 WaitForEnded();
546 Destroy();
549 } // namespace media