1 // Copyright (c) 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.
5 #include "content/browser/renderer_host/media/desktop_capture_device.h"
7 #include "base/basictypes.h"
8 #include "base/sequenced_task_runner.h"
9 #include "base/synchronization/waitable_event.h"
10 #include "base/test/test_timeouts.h"
11 #include "base/threading/sequenced_worker_pool.h"
12 #include "base/time/time.h"
13 #include "testing/gmock/include/gmock/gmock.h"
14 #include "testing/gtest/include/gtest/gtest.h"
15 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
16 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
17 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
20 using ::testing::AnyNumber
;
21 using ::testing::DoAll
;
22 using ::testing::Expectation
;
23 using ::testing::InvokeWithoutArgs
;
24 using ::testing::SaveArg
;
30 MATCHER_P2(EqualsCaptureCapability
, width
, height
, "") {
31 return arg
.width
== width
&& arg
.height
== height
;
34 const int kTestFrameWidth1
= 100;
35 const int kTestFrameHeight1
= 100;
36 const int kTestFrameWidth2
= 200;
37 const int kTestFrameHeight2
= 150;
39 const int kFrameRate
= 30;
41 class MockDeviceClient
: public media::VideoCaptureDevice::Client
{
43 MOCK_METHOD2(ReserveOutputBuffer
,
44 scoped_refptr
<Buffer
>(media::VideoFrame::Format format
,
45 const gfx::Size
& dimensions
));
46 MOCK_METHOD0(OnError
, void());
47 MOCK_METHOD7(OnIncomingCapturedFrame
,
48 void(const uint8
* data
,
54 const media::VideoCaptureFormat
& frame_format
));
55 MOCK_METHOD5(OnIncomingCapturedBuffer
,
56 void(const scoped_refptr
<Buffer
>& buffer
,
57 media::VideoFrame::Format format
,
58 const gfx::Size
& dimensions
,
63 // DesktopFrame wrapper that flips wrapped frame upside down by inverting
65 class InvertedDesktopFrame
: public webrtc::DesktopFrame
{
67 // Takes ownership of |frame|.
68 InvertedDesktopFrame(webrtc::DesktopFrame
* frame
)
69 : webrtc::DesktopFrame(
70 frame
->size(), -frame
->stride(),
71 frame
->data() + (frame
->size().height() - 1) * frame
->stride(),
72 frame
->shared_memory()),
73 original_frame_(frame
) {
74 set_dpi(frame
->dpi());
75 set_capture_time_ms(frame
->capture_time_ms());
76 mutable_updated_region()->Swap(frame
->mutable_updated_region());
78 virtual ~InvertedDesktopFrame() {}
81 scoped_ptr
<webrtc::DesktopFrame
> original_frame_
;
83 DISALLOW_COPY_AND_ASSIGN(InvertedDesktopFrame
);
86 // TODO(sergeyu): Move this to a separate file where it can be reused.
87 class FakeScreenCapturer
: public webrtc::ScreenCapturer
{
92 generate_inverted_frames_(false) {
94 virtual ~FakeScreenCapturer() {}
96 void set_generate_inverted_frames(bool generate_inverted_frames
) {
97 generate_inverted_frames_
= generate_inverted_frames
;
100 // VideoFrameCapturer interface.
101 virtual void Start(Callback
* callback
) OVERRIDE
{
102 callback_
= callback
;
105 virtual void Capture(const webrtc::DesktopRegion
& region
) OVERRIDE
{
106 webrtc::DesktopSize size
;
107 if (frame_index_
% 2 == 0) {
108 size
= webrtc::DesktopSize(kTestFrameWidth1
, kTestFrameHeight1
);
110 size
= webrtc::DesktopSize(kTestFrameWidth2
, kTestFrameHeight2
);
114 webrtc::DesktopFrame
* frame
= new webrtc::BasicDesktopFrame(size
);
115 if (generate_inverted_frames_
)
116 frame
= new InvertedDesktopFrame(frame
);
117 callback_
->OnCaptureCompleted(frame
);
120 virtual void SetMouseShapeObserver(
121 MouseShapeObserver
* mouse_shape_observer
) OVERRIDE
{
127 bool generate_inverted_frames_
;
130 class DesktopCaptureDeviceTest
: public testing::Test
{
132 virtual void SetUp() OVERRIDE
{
133 worker_pool_
= new base::SequencedWorkerPool(3, "TestCaptureThread");
137 scoped_refptr
<base::SequencedWorkerPool
> worker_pool_
;
142 // There is currently no screen capturer implementation for ozone. So disable
143 // the test that uses a real screen-capturer instead of FakeScreenCapturer.
144 // http://crbug.com/260318
145 #if defined(USE_OZONE)
146 #define MAYBE_Capture DISABLED_Capture
148 #define MAYBE_Capture Capture
150 TEST_F(DesktopCaptureDeviceTest
, MAYBE_Capture
) {
151 scoped_ptr
<webrtc::DesktopCapturer
> capturer(
152 webrtc::ScreenCapturer::Create());
153 DesktopCaptureDevice
capture_device(
154 worker_pool_
->GetSequencedTaskRunner(worker_pool_
->GetSequenceToken()),
156 media::VideoCaptureFormat format
;
157 base::WaitableEvent
done_event(false, false);
160 scoped_ptr
<MockDeviceClient
> client(new MockDeviceClient());
161 EXPECT_CALL(*client
, OnError()).Times(0);
162 EXPECT_CALL(*client
, OnIncomingCapturedFrame(_
, _
, _
, _
, _
, _
, _
))
164 DoAll(SaveArg
<1>(&frame_size
),
166 InvokeWithoutArgs(&done_event
, &base::WaitableEvent::Signal
)));
168 media::VideoCaptureParams capture_params
;
169 capture_params
.requested_format
.frame_size
.SetSize(640, 480);
170 capture_params
.requested_format
.frame_rate
= kFrameRate
;
171 capture_params
.requested_format
.pixel_format
= media::PIXEL_FORMAT_I420
;
172 capture_params
.allow_resolution_change
= false;
173 capture_device
.AllocateAndStart(
174 capture_params
, client
.PassAs
<media::VideoCaptureDevice::Client
>());
175 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
176 capture_device
.StopAndDeAllocate();
178 EXPECT_GT(format
.frame_size
.width(), 0);
179 EXPECT_GT(format
.frame_size
.height(), 0);
180 EXPECT_EQ(kFrameRate
, format
.frame_rate
);
181 EXPECT_EQ(media::PIXEL_FORMAT_ARGB
, format
.pixel_format
);
183 EXPECT_EQ(format
.frame_size
.GetArea() * 4, frame_size
);
184 worker_pool_
->FlushForTesting();
187 // Verify that frames are flipped when the capturer generates inverted frames.
188 TEST_F(DesktopCaptureDeviceTest
, InvertedFrame
) {
189 FakeScreenCapturer
* mock_capturer
= new FakeScreenCapturer();
190 mock_capturer
->set_generate_inverted_frames(true);
192 DesktopCaptureDevice
capture_device(
193 worker_pool_
->GetSequencedTaskRunner(worker_pool_
->GetSequenceToken()),
194 scoped_ptr
<webrtc::DesktopCapturer
>(mock_capturer
));
195 base::WaitableEvent
done_event(false, false);
197 scoped_ptr
<MockDeviceClient
> client(new MockDeviceClient());
198 EXPECT_CALL(*client
, OnError()).Times(0);
200 // Expect that |flop_vert| is set to true.
201 EXPECT_CALL(*client
, OnIncomingCapturedFrame(_
, _
, _
, _
, true, false, _
))
203 InvokeWithoutArgs(&done_event
, &base::WaitableEvent::Signal
));
205 media::VideoCaptureParams capture_params
;
206 capture_params
.requested_format
.frame_size
.SetSize(640, 480);
207 capture_params
.requested_format
.frame_rate
= kFrameRate
;
208 capture_params
.requested_format
.pixel_format
= media::PIXEL_FORMAT_I420
;
209 capture_params
.allow_resolution_change
= false;
210 capture_device
.AllocateAndStart(
211 capture_params
, client
.PassAs
<media::VideoCaptureDevice::Client
>());
212 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
213 capture_device
.StopAndDeAllocate();
215 worker_pool_
->FlushForTesting();
218 // Test that screen capturer behaves correctly if the source frame size changes
219 // but the caller cannot cope with variable resolution output.
220 TEST_F(DesktopCaptureDeviceTest
, ScreenResolutionChangeConstantResolution
) {
221 FakeScreenCapturer
* mock_capturer
= new FakeScreenCapturer();
223 DesktopCaptureDevice
capture_device(
224 worker_pool_
->GetSequencedTaskRunner(worker_pool_
->GetSequenceToken()),
225 scoped_ptr
<webrtc::DesktopCapturer
>(mock_capturer
));
227 media::VideoCaptureFormat format
;
228 base::WaitableEvent
done_event(false, false);
231 scoped_ptr
<MockDeviceClient
> client(new MockDeviceClient());
232 EXPECT_CALL(*client
, OnError()).Times(0);
233 EXPECT_CALL(*client
, OnIncomingCapturedFrame(_
, _
, _
, _
, false, false, _
))
235 DoAll(SaveArg
<1>(&frame_size
),
237 InvokeWithoutArgs(&done_event
, &base::WaitableEvent::Signal
)));
239 media::VideoCaptureParams capture_params
;
240 capture_params
.requested_format
.frame_size
.SetSize(kTestFrameWidth1
,
242 capture_params
.requested_format
.frame_rate
= kFrameRate
;
243 capture_params
.requested_format
.pixel_format
= media::PIXEL_FORMAT_I420
;
244 capture_params
.allow_resolution_change
= false;
246 capture_device
.AllocateAndStart(
247 capture_params
, client
.PassAs
<media::VideoCaptureDevice::Client
>());
249 // Capture at least two frames, to ensure that the source frame size has
250 // changed while capturing.
251 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
253 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
255 capture_device
.StopAndDeAllocate();
257 EXPECT_EQ(kTestFrameWidth1
, format
.frame_size
.width());
258 EXPECT_EQ(kTestFrameHeight1
, format
.frame_size
.height());
259 EXPECT_EQ(kFrameRate
, format
.frame_rate
);
260 EXPECT_EQ(media::PIXEL_FORMAT_ARGB
, format
.pixel_format
);
262 EXPECT_EQ(format
.frame_size
.GetArea() * 4, frame_size
);
263 worker_pool_
->FlushForTesting();
266 // Test that screen capturer behaves correctly if the source frame size changes
267 // and the caller can cope with variable resolution output.
268 TEST_F(DesktopCaptureDeviceTest
, ScreenResolutionChangeVariableResolution
) {
269 FakeScreenCapturer
* mock_capturer
= new FakeScreenCapturer();
271 DesktopCaptureDevice
capture_device(
272 worker_pool_
->GetSequencedTaskRunner(worker_pool_
->GetSequenceToken()),
273 scoped_ptr
<webrtc::DesktopCapturer
>(mock_capturer
));
275 media::VideoCaptureFormat format
;
276 base::WaitableEvent
done_event(false, false);
278 scoped_ptr
<MockDeviceClient
> client(new MockDeviceClient());
279 EXPECT_CALL(*client
, OnError()).Times(0);
280 EXPECT_CALL(*client
, OnIncomingCapturedFrame(_
, _
, _
, _
, _
, _
, _
))
282 DoAll(SaveArg
<6>(&format
),
283 InvokeWithoutArgs(&done_event
, &base::WaitableEvent::Signal
)));
285 media::VideoCaptureParams capture_params
;
286 capture_params
.requested_format
.frame_size
.SetSize(kTestFrameWidth2
,
288 capture_params
.requested_format
.frame_rate
= kFrameRate
;
289 capture_params
.requested_format
.pixel_format
= media::PIXEL_FORMAT_I420
;
290 capture_params
.allow_resolution_change
= false;
292 capture_device
.AllocateAndStart(
293 capture_params
, client
.PassAs
<media::VideoCaptureDevice::Client
>());
295 // Capture at least three frames, to ensure that the source frame size has
296 // changed at least twice while capturing.
297 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
299 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
301 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
303 capture_device
.StopAndDeAllocate();
305 EXPECT_EQ(kTestFrameWidth1
, format
.frame_size
.width());
306 EXPECT_EQ(kTestFrameHeight1
, format
.frame_size
.height());
307 EXPECT_EQ(kFrameRate
, format
.frame_rate
);
308 EXPECT_EQ(media::PIXEL_FORMAT_ARGB
, format
.pixel_format
);
309 worker_pool_
->FlushForTesting();
312 } // namespace content