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