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