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/renderers/video_renderer_impl.h"
26 #include "testing/gtest/include/gtest/gtest.h"
29 using ::testing::AnyNumber
;
30 using ::testing::Invoke
;
31 using ::testing::Mock
;
32 using ::testing::NiceMock
;
33 using ::testing::Return
;
34 using ::testing::SaveArg
;
35 using ::testing::StrictMock
;
39 ACTION_P(RunClosure
, closure
) {
43 MATCHER_P(HasTimestamp
, ms
, "") {
44 *result_listener
<< "has timestamp " << arg
->timestamp().InMilliseconds();
45 return arg
->timestamp().InMilliseconds() == ms
;
48 class VideoRendererImplTest
: public testing::TestWithParam
<bool> {
50 VideoRendererImplTest()
51 : tick_clock_(new base::SimpleTestTickClock()),
52 decoder_(new MockVideoDecoder()),
53 demuxer_stream_(DemuxerStream::VIDEO
) {
54 ScopedVector
<VideoDecoder
> decoders
;
55 decoders
.push_back(decoder_
);
57 null_video_sink_
.reset(new NullVideoSink(
58 false, base::TimeDelta::FromSecondsD(1.0 / 60),
59 base::Bind(&MockCB::FrameReceived
, base::Unretained(&mock_cb_
)),
60 message_loop_
.task_runner()));
62 renderer_
.reset(new VideoRendererImpl(
63 message_loop_
.message_loop_proxy(), null_video_sink_
.get(),
64 decoders
.Pass(), true, new MediaLog()));
66 renderer_
->disable_new_video_renderer_for_testing();
67 renderer_
->SetTickClockForTesting(scoped_ptr
<base::TickClock
>(tick_clock_
));
68 null_video_sink_
->set_tick_clock_for_testing(tick_clock_
);
70 // Start wallclock time at a non-zero value.
71 AdvanceWallclockTimeInMs(12345);
73 demuxer_stream_
.set_video_decoder_config(TestVideoConfig::Normal());
75 // We expect these to be called but we don't care how/when.
76 EXPECT_CALL(demuxer_stream_
, Read(_
)).WillRepeatedly(
77 RunCallback
<0>(DemuxerStream::kOk
,
78 scoped_refptr
<DecoderBuffer
>(new DecoderBuffer(0))));
81 virtual ~VideoRendererImplTest() {}
84 InitializeWithLowDelay(false);
87 void InitializeWithLowDelay(bool low_delay
) {
88 // Monitor decodes from the decoder.
89 EXPECT_CALL(*decoder_
, Decode(_
, _
))
90 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::DecodeRequested
));
92 EXPECT_CALL(*decoder_
, Reset(_
))
93 .WillRepeatedly(Invoke(this, &VideoRendererImplTest::FlushRequested
));
95 // Initialize, we shouldn't have any reads.
96 InitializeRenderer(PIPELINE_OK
, low_delay
);
99 void InitializeRenderer(PipelineStatus expected
, bool low_delay
) {
100 SCOPED_TRACE(base::StringPrintf("InitializeRenderer(%d)", expected
));
101 WaitableMessageLoopEvent event
;
102 CallInitialize(event
.GetPipelineStatusCB(), low_delay
, expected
);
103 event
.RunAndWaitForStatus(expected
);
106 void CallInitialize(const PipelineStatusCB
& status_cb
,
108 PipelineStatus decoder_status
) {
110 demuxer_stream_
.set_liveness(DemuxerStream::LIVENESS_LIVE
);
111 EXPECT_CALL(*decoder_
, Initialize(_
, _
, _
, _
)).WillOnce(
112 DoAll(SaveArg
<3>(&output_cb_
), RunCallback
<2>(decoder_status
)));
113 EXPECT_CALL(*this, OnWaitingForDecryptionKey()).Times(0);
114 renderer_
->Initialize(
115 &demuxer_stream_
, status_cb
, media::SetDecryptorReadyCB(),
116 base::Bind(&VideoRendererImplTest::OnStatisticsUpdate
,
117 base::Unretained(this)),
118 base::Bind(&StrictMock
<MockCB
>::BufferingStateChange
,
119 base::Unretained(&mock_cb_
)),
120 ended_event_
.GetClosure(), error_event_
.GetPipelineStatusCB(),
121 base::Bind(&VideoRendererImplTest::GetWallClockTime
,
122 base::Unretained(this)),
123 base::Bind(&VideoRendererImplTest::OnWaitingForDecryptionKey
,
124 base::Unretained(this)));
127 void StartPlayingFrom(int milliseconds
) {
128 SCOPED_TRACE(base::StringPrintf("StartPlayingFrom(%d)", milliseconds
));
129 renderer_
->StartPlayingFrom(
130 base::TimeDelta::FromMilliseconds(milliseconds
));
131 message_loop_
.RunUntilIdle();
135 SCOPED_TRACE("Flush()");
136 WaitableMessageLoopEvent event
;
137 renderer_
->Flush(event
.GetClosure());
142 SCOPED_TRACE("Destroy()");
144 message_loop_
.RunUntilIdle();
147 // Parses a string representation of video frames and generates corresponding
148 // VideoFrame objects in |decode_results_|.
151 // nn - Queue a decoder buffer with timestamp nn * 1000us
152 // abort - Queue an aborted read
153 // error - Queue a decoder error
156 // A clip that is four frames long: "0 10 20 30"
157 // A clip that has a decode error: "60 70 error"
158 void QueueFrames(const std::string
& str
) {
159 std::vector
<std::string
> tokens
;
160 base::SplitString(str
, ' ', &tokens
);
161 for (size_t i
= 0; i
< tokens
.size(); ++i
) {
162 if (tokens
[i
] == "abort") {
163 scoped_refptr
<VideoFrame
> null_frame
;
164 decode_results_
.push_back(
165 std::make_pair(VideoDecoder::kAborted
, null_frame
));
169 if (tokens
[i
] == "error") {
170 scoped_refptr
<VideoFrame
> null_frame
;
171 decode_results_
.push_back(
172 std::make_pair(VideoDecoder::kDecodeError
, null_frame
));
176 int timestamp_in_ms
= 0;
177 if (base::StringToInt(tokens
[i
], ×tamp_in_ms
)) {
178 gfx::Size natural_size
= TestVideoConfig::NormalCodedSize();
179 scoped_refptr
<VideoFrame
> frame
= VideoFrame::CreateFrame(
182 gfx::Rect(natural_size
),
184 base::TimeDelta::FromMilliseconds(timestamp_in_ms
));
185 decode_results_
.push_back(std::make_pair(VideoDecoder::kOk
, frame
));
189 CHECK(false) << "Unrecognized decoder buffer token: " << tokens
[i
];
193 bool IsReadPending() {
194 return !decode_cb_
.is_null();
197 void WaitForError(PipelineStatus expected
) {
198 SCOPED_TRACE(base::StringPrintf("WaitForError(%d)", expected
));
199 error_event_
.RunAndWaitForStatus(expected
);
202 void WaitForEnded() {
203 SCOPED_TRACE("WaitForEnded()");
204 ended_event_
.RunAndWait();
207 void WaitForPendingRead() {
208 SCOPED_TRACE("WaitForPendingRead()");
209 if (!decode_cb_
.is_null())
212 DCHECK(wait_for_pending_decode_cb_
.is_null());
214 WaitableMessageLoopEvent event
;
215 wait_for_pending_decode_cb_
= event
.GetClosure();
218 DCHECK(!decode_cb_
.is_null());
219 DCHECK(wait_for_pending_decode_cb_
.is_null());
222 void SatisfyPendingRead() {
223 CHECK(!decode_cb_
.is_null());
224 CHECK(!decode_results_
.empty());
226 // Post tasks for OutputCB and DecodeCB.
227 scoped_refptr
<VideoFrame
> frame
= decode_results_
.front().second
;
229 message_loop_
.PostTask(FROM_HERE
, base::Bind(output_cb_
, frame
));
230 message_loop_
.PostTask(
231 FROM_HERE
, base::Bind(base::ResetAndReturn(&decode_cb_
),
232 decode_results_
.front().first
));
233 decode_results_
.pop_front();
236 void SatisfyPendingReadWithEndOfStream() {
237 DCHECK(!decode_cb_
.is_null());
239 // Return EOS buffer to trigger EOS frame.
240 EXPECT_CALL(demuxer_stream_
, Read(_
))
241 .WillOnce(RunCallback
<0>(DemuxerStream::kOk
,
242 DecoderBuffer::CreateEOSBuffer()));
244 // Satify pending |decode_cb_| to trigger a new DemuxerStream::Read().
245 message_loop_
.PostTask(
247 base::Bind(base::ResetAndReturn(&decode_cb_
), VideoDecoder::kOk
));
249 WaitForPendingRead();
251 message_loop_
.PostTask(
253 base::Bind(base::ResetAndReturn(&decode_cb_
), VideoDecoder::kOk
));
256 void AdvanceWallclockTimeInMs(int time_ms
) {
257 DCHECK_EQ(&message_loop_
, base::MessageLoop::current());
258 base::AutoLock
l(lock_
);
259 tick_clock_
->Advance(base::TimeDelta::FromMilliseconds(time_ms
));
262 void AdvanceTimeInMs(int time_ms
) {
263 DCHECK_EQ(&message_loop_
, base::MessageLoop::current());
264 base::AutoLock
l(lock_
);
265 time_
+= base::TimeDelta::FromMilliseconds(time_ms
);
268 bool has_ended() const {
269 return ended_event_
.is_signaled();
274 scoped_ptr
<VideoRendererImpl
> renderer_
;
275 base::SimpleTestTickClock
* tick_clock_
; // Owned by |renderer_|.
276 MockVideoDecoder
* decoder_
; // Owned by |renderer_|.
277 NiceMock
<MockDemuxerStream
> demuxer_stream_
;
279 // Use StrictMock<T> to catch missing/extra callbacks.
282 MOCK_METHOD1(FrameReceived
, void(const scoped_refptr
<VideoFrame
>&));
283 MOCK_METHOD1(BufferingStateChange
, void(BufferingState
));
285 StrictMock
<MockCB
> mock_cb_
;
287 // Must be destroyed before |renderer_| since they share |tick_clock_|.
288 scoped_ptr
<NullVideoSink
> null_video_sink_
;
290 PipelineStatistics last_pipeline_statistics_
;
293 base::TimeTicks
GetWallClockTime(base::TimeDelta time
) {
294 base::AutoLock
l(lock_
);
295 return tick_clock_
->NowTicks() + (time
- time_
);
298 void DecodeRequested(const scoped_refptr
<DecoderBuffer
>& buffer
,
299 const VideoDecoder::DecodeCB
& decode_cb
) {
300 DCHECK_EQ(&message_loop_
, base::MessageLoop::current());
301 CHECK(decode_cb_
.is_null());
302 decode_cb_
= decode_cb
;
304 // Wake up WaitForPendingRead() if needed.
305 if (!wait_for_pending_decode_cb_
.is_null())
306 base::ResetAndReturn(&wait_for_pending_decode_cb_
).Run();
308 if (decode_results_
.empty())
311 SatisfyPendingRead();
314 void FlushRequested(const base::Closure
& callback
) {
315 DCHECK_EQ(&message_loop_
, base::MessageLoop::current());
316 decode_results_
.clear();
317 if (!decode_cb_
.is_null()) {
318 QueueFrames("abort");
319 SatisfyPendingRead();
322 message_loop_
.PostTask(FROM_HERE
, callback
);
325 void OnStatisticsUpdate(const PipelineStatistics
& stats
) {
326 last_pipeline_statistics_
= stats
;
329 MOCK_METHOD0(OnWaitingForDecryptionKey
, void(void));
331 base::MessageLoop message_loop_
;
333 // Used to protect |time_|.
335 base::TimeDelta time_
;
337 // Used for satisfying reads.
338 VideoDecoder::OutputCB output_cb_
;
339 VideoDecoder::DecodeCB decode_cb_
;
340 base::TimeDelta next_frame_timestamp_
;
342 WaitableMessageLoopEvent error_event_
;
343 WaitableMessageLoopEvent ended_event_
;
345 // Run during DecodeRequested() to unblock WaitForPendingRead().
346 base::Closure wait_for_pending_decode_cb_
;
348 std::deque
<std::pair
<
349 VideoDecoder::Status
, scoped_refptr
<VideoFrame
> > > decode_results_
;
351 DISALLOW_COPY_AND_ASSIGN(VideoRendererImplTest
);
354 TEST_P(VideoRendererImplTest
, DoNothing
) {
355 // Test that creation and deletion doesn't depend on calls to Initialize()
359 TEST_P(VideoRendererImplTest
, DestroyWithoutInitialize
) {
363 TEST_P(VideoRendererImplTest
, Initialize
) {
368 TEST_P(VideoRendererImplTest
, InitializeAndStartPlayingFrom
) {
370 QueueFrames("0 10 20 30");
371 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(0)));
372 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
377 TEST_P(VideoRendererImplTest
, InitializeAndEndOfStream
) {
380 WaitForPendingRead();
382 SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH");
383 WaitableMessageLoopEvent event
;
384 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
))
385 .WillOnce(RunClosure(event
.GetClosure()));
386 SatisfyPendingReadWithEndOfStream();
389 // Firing a time state changed to true should be ignored...
390 renderer_
->OnTimeStateChanged(true);
391 EXPECT_FALSE(null_video_sink_
->is_started());
395 TEST_P(VideoRendererImplTest
, DestroyWhileInitializing
) {
396 CallInitialize(NewExpectedStatusCB(PIPELINE_ERROR_ABORT
), false, PIPELINE_OK
);
400 TEST_P(VideoRendererImplTest
, DestroyWhileFlushing
) {
402 QueueFrames("0 10 20 30");
403 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(0)));
404 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
406 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_NOTHING
));
407 renderer_
->Flush(NewExpectedClosure());
411 TEST_P(VideoRendererImplTest
, Play
) {
413 QueueFrames("0 10 20 30");
414 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(0)));
415 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
420 TEST_P(VideoRendererImplTest
, FlushWithNothingBuffered
) {
424 // We shouldn't expect a buffering state change since we never reached
425 // BUFFERING_HAVE_ENOUGH.
430 TEST_P(VideoRendererImplTest
, DecodeError_Playing
) {
432 QueueFrames("0 10 20 30");
433 EXPECT_CALL(mock_cb_
, FrameReceived(_
)).Times(testing::AtLeast(1));
434 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
436 renderer_
->OnTimeStateChanged(true);
439 QueueFrames("error");
440 SatisfyPendingRead();
441 WaitForError(PIPELINE_ERROR_DECODE
);
445 TEST_P(VideoRendererImplTest
, DecodeError_DuringStartPlayingFrom
) {
447 QueueFrames("error");
452 TEST_P(VideoRendererImplTest
, StartPlayingFrom_Exact
) {
454 QueueFrames("50 60 70 80 90");
456 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(60)));
457 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
458 StartPlayingFrom(60);
462 TEST_P(VideoRendererImplTest
, StartPlayingFrom_RightBefore
) {
464 QueueFrames("50 60 70 80 90");
466 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(50)));
467 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
468 StartPlayingFrom(59);
472 TEST_P(VideoRendererImplTest
, StartPlayingFrom_RightAfter
) {
474 QueueFrames("50 60 70 80 90");
476 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(60)));
477 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
478 StartPlayingFrom(61);
482 TEST_P(VideoRendererImplTest
, StartPlayingFrom_LowDelay
) {
483 // In low-delay mode only one frame is required to finish preroll.
484 InitializeWithLowDelay(true);
487 // Expect some amount of have enough/nothing due to only requiring one frame.
488 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(0)));
489 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
))
491 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_NOTHING
))
496 SatisfyPendingRead();
498 renderer_
->OnTimeStateChanged(true);
499 WaitableMessageLoopEvent event
;
500 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(10)))
501 .WillOnce(RunClosure(event
.GetClosure()));
508 // Verify that a late decoder response doesn't break invariants in the renderer.
509 TEST_P(VideoRendererImplTest
, DestroyDuringOutstandingRead
) {
511 QueueFrames("0 10 20 30");
512 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(0)));
513 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
516 // Check that there is an outstanding Read() request.
517 EXPECT_TRUE(IsReadPending());
522 TEST_P(VideoRendererImplTest
, VideoDecoder_InitFailure
) {
523 InitializeRenderer(DECODER_ERROR_NOT_SUPPORTED
, false);
527 TEST_P(VideoRendererImplTest
, Underflow
) {
529 QueueFrames("0 30 60 90");
532 WaitableMessageLoopEvent event
;
533 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(0)));
534 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
))
535 .WillOnce(RunClosure(event
.GetClosure()));
538 Mock::VerifyAndClearExpectations(&mock_cb_
);
541 renderer_
->OnTimeStateChanged(true);
543 // Advance time slightly, but enough to exceed the duration of the last frame.
544 // Frames should be dropped and we should NOT signal having nothing.
546 SCOPED_TRACE("Waiting for frame drops");
547 WaitableMessageLoopEvent event
;
548 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(30)))
550 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(60)))
552 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(90)))
553 .WillOnce(RunClosure(event
.GetClosure()));
557 Mock::VerifyAndClearExpectations(&mock_cb_
);
560 // Advance time more. Now we should signal having nothing. And put
561 // the last frame up for display.
563 SCOPED_TRACE("Waiting for BUFFERING_HAVE_NOTHING");
564 WaitableMessageLoopEvent event
;
565 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_NOTHING
))
566 .WillOnce(RunClosure(event
.GetClosure()));
568 // The old rendering path needs wall clock time to increase too.
570 AdvanceWallclockTimeInMs(30);
573 Mock::VerifyAndClearExpectations(&mock_cb_
);
576 // Receiving end of stream should signal having enough.
578 SCOPED_TRACE("Waiting for BUFFERING_HAVE_ENOUGH");
579 WaitableMessageLoopEvent event
;
580 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
))
581 .WillOnce(RunClosure(event
.GetClosure()));
582 SatisfyPendingReadWithEndOfStream();
590 // Verifies that the sink is stopped after rendering the first frame if
591 // playback hasn't started.
592 TEST_P(VideoRendererImplTest
, RenderingStopsAfterFirstFrame
) {
593 // This test is only for the new rendering path.
597 InitializeWithLowDelay(true);
600 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(0)));
601 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
604 SCOPED_TRACE("Waiting for sink to stop.");
605 WaitableMessageLoopEvent event
;
607 null_video_sink_
->set_background_render(true);
608 null_video_sink_
->set_stop_cb(event
.GetClosure());
611 EXPECT_TRUE(IsReadPending());
612 SatisfyPendingReadWithEndOfStream();
617 EXPECT_FALSE(has_ended());
621 // Verifies that the sink is stopped after rendering the first frame if
622 // playback ha started.
623 TEST_P(VideoRendererImplTest
, RenderingStopsAfterOneFrameWithEOS
) {
624 // This test is only for the new rendering path.
628 InitializeWithLowDelay(true);
631 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(0)));
632 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
635 SCOPED_TRACE("Waiting for sink to stop.");
636 WaitableMessageLoopEvent event
;
638 null_video_sink_
->set_stop_cb(event
.GetClosure());
640 renderer_
->OnTimeStateChanged(true);
642 EXPECT_TRUE(IsReadPending());
643 SatisfyPendingReadWithEndOfStream();
646 renderer_
->OnTimeStateChanged(false);
653 // Tests the case where the video started and received a single Render() call,
654 // then the video was put into the background.
655 TEST_P(VideoRendererImplTest
, RenderingStartedThenStopped
) {
656 // This test is only for the new rendering path.
661 QueueFrames("0 30 60 90");
663 // Start the sink and wait for the first callback. Set statistics to a non
664 // zero value, once we have some decoded frames they should be overwritten.
665 last_pipeline_statistics_
.video_frames_dropped
= 1;
667 WaitableMessageLoopEvent event
;
668 EXPECT_CALL(mock_cb_
, BufferingStateChange(BUFFERING_HAVE_ENOUGH
));
669 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(0)))
670 .WillOnce(RunClosure(event
.GetClosure()));
673 Mock::VerifyAndClearExpectations(&mock_cb_
);
674 EXPECT_EQ(0u, last_pipeline_statistics_
.video_frames_dropped
);
677 renderer_
->OnTimeStateChanged(true);
679 // Suspend all future callbacks and synthetically advance the media time,
680 // because this is a background render, we won't underflow by waiting until
681 // a pending read is ready.
682 null_video_sink_
->set_background_render(true);
684 EXPECT_CALL(mock_cb_
, FrameReceived(HasTimestamp(90)));
685 WaitForPendingRead();
686 SatisfyPendingReadWithEndOfStream();
688 // If this wasn't background rendering mode, this would result in two frames
689 // being dropped, but since we set background render to true, none should be
691 EXPECT_EQ(0u, last_pipeline_statistics_
.video_frames_dropped
);
692 EXPECT_EQ(4u, last_pipeline_statistics_
.video_frames_decoded
);
699 INSTANTIATE_TEST_CASE_P(OldVideoRenderer
,
700 VideoRendererImplTest
,
701 testing::Values(false));
702 INSTANTIATE_TEST_CASE_P(NewVideoRenderer
,
703 VideoRendererImplTest
,
704 testing::Values(true));