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 "media/base/data_buffer.h"
18 #include "media/base/gmock_callback_support.h"
19 #include "media/base/limits.h"
20 #include "media/base/mock_filters.h"
21 #include "media/base/test_helpers.h"
22 #include "media/base/video_frame.h"
23 #include "media/renderers/video_renderer_impl.h"
24 #include "testing/gtest/include/gtest/gtest.h"
27 using ::testing::AnyNumber
;
28 using ::testing::Invoke
;
29 using ::testing::NiceMock
;
30 using ::testing::Return
;
31 using ::testing::SaveArg
;
32 using ::testing::StrictMock
;
36 ACTION_P(RunClosure
, closure
) {
40 MATCHER_P(HasTimestamp
, ms
, "") {
41 *result_listener
<< "has timestamp " << arg
->timestamp().InMilliseconds();
42 return arg
->timestamp().InMilliseconds() == ms
;
45 class VideoRendererImplTest
: public ::testing::Test
{
47 VideoRendererImplTest()
48 : decoder_(new MockVideoDecoder()),
49 demuxer_stream_(DemuxerStream::VIDEO
) {
50 ScopedVector
<VideoDecoder
> decoders
;
51 decoders
.push_back(decoder_
);
53 renderer_
.reset(new VideoRendererImpl(message_loop_
.message_loop_proxy(),
54 decoders
.Pass(), true,
57 demuxer_stream_
.set_video_decoder_config(TestVideoConfig::Normal());
59 // We expect these to be called but we don't care how/when.
60 EXPECT_CALL(demuxer_stream_
, Read(_
)).WillRepeatedly(
61 RunCallback
<0>(DemuxerStream::kOk
,
62 scoped_refptr
<DecoderBuffer
>(new DecoderBuffer(0))));
65 virtual ~VideoRendererImplTest() {}
68 InitializeWithLowDelay(false);
71 void InitializeWithLowDelay(bool low_delay
) {
72 // Monitor decodes from the decoder.
73 EXPECT_CALL(*decoder_
, Decode(_
, _
))
74 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::DecodeRequested
));
76 EXPECT_CALL(*decoder_
, Reset(_
))
77 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::FlushRequested
));
79 // Initialize, we shouldn't have any reads.
80 InitializeRenderer(PIPELINE_OK
, low_delay
);
83 void InitializeRenderer(PipelineStatus expected
, bool low_delay
) {
84 SCOPED_TRACE(base::StringPrintf("InitializeRenderer(%d)", expected
));
85 WaitableMessageLoopEvent event
;
86 CallInitialize(event
.GetPipelineStatusCB(), low_delay
, expected
);
87 event
.RunAndWaitForStatus(expected
);
90 void CallInitialize(const PipelineStatusCB
& status_cb
,
92 PipelineStatus decoder_status
) {
94 demuxer_stream_
.set_liveness(DemuxerStream::LIVENESS_LIVE
);
95 EXPECT_CALL(*decoder_
, Initialize(_
, _
, _
, _
)).WillOnce(
96 DoAll(SaveArg
<3>(&output_cb_
), RunCallback
<2>(decoder_status
)));
97 EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
98 renderer_
->Initialize(
99 &demuxer_stream_
, status_cb
, media::SetDecryptorReadyCB(),
100 base::Bind(&VideoRendererImplTest::OnStatisticsUpdate
,
101 base::Unretained(this)),
102 base::Bind(&StrictMock
<MockCB
>::BufferingStateChange
,
103 base::Unretained(&mock_cb_
)),
104 base::Bind(&StrictMock
<MockCB
>::Display
, base::Unretained(&mock_cb_
)),
105 ended_event_
.GetClosure(), error_event_
.GetPipelineStatusCB(),
106 base::Bind(&VideoRendererImplTest::GetTime
, base::Unretained(this)),
107 base::Bind(&VideoRendererImplTest::OnWaitingForDecryptionKey
,
108 base::Unretained(this)));
111 void StartPlayingFrom(int milliseconds
) {
112 SCOPED_TRACE(base::StringPrintf("StartPlayingFrom(%d)", milliseconds
));
113 renderer_
->StartPlayingFrom(
114 base::TimeDelta::FromMilliseconds(milliseconds
));
115 message_loop_
.RunUntilIdle();
119 SCOPED_TRACE("Flush()");
120 WaitableMessageLoopEvent event
;
121 renderer_
->Flush(event
.GetClosure());
126 SCOPED_TRACE("Destroy()");
128 message_loop_
.RunUntilIdle();
131 // Parses a string representation of video frames and generates corresponding
132 // VideoFrame objects in |decode_results_|.
135 // nn - Queue a decoder buffer with timestamp nn * 1000us
136 // abort - Queue an aborted read
137 // error - Queue a decoder error
140 // A clip that is four frames long: "0 10 20 30"
141 // A clip that has a decode error: "60 70 error"
142 void QueueFrames(const std::string
& str
) {
143 std::vector
<std::string
> tokens
;
144 base::SplitString(str
, ' ', &tokens
);
145 for (size_t i
= 0; i
< tokens
.size(); ++i
) {
146 if (tokens
[i
] == "abort") {
147 scoped_refptr
<VideoFrame
> null_frame
;
148 decode_results_
.push_back(
149 std::make_pair(VideoDecoder::kAborted
, null_frame
));
153 if (tokens
[i
] == "error") {
154 scoped_refptr
<VideoFrame
> null_frame
;
155 decode_results_
.push_back(
156 std::make_pair(VideoDecoder::kDecodeError
, null_frame
));
160 int timestamp_in_ms
= 0;
161 if (base::StringToInt(tokens
[i
], ×tamp_in_ms
)) {
162 gfx::Size natural_size
= TestVideoConfig::NormalCodedSize();
163 scoped_refptr
<VideoFrame
> frame
= VideoFrame::CreateFrame(
166 gfx::Rect(natural_size
),
168 base::TimeDelta::FromMilliseconds(timestamp_in_ms
));
169 decode_results_
.push_back(std::make_pair(VideoDecoder::kOk
, frame
));
173 CHECK(false) << "Unrecognized decoder buffer token: " << tokens
[i
];
177 bool IsReadPending() {
178 return !decode_cb_
.is_null();
181 void WaitForError(PipelineStatus expected
) {
182 SCOPED_TRACE(base::StringPrintf("WaitForError(%d)", expected
));
183 error_event_
.RunAndWaitForStatus(expected
);
186 void WaitForEnded() {
187 SCOPED_TRACE("WaitForEnded()");
188 ended_event_
.RunAndWait();
191 void WaitForPendingRead() {
192 SCOPED_TRACE("WaitForPendingRead()");
193 if (!decode_cb_
.is_null())
196 DCHECK(wait_for_pending_decode_cb_
.is_null());
198 WaitableMessageLoopEvent event
;
199 wait_for_pending_decode_cb_
= event
.GetClosure();
202 DCHECK(!decode_cb_
.is_null());
203 DCHECK(wait_for_pending_decode_cb_
.is_null());
206 void SatisfyPendingRead() {
207 CHECK(!decode_cb_
.is_null());
208 CHECK(!decode_results_
.empty());
210 // Post tasks for OutputCB and DecodeCB.
211 scoped_refptr
<VideoFrame
> frame
= decode_results_
.front().second
;
213 message_loop_
.PostTask(FROM_HERE
, base::Bind(output_cb_
, frame
));
214 message_loop_
.PostTask(
215 FROM_HERE
, base::Bind(base::ResetAndReturn(&decode_cb_
),
216 decode_results_
.front().first
));
217 decode_results_
.pop_front();
220 void SatisfyPendingReadWithEndOfStream() {
221 DCHECK(!decode_cb_
.is_null());
223 // Return EOS buffer to trigger EOS frame.
224 EXPECT_CALL(demuxer_stream_
, Read(_
))
225 .WillOnce(RunCallback
<0>(DemuxerStream::kOk
,
226 DecoderBuffer::CreateEOSBuffer()));
228 // Satify pending |decode_cb_| to trigger a new DemuxerStream::Read().
229 message_loop_
.PostTask(
231 base::Bind(base::ResetAndReturn(&decode_cb_
), VideoDecoder::kOk
));
233 WaitForPendingRead();
235 message_loop_
.PostTask(
237 base::Bind(base::ResetAndReturn(&decode_cb_
), VideoDecoder::kOk
));
240 void AdvanceTimeInMs(int time_ms
) {
241 DCHECK_EQ(&message_loop_
, base::MessageLoop::current());
242 base::AutoLock
l(lock_
);
243 time_
+= base::TimeDelta::FromMilliseconds(time_ms
);
248 scoped_ptr
<VideoRendererImpl
> renderer_
;
249 MockVideoDecoder
* decoder_
; // Owned by |renderer_|.
250 NiceMock
<MockDemuxerStream
> demuxer_stream_
;
252 // Use StrictMock<T> to catch missing/extra callbacks.
255 MOCK_METHOD1(Display
, void(const scoped_refptr
<VideoFrame
>&));
256 MOCK_METHOD1(BufferingStateChange
, void(BufferingState
));
258 StrictMock
<MockCB
> mock_cb_
;
261 base::TimeDelta
GetTime() {
262 base::AutoLock
l(lock_
);
266 void DecodeRequested(const scoped_refptr
<DecoderBuffer
>& buffer
,
267 const VideoDecoder::DecodeCB
& decode_cb
) {
268 DCHECK_EQ(&message_loop_
, base::MessageLoop::current());
269 CHECK(decode_cb_
.is_null());
270 decode_cb_
= decode_cb
;
272 // Wake up WaitForPendingRead() if needed.
273 if (!wait_for_pending_decode_cb_
.is_null())
274 base::ResetAndReturn(&wait_for_pending_decode_cb_
).Run();
276 if (decode_results_
.empty())
279 SatisfyPendingRead();
282 void FlushRequested(const base::Closure
& callback
) {
283 DCHECK_EQ(&message_loop_
, base::MessageLoop::current());
284 decode_results_
.clear();
285 if (!decode_cb_
.is_null()) {
286 QueueFrames("abort");
287 SatisfyPendingRead();
290 message_loop_
.PostTask(FROM_HERE
, callback
);
293 void OnStatisticsUpdate(const PipelineStatistics
& stats
) {}
295 MOCK_METHOD0(OnWaitingForDecryptionKey
, void(void));
297 base::MessageLoop message_loop_
;
299 // Used to protect |time_|.
301 base::TimeDelta time_
;
303 // Used for satisfying reads.
304 VideoDecoder::OutputCB output_cb_
;
305 VideoDecoder::DecodeCB decode_cb_
;
306 base::TimeDelta next_frame_timestamp_
;
308 WaitableMessageLoopEvent error_event_
;
309 WaitableMessageLoopEvent ended_event_
;
311 // Run during DecodeRequested() to unblock WaitForPendingRead().
312 base::Closure wait_for_pending_decode_cb_
;
314 std::deque
<std::pair
<
315 VideoDecoder::Status
, scoped_refptr
<VideoFrame
> > > decode_results_
;
317 DISALLOW_COPY_AND_ASSIGN(VideoRendererImplTest
);
320 TEST_F(VideoRendererImplTest
, DoNothing
) {
321 // Test that creation and deletion doesn't depend on calls to Initialize()
325 TEST_F(VideoRendererImplTest
, DestroyWithoutInitialize
) {
329 TEST_F(VideoRendererImplTest
, Initialize
) {
334 TEST_F(VideoRendererImplTest
, InitializeAndStartPlayingFrom
) {
336 QueueFrames("0 10 20 30");
337 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(0)));
338 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
343 TEST_F(VideoRendererImplTest
, DestroyWhileInitializing
) {
344 CallInitialize(NewExpectedStatusCB(PIPELINE_ERROR_ABORT
), false, PIPELINE_OK
);
348 TEST_F(VideoRendererImplTest
, DestroyWhileFlushing
) {
350 QueueFrames("0 10 20 30");
351 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(0)));
352 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
354 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_NOTHING
));
355 renderer_
->Flush(NewExpectedClosure());
359 TEST_F(VideoRendererImplTest
, Play
) {
361 QueueFrames("0 10 20 30");
362 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(0)));
363 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
368 TEST_F(VideoRendererImplTest
, FlushWithNothingBuffered
) {
372 // We shouldn't expect a buffering state change since we never reached
373 // BUFFERING_HAVE_ENOUGH.
378 TEST_F(VideoRendererImplTest
, DecodeError_Playing
) {
380 QueueFrames("0 10 20 30");
381 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(0)));
382 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
385 QueueFrames("error");
386 SatisfyPendingRead();
387 WaitForError(PIPELINE_ERROR_DECODE
);
391 TEST_F(VideoRendererImplTest
, DecodeError_DuringStartPlayingFrom
) {
393 QueueFrames("error");
398 TEST_F(VideoRendererImplTest
, StartPlayingFrom_Exact
) {
400 QueueFrames("50 60 70 80 90");
402 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(60)));
403 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
404 StartPlayingFrom(60);
408 TEST_F(VideoRendererImplTest
, StartPlayingFrom_RightBefore
) {
410 QueueFrames("50 60 70 80 90");
412 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(50)));
413 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
414 StartPlayingFrom(59);
418 TEST_F(VideoRendererImplTest
, StartPlayingFrom_RightAfter
) {
420 QueueFrames("50 60 70 80 90");
422 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(60)));
423 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
424 StartPlayingFrom(61);
428 TEST_F(VideoRendererImplTest
, StartPlayingFrom_LowDelay
) {
429 // In low-delay mode only one frame is required to finish preroll.
430 InitializeWithLowDelay(true);
433 // Expect some amount of have enough/nothing due to only requiring one frame.
434 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(0)));
435 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
))
437 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_NOTHING
))
442 SatisfyPendingRead();
444 WaitableMessageLoopEvent event
;
445 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(10)))
446 .WillOnce(RunClosure(event
.GetClosure()));
453 // Verify that a late decoder response doesn't break invariants in the renderer.
454 TEST_F(VideoRendererImplTest
, DestroyDuringOutstandingRead
) {
456 QueueFrames("0 10 20 30");
457 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(0)));
458 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
461 // Check that there is an outstanding Read() request.
462 EXPECT_TRUE(IsReadPending());
467 TEST_F(VideoRendererImplTest
, VideoDecoder_InitFailure
) {
468 InitializeRenderer(DECODER_ERROR_NOT_SUPPORTED
, false);
472 TEST_F(VideoRendererImplTest
, Underflow
) {
474 QueueFrames("0 10 20 30");
475 EXPECT_CALL(mock_cb_
, Display(HasTimestamp(0)));
476 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
479 // Advance time slightly. Frames should be dropped and we should NOT signal
481 AdvanceTimeInMs(100);
483 // Advance time more. Now we should signal having nothing.
485 SCOPED_TRACE("Waiting for BUFFERING_HAVE_NOTHING");
486 WaitableMessageLoopEvent event
;
487 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_NOTHING
))
488 .WillOnce(RunClosure(event
.GetClosure()));
489 AdvanceTimeInMs(3000); // Must match kTimeToDeclareHaveNothing.
493 // Receiving end of stream should signal having enough.
495 SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH");
496 WaitableMessageLoopEvent event
;
497 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
))
498 .WillOnce(RunClosure(event
.GetClosure()));
499 SatisfyPendingReadWithEndOfStream();