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"
9 #include "base/basictypes.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "base/test/test_timeouts.h"
12 #include "base/time/time.h"
13 #include "content/public/test/test_browser_thread_bundle.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
17 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
18 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
21 using ::testing::AnyNumber;
22 using ::testing::DoAll;
23 using ::testing::Expectation;
24 using ::testing::InvokeWithoutArgs;
25 using ::testing::SaveArg;
31 MATCHER_P2(EqualsCaptureCapability, width, height, "") {
32 return arg.width == width && arg.height == height;
35 const int kTestFrameWidth1 = 100;
36 const int kTestFrameHeight1 = 100;
37 const int kTestFrameWidth2 = 200;
38 const int kTestFrameHeight2 = 150;
40 const int kFrameRate = 30;
42 class MockDeviceClient : public media::VideoCaptureDevice::Client {
44 MOCK_METHOD2(ReserveOutputBuffer,
45 scoped_refptr<Buffer>(media::VideoFrame::Format format,
46 const gfx::Size& dimensions));
47 MOCK_METHOD1(OnError, void(const std::string& reason));
48 MOCK_METHOD5(OnIncomingCapturedData,
49 void(const uint8* data,
51 const media::VideoCaptureFormat& frame_format,
53 base::TimeTicks timestamp));
54 MOCK_METHOD4(OnIncomingCapturedVideoFrame,
55 void(const scoped_refptr<Buffer>& buffer,
56 const media::VideoCaptureFormat& buffer_format,
57 const scoped_refptr<media::VideoFrame>& frame,
58 base::TimeTicks timestamp));
61 // DesktopFrame wrapper that flips wrapped frame upside down by inverting
63 class InvertedDesktopFrame : public webrtc::DesktopFrame {
65 // Takes ownership of |frame|.
66 explicit InvertedDesktopFrame(webrtc::DesktopFrame* frame)
67 : webrtc::DesktopFrame(
70 frame->data() + (frame->size().height() - 1) * frame->stride(),
71 frame->shared_memory()),
72 original_frame_(frame) {
73 set_dpi(frame->dpi());
74 set_capture_time_ms(frame->capture_time_ms());
75 mutable_updated_region()->Swap(frame->mutable_updated_region());
77 ~InvertedDesktopFrame() override {}
80 scoped_ptr<webrtc::DesktopFrame> original_frame_;
82 DISALLOW_COPY_AND_ASSIGN(InvertedDesktopFrame);
85 // TODO(sergeyu): Move this to a separate file where it can be reused.
86 class FakeScreenCapturer : public webrtc::ScreenCapturer {
91 generate_inverted_frames_(false) {
93 ~FakeScreenCapturer() override {}
95 void set_generate_inverted_frames(bool generate_inverted_frames) {
96 generate_inverted_frames_ = generate_inverted_frames;
99 // VideoFrameCapturer interface.
100 void Start(Callback* callback) override { callback_ = callback; }
102 void Capture(const webrtc::DesktopRegion& region) override {
103 webrtc::DesktopSize size;
104 if (frame_index_ % 2 == 0) {
105 size = webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1);
107 size = webrtc::DesktopSize(kTestFrameWidth2, kTestFrameHeight2);
111 webrtc::DesktopFrame* frame = new webrtc::BasicDesktopFrame(size);
112 if (generate_inverted_frames_)
113 frame = new InvertedDesktopFrame(frame);
114 callback_->OnCaptureCompleted(frame);
117 void SetMouseShapeObserver(
118 MouseShapeObserver* mouse_shape_observer) override {}
120 bool GetScreenList(ScreenList* screens) override { return false; }
122 bool SelectScreen(webrtc::ScreenId id) override { return false; }
127 bool generate_inverted_frames_;
132 class DesktopCaptureDeviceTest : public testing::Test {
134 void CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer> capturer) {
135 capture_device_.reset(
136 new DesktopCaptureDevice(capturer.Pass(), DesktopMediaID::TYPE_SCREEN));
140 scoped_ptr<DesktopCaptureDevice> capture_device_;
143 // There is currently no screen capturer implementation for ozone. So disable
144 // the test that uses a real screen-capturer instead of FakeScreenCapturer.
145 // http://crbug.com/260318
146 #if defined(USE_OZONE)
147 #define MAYBE_Capture DISABLED_Capture
149 #define MAYBE_Capture Capture
151 TEST_F(DesktopCaptureDeviceTest, MAYBE_Capture) {
152 scoped_ptr<webrtc::DesktopCapturer> capturer(
153 webrtc::ScreenCapturer::Create());
154 CreateScreenCaptureDevice(capturer.Pass());
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, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
163 DoAll(SaveArg<1>(&frame_size),
165 InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
167 media::VideoCaptureParams capture_params;
168 capture_params.requested_format.frame_size.SetSize(640, 480);
169 capture_params.requested_format.frame_rate = kFrameRate;
170 capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
171 capture_device_->AllocateAndStart(capture_params, client.Pass());
172 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
173 capture_device_->StopAndDeAllocate();
175 EXPECT_GT(format.frame_size.width(), 0);
176 EXPECT_GT(format.frame_size.height(), 0);
177 EXPECT_EQ(kFrameRate, format.frame_rate);
178 EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
180 EXPECT_EQ(format.frame_size.GetArea() * 4, frame_size);
183 // Test that screen capturer behaves correctly if the source frame size changes
184 // but the caller cannot cope with variable resolution output.
185 TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeConstantResolution) {
186 FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
188 CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
190 media::VideoCaptureFormat format;
191 base::WaitableEvent done_event(false, false);
194 scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
195 EXPECT_CALL(*client, OnError(_)).Times(0);
196 EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
197 DoAll(SaveArg<1>(&frame_size),
199 InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
201 media::VideoCaptureParams capture_params;
202 capture_params.requested_format.frame_size.SetSize(kTestFrameWidth1,
204 capture_params.requested_format.frame_rate = kFrameRate;
205 capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
207 capture_device_->AllocateAndStart(capture_params, client.Pass());
209 // Capture at least two frames, to ensure that the source frame size has
210 // changed while capturing.
211 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
213 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
215 capture_device_->StopAndDeAllocate();
217 EXPECT_EQ(kTestFrameWidth1, format.frame_size.width());
218 EXPECT_EQ(kTestFrameHeight1, format.frame_size.height());
219 EXPECT_EQ(kFrameRate, format.frame_rate);
220 EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
222 EXPECT_EQ(format.frame_size.GetArea() * 4, frame_size);
225 // Test that screen capturer behaves correctly if the source frame size changes
226 // and the caller can cope with variable resolution output.
227 TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeVariableResolution) {
228 FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
230 CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
232 media::VideoCaptureFormat format;
233 base::WaitableEvent done_event(false, false);
235 scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
236 EXPECT_CALL(*client, OnError(_)).Times(0);
237 EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
238 DoAll(SaveArg<2>(&format),
239 InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
241 media::VideoCaptureParams capture_params;
242 capture_params.requested_format.frame_size.SetSize(kTestFrameWidth2,
244 capture_params.requested_format.frame_rate = kFrameRate;
245 capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
247 capture_device_->AllocateAndStart(
248 capture_params, client.Pass());
250 // Capture at least three frames, to ensure that the source frame size has
251 // changed at least twice while capturing.
252 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
254 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
256 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
258 capture_device_->StopAndDeAllocate();
260 EXPECT_EQ(kTestFrameWidth1, format.frame_size.width());
261 EXPECT_EQ(kTestFrameHeight1, format.frame_size.height());
262 EXPECT_EQ(kFrameRate, format.frame_rate);
263 EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
266 } // namespace content