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(PIXEL_FORMAT_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 PIXEL_FORMAT_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();
289 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
291 // Another call should trigger a dropped frame callback.
292 EXPECT_CALL(*this, OnFrameDropped());
294 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
296 // Ensure it always happens until the frame is rendered.
297 EXPECT_CALL(*this, OnFrameDropped());
299 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
301 // Call GetCurrentFrame() but not PutCurrentFrame()
302 compositor()->GetCurrentFrame();
304 // The frame should still register as dropped until PutCurrentFrame is called.
305 EXPECT_CALL(*this, OnFrameDropped());
307 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
311 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
313 StopVideoRendererSink(true);
316 TEST_F(VideoFrameCompositorTest
, VideoLayerShutdownWhileRendering
) {
317 EXPECT_CALL(*this, Render(_
, _
, true)).WillOnce(Return(nullptr));
318 StartVideoRendererSink();
319 compositor_
->SetVideoFrameProviderClient(nullptr);
320 StopVideoRendererSink(false);
323 TEST_F(VideoFrameCompositorTest
, StartFiresBackgroundRender
) {
324 scoped_refptr
<VideoFrame
> opaque_frame
= CreateOpaqueFrame();
325 EXPECT_CALL(*this, Render(_
, _
, true)).WillRepeatedly(Return(opaque_frame
));
326 StartVideoRendererSink();
327 StopVideoRendererSink(true);
330 TEST_F(VideoFrameCompositorTest
, BackgroundRenderTicks
) {
331 scoped_refptr
<VideoFrame
> opaque_frame
= CreateOpaqueFrame();
332 compositor_
->set_background_rendering_for_testing(true);
334 base::RunLoop run_loop
;
335 EXPECT_CALL(*this, Render(_
, _
, true))
336 .WillOnce(Return(opaque_frame
))
338 DoAll(RunClosure(run_loop
.QuitClosure()), Return(opaque_frame
)));
339 StartVideoRendererSink();
342 // UpdateCurrentFrame() calls should indicate they are not synthetic.
343 EXPECT_CALL(*this, Render(_
, _
, false)).WillOnce(Return(opaque_frame
));
345 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
347 // Background rendering should tick another render callback.
348 StopVideoRendererSink(true);
351 TEST_F(VideoFrameCompositorTest
,
352 UpdateCurrentFrameWorksWhenBackgroundRendered
) {
353 scoped_refptr
<VideoFrame
> opaque_frame
= CreateOpaqueFrame();
354 compositor_
->set_background_rendering_for_testing(true);
356 // Background render a frame that succeeds immediately.
357 EXPECT_CALL(*this, Render(_
, _
, true)).WillOnce(Return(opaque_frame
));
358 StartVideoRendererSink();
360 // The background render completes immediately, so the next call to
361 // UpdateCurrentFrame is expected to return true to account for the frame
362 // rendered in the background.
363 EXPECT_CALL(*this, Render(_
, _
, false))
364 .WillOnce(Return(scoped_refptr
<VideoFrame
>(opaque_frame
)));
366 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
369 // Second call to UpdateCurrentFrame will return false as no new frame has
370 // been created since the last call.
371 EXPECT_CALL(*this, Render(_
, _
, false))
372 .WillOnce(Return(scoped_refptr
<VideoFrame
>(opaque_frame
)));
374 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
376 StopVideoRendererSink(true);
379 TEST_F(VideoFrameCompositorTest
, GetCurrentFrameAndUpdateIfStale
) {
380 scoped_refptr
<VideoFrame
> opaque_frame_1
= CreateOpaqueFrame();
381 scoped_refptr
<VideoFrame
> opaque_frame_2
= CreateOpaqueFrame();
382 compositor_
->set_background_rendering_for_testing(true);
384 // |current_frame_| should be null at this point since we don't have a client
386 ASSERT_FALSE(compositor()->GetCurrentFrameAndUpdateIfStale());
388 // Starting the video renderer should return a single frame.
389 EXPECT_CALL(*this, Render(_
, _
, true)).WillOnce(Return(opaque_frame_1
));
390 StartVideoRendererSink();
392 // Since we have a client, this call should not call background render, even
393 // if a lot of time has elapsed between calls.
394 tick_clock_
->Advance(base::TimeDelta::FromSeconds(1));
395 ASSERT_EQ(opaque_frame_1
, compositor()->GetCurrentFrameAndUpdateIfStale());
397 // An update current frame call should stop background rendering.
398 EXPECT_CALL(*this, Render(_
, _
, false)).WillOnce(Return(opaque_frame_2
));
400 compositor()->UpdateCurrentFrame(base::TimeTicks(), base::TimeTicks()));
402 // This call should still not call background render.
403 ASSERT_EQ(opaque_frame_2
, compositor()->GetCurrentFrameAndUpdateIfStale());
405 testing::Mock::VerifyAndClearExpectations(this);
407 // Clear our client, which means no mock function calls for Client.
408 compositor()->SetVideoFrameProviderClient(nullptr);
410 // This call should still not call background render, because we aren't in the
411 // background rendering state yet.
412 ASSERT_EQ(opaque_frame_2
, compositor()->GetCurrentFrameAndUpdateIfStale());
414 // Wait for background rendering to tick again.
415 base::RunLoop run_loop
;
416 EXPECT_CALL(*this, Render(_
, _
, true))
418 DoAll(RunClosure(run_loop
.QuitClosure()), Return(opaque_frame_1
)))
419 .WillOnce(Return(opaque_frame_2
));
422 // This call should still not call background render, because not enough time
423 // has elapsed since the last background render call.
424 ASSERT_EQ(opaque_frame_1
, compositor()->GetCurrentFrameAndUpdateIfStale());
426 // Advancing the tick clock should allow a new frame to be requested.
427 tick_clock_
->Advance(base::TimeDelta::FromMilliseconds(10));
428 ASSERT_EQ(opaque_frame_2
, compositor()->GetCurrentFrameAndUpdateIfStale());
430 // Background rendering should tick another render callback.
431 StopVideoRendererSink(false);