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 "modules/desktop_capture/desktop_frame_rotation.h"
12
13 #include <stdint.h>
14
15 #include "modules/desktop_capture/desktop_frame.h"
16 #include "modules/desktop_capture/desktop_region.h"
17 #include "modules/desktop_capture/test_utils.h"
18 #include "test/gtest.h"
19
20 namespace webrtc {
21
22 namespace {
23
24 // A DesktopFrame implementation which stores data in an external int array.
25 class ArrayDesktopFrame : public DesktopFrame {
26 public:
27 ArrayDesktopFrame(DesktopSize size, uint32_t* data);
28 ~ArrayDesktopFrame() override;
29 };
30
ArrayDesktopFrame(DesktopSize size,uint32_t * data)31 ArrayDesktopFrame::ArrayDesktopFrame(DesktopSize size, uint32_t* data)
32 : DesktopFrame(size,
33 size.width() * kBytesPerPixel,
34 reinterpret_cast<uint8_t*>(data),
35 nullptr) {}
36
37 ArrayDesktopFrame::~ArrayDesktopFrame() = default;
38
39 } // namespace
40
TEST(DesktopFrameRotationTest,CopyRect3x4)41 TEST(DesktopFrameRotationTest, CopyRect3x4) {
42 // A DesktopFrame of 4-pixel width by 3-pixel height.
43 static uint32_t frame_pixels[] = {
44 0, 1, 2, 3, //
45 4, 5, 6, 7, //
46 8, 9, 10, 11, //
47 };
48 ArrayDesktopFrame frame(DesktopSize(4, 3), frame_pixels);
49
50 {
51 BasicDesktopFrame target(DesktopSize(4, 3));
52 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
53 Rotation::CLOCK_WISE_0, DesktopVector(), &target);
54 ASSERT_TRUE(DesktopFrameDataEquals(frame, target));
55 }
56
57 // After Rotating clock-wise 90 degree
58 {
59 static uint32_t expected_pixels[] = {
60 8, 4, 0, //
61 9, 5, 1, //
62 10, 6, 2, //
63 11, 7, 3, //
64 };
65 ArrayDesktopFrame expected(DesktopSize(3, 4), expected_pixels);
66
67 BasicDesktopFrame target(DesktopSize(3, 4));
68 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
69 Rotation::CLOCK_WISE_90, DesktopVector(), &target);
70 ASSERT_TRUE(DesktopFrameDataEquals(target, expected));
71 }
72
73 // After Rotating clock-wise 180 degree
74 {
75 static uint32_t expected_pixels[] = {
76 11, 10, 9, 8, //
77 7, 6, 5, 4, //
78 3, 2, 1, 0, //
79 };
80 ArrayDesktopFrame expected(DesktopSize(4, 3), expected_pixels);
81
82 BasicDesktopFrame target(DesktopSize(4, 3));
83 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
84 Rotation::CLOCK_WISE_180, DesktopVector(), &target);
85 ASSERT_TRUE(DesktopFrameDataEquals(target, expected));
86 }
87
88 // After Rotating clock-wise 270 degree
89 {
90 static uint32_t expected_pixels[] = {
91 3, 7, 11, //
92 2, 6, 10, //
93 1, 5, 9, //
94 0, 4, 8, //
95 };
96 ArrayDesktopFrame expected(DesktopSize(3, 4), expected_pixels);
97
98 BasicDesktopFrame target(DesktopSize(3, 4));
99 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
100 Rotation::CLOCK_WISE_270, DesktopVector(), &target);
101 ASSERT_TRUE(DesktopFrameDataEquals(target, expected));
102 }
103 }
104
TEST(DesktopFrameRotationTest,CopyRect3x5)105 TEST(DesktopFrameRotationTest, CopyRect3x5) {
106 // A DesktopFrame of 5-pixel width by 3-pixel height.
107 static uint32_t frame_pixels[] = {
108 0, 1, 2, 3, 4, //
109 5, 6, 7, 8, 9, //
110 10, 11, 12, 13, 14, //
111 };
112 ArrayDesktopFrame frame(DesktopSize(5, 3), frame_pixels);
113
114 {
115 BasicDesktopFrame target(DesktopSize(5, 3));
116 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
117 Rotation::CLOCK_WISE_0, DesktopVector(), &target);
118 ASSERT_TRUE(DesktopFrameDataEquals(target, frame));
119 }
120
121 // After Rotating clock-wise 90 degree
122 {
123 static uint32_t expected_pixels[] = {
124 10, 5, 0, //
125 11, 6, 1, //
126 12, 7, 2, //
127 13, 8, 3, //
128 14, 9, 4, //
129 };
130 ArrayDesktopFrame expected(DesktopSize(3, 5), expected_pixels);
131
132 BasicDesktopFrame target(DesktopSize(3, 5));
133 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
134 Rotation::CLOCK_WISE_90, DesktopVector(), &target);
135 ASSERT_TRUE(DesktopFrameDataEquals(target, expected));
136 }
137
138 // After Rotating clock-wise 180 degree
139 {
140 static uint32_t expected_pixels[]{
141 14, 13, 12, 11, 10, //
142 9, 8, 7, 6, 5, //
143 4, 3, 2, 1, 0, //
144 };
145 ArrayDesktopFrame expected(DesktopSize(5, 3), expected_pixels);
146
147 BasicDesktopFrame target(DesktopSize(5, 3));
148 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
149 Rotation::CLOCK_WISE_180, DesktopVector(), &target);
150 ASSERT_TRUE(DesktopFrameDataEquals(target, expected));
151 }
152
153 // After Rotating clock-wise 270 degree
154 {
155 static uint32_t expected_pixels[] = {
156 4, 9, 14, //
157 3, 8, 13, //
158 2, 7, 12, //
159 1, 6, 11, //
160 0, 5, 10, //
161 };
162 ArrayDesktopFrame expected(DesktopSize(3, 5), expected_pixels);
163
164 BasicDesktopFrame target(DesktopSize(3, 5));
165 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
166 Rotation::CLOCK_WISE_270, DesktopVector(), &target);
167 ASSERT_TRUE(DesktopFrameDataEquals(target, expected));
168 }
169 }
170
TEST(DesktopFrameRotationTest,PartialCopyRect3x5)171 TEST(DesktopFrameRotationTest, PartialCopyRect3x5) {
172 // A DesktopFrame of 5-pixel width by 3-pixel height.
173 static uint32_t frame_pixels[] = {
174 0, 1, 2, 3, 4, //
175 5, 6, 7, 8, 9, //
176 10, 11, 12, 13, 14, //
177 };
178 ArrayDesktopFrame frame(DesktopSize(5, 3), frame_pixels);
179
180 {
181 static uint32_t expected_pixels[] = {
182 0, 0, 0, 0, 0, //
183 0, 6, 7, 8, 0, //
184 0, 0, 0, 0, 0, //
185 };
186 ArrayDesktopFrame expected(DesktopSize(5, 3), expected_pixels);
187
188 BasicDesktopFrame target(DesktopSize(5, 3));
189 ClearDesktopFrame(&target);
190 RotateDesktopFrame(frame, DesktopRect::MakeXYWH(1, 1, 3, 1),
191 Rotation::CLOCK_WISE_0, DesktopVector(), &target);
192 ASSERT_TRUE(DesktopFrameDataEquals(target, expected));
193 }
194
195 {
196 static uint32_t expected_pixels[] = {
197 0, 1, 2, 3, 0, //
198 0, 6, 7, 8, 0, //
199 0, 0, 0, 0, 0, //
200 };
201 ArrayDesktopFrame expected(DesktopSize(5, 3), expected_pixels);
202
203 BasicDesktopFrame target(DesktopSize(5, 3));
204 ClearDesktopFrame(&target);
205 RotateDesktopFrame(frame, DesktopRect::MakeXYWH(1, 0, 3, 2),
206 Rotation::CLOCK_WISE_0, DesktopVector(), &target);
207 ASSERT_TRUE(DesktopFrameDataEquals(target, expected));
208 }
209
210 // After Rotating clock-wise 90 degree
211 {
212 static uint32_t expected_pixels[] = {
213 0, 0, 0, //
214 0, 6, 0, //
215 0, 7, 0, //
216 0, 8, 0, //
217 0, 0, 0, //
218 };
219 ArrayDesktopFrame expected(DesktopSize(3, 5), expected_pixels);
220
221 BasicDesktopFrame target(DesktopSize(3, 5));
222 ClearDesktopFrame(&target);
223 RotateDesktopFrame(frame, DesktopRect::MakeXYWH(1, 1, 3, 1),
224 Rotation::CLOCK_WISE_90, DesktopVector(), &target);
225 ASSERT_TRUE(DesktopFrameDataEquals(target, expected));
226 }
227
228 {
229 static uint32_t expected_pixels[] = {
230 0, 0, 0, //
231 11, 6, 0, //
232 12, 7, 0, //
233 13, 8, 0, //
234 0, 0, 0, //
235 };
236 ArrayDesktopFrame expected(DesktopSize(3, 5), expected_pixels);
237
238 BasicDesktopFrame target(DesktopSize(3, 5));
239 ClearDesktopFrame(&target);
240 RotateDesktopFrame(frame, DesktopRect::MakeXYWH(1, 1, 3, 2),
241 Rotation::CLOCK_WISE_90, DesktopVector(), &target);
242 ASSERT_TRUE(DesktopFrameDataEquals(target, expected));
243 }
244
245 // After Rotating clock-wise 180 degree
246 {
247 static uint32_t expected_pixels[] = {
248 0, 0, 0, 0, 0, //
249 0, 8, 7, 6, 0, //
250 0, 0, 0, 0, 0, //
251 };
252 ArrayDesktopFrame expected(DesktopSize(5, 3), expected_pixels);
253
254 BasicDesktopFrame target(DesktopSize(5, 3));
255 ClearDesktopFrame(&target);
256 RotateDesktopFrame(frame, DesktopRect::MakeXYWH(1, 1, 3, 1),
257 Rotation::CLOCK_WISE_180, DesktopVector(), &target);
258 ASSERT_TRUE(DesktopFrameDataEquals(target, expected));
259 }
260
261 {
262 static uint32_t expected_pixels[] = {
263 0, 13, 12, 11, 0, //
264 0, 8, 7, 6, 0, //
265 0, 0, 0, 0, 0, //
266 };
267 ArrayDesktopFrame expected(DesktopSize(5, 3), expected_pixels);
268
269 BasicDesktopFrame target(DesktopSize(5, 3));
270 ClearDesktopFrame(&target);
271 RotateDesktopFrame(frame, DesktopRect::MakeXYWH(1, 1, 3, 2),
272 Rotation::CLOCK_WISE_180, DesktopVector(), &target);
273 ASSERT_TRUE(DesktopFrameDataEquals(target, expected));
274 }
275
276 // After Rotating clock-wise 270 degree
277 {
278 static uint32_t expected_pixels[] = {
279 0, 0, 0, //
280 0, 8, 0, //
281 0, 7, 0, //
282 0, 6, 0, //
283 0, 0, 0, //
284 };
285 ArrayDesktopFrame expected(DesktopSize(3, 5), expected_pixels);
286
287 BasicDesktopFrame target(DesktopSize(3, 5));
288 ClearDesktopFrame(&target);
289 RotateDesktopFrame(frame, DesktopRect::MakeXYWH(1, 1, 3, 1),
290 Rotation::CLOCK_WISE_270, DesktopVector(), &target);
291 ASSERT_TRUE(DesktopFrameDataEquals(target, expected));
292 }
293
294 {
295 static uint32_t expected_pixels[] = {
296 0, 0, 0, //
297 3, 8, 0, //
298 2, 7, 0, //
299 1, 6, 0, //
300 0, 0, 0, //
301 };
302 ArrayDesktopFrame expected(DesktopSize(3, 5), expected_pixels);
303
304 BasicDesktopFrame target(DesktopSize(3, 5));
305 ClearDesktopFrame(&target);
306 RotateDesktopFrame(frame, DesktopRect::MakeXYWH(1, 0, 3, 2),
307 Rotation::CLOCK_WISE_270, DesktopVector(), &target);
308 ASSERT_TRUE(DesktopFrameDataEquals(target, expected));
309 }
310 }
311
TEST(DesktopFrameRotationTest,WithOffset)312 TEST(DesktopFrameRotationTest, WithOffset) {
313 // A DesktopFrame of 4-pixel width by 3-pixel height.
314 static uint32_t frame_pixels[] = {
315 0, 1, 2, 3, //
316 4, 5, 6, 7, //
317 8, 9, 10, 11, //
318 };
319 ArrayDesktopFrame frame(DesktopSize(4, 3), frame_pixels);
320
321 {
322 static uint32_t expected_pixels[] = {
323 0, 0, 0, 0, 0, 0, 0, 0, //
324 0, 0, 1, 2, 3, 0, 0, 0, //
325 0, 4, 5, 6, 7, 0, 0, 0, //
326 0, 8, 9, 10, 11, 0, 0, 0, //
327 0, 0, 0, 0, 0, 0, 0, 0, //
328 0, 0, 0, 0, 0, 0, 0, 0, //
329 };
330 ArrayDesktopFrame expected(DesktopSize(8, 6), expected_pixels);
331
332 BasicDesktopFrame target(DesktopSize(8, 6));
333 ClearDesktopFrame(&target);
334 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
335 Rotation::CLOCK_WISE_0, DesktopVector(1, 1), &target);
336 ASSERT_TRUE(DesktopFrameDataEquals(target, expected));
337 target.mutable_updated_region()->Subtract(
338 DesktopRect::MakeOriginSize(DesktopVector(1, 1), frame.size()));
339 ASSERT_TRUE(target.updated_region().is_empty());
340 }
341
342 {
343 static uint32_t expected_pixels[] = {
344 0, 0, 0, 0, 0, 0, 0, 0, //
345 0, 11, 10, 9, 8, 0, 0, 0, //
346 0, 7, 6, 5, 4, 0, 0, 0, //
347 0, 3, 2, 1, 0, 0, 0, 0, //
348 0, 0, 0, 0, 0, 0, 0, 0, //
349 0, 0, 0, 0, 0, 0, 0, 0, //
350 };
351 ArrayDesktopFrame expected(DesktopSize(8, 6), expected_pixels);
352
353 BasicDesktopFrame target(DesktopSize(8, 6));
354 ClearDesktopFrame(&target);
355 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
356 Rotation::CLOCK_WISE_180, DesktopVector(1, 1), &target);
357 ASSERT_TRUE(DesktopFrameDataEquals(target, expected));
358 target.mutable_updated_region()->Subtract(
359 DesktopRect::MakeOriginSize(DesktopVector(1, 1), frame.size()));
360 ASSERT_TRUE(target.updated_region().is_empty());
361 }
362
363 {
364 static uint32_t expected_pixels[] = {
365 0, 0, 0, 0, 0, 0, //
366 0, 8, 4, 0, 0, 0, //
367 0, 9, 5, 1, 0, 0, //
368 0, 10, 6, 2, 0, 0, //
369 0, 11, 7, 3, 0, 0, //
370 0, 0, 0, 0, 0, 0, //
371 0, 0, 0, 0, 0, 0, //
372 0, 0, 0, 0, 0, 0, //
373 };
374 ArrayDesktopFrame expected(DesktopSize(6, 8), expected_pixels);
375
376 BasicDesktopFrame target(DesktopSize(6, 8));
377 ClearDesktopFrame(&target);
378 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
379 Rotation::CLOCK_WISE_90, DesktopVector(1, 1), &target);
380 ASSERT_TRUE(DesktopFrameDataEquals(target, expected));
381 target.mutable_updated_region()->Subtract(
382 DesktopRect::MakeXYWH(1, 1, 3, 4));
383 ASSERT_TRUE(target.updated_region().is_empty());
384 }
385
386 {
387 static uint32_t expected_pixels[] = {
388 0, 0, 0, 0, 0, 0, //
389 0, 3, 7, 11, 0, 0, //
390 0, 2, 6, 10, 0, 0, //
391 0, 1, 5, 9, 0, 0, //
392 0, 0, 4, 8, 0, 0, //
393 0, 0, 0, 0, 0, 0, //
394 0, 0, 0, 0, 0, 0, //
395 0, 0, 0, 0, 0, 0, //
396 };
397 ArrayDesktopFrame expected(DesktopSize(6, 8), expected_pixels);
398
399 BasicDesktopFrame target(DesktopSize(6, 8));
400 ClearDesktopFrame(&target);
401 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
402 Rotation::CLOCK_WISE_270, DesktopVector(1, 1), &target);
403 ASSERT_TRUE(DesktopFrameDataEquals(target, expected));
404 target.mutable_updated_region()->Subtract(
405 DesktopRect::MakeXYWH(1, 1, 3, 4));
406 ASSERT_TRUE(target.updated_region().is_empty());
407 }
408 }
409
410 // On a typical machine (Intel(R) Xeon(R) E5-1650 v3 @ 3.50GHz, with O2
411 // optimization, the following case uses ~1.4s to finish. It means entirely
412 // rotating one 2048 x 1536 frame, which is a large enough number to cover most
413 // of desktop computer users, uses around 14ms.
TEST(DesktopFrameRotationTest,DISABLED_PerformanceTest)414 TEST(DesktopFrameRotationTest, DISABLED_PerformanceTest) {
415 BasicDesktopFrame frame(DesktopSize(2048, 1536));
416 BasicDesktopFrame target(DesktopSize(1536, 2048));
417 BasicDesktopFrame target2(DesktopSize(2048, 1536));
418 for (int i = 0; i < 100; i++) {
419 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
420 Rotation::CLOCK_WISE_90, DesktopVector(), &target);
421 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
422 Rotation::CLOCK_WISE_270, DesktopVector(), &target);
423 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
424 Rotation::CLOCK_WISE_0, DesktopVector(), &target2);
425 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
426 Rotation::CLOCK_WISE_180, DesktopVector(), &target2);
427 }
428 }
429
430 // On a typical machine (Intel(R) Xeon(R) E5-1650 v3 @ 3.50GHz, with O2
431 // optimization, the following case uses ~6.7s to finish. It means entirely
432 // rotating one 4096 x 3072 frame uses around 67ms.
TEST(DesktopFrameRotationTest,DISABLED_PerformanceTestOnLargeScreen)433 TEST(DesktopFrameRotationTest, DISABLED_PerformanceTestOnLargeScreen) {
434 BasicDesktopFrame frame(DesktopSize(4096, 3072));
435 BasicDesktopFrame target(DesktopSize(3072, 4096));
436 BasicDesktopFrame target2(DesktopSize(4096, 3072));
437 for (int i = 0; i < 100; i++) {
438 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
439 Rotation::CLOCK_WISE_90, DesktopVector(), &target);
440 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
441 Rotation::CLOCK_WISE_270, DesktopVector(), &target);
442 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
443 Rotation::CLOCK_WISE_0, DesktopVector(), &target2);
444 RotateDesktopFrame(frame, DesktopRect::MakeSize(frame.size()),
445 Rotation::CLOCK_WISE_180, DesktopVector(), &target2);
446 }
447 }
448
449 } // namespace webrtc
450