xref: /aosp_15_r20/external/libvpx/third_party/libyuv/source/rotate.cc (revision fb1b10ab9aebc7c7068eedab379b749d7e3900be)
1*fb1b10abSAndroid Build Coastguard Worker /*
2*fb1b10abSAndroid Build Coastguard Worker  *  Copyright 2011 The LibYuv Project Authors. All rights reserved.
3*fb1b10abSAndroid Build Coastguard Worker  *
4*fb1b10abSAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*fb1b10abSAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*fb1b10abSAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*fb1b10abSAndroid Build Coastguard Worker  *  in the file PATENTS. All contributing project authors may
8*fb1b10abSAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*fb1b10abSAndroid Build Coastguard Worker  */
10*fb1b10abSAndroid Build Coastguard Worker 
11*fb1b10abSAndroid Build Coastguard Worker #include "libyuv/rotate.h"
12*fb1b10abSAndroid Build Coastguard Worker 
13*fb1b10abSAndroid Build Coastguard Worker #include "libyuv/convert.h"
14*fb1b10abSAndroid Build Coastguard Worker #include "libyuv/cpu_id.h"
15*fb1b10abSAndroid Build Coastguard Worker #include "libyuv/planar_functions.h"
16*fb1b10abSAndroid Build Coastguard Worker #include "libyuv/rotate_row.h"
17*fb1b10abSAndroid Build Coastguard Worker #include "libyuv/row.h"
18*fb1b10abSAndroid Build Coastguard Worker 
19*fb1b10abSAndroid Build Coastguard Worker #ifdef __cplusplus
20*fb1b10abSAndroid Build Coastguard Worker namespace libyuv {
21*fb1b10abSAndroid Build Coastguard Worker extern "C" {
22*fb1b10abSAndroid Build Coastguard Worker #endif
23*fb1b10abSAndroid Build Coastguard Worker 
24*fb1b10abSAndroid Build Coastguard Worker LIBYUV_API
TransposePlane(const uint8_t * src,int src_stride,uint8_t * dst,int dst_stride,int width,int height)25*fb1b10abSAndroid Build Coastguard Worker void TransposePlane(const uint8_t* src,
26*fb1b10abSAndroid Build Coastguard Worker                     int src_stride,
27*fb1b10abSAndroid Build Coastguard Worker                     uint8_t* dst,
28*fb1b10abSAndroid Build Coastguard Worker                     int dst_stride,
29*fb1b10abSAndroid Build Coastguard Worker                     int width,
30*fb1b10abSAndroid Build Coastguard Worker                     int height) {
31*fb1b10abSAndroid Build Coastguard Worker   int i = height;
32*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_TRANSPOSEWX16_MSA)
33*fb1b10abSAndroid Build Coastguard Worker   void (*TransposeWx16)(const uint8_t* src, int src_stride, uint8_t* dst,
34*fb1b10abSAndroid Build Coastguard Worker                         int dst_stride, int width) = TransposeWx16_C;
35*fb1b10abSAndroid Build Coastguard Worker #else
36*fb1b10abSAndroid Build Coastguard Worker   void (*TransposeWx8)(const uint8_t* src, int src_stride, uint8_t* dst,
37*fb1b10abSAndroid Build Coastguard Worker                        int dst_stride, int width) = TransposeWx8_C;
38*fb1b10abSAndroid Build Coastguard Worker #endif
39*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_TRANSPOSEWX8_NEON)
40*fb1b10abSAndroid Build Coastguard Worker   if (TestCpuFlag(kCpuHasNEON)) {
41*fb1b10abSAndroid Build Coastguard Worker     TransposeWx8 = TransposeWx8_NEON;
42*fb1b10abSAndroid Build Coastguard Worker   }
43*fb1b10abSAndroid Build Coastguard Worker #endif
44*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_TRANSPOSEWX8_SSSE3)
45*fb1b10abSAndroid Build Coastguard Worker   if (TestCpuFlag(kCpuHasSSSE3)) {
46*fb1b10abSAndroid Build Coastguard Worker     TransposeWx8 = TransposeWx8_Any_SSSE3;
47*fb1b10abSAndroid Build Coastguard Worker     if (IS_ALIGNED(width, 8)) {
48*fb1b10abSAndroid Build Coastguard Worker       TransposeWx8 = TransposeWx8_SSSE3;
49*fb1b10abSAndroid Build Coastguard Worker     }
50*fb1b10abSAndroid Build Coastguard Worker   }
51*fb1b10abSAndroid Build Coastguard Worker #endif
52*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_TRANSPOSEWX8_FAST_SSSE3)
53*fb1b10abSAndroid Build Coastguard Worker   if (TestCpuFlag(kCpuHasSSSE3)) {
54*fb1b10abSAndroid Build Coastguard Worker     TransposeWx8 = TransposeWx8_Fast_Any_SSSE3;
55*fb1b10abSAndroid Build Coastguard Worker     if (IS_ALIGNED(width, 16)) {
56*fb1b10abSAndroid Build Coastguard Worker       TransposeWx8 = TransposeWx8_Fast_SSSE3;
57*fb1b10abSAndroid Build Coastguard Worker     }
58*fb1b10abSAndroid Build Coastguard Worker   }
59*fb1b10abSAndroid Build Coastguard Worker #endif
60*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_TRANSPOSEWX16_MSA)
61*fb1b10abSAndroid Build Coastguard Worker   if (TestCpuFlag(kCpuHasMSA)) {
62*fb1b10abSAndroid Build Coastguard Worker     TransposeWx16 = TransposeWx16_Any_MSA;
63*fb1b10abSAndroid Build Coastguard Worker     if (IS_ALIGNED(width, 16)) {
64*fb1b10abSAndroid Build Coastguard Worker       TransposeWx16 = TransposeWx16_MSA;
65*fb1b10abSAndroid Build Coastguard Worker     }
66*fb1b10abSAndroid Build Coastguard Worker   }
67*fb1b10abSAndroid Build Coastguard Worker #endif
68*fb1b10abSAndroid Build Coastguard Worker 
69*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_TRANSPOSEWX16_MSA)
70*fb1b10abSAndroid Build Coastguard Worker   // Work across the source in 16x16 tiles
71*fb1b10abSAndroid Build Coastguard Worker   while (i >= 16) {
72*fb1b10abSAndroid Build Coastguard Worker     TransposeWx16(src, src_stride, dst, dst_stride, width);
73*fb1b10abSAndroid Build Coastguard Worker     src += 16 * src_stride;  // Go down 16 rows.
74*fb1b10abSAndroid Build Coastguard Worker     dst += 16;               // Move over 16 columns.
75*fb1b10abSAndroid Build Coastguard Worker     i -= 16;
76*fb1b10abSAndroid Build Coastguard Worker   }
77*fb1b10abSAndroid Build Coastguard Worker #else
78*fb1b10abSAndroid Build Coastguard Worker   // Work across the source in 8x8 tiles
79*fb1b10abSAndroid Build Coastguard Worker   while (i >= 8) {
80*fb1b10abSAndroid Build Coastguard Worker     TransposeWx8(src, src_stride, dst, dst_stride, width);
81*fb1b10abSAndroid Build Coastguard Worker     src += 8 * src_stride;  // Go down 8 rows.
82*fb1b10abSAndroid Build Coastguard Worker     dst += 8;               // Move over 8 columns.
83*fb1b10abSAndroid Build Coastguard Worker     i -= 8;
84*fb1b10abSAndroid Build Coastguard Worker   }
85*fb1b10abSAndroid Build Coastguard Worker #endif
86*fb1b10abSAndroid Build Coastguard Worker 
87*fb1b10abSAndroid Build Coastguard Worker   if (i > 0) {
88*fb1b10abSAndroid Build Coastguard Worker     TransposeWxH_C(src, src_stride, dst, dst_stride, width, i);
89*fb1b10abSAndroid Build Coastguard Worker   }
90*fb1b10abSAndroid Build Coastguard Worker }
91*fb1b10abSAndroid Build Coastguard Worker 
92*fb1b10abSAndroid Build Coastguard Worker LIBYUV_API
RotatePlane90(const uint8_t * src,int src_stride,uint8_t * dst,int dst_stride,int width,int height)93*fb1b10abSAndroid Build Coastguard Worker void RotatePlane90(const uint8_t* src,
94*fb1b10abSAndroid Build Coastguard Worker                    int src_stride,
95*fb1b10abSAndroid Build Coastguard Worker                    uint8_t* dst,
96*fb1b10abSAndroid Build Coastguard Worker                    int dst_stride,
97*fb1b10abSAndroid Build Coastguard Worker                    int width,
98*fb1b10abSAndroid Build Coastguard Worker                    int height) {
99*fb1b10abSAndroid Build Coastguard Worker   // Rotate by 90 is a transpose with the source read
100*fb1b10abSAndroid Build Coastguard Worker   // from bottom to top. So set the source pointer to the end
101*fb1b10abSAndroid Build Coastguard Worker   // of the buffer and flip the sign of the source stride.
102*fb1b10abSAndroid Build Coastguard Worker   src += src_stride * (height - 1);
103*fb1b10abSAndroid Build Coastguard Worker   src_stride = -src_stride;
104*fb1b10abSAndroid Build Coastguard Worker   TransposePlane(src, src_stride, dst, dst_stride, width, height);
105*fb1b10abSAndroid Build Coastguard Worker }
106*fb1b10abSAndroid Build Coastguard Worker 
107*fb1b10abSAndroid Build Coastguard Worker LIBYUV_API
RotatePlane270(const uint8_t * src,int src_stride,uint8_t * dst,int dst_stride,int width,int height)108*fb1b10abSAndroid Build Coastguard Worker void RotatePlane270(const uint8_t* src,
109*fb1b10abSAndroid Build Coastguard Worker                     int src_stride,
110*fb1b10abSAndroid Build Coastguard Worker                     uint8_t* dst,
111*fb1b10abSAndroid Build Coastguard Worker                     int dst_stride,
112*fb1b10abSAndroid Build Coastguard Worker                     int width,
113*fb1b10abSAndroid Build Coastguard Worker                     int height) {
114*fb1b10abSAndroid Build Coastguard Worker   // Rotate by 270 is a transpose with the destination written
115*fb1b10abSAndroid Build Coastguard Worker   // from bottom to top. So set the destination pointer to the end
116*fb1b10abSAndroid Build Coastguard Worker   // of the buffer and flip the sign of the destination stride.
117*fb1b10abSAndroid Build Coastguard Worker   dst += dst_stride * (width - 1);
118*fb1b10abSAndroid Build Coastguard Worker   dst_stride = -dst_stride;
119*fb1b10abSAndroid Build Coastguard Worker   TransposePlane(src, src_stride, dst, dst_stride, width, height);
120*fb1b10abSAndroid Build Coastguard Worker }
121*fb1b10abSAndroid Build Coastguard Worker 
122*fb1b10abSAndroid Build Coastguard Worker LIBYUV_API
RotatePlane180(const uint8_t * src,int src_stride,uint8_t * dst,int dst_stride,int width,int height)123*fb1b10abSAndroid Build Coastguard Worker void RotatePlane180(const uint8_t* src,
124*fb1b10abSAndroid Build Coastguard Worker                     int src_stride,
125*fb1b10abSAndroid Build Coastguard Worker                     uint8_t* dst,
126*fb1b10abSAndroid Build Coastguard Worker                     int dst_stride,
127*fb1b10abSAndroid Build Coastguard Worker                     int width,
128*fb1b10abSAndroid Build Coastguard Worker                     int height) {
129*fb1b10abSAndroid Build Coastguard Worker   // Swap first and last row and mirror the content. Uses a temporary row.
130*fb1b10abSAndroid Build Coastguard Worker   align_buffer_64(row, width);
131*fb1b10abSAndroid Build Coastguard Worker   const uint8_t* src_bot = src + src_stride * (height - 1);
132*fb1b10abSAndroid Build Coastguard Worker   uint8_t* dst_bot = dst + dst_stride * (height - 1);
133*fb1b10abSAndroid Build Coastguard Worker   int half_height = (height + 1) >> 1;
134*fb1b10abSAndroid Build Coastguard Worker   int y;
135*fb1b10abSAndroid Build Coastguard Worker   void (*MirrorRow)(const uint8_t* src, uint8_t* dst, int width) = MirrorRow_C;
136*fb1b10abSAndroid Build Coastguard Worker   void (*CopyRow)(const uint8_t* src, uint8_t* dst, int width) = CopyRow_C;
137*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_MIRRORROW_NEON)
138*fb1b10abSAndroid Build Coastguard Worker   if (TestCpuFlag(kCpuHasNEON)) {
139*fb1b10abSAndroid Build Coastguard Worker     MirrorRow = MirrorRow_Any_NEON;
140*fb1b10abSAndroid Build Coastguard Worker     if (IS_ALIGNED(width, 16)) {
141*fb1b10abSAndroid Build Coastguard Worker       MirrorRow = MirrorRow_NEON;
142*fb1b10abSAndroid Build Coastguard Worker     }
143*fb1b10abSAndroid Build Coastguard Worker   }
144*fb1b10abSAndroid Build Coastguard Worker #endif
145*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_MIRRORROW_SSSE3)
146*fb1b10abSAndroid Build Coastguard Worker   if (TestCpuFlag(kCpuHasSSSE3)) {
147*fb1b10abSAndroid Build Coastguard Worker     MirrorRow = MirrorRow_Any_SSSE3;
148*fb1b10abSAndroid Build Coastguard Worker     if (IS_ALIGNED(width, 16)) {
149*fb1b10abSAndroid Build Coastguard Worker       MirrorRow = MirrorRow_SSSE3;
150*fb1b10abSAndroid Build Coastguard Worker     }
151*fb1b10abSAndroid Build Coastguard Worker   }
152*fb1b10abSAndroid Build Coastguard Worker #endif
153*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_MIRRORROW_AVX2)
154*fb1b10abSAndroid Build Coastguard Worker   if (TestCpuFlag(kCpuHasAVX2)) {
155*fb1b10abSAndroid Build Coastguard Worker     MirrorRow = MirrorRow_Any_AVX2;
156*fb1b10abSAndroid Build Coastguard Worker     if (IS_ALIGNED(width, 32)) {
157*fb1b10abSAndroid Build Coastguard Worker       MirrorRow = MirrorRow_AVX2;
158*fb1b10abSAndroid Build Coastguard Worker     }
159*fb1b10abSAndroid Build Coastguard Worker   }
160*fb1b10abSAndroid Build Coastguard Worker #endif
161*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_MIRRORROW_MSA)
162*fb1b10abSAndroid Build Coastguard Worker   if (TestCpuFlag(kCpuHasMSA)) {
163*fb1b10abSAndroid Build Coastguard Worker     MirrorRow = MirrorRow_Any_MSA;
164*fb1b10abSAndroid Build Coastguard Worker     if (IS_ALIGNED(width, 64)) {
165*fb1b10abSAndroid Build Coastguard Worker       MirrorRow = MirrorRow_MSA;
166*fb1b10abSAndroid Build Coastguard Worker     }
167*fb1b10abSAndroid Build Coastguard Worker   }
168*fb1b10abSAndroid Build Coastguard Worker #endif
169*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_COPYROW_SSE2)
170*fb1b10abSAndroid Build Coastguard Worker   if (TestCpuFlag(kCpuHasSSE2)) {
171*fb1b10abSAndroid Build Coastguard Worker     CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2;
172*fb1b10abSAndroid Build Coastguard Worker   }
173*fb1b10abSAndroid Build Coastguard Worker #endif
174*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_COPYROW_AVX)
175*fb1b10abSAndroid Build Coastguard Worker   if (TestCpuFlag(kCpuHasAVX)) {
176*fb1b10abSAndroid Build Coastguard Worker     CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
177*fb1b10abSAndroid Build Coastguard Worker   }
178*fb1b10abSAndroid Build Coastguard Worker #endif
179*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_COPYROW_ERMS)
180*fb1b10abSAndroid Build Coastguard Worker   if (TestCpuFlag(kCpuHasERMS)) {
181*fb1b10abSAndroid Build Coastguard Worker     CopyRow = CopyRow_ERMS;
182*fb1b10abSAndroid Build Coastguard Worker   }
183*fb1b10abSAndroid Build Coastguard Worker #endif
184*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_COPYROW_NEON)
185*fb1b10abSAndroid Build Coastguard Worker   if (TestCpuFlag(kCpuHasNEON)) {
186*fb1b10abSAndroid Build Coastguard Worker     CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
187*fb1b10abSAndroid Build Coastguard Worker   }
188*fb1b10abSAndroid Build Coastguard Worker #endif
189*fb1b10abSAndroid Build Coastguard Worker 
190*fb1b10abSAndroid Build Coastguard Worker   // Odd height will harmlessly mirror the middle row twice.
191*fb1b10abSAndroid Build Coastguard Worker   for (y = 0; y < half_height; ++y) {
192*fb1b10abSAndroid Build Coastguard Worker     MirrorRow(src, row, width);  // Mirror first row into a buffer
193*fb1b10abSAndroid Build Coastguard Worker     src += src_stride;
194*fb1b10abSAndroid Build Coastguard Worker     MirrorRow(src_bot, dst, width);  // Mirror last row into first row
195*fb1b10abSAndroid Build Coastguard Worker     dst += dst_stride;
196*fb1b10abSAndroid Build Coastguard Worker     CopyRow(row, dst_bot, width);  // Copy first mirrored row into last
197*fb1b10abSAndroid Build Coastguard Worker     src_bot -= src_stride;
198*fb1b10abSAndroid Build Coastguard Worker     dst_bot -= dst_stride;
199*fb1b10abSAndroid Build Coastguard Worker   }
200*fb1b10abSAndroid Build Coastguard Worker   free_aligned_buffer_64(row);
201*fb1b10abSAndroid Build Coastguard Worker }
202*fb1b10abSAndroid Build Coastguard Worker 
203*fb1b10abSAndroid Build Coastguard Worker LIBYUV_API
TransposeUV(const uint8_t * src,int src_stride,uint8_t * dst_a,int dst_stride_a,uint8_t * dst_b,int dst_stride_b,int width,int height)204*fb1b10abSAndroid Build Coastguard Worker void TransposeUV(const uint8_t* src,
205*fb1b10abSAndroid Build Coastguard Worker                  int src_stride,
206*fb1b10abSAndroid Build Coastguard Worker                  uint8_t* dst_a,
207*fb1b10abSAndroid Build Coastguard Worker                  int dst_stride_a,
208*fb1b10abSAndroid Build Coastguard Worker                  uint8_t* dst_b,
209*fb1b10abSAndroid Build Coastguard Worker                  int dst_stride_b,
210*fb1b10abSAndroid Build Coastguard Worker                  int width,
211*fb1b10abSAndroid Build Coastguard Worker                  int height) {
212*fb1b10abSAndroid Build Coastguard Worker   int i = height;
213*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_TRANSPOSEUVWX16_MSA)
214*fb1b10abSAndroid Build Coastguard Worker   void (*TransposeUVWx16)(const uint8_t* src, int src_stride, uint8_t* dst_a,
215*fb1b10abSAndroid Build Coastguard Worker                           int dst_stride_a, uint8_t* dst_b, int dst_stride_b,
216*fb1b10abSAndroid Build Coastguard Worker                           int width) = TransposeUVWx16_C;
217*fb1b10abSAndroid Build Coastguard Worker #else
218*fb1b10abSAndroid Build Coastguard Worker   void (*TransposeUVWx8)(const uint8_t* src, int src_stride, uint8_t* dst_a,
219*fb1b10abSAndroid Build Coastguard Worker                          int dst_stride_a, uint8_t* dst_b, int dst_stride_b,
220*fb1b10abSAndroid Build Coastguard Worker                          int width) = TransposeUVWx8_C;
221*fb1b10abSAndroid Build Coastguard Worker #endif
222*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_TRANSPOSEUVWX8_NEON)
223*fb1b10abSAndroid Build Coastguard Worker   if (TestCpuFlag(kCpuHasNEON)) {
224*fb1b10abSAndroid Build Coastguard Worker     TransposeUVWx8 = TransposeUVWx8_NEON;
225*fb1b10abSAndroid Build Coastguard Worker   }
226*fb1b10abSAndroid Build Coastguard Worker #endif
227*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_TRANSPOSEUVWX8_SSE2)
228*fb1b10abSAndroid Build Coastguard Worker   if (TestCpuFlag(kCpuHasSSE2)) {
229*fb1b10abSAndroid Build Coastguard Worker     TransposeUVWx8 = TransposeUVWx8_Any_SSE2;
230*fb1b10abSAndroid Build Coastguard Worker     if (IS_ALIGNED(width, 8)) {
231*fb1b10abSAndroid Build Coastguard Worker       TransposeUVWx8 = TransposeUVWx8_SSE2;
232*fb1b10abSAndroid Build Coastguard Worker     }
233*fb1b10abSAndroid Build Coastguard Worker   }
234*fb1b10abSAndroid Build Coastguard Worker #endif
235*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_TRANSPOSEUVWX16_MSA)
236*fb1b10abSAndroid Build Coastguard Worker   if (TestCpuFlag(kCpuHasMSA)) {
237*fb1b10abSAndroid Build Coastguard Worker     TransposeUVWx16 = TransposeUVWx16_Any_MSA;
238*fb1b10abSAndroid Build Coastguard Worker     if (IS_ALIGNED(width, 8)) {
239*fb1b10abSAndroid Build Coastguard Worker       TransposeUVWx16 = TransposeUVWx16_MSA;
240*fb1b10abSAndroid Build Coastguard Worker     }
241*fb1b10abSAndroid Build Coastguard Worker   }
242*fb1b10abSAndroid Build Coastguard Worker #endif
243*fb1b10abSAndroid Build Coastguard Worker 
244*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_TRANSPOSEUVWX16_MSA)
245*fb1b10abSAndroid Build Coastguard Worker   // Work through the source in 8x8 tiles.
246*fb1b10abSAndroid Build Coastguard Worker   while (i >= 16) {
247*fb1b10abSAndroid Build Coastguard Worker     TransposeUVWx16(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
248*fb1b10abSAndroid Build Coastguard Worker                     width);
249*fb1b10abSAndroid Build Coastguard Worker     src += 16 * src_stride;  // Go down 16 rows.
250*fb1b10abSAndroid Build Coastguard Worker     dst_a += 16;             // Move over 8 columns.
251*fb1b10abSAndroid Build Coastguard Worker     dst_b += 16;             // Move over 8 columns.
252*fb1b10abSAndroid Build Coastguard Worker     i -= 16;
253*fb1b10abSAndroid Build Coastguard Worker   }
254*fb1b10abSAndroid Build Coastguard Worker #else
255*fb1b10abSAndroid Build Coastguard Worker   // Work through the source in 8x8 tiles.
256*fb1b10abSAndroid Build Coastguard Worker   while (i >= 8) {
257*fb1b10abSAndroid Build Coastguard Worker     TransposeUVWx8(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
258*fb1b10abSAndroid Build Coastguard Worker                    width);
259*fb1b10abSAndroid Build Coastguard Worker     src += 8 * src_stride;  // Go down 8 rows.
260*fb1b10abSAndroid Build Coastguard Worker     dst_a += 8;             // Move over 8 columns.
261*fb1b10abSAndroid Build Coastguard Worker     dst_b += 8;             // Move over 8 columns.
262*fb1b10abSAndroid Build Coastguard Worker     i -= 8;
263*fb1b10abSAndroid Build Coastguard Worker   }
264*fb1b10abSAndroid Build Coastguard Worker #endif
265*fb1b10abSAndroid Build Coastguard Worker 
266*fb1b10abSAndroid Build Coastguard Worker   if (i > 0) {
267*fb1b10abSAndroid Build Coastguard Worker     TransposeUVWxH_C(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b,
268*fb1b10abSAndroid Build Coastguard Worker                      width, i);
269*fb1b10abSAndroid Build Coastguard Worker   }
270*fb1b10abSAndroid Build Coastguard Worker }
271*fb1b10abSAndroid Build Coastguard Worker 
272*fb1b10abSAndroid Build Coastguard Worker LIBYUV_API
RotateUV90(const uint8_t * src,int src_stride,uint8_t * dst_a,int dst_stride_a,uint8_t * dst_b,int dst_stride_b,int width,int height)273*fb1b10abSAndroid Build Coastguard Worker void RotateUV90(const uint8_t* src,
274*fb1b10abSAndroid Build Coastguard Worker                 int src_stride,
275*fb1b10abSAndroid Build Coastguard Worker                 uint8_t* dst_a,
276*fb1b10abSAndroid Build Coastguard Worker                 int dst_stride_a,
277*fb1b10abSAndroid Build Coastguard Worker                 uint8_t* dst_b,
278*fb1b10abSAndroid Build Coastguard Worker                 int dst_stride_b,
279*fb1b10abSAndroid Build Coastguard Worker                 int width,
280*fb1b10abSAndroid Build Coastguard Worker                 int height) {
281*fb1b10abSAndroid Build Coastguard Worker   src += src_stride * (height - 1);
282*fb1b10abSAndroid Build Coastguard Worker   src_stride = -src_stride;
283*fb1b10abSAndroid Build Coastguard Worker 
284*fb1b10abSAndroid Build Coastguard Worker   TransposeUV(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b, width,
285*fb1b10abSAndroid Build Coastguard Worker               height);
286*fb1b10abSAndroid Build Coastguard Worker }
287*fb1b10abSAndroid Build Coastguard Worker 
288*fb1b10abSAndroid Build Coastguard Worker LIBYUV_API
RotateUV270(const uint8_t * src,int src_stride,uint8_t * dst_a,int dst_stride_a,uint8_t * dst_b,int dst_stride_b,int width,int height)289*fb1b10abSAndroid Build Coastguard Worker void RotateUV270(const uint8_t* src,
290*fb1b10abSAndroid Build Coastguard Worker                  int src_stride,
291*fb1b10abSAndroid Build Coastguard Worker                  uint8_t* dst_a,
292*fb1b10abSAndroid Build Coastguard Worker                  int dst_stride_a,
293*fb1b10abSAndroid Build Coastguard Worker                  uint8_t* dst_b,
294*fb1b10abSAndroid Build Coastguard Worker                  int dst_stride_b,
295*fb1b10abSAndroid Build Coastguard Worker                  int width,
296*fb1b10abSAndroid Build Coastguard Worker                  int height) {
297*fb1b10abSAndroid Build Coastguard Worker   dst_a += dst_stride_a * (width - 1);
298*fb1b10abSAndroid Build Coastguard Worker   dst_b += dst_stride_b * (width - 1);
299*fb1b10abSAndroid Build Coastguard Worker   dst_stride_a = -dst_stride_a;
300*fb1b10abSAndroid Build Coastguard Worker   dst_stride_b = -dst_stride_b;
301*fb1b10abSAndroid Build Coastguard Worker 
302*fb1b10abSAndroid Build Coastguard Worker   TransposeUV(src, src_stride, dst_a, dst_stride_a, dst_b, dst_stride_b, width,
303*fb1b10abSAndroid Build Coastguard Worker               height);
304*fb1b10abSAndroid Build Coastguard Worker }
305*fb1b10abSAndroid Build Coastguard Worker 
306*fb1b10abSAndroid Build Coastguard Worker // Rotate 180 is a horizontal and vertical flip.
307*fb1b10abSAndroid Build Coastguard Worker LIBYUV_API
RotateUV180(const uint8_t * src,int src_stride,uint8_t * dst_a,int dst_stride_a,uint8_t * dst_b,int dst_stride_b,int width,int height)308*fb1b10abSAndroid Build Coastguard Worker void RotateUV180(const uint8_t* src,
309*fb1b10abSAndroid Build Coastguard Worker                  int src_stride,
310*fb1b10abSAndroid Build Coastguard Worker                  uint8_t* dst_a,
311*fb1b10abSAndroid Build Coastguard Worker                  int dst_stride_a,
312*fb1b10abSAndroid Build Coastguard Worker                  uint8_t* dst_b,
313*fb1b10abSAndroid Build Coastguard Worker                  int dst_stride_b,
314*fb1b10abSAndroid Build Coastguard Worker                  int width,
315*fb1b10abSAndroid Build Coastguard Worker                  int height) {
316*fb1b10abSAndroid Build Coastguard Worker   int i;
317*fb1b10abSAndroid Build Coastguard Worker   void (*MirrorUVRow)(const uint8_t* src, uint8_t* dst_u, uint8_t* dst_v,
318*fb1b10abSAndroid Build Coastguard Worker                       int width) = MirrorUVRow_C;
319*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_MIRRORUVROW_NEON)
320*fb1b10abSAndroid Build Coastguard Worker   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
321*fb1b10abSAndroid Build Coastguard Worker     MirrorUVRow = MirrorUVRow_NEON;
322*fb1b10abSAndroid Build Coastguard Worker   }
323*fb1b10abSAndroid Build Coastguard Worker #endif
324*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_MIRRORUVROW_SSSE3)
325*fb1b10abSAndroid Build Coastguard Worker   if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 16)) {
326*fb1b10abSAndroid Build Coastguard Worker     MirrorUVRow = MirrorUVRow_SSSE3;
327*fb1b10abSAndroid Build Coastguard Worker   }
328*fb1b10abSAndroid Build Coastguard Worker #endif
329*fb1b10abSAndroid Build Coastguard Worker #if defined(HAS_MIRRORUVROW_MSA)
330*fb1b10abSAndroid Build Coastguard Worker   if (TestCpuFlag(kCpuHasMSA) && IS_ALIGNED(width, 32)) {
331*fb1b10abSAndroid Build Coastguard Worker     MirrorUVRow = MirrorUVRow_MSA;
332*fb1b10abSAndroid Build Coastguard Worker   }
333*fb1b10abSAndroid Build Coastguard Worker #endif
334*fb1b10abSAndroid Build Coastguard Worker 
335*fb1b10abSAndroid Build Coastguard Worker   dst_a += dst_stride_a * (height - 1);
336*fb1b10abSAndroid Build Coastguard Worker   dst_b += dst_stride_b * (height - 1);
337*fb1b10abSAndroid Build Coastguard Worker 
338*fb1b10abSAndroid Build Coastguard Worker   for (i = 0; i < height; ++i) {
339*fb1b10abSAndroid Build Coastguard Worker     MirrorUVRow(src, dst_a, dst_b, width);
340*fb1b10abSAndroid Build Coastguard Worker     src += src_stride;
341*fb1b10abSAndroid Build Coastguard Worker     dst_a -= dst_stride_a;
342*fb1b10abSAndroid Build Coastguard Worker     dst_b -= dst_stride_b;
343*fb1b10abSAndroid Build Coastguard Worker   }
344*fb1b10abSAndroid Build Coastguard Worker }
345*fb1b10abSAndroid Build Coastguard Worker 
346*fb1b10abSAndroid Build Coastguard Worker LIBYUV_API
RotatePlane(const uint8_t * src,int src_stride,uint8_t * dst,int dst_stride,int width,int height,enum RotationMode mode)347*fb1b10abSAndroid Build Coastguard Worker int RotatePlane(const uint8_t* src,
348*fb1b10abSAndroid Build Coastguard Worker                 int src_stride,
349*fb1b10abSAndroid Build Coastguard Worker                 uint8_t* dst,
350*fb1b10abSAndroid Build Coastguard Worker                 int dst_stride,
351*fb1b10abSAndroid Build Coastguard Worker                 int width,
352*fb1b10abSAndroid Build Coastguard Worker                 int height,
353*fb1b10abSAndroid Build Coastguard Worker                 enum RotationMode mode) {
354*fb1b10abSAndroid Build Coastguard Worker   if (!src || width <= 0 || height == 0 || !dst) {
355*fb1b10abSAndroid Build Coastguard Worker     return -1;
356*fb1b10abSAndroid Build Coastguard Worker   }
357*fb1b10abSAndroid Build Coastguard Worker 
358*fb1b10abSAndroid Build Coastguard Worker   // Negative height means invert the image.
359*fb1b10abSAndroid Build Coastguard Worker   if (height < 0) {
360*fb1b10abSAndroid Build Coastguard Worker     height = -height;
361*fb1b10abSAndroid Build Coastguard Worker     src = src + (height - 1) * src_stride;
362*fb1b10abSAndroid Build Coastguard Worker     src_stride = -src_stride;
363*fb1b10abSAndroid Build Coastguard Worker   }
364*fb1b10abSAndroid Build Coastguard Worker 
365*fb1b10abSAndroid Build Coastguard Worker   switch (mode) {
366*fb1b10abSAndroid Build Coastguard Worker     case kRotate0:
367*fb1b10abSAndroid Build Coastguard Worker       // copy frame
368*fb1b10abSAndroid Build Coastguard Worker       CopyPlane(src, src_stride, dst, dst_stride, width, height);
369*fb1b10abSAndroid Build Coastguard Worker       return 0;
370*fb1b10abSAndroid Build Coastguard Worker     case kRotate90:
371*fb1b10abSAndroid Build Coastguard Worker       RotatePlane90(src, src_stride, dst, dst_stride, width, height);
372*fb1b10abSAndroid Build Coastguard Worker       return 0;
373*fb1b10abSAndroid Build Coastguard Worker     case kRotate270:
374*fb1b10abSAndroid Build Coastguard Worker       RotatePlane270(src, src_stride, dst, dst_stride, width, height);
375*fb1b10abSAndroid Build Coastguard Worker       return 0;
376*fb1b10abSAndroid Build Coastguard Worker     case kRotate180:
377*fb1b10abSAndroid Build Coastguard Worker       RotatePlane180(src, src_stride, dst, dst_stride, width, height);
378*fb1b10abSAndroid Build Coastguard Worker       return 0;
379*fb1b10abSAndroid Build Coastguard Worker     default:
380*fb1b10abSAndroid Build Coastguard Worker       break;
381*fb1b10abSAndroid Build Coastguard Worker   }
382*fb1b10abSAndroid Build Coastguard Worker   return -1;
383*fb1b10abSAndroid Build Coastguard Worker }
384*fb1b10abSAndroid Build Coastguard Worker 
385*fb1b10abSAndroid Build Coastguard Worker LIBYUV_API
I420Rotate(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_u,int dst_stride_u,uint8_t * dst_v,int dst_stride_v,int width,int height,enum RotationMode mode)386*fb1b10abSAndroid Build Coastguard Worker int I420Rotate(const uint8_t* src_y,
387*fb1b10abSAndroid Build Coastguard Worker                int src_stride_y,
388*fb1b10abSAndroid Build Coastguard Worker                const uint8_t* src_u,
389*fb1b10abSAndroid Build Coastguard Worker                int src_stride_u,
390*fb1b10abSAndroid Build Coastguard Worker                const uint8_t* src_v,
391*fb1b10abSAndroid Build Coastguard Worker                int src_stride_v,
392*fb1b10abSAndroid Build Coastguard Worker                uint8_t* dst_y,
393*fb1b10abSAndroid Build Coastguard Worker                int dst_stride_y,
394*fb1b10abSAndroid Build Coastguard Worker                uint8_t* dst_u,
395*fb1b10abSAndroid Build Coastguard Worker                int dst_stride_u,
396*fb1b10abSAndroid Build Coastguard Worker                uint8_t* dst_v,
397*fb1b10abSAndroid Build Coastguard Worker                int dst_stride_v,
398*fb1b10abSAndroid Build Coastguard Worker                int width,
399*fb1b10abSAndroid Build Coastguard Worker                int height,
400*fb1b10abSAndroid Build Coastguard Worker                enum RotationMode mode) {
401*fb1b10abSAndroid Build Coastguard Worker   int halfwidth = (width + 1) >> 1;
402*fb1b10abSAndroid Build Coastguard Worker   int halfheight = (height + 1) >> 1;
403*fb1b10abSAndroid Build Coastguard Worker   if (!src_y || !src_u || !src_v || width <= 0 || height == 0 || !dst_y ||
404*fb1b10abSAndroid Build Coastguard Worker       !dst_u || !dst_v) {
405*fb1b10abSAndroid Build Coastguard Worker     return -1;
406*fb1b10abSAndroid Build Coastguard Worker   }
407*fb1b10abSAndroid Build Coastguard Worker 
408*fb1b10abSAndroid Build Coastguard Worker   // Negative height means invert the image.
409*fb1b10abSAndroid Build Coastguard Worker   if (height < 0) {
410*fb1b10abSAndroid Build Coastguard Worker     height = -height;
411*fb1b10abSAndroid Build Coastguard Worker     halfheight = (height + 1) >> 1;
412*fb1b10abSAndroid Build Coastguard Worker     src_y = src_y + (height - 1) * src_stride_y;
413*fb1b10abSAndroid Build Coastguard Worker     src_u = src_u + (halfheight - 1) * src_stride_u;
414*fb1b10abSAndroid Build Coastguard Worker     src_v = src_v + (halfheight - 1) * src_stride_v;
415*fb1b10abSAndroid Build Coastguard Worker     src_stride_y = -src_stride_y;
416*fb1b10abSAndroid Build Coastguard Worker     src_stride_u = -src_stride_u;
417*fb1b10abSAndroid Build Coastguard Worker     src_stride_v = -src_stride_v;
418*fb1b10abSAndroid Build Coastguard Worker   }
419*fb1b10abSAndroid Build Coastguard Worker 
420*fb1b10abSAndroid Build Coastguard Worker   switch (mode) {
421*fb1b10abSAndroid Build Coastguard Worker     case kRotate0:
422*fb1b10abSAndroid Build Coastguard Worker       // copy frame
423*fb1b10abSAndroid Build Coastguard Worker       return I420Copy(src_y, src_stride_y, src_u, src_stride_u, src_v,
424*fb1b10abSAndroid Build Coastguard Worker                       src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
425*fb1b10abSAndroid Build Coastguard Worker                       dst_v, dst_stride_v, width, height);
426*fb1b10abSAndroid Build Coastguard Worker     case kRotate90:
427*fb1b10abSAndroid Build Coastguard Worker       RotatePlane90(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
428*fb1b10abSAndroid Build Coastguard Worker       RotatePlane90(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
429*fb1b10abSAndroid Build Coastguard Worker                     halfheight);
430*fb1b10abSAndroid Build Coastguard Worker       RotatePlane90(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
431*fb1b10abSAndroid Build Coastguard Worker                     halfheight);
432*fb1b10abSAndroid Build Coastguard Worker       return 0;
433*fb1b10abSAndroid Build Coastguard Worker     case kRotate270:
434*fb1b10abSAndroid Build Coastguard Worker       RotatePlane270(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
435*fb1b10abSAndroid Build Coastguard Worker       RotatePlane270(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
436*fb1b10abSAndroid Build Coastguard Worker                      halfheight);
437*fb1b10abSAndroid Build Coastguard Worker       RotatePlane270(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
438*fb1b10abSAndroid Build Coastguard Worker                      halfheight);
439*fb1b10abSAndroid Build Coastguard Worker       return 0;
440*fb1b10abSAndroid Build Coastguard Worker     case kRotate180:
441*fb1b10abSAndroid Build Coastguard Worker       RotatePlane180(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
442*fb1b10abSAndroid Build Coastguard Worker       RotatePlane180(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth,
443*fb1b10abSAndroid Build Coastguard Worker                      halfheight);
444*fb1b10abSAndroid Build Coastguard Worker       RotatePlane180(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth,
445*fb1b10abSAndroid Build Coastguard Worker                      halfheight);
446*fb1b10abSAndroid Build Coastguard Worker       return 0;
447*fb1b10abSAndroid Build Coastguard Worker     default:
448*fb1b10abSAndroid Build Coastguard Worker       break;
449*fb1b10abSAndroid Build Coastguard Worker   }
450*fb1b10abSAndroid Build Coastguard Worker   return -1;
451*fb1b10abSAndroid Build Coastguard Worker }
452*fb1b10abSAndroid Build Coastguard Worker 
453*fb1b10abSAndroid Build Coastguard Worker LIBYUV_API
NV12ToI420Rotate(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_u,int dst_stride_u,uint8_t * dst_v,int dst_stride_v,int width,int height,enum RotationMode mode)454*fb1b10abSAndroid Build Coastguard Worker int NV12ToI420Rotate(const uint8_t* src_y,
455*fb1b10abSAndroid Build Coastguard Worker                      int src_stride_y,
456*fb1b10abSAndroid Build Coastguard Worker                      const uint8_t* src_uv,
457*fb1b10abSAndroid Build Coastguard Worker                      int src_stride_uv,
458*fb1b10abSAndroid Build Coastguard Worker                      uint8_t* dst_y,
459*fb1b10abSAndroid Build Coastguard Worker                      int dst_stride_y,
460*fb1b10abSAndroid Build Coastguard Worker                      uint8_t* dst_u,
461*fb1b10abSAndroid Build Coastguard Worker                      int dst_stride_u,
462*fb1b10abSAndroid Build Coastguard Worker                      uint8_t* dst_v,
463*fb1b10abSAndroid Build Coastguard Worker                      int dst_stride_v,
464*fb1b10abSAndroid Build Coastguard Worker                      int width,
465*fb1b10abSAndroid Build Coastguard Worker                      int height,
466*fb1b10abSAndroid Build Coastguard Worker                      enum RotationMode mode) {
467*fb1b10abSAndroid Build Coastguard Worker   int halfwidth = (width + 1) >> 1;
468*fb1b10abSAndroid Build Coastguard Worker   int halfheight = (height + 1) >> 1;
469*fb1b10abSAndroid Build Coastguard Worker   if (!src_y || !src_uv || width <= 0 || height == 0 || !dst_y || !dst_u ||
470*fb1b10abSAndroid Build Coastguard Worker       !dst_v) {
471*fb1b10abSAndroid Build Coastguard Worker     return -1;
472*fb1b10abSAndroid Build Coastguard Worker   }
473*fb1b10abSAndroid Build Coastguard Worker 
474*fb1b10abSAndroid Build Coastguard Worker   // Negative height means invert the image.
475*fb1b10abSAndroid Build Coastguard Worker   if (height < 0) {
476*fb1b10abSAndroid Build Coastguard Worker     height = -height;
477*fb1b10abSAndroid Build Coastguard Worker     halfheight = (height + 1) >> 1;
478*fb1b10abSAndroid Build Coastguard Worker     src_y = src_y + (height - 1) * src_stride_y;
479*fb1b10abSAndroid Build Coastguard Worker     src_uv = src_uv + (halfheight - 1) * src_stride_uv;
480*fb1b10abSAndroid Build Coastguard Worker     src_stride_y = -src_stride_y;
481*fb1b10abSAndroid Build Coastguard Worker     src_stride_uv = -src_stride_uv;
482*fb1b10abSAndroid Build Coastguard Worker   }
483*fb1b10abSAndroid Build Coastguard Worker 
484*fb1b10abSAndroid Build Coastguard Worker   switch (mode) {
485*fb1b10abSAndroid Build Coastguard Worker     case kRotate0:
486*fb1b10abSAndroid Build Coastguard Worker       // copy frame
487*fb1b10abSAndroid Build Coastguard Worker       return NV12ToI420(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
488*fb1b10abSAndroid Build Coastguard Worker                         dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
489*fb1b10abSAndroid Build Coastguard Worker                         width, height);
490*fb1b10abSAndroid Build Coastguard Worker     case kRotate90:
491*fb1b10abSAndroid Build Coastguard Worker       RotatePlane90(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
492*fb1b10abSAndroid Build Coastguard Worker       RotateUV90(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
493*fb1b10abSAndroid Build Coastguard Worker                  dst_stride_v, halfwidth, halfheight);
494*fb1b10abSAndroid Build Coastguard Worker       return 0;
495*fb1b10abSAndroid Build Coastguard Worker     case kRotate270:
496*fb1b10abSAndroid Build Coastguard Worker       RotatePlane270(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
497*fb1b10abSAndroid Build Coastguard Worker       RotateUV270(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
498*fb1b10abSAndroid Build Coastguard Worker                   dst_stride_v, halfwidth, halfheight);
499*fb1b10abSAndroid Build Coastguard Worker       return 0;
500*fb1b10abSAndroid Build Coastguard Worker     case kRotate180:
501*fb1b10abSAndroid Build Coastguard Worker       RotatePlane180(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
502*fb1b10abSAndroid Build Coastguard Worker       RotateUV180(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
503*fb1b10abSAndroid Build Coastguard Worker                   dst_stride_v, halfwidth, halfheight);
504*fb1b10abSAndroid Build Coastguard Worker       return 0;
505*fb1b10abSAndroid Build Coastguard Worker     default:
506*fb1b10abSAndroid Build Coastguard Worker       break;
507*fb1b10abSAndroid Build Coastguard Worker   }
508*fb1b10abSAndroid Build Coastguard Worker   return -1;
509*fb1b10abSAndroid Build Coastguard Worker }
510*fb1b10abSAndroid Build Coastguard Worker 
511*fb1b10abSAndroid Build Coastguard Worker #ifdef __cplusplus
512*fb1b10abSAndroid Build Coastguard Worker }  // extern "C"
513*fb1b10abSAndroid Build Coastguard Worker }  // namespace libyuv
514*fb1b10abSAndroid Build Coastguard Worker #endif
515