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/media/capture/desktop_capture_device.h"
7 #include "base/basictypes.h"
8 #include "base/synchronization/waitable_event.h"
9 #include "base/test/test_timeouts.h"
10 #include "base/time/time.h"
11 #include "content/public/test/test_browser_thread_bundle.h"
12 #include "testing/gmock/include/gmock/gmock.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
15 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
16 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
19 using ::testing::AnyNumber
;
20 using ::testing::DoAll
;
21 using ::testing::Expectation
;
22 using ::testing::InvokeWithoutArgs
;
23 using ::testing::SaveArg
;
29 MATCHER_P2(EqualsCaptureCapability
, width
, height
, "") {
30 return arg
.width
== width
&& arg
.height
== height
;
33 const int kTestFrameWidth1
= 100;
34 const int kTestFrameHeight1
= 100;
35 const int kTestFrameWidth2
= 200;
36 const int kTestFrameHeight2
= 150;
38 const int kFrameRate
= 30;
40 class MockDeviceClient
: public media::VideoCaptureDevice::Client
{
42 MOCK_METHOD2(ReserveOutputBuffer
,
43 scoped_refptr
<Buffer
>(media::VideoFrame::Format format
,
44 const gfx::Size
& dimensions
));
45 MOCK_METHOD1(OnError
, void(const std::string
& reason
));
46 MOCK_METHOD5(OnIncomingCapturedData
,
47 void(const uint8
* data
,
49 const media::VideoCaptureFormat
& frame_format
,
51 base::TimeTicks timestamp
));
52 MOCK_METHOD4(OnIncomingCapturedVideoFrame
,
53 void(const scoped_refptr
<Buffer
>& buffer
,
54 const media::VideoCaptureFormat
& buffer_format
,
55 const scoped_refptr
<media::VideoFrame
>& frame
,
56 base::TimeTicks timestamp
));
59 // DesktopFrame wrapper that flips wrapped frame upside down by inverting
61 class InvertedDesktopFrame
: public webrtc::DesktopFrame
{
63 // Takes ownership of |frame|.
64 InvertedDesktopFrame(webrtc::DesktopFrame
* frame
)
65 : webrtc::DesktopFrame(
66 frame
->size(), -frame
->stride(),
67 frame
->data() + (frame
->size().height() - 1) * frame
->stride(),
68 frame
->shared_memory()),
69 original_frame_(frame
) {
70 set_dpi(frame
->dpi());
71 set_capture_time_ms(frame
->capture_time_ms());
72 mutable_updated_region()->Swap(frame
->mutable_updated_region());
74 virtual ~InvertedDesktopFrame() {}
77 scoped_ptr
<webrtc::DesktopFrame
> original_frame_
;
79 DISALLOW_COPY_AND_ASSIGN(InvertedDesktopFrame
);
82 // TODO(sergeyu): Move this to a separate file where it can be reused.
83 class FakeScreenCapturer
: public webrtc::ScreenCapturer
{
88 generate_inverted_frames_(false) {
90 virtual ~FakeScreenCapturer() {}
92 void set_generate_inverted_frames(bool generate_inverted_frames
) {
93 generate_inverted_frames_
= generate_inverted_frames
;
96 // VideoFrameCapturer interface.
97 virtual void Start(Callback
* callback
) OVERRIDE
{
101 virtual void Capture(const webrtc::DesktopRegion
& region
) OVERRIDE
{
102 webrtc::DesktopSize size
;
103 if (frame_index_
% 2 == 0) {
104 size
= webrtc::DesktopSize(kTestFrameWidth1
, kTestFrameHeight1
);
106 size
= webrtc::DesktopSize(kTestFrameWidth2
, kTestFrameHeight2
);
110 webrtc::DesktopFrame
* frame
= new webrtc::BasicDesktopFrame(size
);
111 if (generate_inverted_frames_
)
112 frame
= new InvertedDesktopFrame(frame
);
113 callback_
->OnCaptureCompleted(frame
);
116 virtual void SetMouseShapeObserver(
117 MouseShapeObserver
* mouse_shape_observer
) OVERRIDE
{
120 virtual bool GetScreenList(ScreenList
* screens
) OVERRIDE
{
124 virtual bool SelectScreen(webrtc::ScreenId id
) OVERRIDE
{
131 bool generate_inverted_frames_
;
136 class DesktopCaptureDeviceTest
: public testing::Test
{
138 void CreateScreenCaptureDevice(scoped_ptr
<webrtc::DesktopCapturer
> capturer
) {
139 capture_device_
.reset(
140 new DesktopCaptureDevice(capturer
.Pass(), DesktopMediaID::TYPE_SCREEN
));
144 scoped_ptr
<DesktopCaptureDevice
> capture_device_
;
147 // There is currently no screen capturer implementation for ozone. So disable
148 // the test that uses a real screen-capturer instead of FakeScreenCapturer.
149 // http://crbug.com/260318
150 #if defined(USE_OZONE)
151 #define MAYBE_Capture DISABLED_Capture
153 #define MAYBE_Capture Capture
155 TEST_F(DesktopCaptureDeviceTest
, MAYBE_Capture
) {
156 scoped_ptr
<webrtc::DesktopCapturer
> capturer(
157 webrtc::ScreenCapturer::Create());
158 CreateScreenCaptureDevice(capturer
.Pass());
160 media::VideoCaptureFormat format
;
161 base::WaitableEvent
done_event(false, false);
164 scoped_ptr
<MockDeviceClient
> client(new MockDeviceClient());
165 EXPECT_CALL(*client
, OnError(_
)).Times(0);
166 EXPECT_CALL(*client
, OnIncomingCapturedData(_
, _
, _
, _
, _
)).WillRepeatedly(
167 DoAll(SaveArg
<1>(&frame_size
),
169 InvokeWithoutArgs(&done_event
, &base::WaitableEvent::Signal
)));
171 media::VideoCaptureParams capture_params
;
172 capture_params
.requested_format
.frame_size
.SetSize(640, 480);
173 capture_params
.requested_format
.frame_rate
= kFrameRate
;
174 capture_params
.requested_format
.pixel_format
= media::PIXEL_FORMAT_I420
;
175 capture_params
.allow_resolution_change
= false;
176 capture_device_
->AllocateAndStart(
177 capture_params
, client
.PassAs
<media::VideoCaptureDevice::Client
>());
178 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
179 capture_device_
->StopAndDeAllocate();
181 EXPECT_GT(format
.frame_size
.width(), 0);
182 EXPECT_GT(format
.frame_size
.height(), 0);
183 EXPECT_EQ(kFrameRate
, format
.frame_rate
);
184 EXPECT_EQ(media::PIXEL_FORMAT_ARGB
, format
.pixel_format
);
186 EXPECT_EQ(format
.frame_size
.GetArea() * 4, frame_size
);
189 // Test that screen capturer behaves correctly if the source frame size changes
190 // but the caller cannot cope with variable resolution output.
191 TEST_F(DesktopCaptureDeviceTest
, ScreenResolutionChangeConstantResolution
) {
192 FakeScreenCapturer
* mock_capturer
= new FakeScreenCapturer();
194 CreateScreenCaptureDevice(scoped_ptr
<webrtc::DesktopCapturer
>(mock_capturer
));
196 media::VideoCaptureFormat format
;
197 base::WaitableEvent
done_event(false, false);
200 scoped_ptr
<MockDeviceClient
> client(new MockDeviceClient());
201 EXPECT_CALL(*client
, OnError(_
)).Times(0);
202 EXPECT_CALL(*client
, OnIncomingCapturedData(_
, _
, _
, _
, _
)).WillRepeatedly(
203 DoAll(SaveArg
<1>(&frame_size
),
205 InvokeWithoutArgs(&done_event
, &base::WaitableEvent::Signal
)));
207 media::VideoCaptureParams capture_params
;
208 capture_params
.requested_format
.frame_size
.SetSize(kTestFrameWidth1
,
210 capture_params
.requested_format
.frame_rate
= kFrameRate
;
211 capture_params
.requested_format
.pixel_format
= media::PIXEL_FORMAT_I420
;
212 capture_params
.allow_resolution_change
= false;
214 capture_device_
->AllocateAndStart(
215 capture_params
, client
.PassAs
<media::VideoCaptureDevice::Client
>());
217 // Capture at least two frames, to ensure that the source frame size has
218 // changed while capturing.
219 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
221 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
223 capture_device_
->StopAndDeAllocate();
225 EXPECT_EQ(kTestFrameWidth1
, format
.frame_size
.width());
226 EXPECT_EQ(kTestFrameHeight1
, format
.frame_size
.height());
227 EXPECT_EQ(kFrameRate
, format
.frame_rate
);
228 EXPECT_EQ(media::PIXEL_FORMAT_ARGB
, format
.pixel_format
);
230 EXPECT_EQ(format
.frame_size
.GetArea() * 4, frame_size
);
233 // Test that screen capturer behaves correctly if the source frame size changes
234 // and the caller can cope with variable resolution output.
235 TEST_F(DesktopCaptureDeviceTest
, ScreenResolutionChangeVariableResolution
) {
236 FakeScreenCapturer
* mock_capturer
= new FakeScreenCapturer();
238 CreateScreenCaptureDevice(scoped_ptr
<webrtc::DesktopCapturer
>(mock_capturer
));
240 media::VideoCaptureFormat format
;
241 base::WaitableEvent
done_event(false, false);
243 scoped_ptr
<MockDeviceClient
> client(new MockDeviceClient());
244 EXPECT_CALL(*client
, OnError(_
)).Times(0);
245 EXPECT_CALL(*client
, OnIncomingCapturedData(_
, _
, _
, _
, _
)).WillRepeatedly(
246 DoAll(SaveArg
<2>(&format
),
247 InvokeWithoutArgs(&done_event
, &base::WaitableEvent::Signal
)));
249 media::VideoCaptureParams capture_params
;
250 capture_params
.requested_format
.frame_size
.SetSize(kTestFrameWidth2
,
252 capture_params
.requested_format
.frame_rate
= kFrameRate
;
253 capture_params
.requested_format
.pixel_format
= media::PIXEL_FORMAT_I420
;
254 capture_params
.allow_resolution_change
= false;
256 capture_device_
->AllocateAndStart(
257 capture_params
, client
.PassAs
<media::VideoCaptureDevice::Client
>());
259 // Capture at least three frames, to ensure that the source frame size has
260 // changed at least twice while capturing.
261 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
263 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
265 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
267 capture_device_
->StopAndDeAllocate();
269 EXPECT_EQ(kTestFrameWidth1
, format
.frame_size
.width());
270 EXPECT_EQ(kTestFrameHeight1
, format
.frame_size
.height());
271 EXPECT_EQ(kFrameRate
, format
.frame_rate
);
272 EXPECT_EQ(media::PIXEL_FORMAT_ARGB
, format
.pixel_format
);
275 } // namespace content