OLD | NEW |
---|---|
(Empty) | |
1 /* | |
2 * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. | |
3 * | |
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 | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #include "webrtc/modules/desktop_capture/screen_capturer_differ_wrapper.h" | |
12 | |
13 #include <initializer_list> | |
14 #include <memory> | |
15 #include <utility> | |
16 #include <vector> | |
17 | |
18 #include "testing/gtest/include/gtest/gtest.h" | |
19 #include "webrtc/base/random.h" | |
20 #include "webrtc/base/timeutils.h" | |
21 #include "webrtc/modules/desktop_capture/desktop_geometry.h" | |
22 #include "webrtc/modules/desktop_capture/desktop_region.h" | |
23 #include "webrtc/modules/desktop_capture/differ_block.h" | |
24 #include "webrtc/modules/desktop_capture/screen_capturer_mock_objects.h" | |
25 #include "webrtc/system_wrappers/include/cpu_features_wrapper.h" | |
26 #include "webrtc/typedefs.h" | |
27 | |
28 namespace webrtc { | |
29 | |
30 namespace { | |
31 | |
32 // ScreenCapturerDifferWrapper always use a 32 pixel block. So we normalize the | |
33 // |rects|. | |
34 DesktopRect NormalizeDesktopRect(DesktopRect rect, DesktopSize size) { | |
35 DesktopRect block_size_rect = DesktopRect::MakeLTRB( | |
36 rect.left() / kBlockSize * kBlockSize, | |
37 rect.top() / kBlockSize * kBlockSize, | |
38 (rect.right() + kBlockSize - 1) / kBlockSize * kBlockSize, | |
39 (rect.bottom() + kBlockSize - 1) / kBlockSize * kBlockSize); | |
40 block_size_rect.IntersectWith(DesktopRect::MakeSize(size)); | |
41 return block_size_rect; | |
42 } | |
43 | |
44 // Compares and asserts |frame|.updated_region() equals to |rects|. This | |
45 // function does not care about the order of the |rects|. | |
46 template <template <typename, typename...> class T = std::initializer_list, | |
47 typename... Rect> | |
48 void AssertUpdatedRegionIs(const DesktopFrame& frame, | |
49 const T<DesktopRect, Rect...>& rects) { | |
50 for (const DesktopRect& rect : rects) { | |
51 DesktopRect block_size_rect = NormalizeDesktopRect(rect, frame.size()); | |
52 bool found = false; | |
53 for (DesktopRegion::Iterator it(frame.updated_region()); !it.IsAtEnd(); | |
54 it.Advance()) { | |
55 if (it.rect().equals(block_size_rect)) { | |
56 found = true; | |
57 break; | |
58 } | |
59 } | |
60 ASSERT_TRUE(found); | |
61 } | |
62 } | |
63 | |
64 // Compares and asserts |frame|.updated_region() covers all rectangles in | |
65 // |rects|, but does not cover areas other than a kBlockSize expansion. This | |
66 // function does not care about the order of the |rects|, and it does not expect | |
67 // DesktopRegion to return an exact area of each rectangle in |rects|. | |
68 template <template <typename, typename...> class T = std::initializer_list, | |
69 typename... Rect> | |
70 void AssertUpdatedRegionCovers(const DesktopFrame& frame, | |
71 const T<DesktopRect, Rect...>& rects) { | |
72 DesktopRegion region; | |
73 for (const auto& rect : rects) { | |
74 region.AddRect(NormalizeDesktopRect(rect, frame.size())); | |
75 } | |
76 ASSERT_TRUE(frame.updated_region().Equals(region)); | |
77 } | |
78 | |
79 template <template <typename, typename...> class T = std::initializer_list, | |
80 typename... Rect> | |
81 void ExecuteDifferWrapperCase(MockScreenCapturer* mock_capturer, | |
82 ScreenCapturerDifferWrapper* capturer, | |
83 MockScreenCapturerCallback* callback, | |
84 const T<DesktopRect, Rect...>& dirty_region, | |
85 bool check_result, | |
86 bool exactly_match) { | |
87 EXPECT_CALL(*callback, | |
88 OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, testing::_)) | |
89 .Times(1) | |
90 .WillOnce(testing::Invoke([&dirty_region, check_result, exactly_match]( | |
91 DesktopCapturer::Result result, | |
92 std::unique_ptr<DesktopFrame>* frame) { | |
93 ASSERT_EQ(result, DesktopCapturer::Result::SUCCESS); | |
94 if (check_result) { | |
95 if (exactly_match) { | |
96 AssertUpdatedRegionIs(**frame, dirty_region); | |
97 } else { | |
98 AssertUpdatedRegionCovers(**frame, dirty_region); | |
99 } | |
100 } | |
101 })); | |
102 EXPECT_CALL(*mock_capturer, Capture(testing::_)).Times(1); | |
103 for (const auto& rect : dirty_region) { | |
104 mock_capturer->dirty_region()->AddRect(rect); | |
105 } | |
106 capturer->Capture(DesktopRegion()); | |
107 } | |
108 | |
109 // Executes a ScreenCapturerDifferWrapper::Capture(), if dirty_region() is not | |
110 // set, this function will reset ScreenCapturerDifferWrapper internal | |
111 // DesktopFrame into white. | |
112 void ExecuteCapturer(MockScreenCapturer* mock_capturer, | |
113 ScreenCapturerDifferWrapper* capturer, | |
114 MockScreenCapturerCallback* callback) { | |
115 EXPECT_CALL(*callback, | |
116 OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, testing::_)) | |
117 .Times(1); | |
118 EXPECT_CALL(*mock_capturer, Capture(testing::_)).Times(1); | |
119 capturer->Capture(DesktopRegion()); | |
120 } | |
121 | |
122 void ExecuteDifferWrapperTest(bool with_hints, | |
123 bool enlarge_dirty_region, | |
124 bool random_dirty_region, | |
125 bool check_result) { | |
126 std::unique_ptr<MockScreenCapturer> mock(new MockScreenCapturer()); | |
127 MockScreenCapturer* mock_capturer = mock.get(); | |
128 ScreenCapturerDifferWrapper capturer(std::move(mock), !with_hints); | |
129 MockScreenCapturerCallback callback; | |
130 *mock_capturer->provide_dirty_region_hints() = with_hints; | |
131 *mock_capturer->enlarge_dirty_region() = enlarge_dirty_region; | |
132 *mock_capturer->random_dirty_region() = random_dirty_region; | |
133 | |
134 EXPECT_CALL(*mock_capturer, Start(testing::_)).Times(1); | |
135 capturer.Start(&callback); | |
136 | |
137 EXPECT_CALL(callback, | |
138 OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, testing::_)) | |
139 .Times(1) | |
140 .WillOnce(testing::Invoke([](DesktopCapturer::Result result, | |
141 std::unique_ptr<DesktopFrame>* frame) { | |
142 ASSERT_EQ(result, DesktopCapturer::Result::SUCCESS); | |
143 AssertUpdatedRegionIs(**frame, | |
144 {DesktopRect::MakeSize((*frame)->size())}); | |
145 })); | |
146 EXPECT_CALL(*mock_capturer, Capture(testing::_)).Times(1); | |
147 capturer.Capture(DesktopRegion()); | |
148 | |
149 ExecuteDifferWrapperCase(mock_capturer, &capturer, &callback, | |
150 {DesktopRect::MakeLTRB(100, 100, 200, 200), | |
151 DesktopRect::MakeLTRB(300, 300, 400, 400)}, | |
152 check_result, true); | |
153 ExecuteCapturer(mock_capturer, &capturer, &callback); | |
154 | |
155 ExecuteDifferWrapperCase( | |
156 mock_capturer, &capturer, &callback, | |
157 {DesktopRect::MakeLTRB(0, 0, 40, 40), | |
158 DesktopRect::MakeLTRB(0, mock_capturer->size()->height() - 40, 40, | |
159 mock_capturer->size()->height()), | |
160 DesktopRect::MakeLTRB(mock_capturer->size()->width() - 40, 0, | |
161 mock_capturer->size()->width(), 40), | |
162 DesktopRect::MakeLTRB(mock_capturer->size()->width() - 40, | |
163 mock_capturer->size()->height() - 40, | |
164 mock_capturer->size()->width(), | |
165 mock_capturer->size()->height())}, | |
166 check_result, true); | |
167 | |
168 Random random(rtc::TimeMillis()); | |
169 // Fuzzing tests. | |
170 for (int i = 0; i < 1000; i++) { | |
171 if (enlarge_dirty_region) { | |
172 *mock_capturer->enlarge_range() = random.Rand(1, 50); | |
173 } | |
174 mock_capturer->size()->set(random.Rand(500, 2000), random.Rand(500, 2000)); | |
175 ExecuteCapturer(mock_capturer, &capturer, &callback); | |
176 std::vector<DesktopRect> dirty_region; | |
177 for (int j = random.Rand(50); j >= 0; j--) { | |
178 // At least a 1 x 1 dirty region. | |
179 const int left = random.Rand(0, mock_capturer->size()->width() - 2); | |
180 const int top = random.Rand(0, mock_capturer->size()->height() - 2); | |
181 const int right = random.Rand(left + 1, mock_capturer->size()->width()); | |
182 const int bottom = random.Rand(top + 1, mock_capturer->size()->height()); | |
183 dirty_region.push_back(DesktopRect::MakeLTRB(left, top, right, bottom)); | |
184 } | |
185 ExecuteDifferWrapperCase(mock_capturer, &capturer, &callback, dirty_region, | |
186 check_result, false); | |
187 } | |
188 } | |
189 | |
190 } // namespace | |
191 | |
192 TEST(ScreenCapturerDifferWrapperTest, FunctionForwarding) { | |
193 std::unique_ptr<MockScreenCapturer> mock(new MockScreenCapturer()); | |
194 MockScreenCapturer* mock_capturer = mock.get(); | |
195 ScreenCapturerDifferWrapper capturer(std::move(mock), true); | |
196 MockScreenCapturerCallback callback; | |
197 | |
198 EXPECT_CALL(*mock_capturer, Start(testing::_)).Times(1); | |
199 capturer.Start(&callback); | |
200 | |
201 EXPECT_CALL(*mock_capturer, Capture(testing::_)).Times(1); | |
202 EXPECT_CALL(callback, | |
203 OnCaptureResultPtr(DesktopCapturer::Result::SUCCESS, testing::_)) | |
204 .Times(1); | |
205 capturer.Capture(DesktopRegion()); | |
206 | |
207 EXPECT_CALL(*mock_capturer, GetScreenList(testing::_)).Times(1); | |
208 ASSERT_TRUE(capturer.GetScreenList(nullptr)); | |
209 | |
210 EXPECT_CALL(*mock_capturer, SelectScreen(testing::_)).Times(2); | |
211 ASSERT_FALSE(capturer.SelectScreen(ScreenId{100})); | |
212 ASSERT_TRUE(capturer.SelectScreen(kFullDesktopScreenId)); | |
213 } | |
214 | |
215 TEST(ScreenCapturerDifferWrapperTest, CaptureWithoutHints) { | |
216 ExecuteDifferWrapperTest(false, false, false, true); | |
217 } | |
218 | |
219 TEST(ScreenCapturerDifferWrapperTest, CaptureWithHints) { | |
220 ExecuteDifferWrapperTest(true, false, false, true); | |
221 } | |
222 | |
223 TEST(ScreenCapturerDifferWrapperTest, CaptureWithEnlargedHints) { | |
224 ExecuteDifferWrapperTest(true, true, false, true); | |
225 } | |
226 | |
227 TEST(ScreenCapturerDifferWrapperTest, CaptureWithRandomHints) { | |
228 ExecuteDifferWrapperTest(true, false, true, true); | |
229 } | |
230 | |
231 TEST(ScreenCapturerDifferWrapperTest, CaptureWithEnlargedAndRandomHints) { | |
232 ExecuteDifferWrapperTest(true, true, true, true); | |
233 } | |
234 | |
235 // SSE2 is not available on ARM / MIPS, so the performance should be extremely | |
236 // lower. | |
237 #if defined(WEBRTC_ARCH_X86_FAMILY) | |
238 // When hints are enabled, ScreenCapturerDifferWrapper has a slightly better | |
239 // performance in current configuration, but not so significant. Following is | |
240 // one run result. | |
241 // [ RUN ] CaptureWithoutHintsPerf | |
242 // [ OK ] CaptureWithoutHintsPerf (8889 ms) | |
243 // [ RUN ] CaptureWithHintsPerf | |
244 // [ OK ] CaptureWithHintsPerf (7814 ms) | |
245 // [ RUN ] CaptureWithEnlargedHintsPerf | |
246 // [ OK ] CaptureWithEnlargedHintsPerf (7999 ms) | |
247 // [ RUN ] CaptureWithRandomHintsPerf | |
248 // [ OK ] CaptureWithRandomHintsPerf (8429 ms) | |
249 // [ RUN ] CaptureWithEnlargedAndRandomHintsPerf | |
250 // [ OK ] CaptureWithEnlargedAndRandomHintsPerf (8552 ms) | |
251 TEST(ScreenCapturerDifferWrapperTest, CaptureWithoutHintsPerf) { | |
Sergey Ulanov
2016/08/12 05:25:51
Perf test shouldn't be mixed with unittests. They
Hzj_jie
2016/08/15 00:38:06
Done.
| |
252 if (WebRtc_GetCPUInfo(kSSE2) == 0) { | |
253 return; | |
254 } | |
255 | |
256 int64_t started = rtc::TimeMillis(); | |
257 ExecuteDifferWrapperTest(false, false, false, false); | |
258 ASSERT_LE(rtc::TimeMillis() - started, 15000); | |
259 } | |
260 | |
261 TEST(ScreenCapturerDifferWrapperTest, CaptureWithHintsPerf) { | |
262 if (WebRtc_GetCPUInfo(kSSE2) == 0) { | |
263 return; | |
264 } | |
265 | |
266 int64_t started = rtc::TimeMillis(); | |
267 ExecuteDifferWrapperTest(true, false, false, false); | |
268 ASSERT_LE(rtc::TimeMillis() - started, 15000); | |
269 } | |
270 | |
271 TEST(ScreenCapturerDifferWrapperTest, CaptureWithEnlargedHintsPerf) { | |
272 if (WebRtc_GetCPUInfo(kSSE2) == 0) { | |
273 return; | |
274 } | |
275 | |
276 int64_t started = rtc::TimeMillis(); | |
277 ExecuteDifferWrapperTest(true, true, false, false); | |
278 ASSERT_LE(rtc::TimeMillis() - started, 15000); | |
279 } | |
280 | |
281 TEST(ScreenCapturerDifferWrapperTest, CaptureWithRandomHintsPerf) { | |
282 if (WebRtc_GetCPUInfo(kSSE2) == 0) { | |
283 return; | |
284 } | |
285 | |
286 int64_t started = rtc::TimeMillis(); | |
287 ExecuteDifferWrapperTest(true, false, true, false); | |
288 ASSERT_LE(rtc::TimeMillis() - started, 15000); | |
289 } | |
290 | |
291 TEST(ScreenCapturerDifferWrapperTest, CaptureWithEnlargedAndRandomHintsPerf) { | |
292 if (WebRtc_GetCPUInfo(kSSE2) == 0) { | |
293 return; | |
294 } | |
295 | |
296 int64_t started = rtc::TimeMillis(); | |
297 ExecuteDifferWrapperTest(true, true, true, false); | |
298 ASSERT_LE(rtc::TimeMillis() - started, 15000); | |
299 } | |
300 #endif | |
301 | |
302 } // namespace webrtc | |
OLD | NEW |