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_METHOD1(ReserveOutputBuffer
,
44 scoped_refptr
<media::VideoFrame
>(const gfx::Size
& size
));
45 MOCK_METHOD0(OnError
, void());
46 MOCK_METHOD1(OnFrameInfo
, void(const media::VideoCaptureCapability
& info
));
47 MOCK_METHOD1(OnFrameInfoChanged
,
48 void(const media::VideoCaptureCapability
& info
));
49 MOCK_METHOD6(OnIncomingCapturedFrame
, void(const uint8
* data
,
55 MOCK_METHOD2(OnIncomingCapturedVideoFrame
,
56 void(const scoped_refptr
<media::VideoFrame
>& frame
,
57 base::Time timestamp
));
60 // TODO(sergeyu): Move this to a separate file where it can be reused.
61 class FakeScreenCapturer
: public webrtc::ScreenCapturer
{
67 virtual ~FakeScreenCapturer() {}
69 // VideoFrameCapturer interface.
70 virtual void Start(Callback
* callback
) OVERRIDE
{
74 virtual void Capture(const webrtc::DesktopRegion
& region
) OVERRIDE
{
75 webrtc::DesktopSize size
;
76 if (frame_index_
% 2 == 0) {
77 size
= webrtc::DesktopSize(kTestFrameWidth1
, kTestFrameHeight1
);
79 size
= webrtc::DesktopSize(kTestFrameWidth2
, kTestFrameHeight2
);
82 callback_
->OnCaptureCompleted(new webrtc::BasicDesktopFrame(size
));
85 virtual void SetMouseShapeObserver(
86 MouseShapeObserver
* mouse_shape_observer
) OVERRIDE
{
94 class DesktopCaptureDeviceTest
: public testing::Test
{
96 virtual void SetUp() OVERRIDE
{
97 worker_pool_
= new base::SequencedWorkerPool(3, "TestCaptureThread");
101 scoped_refptr
<base::SequencedWorkerPool
> worker_pool_
;
106 // There is currently no screen capturer implementation for ozone. So disable
107 // the test that uses a real screen-capturer instead of FakeScreenCapturer.
108 // http://crbug.com/260318
109 #if defined(USE_OZONE)
110 #define MAYBE_Capture DISABLED_Capture
112 #define MAYBE_Capture Capture
114 TEST_F(DesktopCaptureDeviceTest
, MAYBE_Capture
) {
115 scoped_ptr
<webrtc::DesktopCapturer
> capturer(
116 webrtc::ScreenCapturer::Create());
117 DesktopCaptureDevice
capture_device(
118 worker_pool_
->GetSequencedTaskRunner(worker_pool_
->GetSequenceToken()),
120 media::VideoCaptureCapability caps
;
121 base::WaitableEvent
done_event(false, false);
124 scoped_ptr
<MockDeviceClient
> client(new MockDeviceClient());
125 EXPECT_CALL(*client
, OnFrameInfo(_
)).WillOnce(SaveArg
<0>(&caps
));
126 EXPECT_CALL(*client
, OnError()).Times(0);
127 EXPECT_CALL(*client
, OnIncomingCapturedFrame(_
, _
, _
, _
, _
, _
))
129 DoAll(SaveArg
<1>(&frame_size
),
130 InvokeWithoutArgs(&done_event
, &base::WaitableEvent::Signal
)));
132 media::VideoCaptureCapability
capture_format(
133 640, 480, kFrameRate
, media::PIXEL_FORMAT_I420
,
134 media::ConstantResolutionVideoCaptureDevice
);
135 capture_device
.AllocateAndStart(
136 capture_format
, client
.PassAs
<media::VideoCaptureDevice::Client
>());
137 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
138 capture_device
.StopAndDeAllocate();
140 EXPECT_GT(caps
.width
, 0);
141 EXPECT_GT(caps
.height
, 0);
142 EXPECT_EQ(kFrameRate
, caps
.frame_rate
);
143 EXPECT_EQ(media::PIXEL_FORMAT_ARGB
, caps
.color
);
145 EXPECT_EQ(caps
.width
* caps
.height
* 4, frame_size
);
146 worker_pool_
->FlushForTesting();
149 // Test that screen capturer behaves correctly if the source frame size changes
150 // but the caller cannot cope with variable resolution output.
151 TEST_F(DesktopCaptureDeviceTest
, ScreenResolutionChangeConstantResolution
) {
152 FakeScreenCapturer
* mock_capturer
= new FakeScreenCapturer();
154 DesktopCaptureDevice
capture_device(
155 worker_pool_
->GetSequencedTaskRunner(worker_pool_
->GetSequenceToken()),
156 scoped_ptr
<webrtc::DesktopCapturer
>(mock_capturer
));
158 media::VideoCaptureCapability caps
;
159 base::WaitableEvent
done_event(false, false);
162 scoped_ptr
<MockDeviceClient
> client(new MockDeviceClient());
163 Expectation frame_info_called
=
164 EXPECT_CALL(*client
, OnFrameInfo(_
)).WillOnce(SaveArg
<0>(&caps
));
165 EXPECT_CALL(*client
, OnFrameInfoChanged(_
)).Times(0);
166 EXPECT_CALL(*client
, OnError()).Times(0);
167 EXPECT_CALL(*client
, OnIncomingCapturedFrame(_
, _
, _
, _
, _
, _
))
168 .After(frame_info_called
)
170 DoAll(SaveArg
<1>(&frame_size
),
171 InvokeWithoutArgs(&done_event
, &base::WaitableEvent::Signal
)));
173 media::VideoCaptureCapability
capture_format(
177 media::PIXEL_FORMAT_I420
,
178 media::ConstantResolutionVideoCaptureDevice
);
180 capture_device
.AllocateAndStart(
181 capture_format
, client
.PassAs
<media::VideoCaptureDevice::Client
>());
183 // Capture at least two frames, to ensure that the source frame size has
184 // changed while capturing.
185 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
187 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
189 capture_device
.StopAndDeAllocate();
191 EXPECT_EQ(kTestFrameWidth1
, caps
.width
);
192 EXPECT_EQ(kTestFrameHeight1
, caps
.height
);
193 EXPECT_EQ(kFrameRate
, caps
.frame_rate
);
194 EXPECT_EQ(media::PIXEL_FORMAT_ARGB
, caps
.color
);
196 EXPECT_EQ(caps
.width
* caps
.height
* 4, frame_size
);
197 worker_pool_
->FlushForTesting();
200 // Test that screen capturer behaves correctly if the source frame size changes
201 // and the caller can cope with variable resolution output.
202 TEST_F(DesktopCaptureDeviceTest
, ScreenResolutionChangeVariableResolution
) {
203 FakeScreenCapturer
* mock_capturer
= new FakeScreenCapturer();
205 DesktopCaptureDevice
capture_device(
206 worker_pool_
->GetSequencedTaskRunner(worker_pool_
->GetSequenceToken()),
207 scoped_ptr
<webrtc::DesktopCapturer
>(mock_capturer
));
209 media::VideoCaptureCapability caps
;
210 base::WaitableEvent
done_event(false, false);
212 scoped_ptr
<MockDeviceClient
> client(new MockDeviceClient());
213 Expectation frame_info_called
=
214 EXPECT_CALL(*client
, OnFrameInfo(_
)).WillOnce(SaveArg
<0>(&caps
));
215 Expectation first_info_changed
= EXPECT_CALL(
217 OnFrameInfoChanged(EqualsCaptureCapability(
218 kTestFrameWidth2
, kTestFrameHeight2
))).After(frame_info_called
);
219 Expectation second_info_changed
= EXPECT_CALL(
221 OnFrameInfoChanged(EqualsCaptureCapability(
222 kTestFrameWidth1
, kTestFrameHeight1
))).After(first_info_changed
);
223 EXPECT_CALL(*client
, OnFrameInfoChanged(_
)).Times(AnyNumber()).After(
224 second_info_changed
);
225 EXPECT_CALL(*client
, OnError()).Times(0);
226 EXPECT_CALL(*client
, OnIncomingCapturedFrame(_
, _
, _
, _
, _
, _
))
227 .After(frame_info_called
)
229 InvokeWithoutArgs(&done_event
, &base::WaitableEvent::Signal
));
231 media::VideoCaptureCapability
capture_format(
235 media::PIXEL_FORMAT_I420
,
236 media::VariableResolutionVideoCaptureDevice
);
238 capture_device
.AllocateAndStart(
239 capture_format
, client
.PassAs
<media::VideoCaptureDevice::Client
>());
241 // Capture at least three frames, to ensure that the source frame size has
242 // changed at least twice while capturing.
243 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
245 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
247 EXPECT_TRUE(done_event
.TimedWait(TestTimeouts::action_max_timeout()));
249 capture_device
.StopAndDeAllocate();
251 EXPECT_EQ(kTestFrameWidth1
, caps
.width
);
252 EXPECT_EQ(kTestFrameHeight1
, caps
.height
);
253 EXPECT_EQ(kFrameRate
, caps
.frame_rate
);
254 EXPECT_EQ(media::PIXEL_FORMAT_ARGB
, caps
.color
);
255 worker_pool_
->FlushForTesting();
258 } // namespace content