Supervised user import: Listen for profile creation/deletion
[chromium-blink-merge.git] / content / browser / media / capture / desktop_capture_device_unittest.cc
blobc86ddd3857ec569b9c6a11a54a3d2845b621ecdd
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_METHOD9(OnIncomingCapturedYuvData,
63 void (const uint8* y_data,
64 const uint8* u_data,
65 const uint8* v_data,
66 size_t y_stride,
67 size_t u_stride,
68 size_t v_stride,
69 const media::VideoCaptureFormat& frame_format,
70 int clockwise_rotation,
71 const base::TimeTicks& timestamp));
72 MOCK_METHOD0(DoReserveOutputBuffer, void(void));
73 MOCK_METHOD0(DoOnIncomingCapturedBuffer, void(void));
74 MOCK_METHOD0(DoOnIncomingCapturedVideoFrame, void(void));
75 MOCK_METHOD1(OnError, void(const std::string& reason));
77 // Trampoline methods to workaround GMOCK problems with scoped_ptr<>.
78 scoped_ptr<Buffer> ReserveOutputBuffer(media::VideoPixelFormat format,
79 const gfx::Size& dimensions) override {
80 DoReserveOutputBuffer();
81 return scoped_ptr<Buffer>();
83 void OnIncomingCapturedBuffer(scoped_ptr<Buffer> buffer,
84 const media::VideoCaptureFormat& frame_format,
85 const base::TimeTicks& timestamp) override {
86 DoOnIncomingCapturedBuffer();
88 void OnIncomingCapturedVideoFrame(
89 scoped_ptr<Buffer> buffer,
90 const scoped_refptr<media::VideoFrame>& frame,
91 const base::TimeTicks& timestamp) override {
92 DoOnIncomingCapturedVideoFrame();
96 // Creates a DesktopFrame that has the first pixel bytes set to
97 // kFakePixelValueFirst, and the rest of the bytes set to kFakePixelValue, for
98 // UnpackedFrame and InvertedFrame verification.
99 webrtc::BasicDesktopFrame* CreateBasicFrame(const webrtc::DesktopSize& size) {
100 webrtc::BasicDesktopFrame* frame = new webrtc::BasicDesktopFrame(size);;
101 DCHECK_EQ(frame->size().width() * webrtc::DesktopFrame::kBytesPerPixel,
102 frame->stride());
103 memset(frame->data(),
104 kFakePixelValue,
105 frame->stride() * frame->size().height());
106 memset(frame->data(),
107 kFakePixelValueFirst,
108 webrtc::DesktopFrame::kBytesPerPixel);
109 return frame;
112 // DesktopFrame wrapper that flips wrapped frame upside down by inverting
113 // stride.
114 class InvertedDesktopFrame : public webrtc::DesktopFrame {
115 public:
116 // Takes ownership of |frame|.
117 explicit InvertedDesktopFrame(webrtc::DesktopFrame* frame)
118 : webrtc::DesktopFrame(
119 frame->size(),
120 -frame->stride(),
121 frame->data() + (frame->size().height() - 1) * frame->stride(),
122 frame->shared_memory()),
123 original_frame_(frame) {
124 set_dpi(frame->dpi());
125 set_capture_time_ms(frame->capture_time_ms());
126 mutable_updated_region()->Swap(frame->mutable_updated_region());
128 ~InvertedDesktopFrame() override {}
130 private:
131 scoped_ptr<webrtc::DesktopFrame> original_frame_;
133 DISALLOW_COPY_AND_ASSIGN(InvertedDesktopFrame);
136 // DesktopFrame wrapper that copies the input frame and doubles the stride.
137 class UnpackedDesktopFrame : public webrtc::DesktopFrame {
138 public:
139 // Takes ownership of |frame|.
140 explicit UnpackedDesktopFrame(webrtc::DesktopFrame* frame)
141 : webrtc::DesktopFrame(
142 frame->size(),
143 frame->stride() * 2,
144 new uint8_t[frame->stride() * 2 * frame->size().height()],
145 NULL) {
146 memset(data(), kFramePaddingValue, stride() * size().height());
147 CopyPixelsFrom(*frame,
148 webrtc::DesktopVector(),
149 webrtc::DesktopRect::MakeSize(size()));
150 delete frame;
152 ~UnpackedDesktopFrame() override {
153 delete[] data_;
156 DISALLOW_COPY_AND_ASSIGN(UnpackedDesktopFrame);
159 // TODO(sergeyu): Move this to a separate file where it can be reused.
160 class FakeScreenCapturer : public webrtc::ScreenCapturer {
161 public:
162 FakeScreenCapturer()
163 : callback_(NULL),
164 frame_index_(0),
165 generate_inverted_frames_(false),
166 generate_cropped_frames_(false) {
168 ~FakeScreenCapturer() override {}
170 void set_generate_inverted_frames(bool generate_inverted_frames) {
171 generate_inverted_frames_ = generate_inverted_frames;
174 void set_generate_cropped_frames(bool generate_cropped_frames) {
175 generate_cropped_frames_ = generate_cropped_frames;
178 // VideoFrameCapturer interface.
179 void Start(Callback* callback) override { callback_ = callback; }
181 void Capture(const webrtc::DesktopRegion& region) override {
182 webrtc::DesktopSize size;
183 if (frame_index_ % 2 == 0) {
184 size = webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1);
185 } else {
186 size = webrtc::DesktopSize(kTestFrameWidth2, kTestFrameHeight2);
188 frame_index_++;
190 webrtc::DesktopFrame* frame = CreateBasicFrame(size);;
192 if (generate_inverted_frames_) {
193 frame = new InvertedDesktopFrame(frame);
194 } else if (generate_cropped_frames_) {
195 frame = new UnpackedDesktopFrame(frame);
197 callback_->OnCaptureCompleted(frame);
200 bool GetScreenList(ScreenList* screens) override { return false; }
202 bool SelectScreen(webrtc::ScreenId id) override { return false; }
204 private:
205 Callback* callback_;
206 int frame_index_;
207 bool generate_inverted_frames_;
208 bool generate_cropped_frames_;
211 } // namespace
213 class DesktopCaptureDeviceTest : public testing::Test {
214 public:
215 void CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer> capturer) {
216 capture_device_.reset(
217 new DesktopCaptureDevice(capturer.Pass(), DesktopMediaID::TYPE_SCREEN));
220 void CopyFrame(const uint8_t* frame, int size,
221 const media::VideoCaptureFormat&, int, base::TimeTicks) {
222 ASSERT_TRUE(output_frame_.get() != NULL);
223 ASSERT_EQ(output_frame_->stride() * output_frame_->size().height(), size);
224 memcpy(output_frame_->data(), frame, size);
227 protected:
228 scoped_ptr<DesktopCaptureDevice> capture_device_;
229 scoped_ptr<webrtc::DesktopFrame> output_frame_;
232 // There is currently no screen capturer implementation for ozone. So disable
233 // the test that uses a real screen-capturer instead of FakeScreenCapturer.
234 // http://crbug.com/260318
235 #if defined(USE_OZONE)
236 #define MAYBE_Capture DISABLED_Capture
237 #else
238 #define MAYBE_Capture Capture
239 #endif
240 TEST_F(DesktopCaptureDeviceTest, MAYBE_Capture) {
241 scoped_ptr<webrtc::DesktopCapturer> capturer(
242 webrtc::ScreenCapturer::Create(
243 webrtc::DesktopCaptureOptions::CreateDefault()));
244 CreateScreenCaptureDevice(capturer.Pass());
246 media::VideoCaptureFormat format;
247 base::WaitableEvent done_event(false, false);
248 int frame_size;
250 scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
251 EXPECT_CALL(*client, OnError(_)).Times(0);
252 EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
253 DoAll(SaveArg<1>(&frame_size),
254 SaveArg<2>(&format),
255 InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
257 media::VideoCaptureParams capture_params;
258 capture_params.requested_format.frame_size.SetSize(640, 480);
259 capture_params.requested_format.frame_rate = kFrameRate;
260 capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
261 capture_device_->AllocateAndStart(capture_params, client.Pass());
262 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
263 capture_device_->StopAndDeAllocate();
265 EXPECT_GT(format.frame_size.width(), 0);
266 EXPECT_GT(format.frame_size.height(), 0);
267 EXPECT_EQ(kFrameRate, format.frame_rate);
268 EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
270 EXPECT_EQ(format.frame_size.GetArea() * 4, frame_size);
273 // Test that screen capturer behaves correctly if the source frame size changes
274 // but the caller cannot cope with variable resolution output.
275 TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeConstantResolution) {
276 FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
278 CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
280 media::VideoCaptureFormat format;
281 base::WaitableEvent done_event(false, false);
282 int frame_size;
284 scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
285 EXPECT_CALL(*client, OnError(_)).Times(0);
286 EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
287 DoAll(SaveArg<1>(&frame_size),
288 SaveArg<2>(&format),
289 InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
291 media::VideoCaptureParams capture_params;
292 capture_params.requested_format.frame_size.SetSize(kTestFrameWidth1,
293 kTestFrameHeight1);
294 capture_params.requested_format.frame_rate = kFrameRate;
295 capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
297 capture_device_->AllocateAndStart(capture_params, client.Pass());
299 // Capture at least two frames, to ensure that the source frame size has
300 // changed while capturing.
301 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
302 done_event.Reset();
303 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
305 capture_device_->StopAndDeAllocate();
307 EXPECT_EQ(kTestFrameWidth1, format.frame_size.width());
308 EXPECT_EQ(kTestFrameHeight1, format.frame_size.height());
309 EXPECT_EQ(kFrameRate, format.frame_rate);
310 EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
312 EXPECT_EQ(format.frame_size.GetArea() * 4, frame_size);
315 // Test that screen capturer behaves correctly if the source frame size changes
316 // and the caller can cope with variable resolution output.
317 TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeVariableResolution) {
318 FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
320 CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
322 media::VideoCaptureFormat format;
323 base::WaitableEvent done_event(false, false);
325 scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
326 EXPECT_CALL(*client, OnError(_)).Times(0);
327 EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
328 DoAll(SaveArg<2>(&format),
329 InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
331 media::VideoCaptureParams capture_params;
332 capture_params.requested_format.frame_size.SetSize(kTestFrameWidth2,
333 kTestFrameHeight2);
334 capture_params.requested_format.frame_rate = kFrameRate;
335 capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
337 capture_device_->AllocateAndStart(
338 capture_params, client.Pass());
340 // Capture at least three frames, to ensure that the source frame size has
341 // changed at least twice while capturing.
342 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
343 done_event.Reset();
344 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
345 done_event.Reset();
346 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
348 capture_device_->StopAndDeAllocate();
350 EXPECT_EQ(kTestFrameWidth1, format.frame_size.width());
351 EXPECT_EQ(kTestFrameHeight1, format.frame_size.height());
352 EXPECT_EQ(kFrameRate, format.frame_rate);
353 EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
356 // This test verifies that an unpacked frame is converted to a packed frame.
357 TEST_F(DesktopCaptureDeviceTest, UnpackedFrame) {
358 FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
359 mock_capturer->set_generate_cropped_frames(true);
360 CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
362 media::VideoCaptureFormat format;
363 base::WaitableEvent done_event(false, false);
365 int frame_size = 0;
366 output_frame_.reset(new webrtc::BasicDesktopFrame(
367 webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1)));
369 scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
370 EXPECT_CALL(*client, OnError(_)).Times(0);
371 EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
372 DoAll(Invoke(this, &DesktopCaptureDeviceTest::CopyFrame),
373 SaveArg<1>(&frame_size),
374 InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
376 media::VideoCaptureParams capture_params;
377 capture_params.requested_format.frame_size.SetSize(kTestFrameWidth1,
378 kTestFrameHeight1);
379 capture_params.requested_format.frame_rate = kFrameRate;
380 capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
382 capture_device_->AllocateAndStart(capture_params, client.Pass());
384 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
385 done_event.Reset();
386 capture_device_->StopAndDeAllocate();
388 // Verifies that |output_frame_| has the same data as a packed frame of the
389 // same size.
390 scoped_ptr<webrtc::BasicDesktopFrame> expected_frame(CreateBasicFrame(
391 webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1)));
392 EXPECT_EQ(output_frame_->stride() * output_frame_->size().height(),
393 frame_size);
394 EXPECT_EQ(
395 0, memcmp(output_frame_->data(), expected_frame->data(), frame_size));
398 // The test verifies that a bottom-to-top frame is converted to top-to-bottom.
399 TEST_F(DesktopCaptureDeviceTest, InvertedFrame) {
400 FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
401 mock_capturer->set_generate_inverted_frames(true);
402 CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
404 media::VideoCaptureFormat format;
405 base::WaitableEvent done_event(false, false);
407 int frame_size = 0;
408 output_frame_.reset(new webrtc::BasicDesktopFrame(
409 webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1)));
411 scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
412 EXPECT_CALL(*client, OnError(_)).Times(0);
413 EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
414 DoAll(Invoke(this, &DesktopCaptureDeviceTest::CopyFrame),
415 SaveArg<1>(&frame_size),
416 InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
418 media::VideoCaptureParams capture_params;
419 capture_params.requested_format.frame_size.SetSize(kTestFrameWidth1,
420 kTestFrameHeight1);
421 capture_params.requested_format.frame_rate = kFrameRate;
422 capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
424 capture_device_->AllocateAndStart(capture_params, client.Pass());
426 EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
427 done_event.Reset();
428 capture_device_->StopAndDeAllocate();
430 // Verifies that |output_frame_| has the same pixel values as the inverted
431 // frame.
432 scoped_ptr<webrtc::DesktopFrame> inverted_frame(
433 new InvertedDesktopFrame(CreateBasicFrame(
434 webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1))));
435 EXPECT_EQ(output_frame_->stride() * output_frame_->size().height(),
436 frame_size);
437 for (int i = 0; i < output_frame_->size().height(); ++i) {
438 EXPECT_EQ(0,
439 memcmp(inverted_frame->data() + i * inverted_frame->stride(),
440 output_frame_->data() + i * output_frame_->stride(),
441 output_frame_->stride()));
445 } // namespace content