desktop_frame_unittest.cc (14466B)
1 /* 2 * Copyright (c) 2019 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 "modules/desktop_capture/desktop_frame.h" 12 13 #include <cstdint> 14 #include <cstring> 15 #include <memory> 16 #include <optional> 17 18 #include "api/array_view.h" 19 #include "modules/desktop_capture/desktop_geometry.h" 20 #include "test/gtest.h" 21 22 namespace webrtc { 23 24 namespace { 25 26 std::unique_ptr<DesktopFrame> CreateTestFrame(DesktopRect rect, 27 int pixels_value) { 28 DesktopSize size = rect.size(); 29 auto frame = std::make_unique<BasicDesktopFrame>(size); 30 frame->set_top_left(rect.top_left()); 31 memset(frame->data(), pixels_value, frame->stride() * size.height()); 32 return frame; 33 } 34 35 struct TestData { 36 const char* description; 37 DesktopRect dest_frame_rect; 38 DesktopRect src_frame_rect; 39 double horizontal_scale; 40 double vertical_scale; 41 DesktopRect expected_overlap_rect; 42 }; 43 44 void RunTest(const TestData& test) { 45 // Copy a source frame with all bits set into a dest frame with none set. 46 auto dest_frame = CreateTestFrame(test.dest_frame_rect, 0); 47 auto src_frame = CreateTestFrame(test.src_frame_rect, 0xff); 48 49 dest_frame->CopyIntersectingPixelsFrom(*src_frame, test.horizontal_scale, 50 test.vertical_scale); 51 52 // Translate the expected overlap rect to be relative to the dest frame/rect. 53 DesktopVector dest_frame_origin = test.dest_frame_rect.top_left(); 54 DesktopRect relative_expected_overlap_rect = test.expected_overlap_rect; 55 relative_expected_overlap_rect.Translate(-dest_frame_origin.x(), 56 -dest_frame_origin.y()); 57 58 // Confirm bits are now set in the dest frame if & only if they fall in the 59 // expected range. 60 for (int y = 0; y < dest_frame->size().height(); ++y) { 61 SCOPED_TRACE(y); 62 63 for (int x = 0; x < dest_frame->size().width(); ++x) { 64 SCOPED_TRACE(x); 65 66 DesktopVector point(x, y); 67 uint8_t* data = dest_frame->GetFrameDataAtPos(point); 68 uint32_t pixel_value = *reinterpret_cast<uint32_t*>(data); 69 bool was_copied = pixel_value == 0xffffffff; 70 ASSERT_TRUE(was_copied || pixel_value == 0); 71 72 bool expected_to_be_copied = 73 relative_expected_overlap_rect.Contains(point); 74 75 ASSERT_EQ(was_copied, expected_to_be_copied); 76 } 77 } 78 } 79 80 void RunTests(ArrayView<const TestData> tests) { 81 for (const TestData& test : tests) { 82 SCOPED_TRACE(test.description); 83 84 RunTest(test); 85 } 86 } 87 88 } // namespace 89 90 TEST(DesktopFrameTest, NewFrameIsBlack) { 91 auto frame = std::make_unique<BasicDesktopFrame>(DesktopSize(10, 10)); 92 EXPECT_TRUE(frame->FrameDataIsBlack()); 93 } 94 95 TEST(DesktopFrameTest, EmptyFrameIsNotBlack) { 96 auto frame = std::make_unique<BasicDesktopFrame>(DesktopSize()); 97 EXPECT_FALSE(frame->FrameDataIsBlack()); 98 } 99 100 TEST(DesktopFrameTest, FrameHasDefaultDeviceScaleFactor) { 101 auto frame = std::make_unique<BasicDesktopFrame>(DesktopSize()); 102 EXPECT_EQ(frame->device_scale_factor(), std::nullopt); 103 } 104 105 TEST(DesktopFrameTest, FrameSetsDeviceScaleFactorCorrectly) { 106 auto frame = std::make_unique<BasicDesktopFrame>(DesktopSize()); 107 EXPECT_EQ(frame->device_scale_factor(), std::nullopt); 108 float device_scale_factor = 1.5f; 109 frame->set_device_scale_factor(device_scale_factor); 110 EXPECT_EQ(frame->device_scale_factor(), device_scale_factor); 111 } 112 113 TEST(DesktopFrameTest, FrameDataSwitchesBetweenNonBlackAndBlack) { 114 auto frame = CreateTestFrame(DesktopRect::MakeXYWH(0, 0, 10, 10), 0xff); 115 EXPECT_FALSE(frame->FrameDataIsBlack()); 116 frame->SetFrameDataToBlack(); 117 EXPECT_TRUE(frame->FrameDataIsBlack()); 118 } 119 120 TEST(DesktopFrameTest, CopyIntersectingPixelsMatchingRects) { 121 const TestData tests[] = { 122 {.description = "0 origin", 123 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 124 .src_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 125 .horizontal_scale = 1.0, 126 .vertical_scale = 1.0, 127 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 0, 2, 2)}, 128 129 {.description = "Negative origin", 130 .dest_frame_rect = DesktopRect::MakeXYWH(-1, -1, 2, 2), 131 .src_frame_rect = DesktopRect::MakeXYWH(-1, -1, 2, 2), 132 .horizontal_scale = 1.0, 133 .vertical_scale = 1.0, 134 .expected_overlap_rect = DesktopRect::MakeXYWH(-1, -1, 2, 2)}}; 135 136 RunTests(tests); 137 } 138 139 TEST(DesktopFrameTest, CopyIntersectingPixelsMatchingRectsScaled) { 140 // The scale factors shouldn't affect matching rects (they're only applied 141 // to any difference between the origins) 142 const TestData tests[] = { 143 {.description = "0 origin 2x", 144 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 145 .src_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 146 .horizontal_scale = 2.0, 147 .vertical_scale = 2.0, 148 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 0, 2, 2)}, 149 150 {.description = "0 origin 0.5x", 151 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 152 .src_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 153 .horizontal_scale = 0.5, 154 .vertical_scale = 0.5, 155 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 0, 2, 2)}, 156 157 {.description = "Negative origin 2x", 158 .dest_frame_rect = DesktopRect::MakeXYWH(-1, -1, 2, 2), 159 .src_frame_rect = DesktopRect::MakeXYWH(-1, -1, 2, 2), 160 .horizontal_scale = 2.0, 161 .vertical_scale = 2.0, 162 .expected_overlap_rect = DesktopRect::MakeXYWH(-1, -1, 2, 2)}, 163 164 {.description = "Negative origin 0.5x", 165 .dest_frame_rect = DesktopRect::MakeXYWH(-1, -1, 2, 2), 166 .src_frame_rect = DesktopRect::MakeXYWH(-1, -1, 2, 2), 167 .horizontal_scale = 0.5, 168 .vertical_scale = 0.5, 169 .expected_overlap_rect = DesktopRect::MakeXYWH(-1, -1, 2, 2)}}; 170 171 RunTests(tests); 172 } 173 174 TEST(DesktopFrameTest, CopyIntersectingPixelsFullyContainedRects) { 175 const TestData tests[] = { 176 {.description = "0 origin top left", 177 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 178 .src_frame_rect = DesktopRect::MakeXYWH(0, 0, 1, 1), 179 .horizontal_scale = 1.0, 180 .vertical_scale = 1.0, 181 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 0, 1, 1)}, 182 183 {.description = "0 origin bottom right", 184 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 185 .src_frame_rect = DesktopRect::MakeXYWH(1, 1, 1, 1), 186 .horizontal_scale = 1.0, 187 .vertical_scale = 1.0, 188 .expected_overlap_rect = DesktopRect::MakeXYWH(1, 1, 1, 1)}, 189 190 {.description = "Negative origin bottom left", 191 .dest_frame_rect = DesktopRect::MakeXYWH(-1, -1, 2, 2), 192 .src_frame_rect = DesktopRect::MakeXYWH(-1, 0, 1, 1), 193 .horizontal_scale = 1.0, 194 .vertical_scale = 1.0, 195 .expected_overlap_rect = DesktopRect::MakeXYWH(-1, 0, 1, 1)}}; 196 197 RunTests(tests); 198 } 199 200 TEST(DesktopFrameTest, CopyIntersectingPixelsFullyContainedRectsScaled) { 201 const TestData tests[] = { 202 {.description = "0 origin top left 2x", 203 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 204 .src_frame_rect = DesktopRect::MakeXYWH(0, 0, 1, 1), 205 .horizontal_scale = 2.0, 206 .vertical_scale = 2.0, 207 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 0, 1, 1)}, 208 209 {.description = "0 origin top left 0.5x", 210 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 211 .src_frame_rect = DesktopRect::MakeXYWH(0, 0, 1, 1), 212 .horizontal_scale = 0.5, 213 .vertical_scale = 0.5, 214 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 0, 1, 1)}, 215 216 {.description = "0 origin bottom left 2x", 217 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 4, 4), 218 .src_frame_rect = DesktopRect::MakeXYWH(1, 1, 2, 2), 219 .horizontal_scale = 2.0, 220 .vertical_scale = 2.0, 221 .expected_overlap_rect = DesktopRect::MakeXYWH(2, 2, 2, 2)}, 222 223 {.description = "0 origin bottom middle 2x/1x", 224 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 4, 3), 225 .src_frame_rect = DesktopRect::MakeXYWH(1, 1, 2, 2), 226 .horizontal_scale = 2.0, 227 .vertical_scale = 1.0, 228 .expected_overlap_rect = DesktopRect::MakeXYWH(2, 1, 2, 2)}, 229 230 {.description = "0 origin middle 0.5x", 231 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 3, 3), 232 .src_frame_rect = DesktopRect::MakeXYWH(2, 2, 1, 1), 233 .horizontal_scale = 0.5, 234 .vertical_scale = 0.5, 235 .expected_overlap_rect = DesktopRect::MakeXYWH(1, 1, 1, 1)}, 236 237 {.description = "Negative origin bottom left 2x", 238 .dest_frame_rect = DesktopRect::MakeXYWH(-1, -1, 3, 3), 239 .src_frame_rect = DesktopRect::MakeXYWH(-1, 0, 1, 1), 240 .horizontal_scale = 2.0, 241 .vertical_scale = 2.0, 242 .expected_overlap_rect = DesktopRect::MakeXYWH(-1, 1, 1, 1)}, 243 244 {.description = "Negative origin near middle 0.5x", 245 .dest_frame_rect = DesktopRect::MakeXYWH(-2, -2, 2, 2), 246 .src_frame_rect = DesktopRect::MakeXYWH(0, 0, 1, 1), 247 .horizontal_scale = 0.5, 248 .vertical_scale = 0.5, 249 .expected_overlap_rect = DesktopRect::MakeXYWH(-1, -1, 1, 1)}}; 250 251 RunTests(tests); 252 } 253 254 TEST(DesktopFrameTest, CopyIntersectingPixelsPartiallyContainedRects) { 255 const TestData tests[] = { 256 {.description = "Top left", 257 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 258 .src_frame_rect = DesktopRect::MakeXYWH(-1, -1, 2, 2), 259 .horizontal_scale = 1.0, 260 .vertical_scale = 1.0, 261 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 0, 1, 1)}, 262 263 {.description = "Top right", 264 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 265 .src_frame_rect = DesktopRect::MakeXYWH(1, -1, 2, 2), 266 .horizontal_scale = 1.0, 267 .vertical_scale = 1.0, 268 .expected_overlap_rect = DesktopRect::MakeXYWH(1, 0, 1, 1)}, 269 270 {.description = "Bottom right", 271 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 272 .src_frame_rect = DesktopRect::MakeXYWH(1, 1, 2, 2), 273 .horizontal_scale = 1.0, 274 .vertical_scale = 1.0, 275 .expected_overlap_rect = DesktopRect::MakeXYWH(1, 1, 1, 1)}, 276 277 {.description = "Bottom left", 278 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 279 .src_frame_rect = DesktopRect::MakeXYWH(-1, 1, 2, 2), 280 .horizontal_scale = 1.0, 281 .vertical_scale = 1.0, 282 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 1, 1, 1)}}; 283 284 RunTests(tests); 285 } 286 287 TEST(DesktopFrameTest, CopyIntersectingPixelsPartiallyContainedRectsScaled) { 288 const TestData tests[] = { 289 {.description = "Top left 2x", 290 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 291 .src_frame_rect = DesktopRect::MakeXYWH(-1, -1, 3, 3), 292 .horizontal_scale = 2.0, 293 .vertical_scale = 2.0, 294 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 0, 1, 1)}, 295 296 {.description = "Top right 0.5x", 297 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 298 .src_frame_rect = DesktopRect::MakeXYWH(2, -2, 2, 2), 299 .horizontal_scale = 0.5, 300 .vertical_scale = 0.5, 301 .expected_overlap_rect = DesktopRect::MakeXYWH(1, 0, 1, 1)}, 302 303 {.description = "Bottom right 2x", 304 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 3, 3), 305 .src_frame_rect = DesktopRect::MakeXYWH(-1, 1, 3, 3), 306 .horizontal_scale = 2.0, 307 .vertical_scale = 2.0, 308 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 2, 1, 1)}, 309 310 {.description = "Bottom left 0.5x", 311 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 312 .src_frame_rect = DesktopRect::MakeXYWH(-2, 2, 2, 2), 313 .horizontal_scale = 0.5, 314 .vertical_scale = 0.5, 315 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 1, 1, 1)}}; 316 317 RunTests(tests); 318 } 319 320 TEST(DesktopFrameTest, CopyIntersectingPixelsUncontainedRects) { 321 const TestData tests[] = { 322 {.description = "Left", 323 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 324 .src_frame_rect = DesktopRect::MakeXYWH(-1, 0, 1, 2), 325 .horizontal_scale = 1.0, 326 .vertical_scale = 1.0, 327 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 0, 0, 0)}, 328 329 {.description = "Top", 330 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 331 .src_frame_rect = DesktopRect::MakeXYWH(0, -1, 2, 1), 332 .horizontal_scale = 1.0, 333 .vertical_scale = 1.0, 334 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 0, 0, 0)}, 335 336 {.description = "Right", 337 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 338 .src_frame_rect = DesktopRect::MakeXYWH(2, 0, 1, 2), 339 .horizontal_scale = 1.0, 340 .vertical_scale = 1.0, 341 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 0, 0, 0)}, 342 343 {.description = "Bottom", 344 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 345 .src_frame_rect = DesktopRect::MakeXYWH(0, 2, 2, 1), 346 .horizontal_scale = 1.0, 347 .vertical_scale = 1.0, 348 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 0, 0, 0)}}; 349 350 RunTests(tests); 351 } 352 353 TEST(DesktopFrameTest, CopyIntersectingPixelsUncontainedRectsScaled) { 354 const TestData tests[] = { 355 {.description = "Left 2x", 356 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 357 .src_frame_rect = DesktopRect::MakeXYWH(-1, 0, 2, 2), 358 .horizontal_scale = 2.0, 359 .vertical_scale = 2.0, 360 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 0, 0, 0)}, 361 362 {.description = "Top 0.5x", 363 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 364 .src_frame_rect = DesktopRect::MakeXYWH(0, -2, 2, 1), 365 .horizontal_scale = 0.5, 366 .vertical_scale = 0.5, 367 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 0, 0, 0)}, 368 369 {.description = "Right 2x", 370 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 371 .src_frame_rect = DesktopRect::MakeXYWH(1, 0, 1, 2), 372 .horizontal_scale = 2.0, 373 .vertical_scale = 2.0, 374 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 0, 0, 0)}, 375 376 {.description = "Bottom 0.5x", 377 .dest_frame_rect = DesktopRect::MakeXYWH(0, 0, 2, 2), 378 .src_frame_rect = DesktopRect::MakeXYWH(0, 4, 2, 1), 379 .horizontal_scale = 0.5, 380 .vertical_scale = 0.5, 381 .expected_overlap_rect = DesktopRect::MakeXYWH(0, 0, 0, 0)}}; 382 383 RunTests(tests); 384 } 385 386 } // namespace webrtc