OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 4 * Use of this source code is governed by a BSD-style license |
5 * that can be found in the LICENSE file in the root of the source | 5 * that can be found in the LICENSE file in the root of the source |
6 * tree. An additional intellectual property rights grant can be found | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #include <string.h> | |
12 | |
13 #include <algorithm> | |
14 #include <initializer_list> | |
15 #include <memory> | 11 #include <memory> |
16 #include <utility> | |
17 | 12 |
18 #include "webrtc/modules/desktop_capture/screen_capturer.h" | 13 #include "webrtc/modules/desktop_capture/screen_capturer.h" |
19 | 14 |
20 #include "webrtc/test/gmock.h" | 15 #include "webrtc/test/gmock.h" |
21 #include "webrtc/test/gtest.h" | 16 #include "webrtc/test/gtest.h" |
22 #include "webrtc/base/checks.h" | |
23 #include "webrtc/base/constructormagic.h" | 17 #include "webrtc/base/constructormagic.h" |
24 #include "webrtc/base/logging.h" | 18 #include "webrtc/base/logging.h" |
25 #include "webrtc/modules/desktop_capture/rgba_color.h" | |
26 #include "webrtc/modules/desktop_capture/desktop_capture_options.h" | 19 #include "webrtc/modules/desktop_capture/desktop_capture_options.h" |
27 #include "webrtc/modules/desktop_capture/desktop_frame.h" | 20 #include "webrtc/modules/desktop_capture/desktop_frame.h" |
28 #include "webrtc/modules/desktop_capture/desktop_region.h" | 21 #include "webrtc/modules/desktop_capture/desktop_region.h" |
29 #include "webrtc/modules/desktop_capture/screen_capturer_mock_objects.h" | 22 #include "webrtc/modules/desktop_capture/screen_capturer_mock_objects.h" |
30 #include "webrtc/modules/desktop_capture/screen_drawer.h" | |
31 #include "webrtc/system_wrappers/include/sleep.h" | |
32 | 23 |
33 #if defined(WEBRTC_WIN) | 24 #if defined(WEBRTC_WIN) |
34 #include "webrtc/modules/desktop_capture/win/screen_capturer_win_directx.h" | 25 #include "webrtc/modules/desktop_capture/win/screen_capturer_win_directx.h" |
35 #endif // defined(WEBRTC_WIN) | 26 #endif // defined(WEBRTC_WIN) |
36 | 27 |
37 using ::testing::_; | 28 using ::testing::_; |
38 using ::testing::AnyNumber; | |
39 using ::testing::Return; | |
40 | 29 |
41 const int kTestSharedMemoryId = 123; | 30 const int kTestSharedMemoryId = 123; |
42 | 31 |
43 namespace webrtc { | 32 namespace webrtc { |
44 | 33 |
45 namespace { | |
46 | |
47 ACTION_P(SaveUniquePtrArg, dest) { | |
48 *dest = std::move(*arg1); | |
49 } | |
50 | |
51 // Returns true if color in |rect| of |frame| is |color|. | |
52 bool ArePixelsColoredBy(const DesktopFrame& frame, | |
53 DesktopRect rect, | |
54 RgbaColor color, | |
55 bool may_partially_draw) { | |
56 if (!may_partially_draw) { | |
57 // updated_region() should cover the painted area. | |
58 DesktopRegion updated_region(frame.updated_region()); | |
59 updated_region.IntersectWith(rect); | |
60 if (!updated_region.Equals(DesktopRegion(rect))) { | |
61 return false; | |
62 } | |
63 } | |
64 | |
65 // Color in the |rect| should be |color|. | |
66 uint8_t* row = frame.GetFrameDataAtPos(rect.top_left()); | |
67 for (int i = 0; i < rect.height(); i++) { | |
68 uint8_t* column = row; | |
69 for (int j = 0; j < rect.width(); j++) { | |
70 if (color != RgbaColor(column)) { | |
71 return false; | |
72 } | |
73 column += DesktopFrame::kBytesPerPixel; | |
74 } | |
75 row += frame.stride(); | |
76 } | |
77 return true; | |
78 } | |
79 | |
80 } // namespace | |
81 | |
82 class ScreenCapturerTest : public testing::Test { | 34 class ScreenCapturerTest : public testing::Test { |
83 public: | 35 public: |
84 void SetUp() override { | 36 void SetUp() override { |
85 capturer_.reset( | 37 capturer_.reset( |
86 ScreenCapturer::Create(DesktopCaptureOptions::CreateDefault())); | 38 ScreenCapturer::Create(DesktopCaptureOptions::CreateDefault())); |
87 } | 39 } |
88 | 40 |
89 protected: | 41 protected: |
90 void TestCaptureUpdatedRegion( | |
91 std::initializer_list<ScreenCapturer*> capturers) { | |
92 RTC_DCHECK(capturers.size() > 0); | |
93 // A large enough area for the tests, which should be able to fulfill by | |
94 // most of systems. | |
95 const int kTestArea = 512; | |
96 const int kRectSize = 32; | |
97 std::unique_ptr<ScreenDrawer> drawer = ScreenDrawer::Create(); | |
98 if (!drawer || drawer->DrawableRegion().is_empty()) { | |
99 LOG(LS_WARNING) << "No ScreenDrawer implementation for current platform."; | |
100 return; | |
101 } | |
102 if (drawer->DrawableRegion().width() < kTestArea || | |
103 drawer->DrawableRegion().height() < kTestArea) { | |
104 LOG(LS_WARNING) << "ScreenDrawer::DrawableRegion() is too small for the " | |
105 "CaptureUpdatedRegion tests."; | |
106 return; | |
107 } | |
108 | |
109 for (ScreenCapturer* capturer : capturers) { | |
110 capturer->Start(&callback_); | |
111 } | |
112 | |
113 // Draw a set of |kRectSize| by |kRectSize| rectangles at (|i|, |i|), or | |
114 // |i| by |i| rectangles at (|kRectSize|, |kRectSize|). One of (controlled | |
115 // by |c|) its primary colors is |i|, and the other two are 0x7f. So we | |
116 // won't draw a black or white rectangle. | |
117 for (int c = 0; c < 3; c++) { | |
118 // A fixed size rectangle. | |
119 for (int i = 0; i < kTestArea - kRectSize; i += 16) { | |
120 DesktopRect rect = DesktopRect::MakeXYWH(i, i, kRectSize, kRectSize); | |
121 rect.Translate(drawer->DrawableRegion().top_left()); | |
122 RgbaColor color((c == 0 ? (i & 0xff) : 0x7f), | |
123 (c == 1 ? (i & 0xff) : 0x7f), | |
124 (c == 2 ? (i & 0xff) : 0x7f)); | |
125 TestCaptureOneFrame(capturers, drawer.get(), rect, color); | |
126 } | |
127 | |
128 // A variable-size rectangle. | |
129 for (int i = 0; i < kTestArea - kRectSize; i += 16) { | |
130 DesktopRect rect = DesktopRect::MakeXYWH(kRectSize, kRectSize, i, i); | |
131 rect.Translate(drawer->DrawableRegion().top_left()); | |
132 RgbaColor color((c == 0 ? (i & 0xff) : 0x7f), | |
133 (c == 1 ? (i & 0xff) : 0x7f), | |
134 (c == 2 ? (i & 0xff) : 0x7f)); | |
135 TestCaptureOneFrame(capturers, drawer.get(), rect, color); | |
136 } | |
137 } | |
138 } | |
139 | |
140 void TestCaptureUpdatedRegion() { | |
141 TestCaptureUpdatedRegion({capturer_.get()}); | |
142 } | |
143 | |
144 #if defined(WEBRTC_WIN) | 42 #if defined(WEBRTC_WIN) |
145 // Enable allow_directx_capturer in DesktopCaptureOptions, but let | 43 // Enable allow_directx_capturer in DesktopCaptureOptions, but let |
146 // ScreenCapturer::Create to decide whether a DirectX capturer should be used. | 44 // ScreenCapturer::Create to decide whether a DirectX capturer should be used. |
147 void MaybeCreateDirectxCapturer() { | 45 void MaybeCreateDirectxCapturer() { |
148 DesktopCaptureOptions options(DesktopCaptureOptions::CreateDefault()); | 46 DesktopCaptureOptions options(DesktopCaptureOptions::CreateDefault()); |
149 options.set_allow_directx_capturer(true); | 47 options.set_allow_directx_capturer(true); |
150 capturer_.reset(ScreenCapturer::Create(options)); | 48 capturer_.reset(ScreenCapturer::Create(options)); |
151 } | 49 } |
152 | 50 |
153 bool CreateDirectxCapturer() { | 51 bool CreateDirectxCapturer() { |
154 if (!ScreenCapturerWinDirectx::IsSupported()) { | 52 if (!ScreenCapturerWinDirectx::IsSupported()) { |
155 LOG(LS_WARNING) << "Directx capturer is not supported"; | 53 LOG(LS_WARNING) << "Directx capturer is not supported"; |
156 return false; | 54 return false; |
157 } | 55 } |
158 | 56 |
159 MaybeCreateDirectxCapturer(); | 57 MaybeCreateDirectxCapturer(); |
160 return true; | 58 return true; |
161 } | 59 } |
162 | 60 |
163 void CreateMagnifierCapturer() { | 61 void CreateMagnifierCapturer() { |
164 DesktopCaptureOptions options(DesktopCaptureOptions::CreateDefault()); | 62 DesktopCaptureOptions options(DesktopCaptureOptions::CreateDefault()); |
165 options.set_allow_use_magnification_api(true); | 63 options.set_allow_use_magnification_api(true); |
166 capturer_.reset(ScreenCapturer::Create(options)); | 64 capturer_.reset(ScreenCapturer::Create(options)); |
167 } | 65 } |
168 #endif // defined(WEBRTC_WIN) | 66 #endif // defined(WEBRTC_WIN) |
169 | 67 |
170 std::unique_ptr<ScreenCapturer> capturer_; | 68 std::unique_ptr<ScreenCapturer> capturer_; |
171 MockScreenCapturerCallback callback_; | 69 MockScreenCapturerCallback callback_; |
172 | |
173 private: | |
174 // Repeats capturing the frame by using |capturers| one-by-one for 600 times, | |
175 // typically 30 seconds, until they succeeded captured a |color| rectangle at | |
176 // |rect|. This function uses |drawer|->WaitForPendingDraws() between two | |
177 // attempts to wait for the screen to update. | |
178 void TestCaptureOneFrame(std::vector<ScreenCapturer*> capturers, | |
179 ScreenDrawer* drawer, | |
180 DesktopRect rect, | |
181 RgbaColor color) { | |
182 const int wait_capture_round = 600; | |
183 drawer->Clear(); | |
184 size_t succeeded_capturers = 0; | |
185 for (int i = 0; i < wait_capture_round; i++) { | |
186 drawer->DrawRectangle(rect, color); | |
187 drawer->WaitForPendingDraws(); | |
188 for (size_t j = 0; j < capturers.size(); j++) { | |
189 if (capturers[j] == nullptr) { | |
190 // ScreenCapturer should return an empty updated_region() if no | |
191 // update detected. So we won't test it again if it has captured | |
192 // the rectangle we drew. | |
193 continue; | |
194 } | |
195 std::unique_ptr<DesktopFrame> frame = CaptureFrame(capturers[j]); | |
196 if (!frame) { | |
197 // CaptureFrame() has triggered an assertion failure already, we | |
198 // only need to return here. | |
199 return; | |
200 } | |
201 | |
202 if (ArePixelsColoredBy( | |
203 *frame, rect, color, drawer->MayDrawIncompleteShapes())) { | |
204 capturers[j] = nullptr; | |
205 succeeded_capturers++; | |
206 } | |
207 } | |
208 | |
209 if (succeeded_capturers == capturers.size()) { | |
210 break; | |
211 } | |
212 } | |
213 | |
214 ASSERT_EQ(succeeded_capturers, capturers.size()); | |
215 } | |
216 | |
217 // Expects |capturer| to successfully capture a frame, and returns it. | |
218 std::unique_ptr<DesktopFrame> CaptureFrame(ScreenCapturer* capturer) { | |
219 std::unique_ptr<DesktopFrame> frame; | |
220 EXPECT_CALL(callback_, | |
221 OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _)) | |
222 .WillOnce(SaveUniquePtrArg(&frame)); | |
223 capturer->CaptureFrame(); | |
224 EXPECT_TRUE(frame); | |
225 return frame; | |
226 } | |
227 }; | 70 }; |
228 | 71 |
229 class FakeSharedMemory : public SharedMemory { | 72 class FakeSharedMemory : public SharedMemory { |
230 public: | 73 public: |
231 FakeSharedMemory(char* buffer, size_t size) | 74 FakeSharedMemory(char* buffer, size_t size) |
232 : SharedMemory(buffer, size, 0, kTestSharedMemoryId), | 75 : SharedMemory(buffer, size, 0, kTestSharedMemoryId), |
233 buffer_(buffer) { | 76 buffer_(buffer) { |
234 } | 77 } |
235 virtual ~FakeSharedMemory() { | 78 virtual ~FakeSharedMemory() { |
236 delete[] buffer_; | 79 delete[] buffer_; |
(...skipping 10 matching lines...) Expand all Loading... |
247 | 90 |
248 std::unique_ptr<SharedMemory> CreateSharedMemory(size_t size) override { | 91 std::unique_ptr<SharedMemory> CreateSharedMemory(size_t size) override { |
249 return std::unique_ptr<SharedMemory>( | 92 return std::unique_ptr<SharedMemory>( |
250 new FakeSharedMemory(new char[size], size)); | 93 new FakeSharedMemory(new char[size], size)); |
251 } | 94 } |
252 | 95 |
253 private: | 96 private: |
254 RTC_DISALLOW_COPY_AND_ASSIGN(FakeSharedMemoryFactory); | 97 RTC_DISALLOW_COPY_AND_ASSIGN(FakeSharedMemoryFactory); |
255 }; | 98 }; |
256 | 99 |
| 100 ACTION_P(SaveUniquePtrArg, dest) { |
| 101 *dest = std::move(*arg1); |
| 102 } |
| 103 |
257 TEST_F(ScreenCapturerTest, GetScreenListAndSelectScreen) { | 104 TEST_F(ScreenCapturerTest, GetScreenListAndSelectScreen) { |
258 webrtc::ScreenCapturer::ScreenList screens; | 105 webrtc::ScreenCapturer::ScreenList screens; |
259 EXPECT_TRUE(capturer_->GetScreenList(&screens)); | 106 EXPECT_TRUE(capturer_->GetScreenList(&screens)); |
260 for (webrtc::ScreenCapturer::ScreenList::iterator it = screens.begin(); | 107 for (webrtc::ScreenCapturer::ScreenList::iterator it = screens.begin(); |
261 it != screens.end(); ++it) { | 108 it != screens.end(); ++it) { |
262 EXPECT_TRUE(capturer_->SelectScreen(it->id)); | 109 EXPECT_TRUE(capturer_->SelectScreen(it->id)); |
263 } | 110 } |
264 } | 111 } |
265 | 112 |
266 TEST_F(ScreenCapturerTest, StartCapturer) { | 113 TEST_F(ScreenCapturerTest, StartCapturer) { |
267 capturer_->Start(&callback_); | 114 capturer_->Start(&callback_); |
268 } | 115 } |
269 | 116 |
270 TEST_F(ScreenCapturerTest, Capture) { | 117 TEST_F(ScreenCapturerTest, Capture) { |
271 // Assume that Start() treats the screen as invalid initially. | 118 // Assume that Start() treats the screen as invalid initially. |
(...skipping 14 matching lines...) Expand all Loading... |
286 | 133 |
287 // Verify that the region contains whole screen. | 134 // Verify that the region contains whole screen. |
288 EXPECT_FALSE(frame->updated_region().is_empty()); | 135 EXPECT_FALSE(frame->updated_region().is_empty()); |
289 DesktopRegion::Iterator it(frame->updated_region()); | 136 DesktopRegion::Iterator it(frame->updated_region()); |
290 ASSERT_TRUE(!it.IsAtEnd()); | 137 ASSERT_TRUE(!it.IsAtEnd()); |
291 EXPECT_TRUE(it.rect().equals(DesktopRect::MakeSize(frame->size()))); | 138 EXPECT_TRUE(it.rect().equals(DesktopRect::MakeSize(frame->size()))); |
292 it.Advance(); | 139 it.Advance(); |
293 EXPECT_TRUE(it.IsAtEnd()); | 140 EXPECT_TRUE(it.IsAtEnd()); |
294 } | 141 } |
295 | 142 |
296 // Disabled due to being flaky due to the fact that it uses rendering / UI, see | |
297 // webrtc/6366. | |
298 TEST_F(ScreenCapturerTest, DISABLED_CaptureUpdatedRegion) { | |
299 TestCaptureUpdatedRegion(); | |
300 } | |
301 | |
302 // Disabled due to being flaky due to the fact that it uses rendering / UI, see | |
303 // webrtc/6366. | |
304 TEST_F(ScreenCapturerTest, DISABLED_TwoCapturers) { | |
305 std::unique_ptr<ScreenCapturer> capturer2 = std::move(capturer_); | |
306 SetUp(); | |
307 TestCaptureUpdatedRegion({capturer_.get(), capturer2.get()}); | |
308 } | |
309 | |
310 #if defined(WEBRTC_WIN) | 143 #if defined(WEBRTC_WIN) |
311 | 144 |
312 TEST_F(ScreenCapturerTest, UseSharedBuffers) { | 145 TEST_F(ScreenCapturerTest, UseSharedBuffers) { |
313 std::unique_ptr<DesktopFrame> frame; | 146 std::unique_ptr<DesktopFrame> frame; |
314 EXPECT_CALL(callback_, | 147 EXPECT_CALL(callback_, |
315 OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _)) | 148 OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _)) |
316 .WillOnce(SaveUniquePtrArg(&frame)); | 149 .WillOnce(SaveUniquePtrArg(&frame)); |
317 | 150 |
318 capturer_->Start(&callback_); | 151 capturer_->Start(&callback_); |
319 capturer_->SetSharedMemoryFactory( | 152 capturer_->SetSharedMemoryFactory( |
320 std::unique_ptr<SharedMemoryFactory>(new FakeSharedMemoryFactory())); | 153 std::unique_ptr<SharedMemoryFactory>(new FakeSharedMemoryFactory())); |
321 capturer_->CaptureFrame(); | 154 capturer_->CaptureFrame(); |
322 | 155 |
323 ASSERT_TRUE(frame); | 156 ASSERT_TRUE(frame); |
324 ASSERT_TRUE(frame->shared_memory()); | 157 ASSERT_TRUE(frame->shared_memory()); |
325 EXPECT_EQ(frame->shared_memory()->id(), kTestSharedMemoryId); | 158 EXPECT_EQ(frame->shared_memory()->id(), kTestSharedMemoryId); |
326 } | 159 } |
327 | 160 |
328 TEST_F(ScreenCapturerTest, UseMagnifier) { | 161 TEST_F(ScreenCapturerTest, UseMagnifier) { |
329 CreateMagnifierCapturer(); | 162 CreateMagnifierCapturer(); |
330 | |
331 std::unique_ptr<DesktopFrame> frame; | 163 std::unique_ptr<DesktopFrame> frame; |
332 EXPECT_CALL(callback_, | 164 EXPECT_CALL(callback_, |
333 OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _)) | 165 OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, _)) |
334 .WillOnce(SaveUniquePtrArg(&frame)); | 166 .WillOnce(SaveUniquePtrArg(&frame)); |
335 | 167 |
336 capturer_->Start(&callback_); | 168 capturer_->Start(&callback_); |
337 capturer_->CaptureFrame(); | 169 capturer_->CaptureFrame(); |
338 ASSERT_TRUE(frame); | 170 ASSERT_TRUE(frame); |
339 } | 171 } |
340 | 172 |
(...skipping 24 matching lines...) Expand all Loading... |
365 | 197 |
366 capturer_->Start(&callback_); | 198 capturer_->Start(&callback_); |
367 capturer_->SetSharedMemoryFactory( | 199 capturer_->SetSharedMemoryFactory( |
368 std::unique_ptr<SharedMemoryFactory>(new FakeSharedMemoryFactory())); | 200 std::unique_ptr<SharedMemoryFactory>(new FakeSharedMemoryFactory())); |
369 capturer_->CaptureFrame(); | 201 capturer_->CaptureFrame(); |
370 ASSERT_TRUE(frame); | 202 ASSERT_TRUE(frame); |
371 ASSERT_TRUE(frame->shared_memory()); | 203 ASSERT_TRUE(frame->shared_memory()); |
372 EXPECT_EQ(frame->shared_memory()->id(), kTestSharedMemoryId); | 204 EXPECT_EQ(frame->shared_memory()->id(), kTestSharedMemoryId); |
373 } | 205 } |
374 | 206 |
375 // Disabled due to being flaky due to the fact that it uses rendering / UI, see | |
376 // webrtc/6366. | |
377 TEST_F(ScreenCapturerTest, DISABLED_CaptureUpdatedRegionWithDirectxCapturer) { | |
378 if (!CreateDirectxCapturer()) { | |
379 return; | |
380 } | |
381 | |
382 TestCaptureUpdatedRegion(); | |
383 } | |
384 | |
385 // Disabled due to being flaky due to the fact that it uses rendering / UI, see | |
386 // webrtc/6366. | |
387 TEST_F(ScreenCapturerTest, DISABLED_TwoDirectxCapturers) { | |
388 if (!CreateDirectxCapturer()) { | |
389 return; | |
390 } | |
391 | |
392 std::unique_ptr<ScreenCapturer> capturer2 = std::move(capturer_); | |
393 RTC_CHECK(CreateDirectxCapturer()); | |
394 TestCaptureUpdatedRegion({capturer_.get(), capturer2.get()}); | |
395 } | |
396 | |
397 // Disabled due to being flaky due to the fact that it uses rendering / UI, see | |
398 // webrtc/6366. | |
399 TEST_F(ScreenCapturerTest, DISABLED_CaptureUpdatedRegionWithMagnifierCapturer) { | |
400 CreateMagnifierCapturer(); | |
401 TestCaptureUpdatedRegion(); | |
402 } | |
403 | |
404 // Disabled due to being flaky due to the fact that it uses rendering / UI, see | |
405 // webrtc/6366. | |
406 TEST_F(ScreenCapturerTest, DISABLED_TwoMagnifierCapturers) { | |
407 CreateMagnifierCapturer(); | |
408 std::unique_ptr<ScreenCapturer> capturer2 = std::move(capturer_); | |
409 CreateMagnifierCapturer(); | |
410 TestCaptureUpdatedRegion({capturer_.get(), capturer2.get()}); | |
411 } | |
412 | |
413 // Disabled due to being flaky due to the fact that it uses rendering / UI, see | |
414 // webrtc/6366. | |
415 TEST_F(ScreenCapturerTest, | |
416 DISABLED_MaybeCaptureUpdatedRegionWithDirectxCapturer) { | |
417 // Even DirectX capturer is not supported in current system, we should be able | |
418 // to select a usable capturer. | |
419 MaybeCreateDirectxCapturer(); | |
420 TestCaptureUpdatedRegion(); | |
421 } | |
422 | |
423 #endif // defined(WEBRTC_WIN) | 207 #endif // defined(WEBRTC_WIN) |
424 | 208 |
425 } // namespace webrtc | 209 } // namespace webrtc |
OLD | NEW |