ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / content / browser / media / capture / desktop_capture_device_unittest.cc
blob842b57e9fa644cfafe09416a9e5b6ddf891dcf76
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 <string>
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_capture_options.h"
17 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
18 #include "third_party/webrtc/modules/desktop_capture/desktop_geometry.h"
19 #include "third_party/webrtc/modules/desktop_capture/screen_capturer.h"
21 using ::testing::_;
22 using ::testing::AnyNumber;
23 using ::testing::DoAll;
24 using ::testing::Expectation;
25 using ::testing::InvokeWithoutArgs;
26 using ::testing::SaveArg;
28 namespace content {
30 namespace {
32 MATCHER_P2(EqualsCaptureCapability, width, height, "") {
33 return arg.width == width && arg.height == height;
36 const int kTestFrameWidth1 = 100;
37 const int kTestFrameHeight1 = 100;
38 const int kTestFrameWidth2 = 200;
39 const int kTestFrameHeight2 = 150;
41 const int kFrameRate = 30;
43 // The value of the padding bytes in unpacked frames.
44 const uint8_t kFramePaddingValue = 0;
46 // Use a special value for frame pixels to tell pixel bytes apart from the
47 // padding bytes in the unpacked frame test.
48 const uint8_t kFakePixelValue = 1;
50 // Use a special value for the first pixel to verify the result in the inverted
51 // frame test.
52 const uint8_t kFakePixelValueFirst = 2;
54 class MockDeviceClient : public media::VideoCaptureDevice::Client {
55 public:
56 MOCK_METHOD5(OnIncomingCapturedData,
57 void(const uint8* data,
58 int length,
59 const media::VideoCaptureFormat& frame_format,
60 int rotation,
61 const base::TimeTicks& timestamp));
62 MOCK_METHOD2(ReserveOutputBuffer,
63 scoped_refptr<Buffer>(media::VideoFrame::Format format,
64 const gfx::Size& dimensions));
65 MOCK_METHOD4(OnIncomingCapturedVideoFrame,
66 void(const scoped_refptr<Buffer>& buffer,
67 const media::VideoCaptureFormat& buffer_format,
68 const scoped_refptr<media::VideoFrame>& frame,
69 const base::TimeTicks& timestamp));
70 MOCK_METHOD1(OnError, void(const std::string& reason));
73 // Creates a DesktopFrame that has the first pixel bytes set to
74 // kFakePixelValueFirst, and the rest of the bytes set to kFakePixelValue, for
75 // UnpackedFrame and InvertedFrame verification.
76 webrtc::BasicDesktopFrame* CreateBasicFrame(const webrtc::DesktopSize& size) {
77 webrtc::BasicDesktopFrame* frame = new webrtc::BasicDesktopFrame(size);;
78 DCHECK_EQ(frame->size().width() * webrtc::DesktopFrame::kBytesPerPixel,
79 frame->stride());
80 memset(frame->data(),
81 kFakePixelValue,
82 frame->stride() * frame->size().height());
83 memset(frame->data(),
84 kFakePixelValueFirst,
85 webrtc::DesktopFrame::kBytesPerPixel);
86 return frame;
89 // DesktopFrame wrapper that flips wrapped frame upside down by inverting
90 // stride.
91 class InvertedDesktopFrame : public webrtc::DesktopFrame {
92 public:
93 // Takes ownership of |frame|.
94 explicit InvertedDesktopFrame(webrtc::DesktopFrame* frame)
95 : webrtc::DesktopFrame(
96 frame->size(),
97 -frame->stride(),
98 frame->data() + (frame->size().height() - 1) * frame->stride(),
99 frame->shared_memory()),
100 original_frame_(frame) {
101 set_dpi(frame->dpi());
102 set_capture_time_ms(frame->capture_time_ms());
103 mutable_updated_region()->Swap(frame->mutable_updated_region());
105 ~InvertedDesktopFrame() override {}
107 private:
108 scoped_ptr<webrtc::DesktopFrame> original_frame_;
110 DISALLOW_COPY_AND_ASSIGN(InvertedDesktopFrame);
113 // DesktopFrame wrapper that copies the input frame and doubles the stride.
114 class UnpackedDesktopFrame : public webrtc::DesktopFrame {
115 public:
116 // Takes ownership of |frame|.
117 explicit UnpackedDesktopFrame(webrtc::DesktopFrame* frame)
118 : webrtc::DesktopFrame(
119 frame->size(),
120 frame->stride() * 2,
121 new uint8_t[frame->stride() * 2 * frame->size().height()],
122 NULL) {
123 memset(data(), kFramePaddingValue, stride() * size().height());
124 CopyPixelsFrom(*frame,
125 webrtc::DesktopVector(),
126 webrtc::DesktopRect::MakeSize(size()));
127 delete frame;
129 ~UnpackedDesktopFrame() override {
130 delete[] data_;
133 DISALLOW_COPY_AND_ASSIGN(UnpackedDesktopFrame);
136 // TODO(sergeyu): Move this to a separate file where it can be reused.
137 class FakeScreenCapturer : public webrtc::ScreenCapturer {
138 public:
139 FakeScreenCapturer()
140 : callback_(NULL),
141 frame_index_(0),
142 generate_inverted_frames_(false),
143 generate_cropped_frames_(false) {
145 ~FakeScreenCapturer() override {}
147 void set_generate_inverted_frames(bool generate_inverted_frames) {
148 generate_inverted_frames_ = generate_inverted_frames;
151 void set_generate_cropped_frames(bool generate_cropped_frames) {
152 generate_cropped_frames_ = generate_cropped_frames;
155 // VideoFrameCapturer interface.
156 void Start(Callback* callback) override { callback_ = callback; }
158 void Capture(const webrtc::DesktopRegion& region) override {
159 webrtc::DesktopSize size;
160 if (frame_index_ % 2 == 0) {
161 size = webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1);
162 } else {
163 size = webrtc::DesktopSize(kTestFrameWidth2, kTestFrameHeight2);
165 frame_index_++;
167 webrtc::DesktopFrame* frame = CreateBasicFrame(size);;
169 if (generate_inverted_frames_) {
170 frame = new InvertedDesktopFrame(frame);
171 } else if (generate_cropped_frames_) {
172 frame = new UnpackedDesktopFrame(frame);
174 callback_->OnCaptureCompleted(frame);
177 bool GetScreenList(ScreenList* screens) override { return false; }
179 bool SelectScreen(webrtc::ScreenId id) override { return false; }
181 private:
182 Callback* callback_;
183 int frame_index_;
184 bool generate_inverted_frames_;
185 bool generate_cropped_frames_;
188 } // namespace
190 class DesktopCaptureDeviceTest : public testing::Test {
191 public:
192 void CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer> capturer) {
193 capture_device_.reset(
194 new DesktopCaptureDevice(capturer.Pass(), DesktopMediaID::TYPE_SCREEN));
197 void CopyFrame(const uint8_t* frame, int size,
198 const media::VideoCaptureFormat&, int, base::TimeTicks) {
199 ASSERT_TRUE(output_frame_.get() != NULL);
200 ASSERT_EQ(output_frame_->stride() * output_frame_->size().height(), size);
201 memcpy(output_frame_->data(), frame, size);
204 protected:
205 scoped_ptr<DesktopCaptureDevice> capture_device_;
206 scoped_ptr<webrtc::DesktopFrame> output_frame_;
209 // There is currently no screen capturer implementation for ozone. So disable
210 // the test that uses a real screen-capturer instead of FakeScreenCapturer.
211 // http://crbug.com/260318
212 #if defined(USE_OZONE)
213 #define MAYBE_Capture DISABLED_Capture
214 #else
215 #define MAYBE_Capture Capture
216 #endif
217 TEST_F(DesktopCaptureDeviceTest, MAYBE_Capture) {
218 scoped_ptr<webrtc::DesktopCapturer> capturer(
219 webrtc::ScreenCapturer::Create(
220 webrtc::DesktopCaptureOptions::CreateDefault()));
221 CreateScreenCaptureDevice(capturer.Pass());
223 media::VideoCaptureFormat format;
224 base::WaitableEvent done_event(false, false);
225 int frame_size;
227 scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
228 EXPECT_CALL(*client, OnError(_)).Times(0);
229 EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
230 DoAll(SaveArg<1>(&frame_size),
231 SaveArg<2>(&format),
232 InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
234 media::VideoCaptureParams capture_params;
235 capture_params.requested_format.frame_size.SetSize(640, 480);
236 capture_params.requested_format.frame_rate = kFrameRate;
237 capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
238 capture_device_->AllocateAndStart(capture_params, client.Pass());
239 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
240 capture_device_->StopAndDeAllocate();
242 EXPECT_GT(format.frame_size.width(), 0);
243 EXPECT_GT(format.frame_size.height(), 0);
244 EXPECT_EQ(kFrameRate, format.frame_rate);
245 EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
247 EXPECT_EQ(format.frame_size.GetArea() * 4, frame_size);
250 // Test that screen capturer behaves correctly if the source frame size changes
251 // but the caller cannot cope with variable resolution output.
252 TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeConstantResolution) {
253 FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
255 CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
257 media::VideoCaptureFormat format;
258 base::WaitableEvent done_event(false, false);
259 int frame_size;
261 scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
262 EXPECT_CALL(*client, OnError(_)).Times(0);
263 EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
264 DoAll(SaveArg<1>(&frame_size),
265 SaveArg<2>(&format),
266 InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
268 media::VideoCaptureParams capture_params;
269 capture_params.requested_format.frame_size.SetSize(kTestFrameWidth1,
270 kTestFrameHeight1);
271 capture_params.requested_format.frame_rate = kFrameRate;
272 capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
274 capture_device_->AllocateAndStart(capture_params, client.Pass());
276 // Capture at least two frames, to ensure that the source frame size has
277 // changed while capturing.
278 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
279 done_event.Reset();
280 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
282 capture_device_->StopAndDeAllocate();
284 EXPECT_EQ(kTestFrameWidth1, format.frame_size.width());
285 EXPECT_EQ(kTestFrameHeight1, format.frame_size.height());
286 EXPECT_EQ(kFrameRate, format.frame_rate);
287 EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
289 EXPECT_EQ(format.frame_size.GetArea() * 4, frame_size);
292 // Test that screen capturer behaves correctly if the source frame size changes
293 // and the caller can cope with variable resolution output.
294 TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeVariableResolution) {
295 FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
297 CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
299 media::VideoCaptureFormat format;
300 base::WaitableEvent done_event(false, false);
302 scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
303 EXPECT_CALL(*client, OnError(_)).Times(0);
304 EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
305 DoAll(SaveArg<2>(&format),
306 InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
308 media::VideoCaptureParams capture_params;
309 capture_params.requested_format.frame_size.SetSize(kTestFrameWidth2,
310 kTestFrameHeight2);
311 capture_params.requested_format.frame_rate = kFrameRate;
312 capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
314 capture_device_->AllocateAndStart(
315 capture_params, client.Pass());
317 // Capture at least three frames, to ensure that the source frame size has
318 // changed at least twice while capturing.
319 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
320 done_event.Reset();
321 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
322 done_event.Reset();
323 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
325 capture_device_->StopAndDeAllocate();
327 EXPECT_EQ(kTestFrameWidth1, format.frame_size.width());
328 EXPECT_EQ(kTestFrameHeight1, format.frame_size.height());
329 EXPECT_EQ(kFrameRate, format.frame_rate);
330 EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
333 // This test verifies that an unpacked frame is converted to a packed frame.
334 TEST_F(DesktopCaptureDeviceTest, UnpackedFrame) {
335 FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
336 mock_capturer->set_generate_cropped_frames(true);
337 CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
339 media::VideoCaptureFormat format;
340 base::WaitableEvent done_event(false, false);
342 int frame_size = 0;
343 output_frame_.reset(new webrtc::BasicDesktopFrame(
344 webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1)));
346 scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
347 EXPECT_CALL(*client, OnError(_)).Times(0);
348 EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
349 DoAll(Invoke(this, &DesktopCaptureDeviceTest::CopyFrame),
350 SaveArg<1>(&frame_size),
351 InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
353 media::VideoCaptureParams capture_params;
354 capture_params.requested_format.frame_size.SetSize(kTestFrameWidth1,
355 kTestFrameHeight1);
356 capture_params.requested_format.frame_rate = kFrameRate;
357 capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
359 capture_device_->AllocateAndStart(capture_params, client.Pass());
361 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
362 done_event.Reset();
363 capture_device_->StopAndDeAllocate();
365 // Verifies that |output_frame_| has the same data as a packed frame of the
366 // same size.
367 scoped_ptr<webrtc::BasicDesktopFrame> expected_frame(CreateBasicFrame(
368 webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1)));
369 EXPECT_EQ(output_frame_->stride() * output_frame_->size().height(),
370 frame_size);
371 EXPECT_EQ(
372 0, memcmp(output_frame_->data(), expected_frame->data(), frame_size));
375 // The test verifies that a bottom-to-top frame is converted to top-to-bottom.
376 TEST_F(DesktopCaptureDeviceTest, InvertedFrame) {
377 FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
378 mock_capturer->set_generate_inverted_frames(true);
379 CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
381 media::VideoCaptureFormat format;
382 base::WaitableEvent done_event(false, false);
384 int frame_size = 0;
385 output_frame_.reset(new webrtc::BasicDesktopFrame(
386 webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1)));
388 scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
389 EXPECT_CALL(*client, OnError(_)).Times(0);
390 EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
391 DoAll(Invoke(this, &DesktopCaptureDeviceTest::CopyFrame),
392 SaveArg<1>(&frame_size),
393 InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
395 media::VideoCaptureParams capture_params;
396 capture_params.requested_format.frame_size.SetSize(kTestFrameWidth1,
397 kTestFrameHeight1);
398 capture_params.requested_format.frame_rate = kFrameRate;
399 capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
401 capture_device_->AllocateAndStart(capture_params, client.Pass());
403 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
404 done_event.Reset();
405 capture_device_->StopAndDeAllocate();
407 // Verifies that |output_frame_| has the same pixel values as the inverted
408 // frame.
409 scoped_ptr<webrtc::DesktopFrame> inverted_frame(
410 new InvertedDesktopFrame(CreateBasicFrame(
411 webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1))));
412 EXPECT_EQ(output_frame_->stride() * output_frame_->size().height(),
413 frame_size);
414 for (int i = 0; i < output_frame_->size().height(); ++i) {
415 EXPECT_EQ(0,
416 memcmp(inverted_frame->data() + i * inverted_frame->stride(),
417 output_frame_->data() + i * output_frame_->stride(),
418 output_frame_->stride()));
422 } // namespace content