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