Chromium Code Reviews| 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 |