1 // Copyright 2014 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.
6 #include "base/message_loop/message_loop.h"
7 #include "base/run_loop.h"
8 #include "base/test/simple_test_tick_clock.h"
9 #include "cc/layers/video_frame_provider.h"
10 #include "media/base/video_frame.h"
11 #include "media/blink/video_frame_compositor.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
17 using testing::Return
;
21 ACTION_P(RunClosure
, closure
) {
25 class VideoFrameCompositorTest
: public testing::Test
,
26 public cc::VideoFrameProvider::Client
,
27 public VideoRendererSink::RenderCallback
{
29 VideoFrameCompositorTest()
30 : tick_clock_(new base::SimpleTestTickClock()),
31 compositor_(new VideoFrameCompositor(
32 message_loop
.task_runner(),
33 base::Bind(&VideoFrameCompositorTest::NaturalSizeChanged
,
34 base::Unretained(this)),
35 base::Bind(&VideoFrameCompositorTest::OpacityChanged
,
36 base::Unretained(this)))),
37 did_receive_frame_count_(0),
38 natural_size_changed_count_(0),
39 opacity_changed_count_(0),
41 compositor_
->SetVideoFrameProviderClient(this);
42 compositor_
->set_tick_clock_for_testing(
43 scoped_ptr
<base::TickClock
>(tick_clock_
));
44 // Disable background rendering by default.
45 compositor_
->set_background_rendering_for_testing(false);
48 ~VideoFrameCompositorTest() override
{
49 compositor_
->SetVideoFrameProviderClient(nullptr);
52 scoped_refptr
<VideoFrame
> CreateOpaqueFrame() {
54 return VideoFrame::CreateFrame(VideoFrame::YV12
, size
, gfx::Rect(size
),
55 size
, base::TimeDelta());
58 VideoFrameCompositor
* compositor() { return compositor_
.get(); }
59 int did_receive_frame_count() { return did_receive_frame_count_
; }
60 int natural_size_changed_count() { return natural_size_changed_count_
; }
61 gfx::Size
natural_size() { return natural_size_
; }
63 int opacity_changed_count() { return opacity_changed_count_
; }
64 bool opaque() { return opaque_
; }
67 // cc::VideoFrameProvider::Client implementation.
68 void StopUsingProvider() override
{}
69 MOCK_METHOD0(StartRendering
, void());
70 MOCK_METHOD0(StopRendering
, void());
71 void DidReceiveFrame() override
{ ++did_receive_frame_count_
; }
72 void DidUpdateMatrix(const float* matrix
) override
{}
74 // VideoRendererSink::RenderCallback implementation.
76 scoped_refptr
<VideoFrame
>(base::TimeTicks
,
79 MOCK_METHOD0(OnFrameDropped
, void());
81 void NaturalSizeChanged(gfx::Size natural_size
) {
82 ++natural_size_changed_count_
;
83 natural_size_
= natural_size
;
86 void OpacityChanged(bool opaque
) {
87 ++opacity_changed_count_
;
91 void StartVideoRendererSink() {
92 EXPECT_CALL(*this, StartRendering());
93 const bool had_current_frame
= !!compositor_
->GetCurrentFrame();
94 compositor()->Start(this);
95 // If we previously had a frame, we should still have one now.
96 EXPECT_EQ(had_current_frame
, !!compositor_
->GetCurrentFrame());
97 message_loop
.RunUntilIdle();
100 void StopVideoRendererSink(bool have_client
) {
102 EXPECT_CALL(*this, StopRendering());
103 const bool had_current_frame
= !!compositor_
->GetCurrentFrame();
104 compositor()->Stop();
105 // If we previously had a frame, we should still have one now.
106 EXPECT_EQ(had_current_frame
, !!compositor_
->GetCurrentFrame());
107 message_loop
.RunUntilIdle();
111 compositor()->GetCurrentFrame();
112 compositor()->PutCurrentFrame();
115 base::MessageLoop message_loop
;
116 base::SimpleTestTickClock
* tick_clock_
; // Owned by |compositor_|
117 scoped_ptr
<VideoFrameCompositor
> compositor_
;
119 int did_receive_frame_count_
;
120 int natural_size_changed_count_
;
121 gfx::Size natural_size_
;
122 int opacity_changed_count_
;
125 DISALLOW_COPY_AND_ASSIGN(VideoFrameCompositorTest
);
128 TEST_F(VideoFrameCompositorTest
, InitialValues
) {
129 EXPECT_FALSE(compositor()->GetCurrentFrame().get());
132 TEST_F(VideoFrameCompositorTest
, PaintFrameUsingOldRenderingPath
) {
133 scoped_refptr
<VideoFrame
> expected
= VideoFrame::CreateEOSFrame();
135 // Should notify compositor synchronously.
136 EXPECT_EQ(0, did_receive_frame_count());
137 compositor()->PaintFrameUsingOldRenderingPath(expected
);
138 scoped_refptr
<VideoFrame
> actual
= compositor()->GetCurrentFrame();
139 EXPECT_EQ(expected
, actual
);
140 EXPECT_EQ(1, did_receive_frame_count());
143 TEST_F(VideoFrameCompositorTest
, NaturalSizeChanged
) {
144 gfx::Size
initial_size(8, 8);
145 scoped_refptr
<VideoFrame
> initial_frame
=
146 VideoFrame::CreateBlackFrame(initial_size
);
148 gfx::Size
larger_size(16, 16);
149 scoped_refptr
<VideoFrame
> larger_frame
=
150 VideoFrame::CreateBlackFrame(larger_size
);
152 gfx::Size
empty_size(0, 0);
154 // Initial expectations.
155 EXPECT_EQ(empty_size
, natural_size());
156 EXPECT_EQ(0, natural_size_changed_count());
158 // Callback isn't fired for the first frame.
159 compositor()->PaintFrameUsingOldRenderingPath(initial_frame
);
160 EXPECT_EQ(empty_size
, natural_size());
161 EXPECT_EQ(0, natural_size_changed_count());
163 // Callback should be fired once.
164 compositor()->PaintFrameUsingOldRenderingPath(larger_frame
);
165 EXPECT_EQ(larger_size
, natural_size());
166 EXPECT_EQ(1, natural_size_changed_count());
168 compositor()->PaintFrameUsingOldRenderingPath(larger_frame
);
169 EXPECT_EQ(larger_size
, natural_size());
170 EXPECT_EQ(1, natural_size_changed_count());
172 // Callback is fired once more when switching back to initial size.
173 compositor()->PaintFrameUsingOldRenderingPath(initial_frame
);
174 EXPECT_EQ(initial_size
, natural_size());
175 EXPECT_EQ(2, natural_size_changed_count());
177 compositor()->PaintFrameUsingOldRenderingPath(initial_frame
);
178 EXPECT_EQ(initial_size
, natural_size());
179 EXPECT_EQ(2, natural_size_changed_count());
181 natural_size_changed_count_
= 0;
182 natural_size_
= empty_size
;
183 compositor()->clear_current_frame_for_testing();
185 EXPECT_CALL(*this, Render(_
, _
, _
))
186 .WillOnce(Return(initial_frame
))
187 .WillOnce(Return(larger_frame
))
188 .WillOnce(Return(initial_frame
))
189 .WillOnce(Return(initial_frame
));
190 StartVideoRendererSink();
192 // Starting the sink will issue one Render() call, ensure the callback isn't
193 // fired for the first frame.
194 EXPECT_EQ(0, natural_size_changed_count());
195 EXPECT_EQ(empty_size
, natural_size());
197 // Once another frame is received with a different size it should fire.
199 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
201 EXPECT_EQ(larger_size
, natural_size());
202 EXPECT_EQ(1, natural_size_changed_count());
205 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
207 EXPECT_EQ(initial_size
, natural_size());
208 EXPECT_EQ(2, natural_size_changed_count());
211 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
212 EXPECT_EQ(initial_size
, natural_size());
213 EXPECT_EQ(2, natural_size_changed_count());
216 StopVideoRendererSink(true);
219 TEST_F(VideoFrameCompositorTest
, OpacityChanged
) {
220 gfx::Size
size(8, 8);
221 scoped_refptr
<VideoFrame
> opaque_frame
= CreateOpaqueFrame();
222 scoped_refptr
<VideoFrame
> not_opaque_frame
= VideoFrame::CreateFrame(
223 VideoFrame::YV12A
, size
, gfx::Rect(size
), size
, base::TimeDelta());
225 // Initial expectations.
226 EXPECT_FALSE(opaque());
227 EXPECT_EQ(0, opacity_changed_count());
229 // Callback is fired for the first frame.
230 compositor()->PaintFrameUsingOldRenderingPath(not_opaque_frame
);
231 EXPECT_FALSE(opaque());
232 EXPECT_EQ(1, opacity_changed_count());
234 // Callback shouldn't be first subsequent times with same opaqueness.
235 compositor()->PaintFrameUsingOldRenderingPath(not_opaque_frame
);
236 EXPECT_FALSE(opaque());
237 EXPECT_EQ(1, opacity_changed_count());
239 // Callback is fired when using opacity changes.
240 compositor()->PaintFrameUsingOldRenderingPath(opaque_frame
);
241 EXPECT_TRUE(opaque());
242 EXPECT_EQ(2, opacity_changed_count());
244 // Callback shouldn't be first subsequent times with same opaqueness.
245 compositor()->PaintFrameUsingOldRenderingPath(opaque_frame
);
246 EXPECT_TRUE(opaque());
247 EXPECT_EQ(2, opacity_changed_count());
249 opacity_changed_count_
= 0;
250 compositor()->clear_current_frame_for_testing();
252 EXPECT_CALL(*this, Render(_
, _
, _
))
253 .WillOnce(Return(not_opaque_frame
))
254 .WillOnce(Return(not_opaque_frame
))
255 .WillOnce(Return(opaque_frame
))
256 .WillOnce(Return(opaque_frame
));
257 StartVideoRendererSink();
258 EXPECT_FALSE(opaque());
259 EXPECT_EQ(1, opacity_changed_count());
262 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
264 EXPECT_FALSE(opaque());
265 EXPECT_EQ(1, opacity_changed_count());
268 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
270 EXPECT_TRUE(opaque());
271 EXPECT_EQ(2, opacity_changed_count());
274 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
275 EXPECT_TRUE(opaque());
276 EXPECT_EQ(2, opacity_changed_count());
279 StopVideoRendererSink(true);
282 TEST_F(VideoFrameCompositorTest
, VideoRendererSinkFrameDropped
) {
283 scoped_refptr
<VideoFrame
> opaque_frame
= CreateOpaqueFrame();
285 EXPECT_CALL(*this, Render(_
, _
, _
)).WillRepeatedly(Return(opaque_frame
));
286 StartVideoRendererSink();
288 // The first UpdateCurrentFrame() after a background render, which starting
289 // the sink does automatically, won't report a dropped frame.
291 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
293 // Another call should trigger a dropped frame callback.
294 EXPECT_CALL(*this, OnFrameDropped());
296 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
298 // Ensure it always happens until the frame is rendered.
299 EXPECT_CALL(*this, OnFrameDropped());
301 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
303 // Call GetCurrentFrame() but not PutCurrentFrame()
304 compositor()->GetCurrentFrame();
306 // The frame should still register as dropped until PutCurrentFrame is called.
307 EXPECT_CALL(*this, OnFrameDropped());
309 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
313 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
315 StopVideoRendererSink(true);
318 TEST_F(VideoFrameCompositorTest
, VideoLayerShutdownWhileRendering
) {
319 EXPECT_CALL(*this, Render(_
, _
, true)).WillOnce(Return(nullptr));
320 StartVideoRendererSink();
321 compositor_
->SetVideoFrameProviderClient(nullptr);
322 StopVideoRendererSink(false);
325 TEST_F(VideoFrameCompositorTest
, StartFiresBackgroundRender
) {
326 scoped_refptr
<VideoFrame
> opaque_frame
= CreateOpaqueFrame();
327 EXPECT_CALL(*this, Render(_
, _
, true)).WillRepeatedly(Return(opaque_frame
));
328 StartVideoRendererSink();
329 StopVideoRendererSink(true);
332 TEST_F(VideoFrameCompositorTest
, BackgroundRenderTicks
) {
333 scoped_refptr
<VideoFrame
> opaque_frame
= CreateOpaqueFrame();
334 compositor_
->set_background_rendering_for_testing(true);
336 base::RunLoop run_loop
;
337 EXPECT_CALL(*this, Render(_
, _
, true))
338 .WillOnce(Return(opaque_frame
))
340 DoAll(RunClosure(run_loop
.QuitClosure()), Return(opaque_frame
)));
341 StartVideoRendererSink();
344 // UpdateCurrentFrame() calls should indicate they are not synthetic.
345 EXPECT_CALL(*this, Render(_
, _
, false)).WillOnce(Return(opaque_frame
));
347 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
349 // Background rendering should tick another render callback.
350 StopVideoRendererSink(true);
353 TEST_F(VideoFrameCompositorTest
,
354 UpdateCurrentFrameWorksWhenBackgroundRendered
) {
355 scoped_refptr
<VideoFrame
> opaque_frame
= CreateOpaqueFrame();
356 compositor_
->set_background_rendering_for_testing(true);
358 // Background render a frame that succeeds immediately.
359 EXPECT_CALL(*this, Render(_
, _
, true)).WillOnce(Return(opaque_frame
));
360 StartVideoRendererSink();
362 // The background render completes immediately, so the next call to
363 // UpdateCurrentFrame is expected to return true to account for the frame
364 // rendered in the background.
365 EXPECT_CALL(*this, Render(_
, _
, false))
366 .WillOnce(Return(scoped_refptr
<VideoFrame
>(opaque_frame
)));
368 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
371 // Second call to UpdateCurrentFrame will return false as no new frame has
372 // been created since the last call.
373 EXPECT_CALL(*this, Render(_
, _
, false))
374 .WillOnce(Return(scoped_refptr
<VideoFrame
>(opaque_frame
)));
376 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
378 StopVideoRendererSink(true);
381 TEST_F(VideoFrameCompositorTest
, GetCurrentFrameAndUpdateIfStale
) {
382 scoped_refptr
<VideoFrame
> opaque_frame_1
= CreateOpaqueFrame();
383 scoped_refptr
<VideoFrame
> opaque_frame_2
= CreateOpaqueFrame();
384 compositor_
->set_background_rendering_for_testing(true);
386 // |current_frame_| should be null at this point since we don't have a client
388 ASSERT_FALSE(compositor()->GetCurrentFrameAndUpdateIfStale());
390 // Starting the video renderer should return a single frame.
391 EXPECT_CALL(*this, Render(_
, _
, true)).WillOnce(Return(opaque_frame_1
));
392 StartVideoRendererSink();
394 // Since we have a client, this call should not call background render, even
395 // if a lot of time has elapsed between calls.
396 tick_clock_
->Advance(base::TimeDelta::FromSeconds(1));
397 ASSERT_EQ(opaque_frame_1
, compositor()->GetCurrentFrameAndUpdateIfStale());
399 // An update current frame call should stop background rendering.
400 EXPECT_CALL(*this, Render(_
, _
, false)).WillOnce(Return(opaque_frame_2
));
402 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
404 // This call should still not call background render.
405 ASSERT_EQ(opaque_frame_2
, compositor()->GetCurrentFrameAndUpdateIfStale());
407 testing::Mock::VerifyAndClearExpectations(this);
409 // Clear our client, which means no mock function calls for Client.
410 compositor()->SetVideoFrameProviderClient(nullptr);
412 // This call should still not call background render, because we aren't in the
413 // background rendering state yet.
414 ASSERT_EQ(opaque_frame_2
, compositor()->GetCurrentFrameAndUpdateIfStale());
416 // Wait for background rendering to tick again.
417 base::RunLoop run_loop
;
418 EXPECT_CALL(*this, Render(_
, _
, true))
420 DoAll(RunClosure(run_loop
.QuitClosure()), Return(opaque_frame_1
)))
421 .WillOnce(Return(opaque_frame_2
));
424 // This call should still not call background render, because not enough time
425 // has elapsed since the last background render call.
426 ASSERT_EQ(opaque_frame_1
, compositor()->GetCurrentFrameAndUpdateIfStale());
428 // Advancing the tick clock should allow a new frame to be requested.
429 tick_clock_
->Advance(base::TimeDelta::FromMilliseconds(10));
430 ASSERT_EQ(opaque_frame_2
, compositor()->GetCurrentFrameAndUpdateIfStale());
432 // Background rendering should tick another render callback.
433 StopVideoRendererSink(false);