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.
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"
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
;
38 ACTION_P(RunClosure
, closure
) {
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
{
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 decoders
.Pass(), true,
59 renderer_
->SetTickClockForTesting(scoped_ptr
<base::TickClock
>(tick_clock_
));
61 // Start wallclock time at a non-zero value.
62 AdvanceWallclockTimeInMs(12345);
64 demuxer_stream_
.set_video_decoder_config(TestVideoConfig::Normal());
66 // We expect these to be called but we don't care how/when.
67 EXPECT_CALL(demuxer_stream_
, Read(_
)).WillRepeatedly(
68 RunCallback
<0>(DemuxerStream::kOk
,
69 scoped_refptr
<DecoderBuffer
>(new DecoderBuffer(0))));
72 virtual ~VideoRendererImplTest() {}
75 InitializeWithLowDelay(false);
78 void InitializeWithLowDelay(bool low_delay
) {
79 // Monitor decodes from the decoder.
80 EXPECT_CALL(*decoder_
, Decode(_
, _
))
81 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::DecodeRequested
));
83 EXPECT_CALL(*decoder_
, Reset(_
))
84 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::FlushRequested
));
86 // Initialize, we shouldn't have any reads.
87 InitializeRenderer(PIPELINE_OK
, low_delay
);
90 void InitializeRenderer(PipelineStatus expected
, bool low_delay
) {
91 SCOPED_TRACE(base::StringPrintf("InitializeRenderer(%d)", expected
));
92 WaitableMessageLoopEvent event
;
93 CallInitialize(event
.GetPipelineStatusCB(), low_delay
, expected
);
94 event
.RunAndWaitForStatus(expected
);
97 void CallInitialize(const PipelineStatusCB
& status_cb
,
99 PipelineStatus decoder_status
) {
101 demuxer_stream_
.set_liveness(DemuxerStream::LIVENESS_LIVE
);
102 EXPECT_CALL(*decoder_
, Initialize(_
, _
, _
, _
)).WillOnce(
103 DoAll(SaveArg
<3>(&output_cb_
), RunCallback
<2>(decoder_status
)));
104 EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
105 renderer_
->Initialize(
106 &demuxer_stream_
, status_cb
, media::SetDecryptorReadyCB(),
107 base::Bind(&VideoRendererImplTest::OnStatisticsUpdate
,
108 base::Unretained(this)),
109 base::Bind(&StrictMock
<MockCB
>::BufferingStateChange
,
110 base::Unretained(&mock_cb_
)),
111 base::Bind(&StrictMock
<MockCB
>::Display
, 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();
127 SCOPED_TRACE("Flush()");
128 WaitableMessageLoopEvent event
;
129 renderer_
->Flush(event
.GetClosure());
134 SCOPED_TRACE("Destroy()");
136 message_loop_
.RunUntilIdle();
139 // Parses a string representation of video frames and generates corresponding
140 // VideoFrame objects in |decode_results_|.
143 // nn - Queue a decoder buffer with timestamp nn * 1000us
144 // abort - Queue an aborted read
145 // error - Queue a decoder error
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
));
161 if (tokens
[i
] == "error") {
162 scoped_refptr
<VideoFrame
> null_frame
;
163 decode_results_
.push_back(
164 std::make_pair(VideoDecoder::kDecodeError
, null_frame
));
168 int timestamp_in_ms
= 0;
169 if (base::StringToInt(tokens
[i
], ×tamp_in_ms
)) {
170 gfx::Size natural_size
= TestVideoConfig::NormalCodedSize();
171 scoped_refptr
<VideoFrame
> frame
= VideoFrame::CreateFrame(
174 gfx::Rect(natural_size
),
176 base::TimeDelta::FromMilliseconds(timestamp_in_ms
));
177 decode_results_
.push_back(std::make_pair(VideoDecoder::kOk
, frame
));
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())
204 DCHECK(wait_for_pending_decode_cb_
.is_null());
206 WaitableMessageLoopEvent event
;
207 wait_for_pending_decode_cb_
= event
.GetClosure();
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
;
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(
239 base::Bind(base::ResetAndReturn(&decode_cb_
), VideoDecoder::kOk
));
241 WaitForPendingRead();
243 message_loop_
.PostTask(
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
);
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.
270 MOCK_METHOD1(Display
, void(const scoped_refptr
<VideoFrame
>&));
271 MOCK_METHOD1(BufferingStateChange
, void(BufferingState
));
273 StrictMock
<MockCB
> mock_cb_
;
276 base::TimeTicks
GetWallClockTime(base::TimeDelta time
) {
277 base::AutoLock
l(lock_
);
278 return tick_clock_
->NowTicks() + (time
- time_
);
281 void DecodeRequested(const scoped_refptr
<DecoderBuffer
>& buffer
,
282 const VideoDecoder::DecodeCB
& decode_cb
) {
283 DCHECK_EQ(&message_loop_
, base::MessageLoop::current());
284 CHECK(decode_cb_
.is_null());
285 decode_cb_
= decode_cb
;
287 // Wake up WaitForPendingRead() if needed.
288 if (!wait_for_pending_decode_cb_
.is_null())
289 base::ResetAndReturn(&wait_for_pending_decode_cb_
).Run();
291 if (decode_results_
.empty())
294 SatisfyPendingRead();
297 void FlushRequested(const base::Closure
& callback
) {
298 DCHECK_EQ(&message_loop_
, base::MessageLoop::current());
299 decode_results_
.clear();
300 if (!decode_cb_
.is_null()) {
301 QueueFrames("abort");
302 SatisfyPendingRead();
305 message_loop_
.PostTask(FROM_HERE
, callback
);
308 void OnStatisticsUpdate(const PipelineStatistics
& stats
) {}
310 MOCK_METHOD0(OnWaitingForDecryptionKey
, void(void));
312 base::MessageLoop message_loop_
;
314 // Used to protect |time_|.
316 base::TimeDelta time_
;
318 // Used for satisfying reads.
319 VideoDecoder::OutputCB output_cb_
;
320 VideoDecoder::DecodeCB decode_cb_
;
321 base::TimeDelta next_frame_timestamp_
;
323 WaitableMessageLoopEvent error_event_
;
324 WaitableMessageLoopEvent ended_event_
;
326 // Run during DecodeRequested() to unblock WaitForPendingRead().
327 base::Closure wait_for_pending_decode_cb_
;
329 std::deque
<std::pair
<
330 VideoDecoder::Status
, scoped_refptr
<VideoFrame
> > > decode_results_
;
332 DISALLOW_COPY_AND_ASSIGN(VideoRendererImplTest
);
335 TEST_F(VideoRendererImplTest
, DoNothing
) {
336 // Test that creation and deletion doesn't depend on calls to Initialize()
340 TEST_F(VideoRendererImplTest
, DestroyWithoutInitialize
) {
344 TEST_F(VideoRendererImplTest
, Initialize
) {
349 TEST_F(VideoRendererImplTest
, InitializeAndStartPlayingFrom
) {
351 QueueFrames("0 10 20 30");
352 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(0)));
353 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
358 TEST_F(VideoRendererImplTest
, DestroyWhileInitializing
) {
359 CallInitialize(NewExpectedStatusCB(PIPELINE_ERROR_ABORT
), false, PIPELINE_OK
);
363 TEST_F(VideoRendererImplTest
, DestroyWhileFlushing
) {
365 QueueFrames("0 10 20 30");
366 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(0)));
367 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
369 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_NOTHING
));
370 renderer_
->Flush(NewExpectedClosure());
374 TEST_F(VideoRendererImplTest
, Play
) {
376 QueueFrames("0 10 20 30");
377 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(0)));
378 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
383 TEST_F(VideoRendererImplTest
, FlushWithNothingBuffered
) {
387 // We shouldn't expect a buffering state change since we never reached
388 // BUFFERING_HAVE_ENOUGH.
393 TEST_F(VideoRendererImplTest
, DecodeError_Playing
) {
395 QueueFrames("0 10 20 30");
396 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(0)));
397 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
400 QueueFrames("error");
401 SatisfyPendingRead();
402 WaitForError(PIPELINE_ERROR_DECODE
);
406 TEST_F(VideoRendererImplTest
, DecodeError_DuringStartPlayingFrom
) {
408 QueueFrames("error");
413 TEST_F(VideoRendererImplTest
, StartPlayingFrom_Exact
) {
415 QueueFrames("50 60 70 80 90");
417 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(60)));
418 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
419 StartPlayingFrom(60);
423 TEST_F(VideoRendererImplTest
, StartPlayingFrom_RightBefore
) {
425 QueueFrames("50 60 70 80 90");
427 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(50)));
428 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
429 StartPlayingFrom(59);
433 TEST_F(VideoRendererImplTest
, StartPlayingFrom_RightAfter
) {
435 QueueFrames("50 60 70 80 90");
437 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(60)));
438 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
439 StartPlayingFrom(61);
443 TEST_F(VideoRendererImplTest
, StartPlayingFrom_LowDelay
) {
444 // In low-delay mode only one frame is required to finish preroll.
445 InitializeWithLowDelay(true);
448 // Expect some amount of have enough/nothing due to only requiring one frame.
449 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(0)));
450 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
))
452 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_NOTHING
))
457 SatisfyPendingRead();
459 WaitableMessageLoopEvent event
;
460 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(10)))
461 .WillOnce(RunClosure(event
.GetClosure()));
468 // Verify that a late decoder response doesn't break invariants in the renderer.
469 TEST_F(VideoRendererImplTest
, DestroyDuringOutstandingRead
) {
471 QueueFrames("0 10 20 30");
472 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(0)));
473 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
476 // Check that there is an outstanding Read() request.
477 EXPECT_TRUE(IsReadPending());
482 TEST_F(VideoRendererImplTest
, VideoDecoder_InitFailure
) {
483 InitializeRenderer(DECODER_ERROR_NOT_SUPPORTED
, false);
487 TEST_F(VideoRendererImplTest
, Underflow
) {
489 QueueFrames("0 10 20 30");
492 WaitableMessageLoopEvent event
;
493 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(0)));
494 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
))
495 .WillOnce(RunClosure(event
.GetClosure()));
498 Mock::VerifyAndClearExpectations(&mock_cb_
);
501 // Advance time slightly, but enough to exceed the duration of the last frame.
502 // Frames should be dropped and we should NOT signal having nothing.
504 SCOPED_TRACE("Waiting for frame drops");
505 WaitableMessageLoopEvent event
;
506 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(10))).Times(0);
507 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(20))).Times(0);
508 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(30)))
509 .WillOnce(RunClosure(event
.GetClosure()));
512 Mock::VerifyAndClearExpectations(&mock_cb_
);
515 // Advance time more, such that a new frame should have been displayed by now.
517 SCOPED_TRACE("Waiting for BUFFERING_HAVE_NOTHING");
518 WaitableMessageLoopEvent event
;
519 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_NOTHING
))
520 .WillOnce(RunClosure(event
.GetClosure()));
521 AdvanceWallclockTimeInMs(9);
523 Mock::VerifyAndClearExpectations(&mock_cb_
);
526 // Receiving end of stream should signal having enough.
528 SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH");
529 WaitableMessageLoopEvent event
;
530 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
))
531 .WillOnce(RunClosure(event
.GetClosure()));
532 SatisfyPendingReadWithEndOfStream();