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/null_video_sink.h"
23 #include "media/base/test_helpers.h"
24 #include "media/base/video_frame.h"
25 #include "media/base/wall_clock_time_source.h"
26 #include "media/renderers/video_renderer_impl.h"
27 #include "testing/gtest/include/gtest/gtest.h"
30 using ::testing::AnyNumber
;
31 using ::testing::Invoke
;
32 using ::testing::Mock
;
33 using ::testing::NiceMock
;
34 using ::testing::Return
;
35 using ::testing::SaveArg
;
36 using ::testing::StrictMock
;
40 ACTION_P(RunClosure
, closure
) {
44 MATCHER_P(HasTimestamp
, ms
, "") {
45 *result_listener
<< "has timestamp " << arg
->timestamp().InMilliseconds();
46 return arg
->timestamp().InMilliseconds() == ms
;
49 class VideoRendererImplTest
: public testing::TestWithParam
<bool> {
51 VideoRendererImplTest()
52 : tick_clock_(new base::SimpleTestTickClock()),
53 decoder_(new MockVideoDecoder()),
54 demuxer_stream_(DemuxerStream::VIDEO
) {
55 ScopedVector
<VideoDecoder
> decoders
;
56 decoders
.push_back(decoder_
);
58 null_video_sink_
.reset(new NullVideoSink(
59 false, base::TimeDelta::FromSecondsD(1.0 / 60),
60 base::Bind(&MockCB::FrameReceived
, base::Unretained(&mock_cb_
)),
61 message_loop_
.task_runner()));
63 renderer_
.reset(new VideoRendererImpl(
64 message_loop_
.message_loop_proxy(), null_video_sink_
.get(),
65 decoders
.Pass(), true, new MediaLog()));
67 renderer_
->disable_new_video_renderer_for_testing();
68 renderer_
->SetTickClockForTesting(scoped_ptr
<base::TickClock
>(tick_clock_
));
69 null_video_sink_
->set_tick_clock_for_testing(tick_clock_
);
70 time_source_
.set_tick_clock_for_testing(tick_clock_
);
72 // Start wallclock time at a non-zero value.
73 AdvanceWallclockTimeInMs(12345);
75 demuxer_stream_
.set_video_decoder_config(TestVideoConfig::Normal());
77 // We expect these to be called but we don't care how/when.
78 EXPECT_CALL(demuxer_stream_
, Read(_
)).WillRepeatedly(
79 RunCallback
<0>(DemuxerStream::kOk
,
80 scoped_refptr
<DecoderBuffer
>(new DecoderBuffer(0))));
83 virtual ~VideoRendererImplTest() {}
86 InitializeWithLowDelay(false);
89 void InitializeWithLowDelay(bool low_delay
) {
90 // Monitor decodes from the decoder.
91 EXPECT_CALL(*decoder_
, Decode(_
, _
))
92 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::DecodeRequested
));
94 EXPECT_CALL(*decoder_
, Reset(_
))
95 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::FlushRequested
));
97 // Initialize, we shouldn't have any reads.
98 InitializeRenderer(PIPELINE_OK
, low_delay
);
101 void InitializeRenderer(PipelineStatus expected
, bool low_delay
) {
102 SCOPED_TRACE(base::StringPrintf("InitializeRenderer(%d)", expected
));
103 WaitableMessageLoopEvent event
;
104 CallInitialize(event
.GetPipelineStatusCB(), low_delay
, expected
);
105 event
.RunAndWaitForStatus(expected
);
108 void CallInitialize(const PipelineStatusCB
& status_cb
,
110 PipelineStatus decoder_status
) {
112 demuxer_stream_
.set_liveness(DemuxerStream::LIVENESS_LIVE
);
113 EXPECT_CALL(*decoder_
, Initialize(_
, _
, _
, _
))
115 DoAll(SaveArg
<3>(&output_cb_
), RunCallback
<2>(decoder_status
)));
116 EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
117 renderer_
->Initialize(
118 &demuxer_stream_
, status_cb
, media::SetDecryptorReadyCB(),
119 base::Bind(&VideoRendererImplTest::OnStatisticsUpdate
,
120 base::Unretained(this)),
121 base::Bind(&StrictMock
<MockCB
>::BufferingStateChange
,
122 base::Unretained(&mock_cb_
)),
123 ended_event_
.GetClosure(), error_event_
.GetPipelineStatusCB(),
124 base::Bind(&WallClockTimeSource::GetWallClockTimes
,
125 base::Unretained(&time_source_
)),
126 base::Bind(&VideoRendererImplTest::OnWaitingForDecryptionKey
,
127 base::Unretained(this)));
130 void StartPlayingFrom(int milliseconds
) {
131 SCOPED_TRACE(base::StringPrintf("StartPlayingFrom(%d)", milliseconds
));
132 const base::TimeDelta media_time
=
133 base::TimeDelta::FromMilliseconds(milliseconds
);
134 time_source_
.SetMediaTime(media_time
);
135 renderer_
->StartPlayingFrom(media_time
);
136 message_loop_
.RunUntilIdle();
140 SCOPED_TRACE("Flush()");
141 WaitableMessageLoopEvent event
;
142 renderer_
->Flush(event
.GetClosure());
147 SCOPED_TRACE("Destroy()");
149 message_loop_
.RunUntilIdle();
152 // Parses a string representation of video frames and generates corresponding
153 // VideoFrame objects in |decode_results_|.
156 // nn - Queue a decoder buffer with timestamp nn * 1000us
157 // abort - Queue an aborted read
158 // error - Queue a decoder error
161 // A clip that is four frames long: "0 10 20 30"
162 // A clip that has a decode error: "60 70 error"
163 void QueueFrames(const std::string
& str
) {
164 std::vector
<std::string
> tokens
;
165 base::SplitString(str
, ' ', &tokens
);
166 for (size_t i
= 0; i
< tokens
.size(); ++i
) {
167 if (tokens
[i
] == "abort") {
168 scoped_refptr
<VideoFrame
> null_frame
;
169 decode_results_
.push_back(
170 std::make_pair(VideoDecoder::kAborted
, null_frame
));
174 if (tokens
[i
] == "error") {
175 scoped_refptr
<VideoFrame
> null_frame
;
176 decode_results_
.push_back(
177 std::make_pair(VideoDecoder::kDecodeError
, null_frame
));
181 int timestamp_in_ms
= 0;
182 if (base::StringToInt(tokens
[i
], ×tamp_in_ms
)) {
183 gfx::Size natural_size
= TestVideoConfig::NormalCodedSize();
184 scoped_refptr
<VideoFrame
> frame
= VideoFrame::CreateFrame(
187 gfx::Rect(natural_size
),
189 base::TimeDelta::FromMilliseconds(timestamp_in_ms
));
190 decode_results_
.push_back(std::make_pair(VideoDecoder::kOk
, frame
));
194 CHECK(false) << "Unrecognized decoder buffer token: " << tokens
[i
];
198 bool IsReadPending() {
199 return !decode_cb_
.is_null();
202 void WaitForError(PipelineStatus expected
) {
203 SCOPED_TRACE(base::StringPrintf("WaitForError(%d)", expected
));
204 error_event_
.RunAndWaitForStatus(expected
);
207 void WaitForEnded() {
208 SCOPED_TRACE("WaitForEnded()");
209 ended_event_
.RunAndWait();
212 void WaitForPendingRead() {
213 SCOPED_TRACE("WaitForPendingRead()");
214 if (!decode_cb_
.is_null())
217 DCHECK(wait_for_pending_decode_cb_
.is_null());
219 WaitableMessageLoopEvent event
;
220 wait_for_pending_decode_cb_
= event
.GetClosure();
223 DCHECK(!decode_cb_
.is_null());
224 DCHECK(wait_for_pending_decode_cb_
.is_null());
227 void SatisfyPendingRead() {
228 CHECK(!decode_cb_
.is_null());
229 CHECK(!decode_results_
.empty());
231 // Post tasks for OutputCB and DecodeCB.
232 scoped_refptr
<VideoFrame
> frame
= decode_results_
.front().second
;
234 message_loop_
.PostTask(FROM_HERE
, base::Bind(output_cb_
, frame
));
235 message_loop_
.PostTask(
236 FROM_HERE
, base::Bind(base::ResetAndReturn(&decode_cb_
),
237 decode_results_
.front().first
));
238 decode_results_
.pop_front();
241 void SatisfyPendingReadWithEndOfStream() {
242 DCHECK(!decode_cb_
.is_null());
244 // Return EOS buffer to trigger EOS frame.
245 EXPECT_CALL(demuxer_stream_
, Read(_
))
246 .WillOnce(RunCallback
<0>(DemuxerStream::kOk
,
247 DecoderBuffer::CreateEOSBuffer()));
249 // Satify pending |decode_cb_| to trigger a new DemuxerStream::Read().
250 message_loop_
.PostTask(
252 base::Bind(base::ResetAndReturn(&decode_cb_
), VideoDecoder::kOk
));
254 WaitForPendingRead();
256 message_loop_
.PostTask(
258 base::Bind(base::ResetAndReturn(&decode_cb_
), VideoDecoder::kOk
));
261 void AdvanceWallclockTimeInMs(int time_ms
) {
262 DCHECK_EQ(&message_loop_
, base::MessageLoop::current());
263 base::AutoLock
l(lock_
);
264 tick_clock_
->Advance(base::TimeDelta::FromMilliseconds(time_ms
));
267 void AdvanceTimeInMs(int time_ms
) {
268 DCHECK_EQ(&message_loop_
, base::MessageLoop::current());
269 base::AutoLock
l(lock_
);
270 time_
+= base::TimeDelta::FromMilliseconds(time_ms
);
271 time_source_
.StopTicking();
272 time_source_
.SetMediaTime(time_
);
273 time_source_
.StartTicking();
276 bool has_ended() const {
277 return ended_event_
.is_signaled();
282 scoped_ptr
<VideoRendererImpl
> renderer_
;
283 base::SimpleTestTickClock
* tick_clock_
; // Owned by |renderer_|.
284 MockVideoDecoder
* decoder_
; // Owned by |renderer_|.
285 NiceMock
<MockDemuxerStream
> demuxer_stream_
;
287 // Use StrictMock<T> to catch missing/extra callbacks.
290 MOCK_METHOD1(FrameReceived
, void(const scoped_refptr
<VideoFrame
>&));
291 MOCK_METHOD1(BufferingStateChange
, void(BufferingState
));
293 StrictMock
<MockCB
> mock_cb_
;
295 // Must be destroyed before |renderer_| since they share |tick_clock_|.
296 scoped_ptr
<NullVideoSink
> null_video_sink_
;
298 PipelineStatistics last_pipeline_statistics_
;
300 WallClockTimeSource time_source_
;
303 void DecodeRequested(const scoped_refptr
<DecoderBuffer
>& buffer
,
304 const VideoDecoder::DecodeCB
& decode_cb
) {
305 DCHECK_EQ(&message_loop_
, base::MessageLoop::current());
306 CHECK(decode_cb_
.is_null());
307 decode_cb_
= decode_cb
;
309 // Wake up WaitForPendingRead() if needed.
310 if (!wait_for_pending_decode_cb_
.is_null())
311 base::ResetAndReturn(&wait_for_pending_decode_cb_
).Run();
313 if (decode_results_
.empty())
316 SatisfyPendingRead();
319 void FlushRequested(const base::Closure
& callback
) {
320 DCHECK_EQ(&message_loop_
, base::MessageLoop::current());
321 decode_results_
.clear();
322 if (!decode_cb_
.is_null()) {
323 QueueFrames("abort");
324 SatisfyPendingRead();
327 message_loop_
.PostTask(FROM_HERE
, callback
);
330 void OnStatisticsUpdate(const PipelineStatistics
& stats
) {
331 last_pipeline_statistics_
= stats
;
334 MOCK_METHOD0(OnWaitingForDecryptionKey
, void(void));
336 base::MessageLoop message_loop_
;
338 // Used to protect |time_|.
340 base::TimeDelta time_
;
342 // Used for satisfying reads.
343 VideoDecoder::OutputCB output_cb_
;
344 VideoDecoder::DecodeCB decode_cb_
;
345 base::TimeDelta next_frame_timestamp_
;
347 WaitableMessageLoopEvent error_event_
;
348 WaitableMessageLoopEvent ended_event_
;
350 // Run during DecodeRequested() to unblock WaitForPendingRead().
351 base::Closure wait_for_pending_decode_cb_
;
353 std::deque
<std::pair
<
354 VideoDecoder::Status
, scoped_refptr
<VideoFrame
> > > decode_results_
;
356 DISALLOW_COPY_AND_ASSIGN(VideoRendererImplTest
);
359 TEST_P(VideoRendererImplTest
, DoNothing
) {
360 // Test that creation and deletion doesn't depend on calls to Initialize()
364 TEST_P(VideoRendererImplTest
, DestroyWithoutInitialize
) {
368 TEST_P(VideoRendererImplTest
, Initialize
) {
373 TEST_P(VideoRendererImplTest
, InitializeAndStartPlayingFrom
) {
375 QueueFrames("0 10 20 30");
376 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(0)));
377 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
382 TEST_P(VideoRendererImplTest
, InitializeAndEndOfStream
) {
385 WaitForPendingRead();
387 SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH");
388 WaitableMessageLoopEvent event
;
389 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
))
390 .WillOnce(RunClosure(event
.GetClosure()));
391 SatisfyPendingReadWithEndOfStream();
394 // Firing a time state changed to true should be ignored...
395 renderer_
->OnTimeStateChanged(true);
396 EXPECT_FALSE(null_video_sink_
->is_started());
400 TEST_P(VideoRendererImplTest
, DestroyWhileInitializing
) {
401 CallInitialize(NewExpectedStatusCB(PIPELINE_ERROR_ABORT
), false, PIPELINE_OK
);
405 TEST_P(VideoRendererImplTest
, DestroyWhileFlushing
) {
407 QueueFrames("0 10 20 30");
408 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(0)));
409 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
411 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_NOTHING
));
412 renderer_
->Flush(NewExpectedClosure());
416 TEST_P(VideoRendererImplTest
, Play
) {
418 QueueFrames("0 10 20 30");
419 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(0)));
420 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
425 TEST_P(VideoRendererImplTest
, FlushWithNothingBuffered
) {
429 // We shouldn't expect a buffering state change since we never reached
430 // BUFFERING_HAVE_ENOUGH.
435 TEST_P(VideoRendererImplTest
, DecodeError_Playing
) {
437 QueueFrames("0 10 20 30");
438 EXPECT_CALL(mock_cb_
, FrameReceived(_
)).Times(testing::AtLeast(1));
439 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
441 renderer_
->OnTimeStateChanged(true);
442 time_source_
.StartTicking();
445 QueueFrames("error");
446 SatisfyPendingRead();
447 WaitForError(PIPELINE_ERROR_DECODE
);
451 TEST_P(VideoRendererImplTest
, DecodeError_DuringStartPlayingFrom
) {
453 QueueFrames("error");
458 TEST_P(VideoRendererImplTest
, StartPlayingFrom_Exact
) {
460 QueueFrames("50 60 70 80 90");
462 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(60)));
463 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
464 StartPlayingFrom(60);
468 TEST_P(VideoRendererImplTest
, StartPlayingFrom_RightBefore
) {
470 QueueFrames("50 60 70 80 90");
472 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(50)));
473 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
474 StartPlayingFrom(59);
478 TEST_P(VideoRendererImplTest
, StartPlayingFrom_RightAfter
) {
480 QueueFrames("50 60 70 80 90");
482 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(60)));
483 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
484 StartPlayingFrom(61);
488 TEST_P(VideoRendererImplTest
, StartPlayingFrom_LowDelay
) {
489 // In low-delay mode only one frame is required to finish preroll.
490 InitializeWithLowDelay(true);
493 // Expect some amount of have enough/nothing due to only requiring one frame.
494 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(0)));
495 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
))
497 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_NOTHING
))
502 SatisfyPendingRead();
504 renderer_
->OnTimeStateChanged(true);
505 time_source_
.StartTicking();
507 WaitableMessageLoopEvent event
;
508 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(10)))
509 .WillOnce(RunClosure(event
.GetClosure()));
516 // Verify that a late decoder response doesn't break invariants in the renderer.
517 TEST_P(VideoRendererImplTest
, DestroyDuringOutstandingRead
) {
519 QueueFrames("0 10 20 30");
520 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(0)));
521 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
524 // Check that there is an outstanding Read() request.
525 EXPECT_TRUE(IsReadPending());
530 TEST_P(VideoRendererImplTest
, VideoDecoder_InitFailure
) {
531 InitializeRenderer(DECODER_ERROR_NOT_SUPPORTED
, false);
535 TEST_P(VideoRendererImplTest
, Underflow
) {
537 QueueFrames("0 30 60 90");
540 WaitableMessageLoopEvent event
;
541 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(0)));
542 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
))
543 .WillOnce(RunClosure(event
.GetClosure()));
546 Mock::VerifyAndClearExpectations(&mock_cb_
);
549 renderer_
->OnTimeStateChanged(true);
551 // Advance time slightly, but enough to exceed the duration of the last frame.
552 // Frames should be dropped and we should NOT signal having nothing.
554 SCOPED_TRACE("Waiting for frame drops");
555 WaitableMessageLoopEvent event
;
557 // Note: Starting the TimeSource will cause the old VideoRendererImpl to
558 // start rendering frames on its own thread, so the first frame may be
560 time_source_
.StartTicking();
562 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(30))).Times(0);
564 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(30))).Times(AnyNumber());
566 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(60))).Times(0);
567 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(90)))
568 .WillOnce(RunClosure(event
.GetClosure()));
572 Mock::VerifyAndClearExpectations(&mock_cb_
);
575 // Advance time more. Now we should signal having nothing. And put
576 // the last frame up for display.
578 SCOPED_TRACE("Waiting for BUFFERING_HAVE_NOTHING");
579 WaitableMessageLoopEvent event
;
580 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_NOTHING
))
581 .WillOnce(RunClosure(event
.GetClosure()));
583 // The old rendering path needs wall clock time to increase too.
585 AdvanceWallclockTimeInMs(30);
588 Mock::VerifyAndClearExpectations(&mock_cb_
);
591 // Receiving end of stream should signal having enough.
593 SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH");
594 WaitableMessageLoopEvent event
;
595 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
))
596 .WillOnce(RunClosure(event
.GetClosure()));
597 SatisfyPendingReadWithEndOfStream();
605 // Verifies that the sink is stopped after rendering the first frame if
606 // playback hasn't started.
607 TEST_P(VideoRendererImplTest
, RenderingStopsAfterFirstFrame
) {
608 // This test is only for the new rendering path.
612 InitializeWithLowDelay(true);
615 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(0)));
616 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
619 SCOPED_TRACE("Waiting for sink to stop.");
620 WaitableMessageLoopEvent event
;
622 null_video_sink_
->set_background_render(true);
623 null_video_sink_
->set_stop_cb(event
.GetClosure());
626 EXPECT_TRUE(IsReadPending());
627 SatisfyPendingReadWithEndOfStream();
632 EXPECT_FALSE(has_ended());
636 // Verifies that the sink is stopped after rendering the first frame if
637 // playback ha started.
638 TEST_P(VideoRendererImplTest
, RenderingStopsAfterOneFrameWithEOS
) {
639 // This test is only for the new rendering path.
643 InitializeWithLowDelay(true);
646 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(0)));
647 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
650 SCOPED_TRACE("Waiting for sink to stop.");
651 WaitableMessageLoopEvent event
;
653 null_video_sink_
->set_stop_cb(event
.GetClosure());
655 renderer_
->OnTimeStateChanged(true);
657 EXPECT_TRUE(IsReadPending());
658 SatisfyPendingReadWithEndOfStream();
661 renderer_
->OnTimeStateChanged(false);
668 // Tests the case where the video started and received a single Render() call,
669 // then the video was put into the background.
670 TEST_P(VideoRendererImplTest
, RenderingStartedThenStopped
) {
671 // This test is only for the new rendering path.
676 QueueFrames("0 30 60 90");
678 // Start the sink and wait for the first callback. Set statistics to a non
679 // zero value, once we have some decoded frames they should be overwritten.
680 last_pipeline_statistics_
.video_frames_dropped
= 1;
682 WaitableMessageLoopEvent event
;
683 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
684 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(0)))
685 .WillOnce(RunClosure(event
.GetClosure()));
688 Mock::VerifyAndClearExpectations(&mock_cb_
);
689 EXPECT_EQ(0u, last_pipeline_statistics_
.video_frames_dropped
);
692 renderer_
->OnTimeStateChanged(true);
693 time_source_
.StartTicking();
695 // Suspend all future callbacks and synthetically advance the media time,
696 // because this is a background render, we won't underflow by waiting until
697 // a pending read is ready.
698 null_video_sink_
->set_background_render(true);
700 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(90)));
701 WaitForPendingRead();
702 SatisfyPendingReadWithEndOfStream();
704 // If this wasn't background rendering mode, this would result in two frames
705 // being dropped, but since we set background render to true, none should be
707 EXPECT_EQ(0u, last_pipeline_statistics_
.video_frames_dropped
);
708 EXPECT_EQ(4u, last_pipeline_statistics_
.video_frames_decoded
);
715 INSTANTIATE_TEST_CASE_P(OldVideoRenderer
,
716 VideoRendererImplTest
,
717 testing::Values(false));
718 INSTANTIATE_TEST_CASE_P(NewVideoRenderer
,
719 VideoRendererImplTest
,
720 testing::Values(true));