Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / content / browser / media / capture / desktop_capture_device_unittest.cc
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.
4
5 #include "content/browser/media/capture/desktop_capture_device.h"
6
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/threading/thread.h"
13 #include "base/time/time.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"
19
20 using ::testing::_;
21 using ::testing::AnyNumber;
22 using ::testing::DoAll;
23 using ::testing::Expectation;
24 using ::testing::InvokeWithoutArgs;
25 using ::testing::SaveArg;
26
27 namespace content {
28
29 namespace {
30
31 MATCHER_P2(EqualsCaptureCapability, width, height, "") {
32   return arg.width == width && arg.height == height;
33 }
34
35 const int kTestFrameWidth1 = 100;
36 const int kTestFrameHeight1 = 100;
37 const int kTestFrameWidth2 = 200;
38 const int kTestFrameHeight2 = 150;
39
40 const int kFrameRate = 30;
41
42 class MockDeviceClient : public media::VideoCaptureDevice::Client {
43  public:
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,
50                     int length,
51                     const media::VideoCaptureFormat& frame_format,
52                     int rotation,
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));
59 };
60
61 // DesktopFrame wrapper that flips wrapped frame upside down by inverting
62 // stride.
63 class InvertedDesktopFrame : public webrtc::DesktopFrame {
64  public:
65   // Takes ownership of |frame|.
66   InvertedDesktopFrame(webrtc::DesktopFrame* frame)
67       : webrtc::DesktopFrame(
68             frame->size(), -frame->stride(),
69             frame->data() + (frame->size().height() - 1) * frame->stride(),
70             frame->shared_memory()),
71         original_frame_(frame) {
72     set_dpi(frame->dpi());
73     set_capture_time_ms(frame->capture_time_ms());
74     mutable_updated_region()->Swap(frame->mutable_updated_region());
75   }
76   virtual ~InvertedDesktopFrame() {}
77
78  private:
79   scoped_ptr<webrtc::DesktopFrame> original_frame_;
80
81   DISALLOW_COPY_AND_ASSIGN(InvertedDesktopFrame);
82 };
83
84 // TODO(sergeyu): Move this to a separate file where it can be reused.
85 class FakeScreenCapturer : public webrtc::ScreenCapturer {
86  public:
87   FakeScreenCapturer()
88       : callback_(NULL),
89         frame_index_(0),
90         generate_inverted_frames_(false) {
91   }
92   virtual ~FakeScreenCapturer() {}
93
94   void set_generate_inverted_frames(bool generate_inverted_frames) {
95     generate_inverted_frames_ = generate_inverted_frames;
96   }
97
98   // VideoFrameCapturer interface.
99   virtual void Start(Callback* callback) OVERRIDE {
100     callback_ = callback;
101   }
102
103   virtual void Capture(const webrtc::DesktopRegion& region) OVERRIDE {
104     webrtc::DesktopSize size;
105     if (frame_index_ % 2 == 0) {
106       size = webrtc::DesktopSize(kTestFrameWidth1, kTestFrameHeight1);
107     } else {
108       size = webrtc::DesktopSize(kTestFrameWidth2, kTestFrameHeight2);
109     }
110     frame_index_++;
111
112     webrtc::DesktopFrame* frame = new webrtc::BasicDesktopFrame(size);
113     if (generate_inverted_frames_)
114       frame = new InvertedDesktopFrame(frame);
115     callback_->OnCaptureCompleted(frame);
116   }
117
118   virtual void SetMouseShapeObserver(
119       MouseShapeObserver* mouse_shape_observer) OVERRIDE {
120   }
121
122   virtual bool GetScreenList(ScreenList* screens) OVERRIDE {
123     return false;
124   }
125
126   virtual bool SelectScreen(webrtc::ScreenId id) OVERRIDE {
127     return false;
128   }
129
130  private:
131   Callback* callback_;
132   int frame_index_;
133   bool generate_inverted_frames_;
134 };
135
136 }  // namespace
137
138 class DesktopCaptureDeviceTest : public testing::Test {
139  public:
140   virtual void SetUp() OVERRIDE {
141     worker_pool_ = new base::SequencedWorkerPool(3, "TestCaptureThread");
142   }
143
144   void CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer> capturer) {
145     capture_device_.reset(new DesktopCaptureDevice(
146         worker_pool_->GetSequencedTaskRunner(worker_pool_->GetSequenceToken()),
147         thread_.Pass(),
148         capturer.Pass(),
149         DesktopMediaID::TYPE_SCREEN));
150   }
151
152  protected:
153   scoped_refptr<base::SequencedWorkerPool> worker_pool_;
154   scoped_ptr<base::Thread> thread_;
155   scoped_ptr<DesktopCaptureDevice> capture_device_;
156 };
157
158 // There is currently no screen capturer implementation for ozone. So disable
159 // the test that uses a real screen-capturer instead of FakeScreenCapturer.
160 // http://crbug.com/260318
161 #if defined(USE_OZONE)
162 #define MAYBE_Capture DISABLED_Capture
163 #else
164 #define MAYBE_Capture Capture
165 #endif
166 TEST_F(DesktopCaptureDeviceTest, MAYBE_Capture) {
167   scoped_ptr<webrtc::DesktopCapturer> capturer(
168       webrtc::ScreenCapturer::Create());
169   CreateScreenCaptureDevice(capturer.Pass());
170
171   media::VideoCaptureFormat format;
172   base::WaitableEvent done_event(false, false);
173   int frame_size;
174
175   scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
176   EXPECT_CALL(*client, OnError(_)).Times(0);
177   EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
178       DoAll(SaveArg<1>(&frame_size),
179             SaveArg<2>(&format),
180             InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
181
182   media::VideoCaptureParams capture_params;
183   capture_params.requested_format.frame_size.SetSize(640, 480);
184   capture_params.requested_format.frame_rate = kFrameRate;
185   capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
186   capture_params.allow_resolution_change = false;
187   capture_device_->AllocateAndStart(
188       capture_params, client.PassAs<media::VideoCaptureDevice::Client>());
189   EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
190   capture_device_->StopAndDeAllocate();
191
192   EXPECT_GT(format.frame_size.width(), 0);
193   EXPECT_GT(format.frame_size.height(), 0);
194   EXPECT_EQ(kFrameRate, format.frame_rate);
195   EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
196
197   EXPECT_EQ(format.frame_size.GetArea() * 4, frame_size);
198   worker_pool_->FlushForTesting();
199 }
200
201 // Test that screen capturer behaves correctly if the source frame size changes
202 // but the caller cannot cope with variable resolution output.
203 TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeConstantResolution) {
204   FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
205
206   CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
207
208   media::VideoCaptureFormat format;
209   base::WaitableEvent done_event(false, false);
210   int frame_size;
211
212   scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
213   EXPECT_CALL(*client, OnError(_)).Times(0);
214   EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
215       DoAll(SaveArg<1>(&frame_size),
216             SaveArg<2>(&format),
217             InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
218
219   media::VideoCaptureParams capture_params;
220   capture_params.requested_format.frame_size.SetSize(kTestFrameWidth1,
221                                                      kTestFrameHeight1);
222   capture_params.requested_format.frame_rate = kFrameRate;
223   capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
224   capture_params.allow_resolution_change = false;
225
226   capture_device_->AllocateAndStart(
227       capture_params, client.PassAs<media::VideoCaptureDevice::Client>());
228
229   // Capture at least two frames, to ensure that the source frame size has
230   // changed while capturing.
231   EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
232   done_event.Reset();
233   EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
234
235   capture_device_->StopAndDeAllocate();
236
237   EXPECT_EQ(kTestFrameWidth1, format.frame_size.width());
238   EXPECT_EQ(kTestFrameHeight1, format.frame_size.height());
239   EXPECT_EQ(kFrameRate, format.frame_rate);
240   EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
241
242   EXPECT_EQ(format.frame_size.GetArea() * 4, frame_size);
243   worker_pool_->FlushForTesting();
244 }
245
246 // Test that screen capturer behaves correctly if the source frame size changes
247 // and the caller can cope with variable resolution output.
248 TEST_F(DesktopCaptureDeviceTest, ScreenResolutionChangeVariableResolution) {
249   FakeScreenCapturer* mock_capturer = new FakeScreenCapturer();
250
251   CreateScreenCaptureDevice(scoped_ptr<webrtc::DesktopCapturer>(mock_capturer));
252
253   media::VideoCaptureFormat format;
254   base::WaitableEvent done_event(false, false);
255
256   scoped_ptr<MockDeviceClient> client(new MockDeviceClient());
257   EXPECT_CALL(*client, OnError(_)).Times(0);
258   EXPECT_CALL(*client, OnIncomingCapturedData(_, _, _, _, _)).WillRepeatedly(
259       DoAll(SaveArg<2>(&format),
260             InvokeWithoutArgs(&done_event, &base::WaitableEvent::Signal)));
261
262   media::VideoCaptureParams capture_params;
263   capture_params.requested_format.frame_size.SetSize(kTestFrameWidth2,
264                                                      kTestFrameHeight2);
265   capture_params.requested_format.frame_rate = kFrameRate;
266   capture_params.requested_format.pixel_format = media::PIXEL_FORMAT_I420;
267   capture_params.allow_resolution_change = false;
268
269   capture_device_->AllocateAndStart(
270       capture_params, client.PassAs<media::VideoCaptureDevice::Client>());
271
272   // Capture at least three frames, to ensure that the source frame size has
273   // changed at least twice while capturing.
274   EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
275   done_event.Reset();
276   EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
277   done_event.Reset();
278   EXPECT_TRUE(done_event.TimedWait(TestTimeouts::action_max_timeout()));
279
280   capture_device_->StopAndDeAllocate();
281
282   EXPECT_EQ(kTestFrameWidth1, format.frame_size.width());
283   EXPECT_EQ(kTestFrameHeight1, format.frame_size.height());
284   EXPECT_EQ(kFrameRate, format.frame_rate);
285   EXPECT_EQ(media::PIXEL_FORMAT_ARGB, format.pixel_format);
286   worker_pool_->FlushForTesting();
287 }
288
289 }  // namespace content