]> granicus.if.org Git - libvpx/blob - third_party/libyuv/source/convert_from.cc
b743cde264bd7e0b42f7906d631651389a3265be
[libvpx] / third_party / libyuv / source / convert_from.cc
1 /*
2  *  Copyright 2012 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/convert_from.h"
12
13 #include "libyuv/basic_types.h"
14 #include "libyuv/convert.h"  // For I420Copy
15 #include "libyuv/cpu_id.h"
16 #include "libyuv/planar_functions.h"
17 #include "libyuv/rotate.h"
18 #include "libyuv/scale.h"  // For ScalePlane()
19 #include "libyuv/video_common.h"
20 #include "libyuv/row.h"
21
22 #ifdef __cplusplus
23 namespace libyuv {
24 extern "C" {
25 #endif
26
27 #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
28 static __inline int Abs(int v) {
29   return v >= 0 ? v : -v;
30 }
31
32 // I420 To any I4xx YUV format with mirroring.
33 static int I420ToI4xx(const uint8* src_y, int src_stride_y,
34                       const uint8* src_u, int src_stride_u,
35                       const uint8* src_v, int src_stride_v,
36                       uint8* dst_y, int dst_stride_y,
37                       uint8* dst_u, int dst_stride_u,
38                       uint8* dst_v, int dst_stride_v,
39                       int src_y_width, int src_y_height,
40                       int dst_uv_width, int dst_uv_height) {
41   const int dst_y_width = Abs(src_y_width);
42   const int dst_y_height = Abs(src_y_height);
43   const int src_uv_width = SUBSAMPLE(src_y_width, 1, 1);
44   const int src_uv_height = SUBSAMPLE(src_y_height, 1, 1);
45   if (src_y_width == 0 || src_y_height == 0 ||
46       dst_uv_width <= 0 || dst_uv_height <= 0) {
47     return -1;
48   }
49   ScalePlane(src_y, src_stride_y, src_y_width, src_y_height,
50              dst_y, dst_stride_y, dst_y_width, dst_y_height,
51              kFilterBilinear);
52   ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height,
53              dst_u, dst_stride_u, dst_uv_width, dst_uv_height,
54              kFilterBilinear);
55   ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height,
56              dst_v, dst_stride_v, dst_uv_width, dst_uv_height,
57              kFilterBilinear);
58   return 0;
59 }
60
61 // 420 chroma is 1/2 width, 1/2 height
62 // 422 chroma is 1/2 width, 1x height
63 LIBYUV_API
64 int I420ToI422(const uint8* src_y, int src_stride_y,
65                const uint8* src_u, int src_stride_u,
66                const uint8* src_v, int src_stride_v,
67                uint8* dst_y, int dst_stride_y,
68                uint8* dst_u, int dst_stride_u,
69                uint8* dst_v, int dst_stride_v,
70                int width, int height) {
71   const int dst_uv_width = (Abs(width) + 1) >> 1;
72   const int dst_uv_height = Abs(height);
73   return I420ToI4xx(src_y, src_stride_y,
74                     src_u, src_stride_u,
75                     src_v, src_stride_v,
76                     dst_y, dst_stride_y,
77                     dst_u, dst_stride_u,
78                     dst_v, dst_stride_v,
79                     width, height,
80                     dst_uv_width, dst_uv_height);
81 }
82
83 // 420 chroma is 1/2 width, 1/2 height
84 // 444 chroma is 1x width, 1x height
85 LIBYUV_API
86 int I420ToI444(const uint8* src_y, int src_stride_y,
87                const uint8* src_u, int src_stride_u,
88                const uint8* src_v, int src_stride_v,
89                uint8* dst_y, int dst_stride_y,
90                uint8* dst_u, int dst_stride_u,
91                uint8* dst_v, int dst_stride_v,
92                int width, int height) {
93   const int dst_uv_width = Abs(width);
94   const int dst_uv_height = Abs(height);
95   return I420ToI4xx(src_y, src_stride_y,
96                     src_u, src_stride_u,
97                     src_v, src_stride_v,
98                     dst_y, dst_stride_y,
99                     dst_u, dst_stride_u,
100                     dst_v, dst_stride_v,
101                     width, height,
102                     dst_uv_width, dst_uv_height);
103 }
104
105 // 420 chroma is 1/2 width, 1/2 height
106 // 411 chroma is 1/4 width, 1x height
107 LIBYUV_API
108 int I420ToI411(const uint8* src_y, int src_stride_y,
109                const uint8* src_u, int src_stride_u,
110                const uint8* src_v, int src_stride_v,
111                uint8* dst_y, int dst_stride_y,
112                uint8* dst_u, int dst_stride_u,
113                uint8* dst_v, int dst_stride_v,
114                int width, int height) {
115   const int dst_uv_width = (Abs(width) + 3) >> 2;
116   const int dst_uv_height = Abs(height);
117   return I420ToI4xx(src_y, src_stride_y,
118                     src_u, src_stride_u,
119                     src_v, src_stride_v,
120                     dst_y, dst_stride_y,
121                     dst_u, dst_stride_u,
122                     dst_v, dst_stride_v,
123                     width, height,
124                     dst_uv_width, dst_uv_height);
125 }
126
127 // Copy to I400. Source can be I420,422,444,400,NV12,NV21
128 LIBYUV_API
129 int I400Copy(const uint8* src_y, int src_stride_y,
130              uint8* dst_y, int dst_stride_y,
131              int width, int height) {
132   if (!src_y || !dst_y ||
133       width <= 0 || height == 0) {
134     return -1;
135   }
136   // Negative height means invert the image.
137   if (height < 0) {
138     height = -height;
139     src_y = src_y + (height - 1) * src_stride_y;
140     src_stride_y = -src_stride_y;
141   }
142   CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
143   return 0;
144 }
145
146 LIBYUV_API
147 int I422ToYUY2(const uint8* src_y, int src_stride_y,
148                const uint8* src_u, int src_stride_u,
149                const uint8* src_v, int src_stride_v,
150                uint8* dst_yuy2, int dst_stride_yuy2,
151                int width, int height) {
152   int y;
153   void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u,
154                         const uint8* src_v, uint8* dst_yuy2, int width) =
155       I422ToYUY2Row_C;
156   if (!src_y || !src_u || !src_v || !dst_yuy2 ||
157       width <= 0 || height == 0) {
158     return -1;
159   }
160   // Negative height means invert the image.
161   if (height < 0) {
162     height = -height;
163     dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
164     dst_stride_yuy2 = -dst_stride_yuy2;
165   }
166   // Coalesce rows.
167   if (src_stride_y == width &&
168       src_stride_u * 2 == width &&
169       src_stride_v * 2 == width &&
170       dst_stride_yuy2 == width * 2) {
171     width *= height;
172     height = 1;
173     src_stride_y = src_stride_u = src_stride_v = dst_stride_yuy2 = 0;
174   }
175 #if defined(HAS_I422TOYUY2ROW_SSE2)
176   if (TestCpuFlag(kCpuHasSSE2)) {
177     I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
178     if (IS_ALIGNED(width, 16)) {
179       I422ToYUY2Row = I422ToYUY2Row_SSE2;
180     }
181   }
182 #endif
183 #if defined(HAS_I422TOYUY2ROW_NEON)
184   if (TestCpuFlag(kCpuHasNEON)) {
185     I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
186     if (IS_ALIGNED(width, 16)) {
187       I422ToYUY2Row = I422ToYUY2Row_NEON;
188     }
189   }
190 #endif
191
192   for (y = 0; y < height; ++y) {
193     I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
194     src_y += src_stride_y;
195     src_u += src_stride_u;
196     src_v += src_stride_v;
197     dst_yuy2 += dst_stride_yuy2;
198   }
199   return 0;
200 }
201
202 LIBYUV_API
203 int I420ToYUY2(const uint8* src_y, int src_stride_y,
204                const uint8* src_u, int src_stride_u,
205                const uint8* src_v, int src_stride_v,
206                uint8* dst_yuy2, int dst_stride_yuy2,
207                int width, int height) {
208   int y;
209   void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u,
210                         const uint8* src_v, uint8* dst_yuy2, int width) =
211       I422ToYUY2Row_C;
212   if (!src_y || !src_u || !src_v || !dst_yuy2 ||
213       width <= 0 || height == 0) {
214     return -1;
215   }
216   // Negative height means invert the image.
217   if (height < 0) {
218     height = -height;
219     dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
220     dst_stride_yuy2 = -dst_stride_yuy2;
221   }
222 #if defined(HAS_I422TOYUY2ROW_SSE2)
223   if (TestCpuFlag(kCpuHasSSE2)) {
224     I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
225     if (IS_ALIGNED(width, 16)) {
226       I422ToYUY2Row = I422ToYUY2Row_SSE2;
227     }
228   }
229 #endif
230 #if defined(HAS_I422TOYUY2ROW_NEON)
231   if (TestCpuFlag(kCpuHasNEON)) {
232     I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
233     if (IS_ALIGNED(width, 16)) {
234       I422ToYUY2Row = I422ToYUY2Row_NEON;
235     }
236   }
237 #endif
238
239   for (y = 0; y < height - 1; y += 2) {
240     I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
241     I422ToYUY2Row(src_y + src_stride_y, src_u, src_v,
242                   dst_yuy2 + dst_stride_yuy2, width);
243     src_y += src_stride_y * 2;
244     src_u += src_stride_u;
245     src_v += src_stride_v;
246     dst_yuy2 += dst_stride_yuy2 * 2;
247   }
248   if (height & 1) {
249     I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
250   }
251   return 0;
252 }
253
254 LIBYUV_API
255 int I422ToUYVY(const uint8* src_y, int src_stride_y,
256                const uint8* src_u, int src_stride_u,
257                const uint8* src_v, int src_stride_v,
258                uint8* dst_uyvy, int dst_stride_uyvy,
259                int width, int height) {
260   int y;
261   void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u,
262                         const uint8* src_v, uint8* dst_uyvy, int width) =
263       I422ToUYVYRow_C;
264   if (!src_y || !src_u || !src_v || !dst_uyvy ||
265       width <= 0 || height == 0) {
266     return -1;
267   }
268   // Negative height means invert the image.
269   if (height < 0) {
270     height = -height;
271     dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
272     dst_stride_uyvy = -dst_stride_uyvy;
273   }
274   // Coalesce rows.
275   if (src_stride_y == width &&
276       src_stride_u * 2 == width &&
277       src_stride_v * 2 == width &&
278       dst_stride_uyvy == width * 2) {
279     width *= height;
280     height = 1;
281     src_stride_y = src_stride_u = src_stride_v = dst_stride_uyvy = 0;
282   }
283 #if defined(HAS_I422TOUYVYROW_SSE2)
284   if (TestCpuFlag(kCpuHasSSE2)) {
285     I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
286     if (IS_ALIGNED(width, 16)) {
287       I422ToUYVYRow = I422ToUYVYRow_SSE2;
288     }
289   }
290 #endif
291 #if defined(HAS_I422TOUYVYROW_NEON)
292   if (TestCpuFlag(kCpuHasNEON)) {
293     I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
294     if (IS_ALIGNED(width, 16)) {
295       I422ToUYVYRow = I422ToUYVYRow_NEON;
296     }
297   }
298 #endif
299
300   for (y = 0; y < height; ++y) {
301     I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
302     src_y += src_stride_y;
303     src_u += src_stride_u;
304     src_v += src_stride_v;
305     dst_uyvy += dst_stride_uyvy;
306   }
307   return 0;
308 }
309
310 LIBYUV_API
311 int I420ToUYVY(const uint8* src_y, int src_stride_y,
312                const uint8* src_u, int src_stride_u,
313                const uint8* src_v, int src_stride_v,
314                uint8* dst_uyvy, int dst_stride_uyvy,
315                int width, int height) {
316   int y;
317   void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u,
318                         const uint8* src_v, uint8* dst_uyvy, int width) =
319       I422ToUYVYRow_C;
320   if (!src_y || !src_u || !src_v || !dst_uyvy ||
321       width <= 0 || height == 0) {
322     return -1;
323   }
324   // Negative height means invert the image.
325   if (height < 0) {
326     height = -height;
327     dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
328     dst_stride_uyvy = -dst_stride_uyvy;
329   }
330 #if defined(HAS_I422TOUYVYROW_SSE2)
331   if (TestCpuFlag(kCpuHasSSE2)) {
332     I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
333     if (IS_ALIGNED(width, 16)) {
334       I422ToUYVYRow = I422ToUYVYRow_SSE2;
335     }
336   }
337 #endif
338 #if defined(HAS_I422TOUYVYROW_NEON)
339   if (TestCpuFlag(kCpuHasNEON)) {
340     I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
341     if (IS_ALIGNED(width, 16)) {
342       I422ToUYVYRow = I422ToUYVYRow_NEON;
343     }
344   }
345 #endif
346
347   for (y = 0; y < height - 1; y += 2) {
348     I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
349     I422ToUYVYRow(src_y + src_stride_y, src_u, src_v,
350                   dst_uyvy + dst_stride_uyvy, width);
351     src_y += src_stride_y * 2;
352     src_u += src_stride_u;
353     src_v += src_stride_v;
354     dst_uyvy += dst_stride_uyvy * 2;
355   }
356   if (height & 1) {
357     I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
358   }
359   return 0;
360 }
361
362 LIBYUV_API
363 int I420ToNV12(const uint8* src_y, int src_stride_y,
364                const uint8* src_u, int src_stride_u,
365                const uint8* src_v, int src_stride_v,
366                uint8* dst_y, int dst_stride_y,
367                uint8* dst_uv, int dst_stride_uv,
368                int width, int height) {
369   int y;
370   void (*MergeUVRow_)(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
371       int width) = MergeUVRow_C;
372   // Coalesce rows.
373   int halfwidth = (width + 1) >> 1;
374   int halfheight = (height + 1) >> 1;
375   if (!src_y || !src_u || !src_v || !dst_y || !dst_uv ||
376       width <= 0 || height == 0) {
377     return -1;
378   }
379   // Negative height means invert the image.
380   if (height < 0) {
381     height = -height;
382     halfheight = (height + 1) >> 1;
383     dst_y = dst_y + (height - 1) * dst_stride_y;
384     dst_uv = dst_uv + (halfheight - 1) * dst_stride_uv;
385     dst_stride_y = -dst_stride_y;
386     dst_stride_uv = -dst_stride_uv;
387   }
388   if (src_stride_y == width &&
389       dst_stride_y == width) {
390     width *= height;
391     height = 1;
392     src_stride_y = dst_stride_y = 0;
393   }
394   // Coalesce rows.
395   if (src_stride_u == halfwidth &&
396       src_stride_v == halfwidth &&
397       dst_stride_uv == halfwidth * 2) {
398     halfwidth *= halfheight;
399     halfheight = 1;
400     src_stride_u = src_stride_v = dst_stride_uv = 0;
401   }
402 #if defined(HAS_MERGEUVROW_SSE2)
403   if (TestCpuFlag(kCpuHasSSE2)) {
404     MergeUVRow_ = MergeUVRow_Any_SSE2;
405     if (IS_ALIGNED(halfwidth, 16)) {
406       MergeUVRow_ = MergeUVRow_SSE2;
407     }
408   }
409 #endif
410 #if defined(HAS_MERGEUVROW_AVX2)
411   if (TestCpuFlag(kCpuHasAVX2)) {
412     MergeUVRow_ = MergeUVRow_Any_AVX2;
413     if (IS_ALIGNED(halfwidth, 32)) {
414       MergeUVRow_ = MergeUVRow_AVX2;
415     }
416   }
417 #endif
418 #if defined(HAS_MERGEUVROW_NEON)
419   if (TestCpuFlag(kCpuHasNEON)) {
420     MergeUVRow_ = MergeUVRow_Any_NEON;
421     if (IS_ALIGNED(halfwidth, 16)) {
422       MergeUVRow_ = MergeUVRow_NEON;
423     }
424   }
425 #endif
426
427   CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
428   for (y = 0; y < halfheight; ++y) {
429     // Merge a row of U and V into a row of UV.
430     MergeUVRow_(src_u, src_v, dst_uv, halfwidth);
431     src_u += src_stride_u;
432     src_v += src_stride_v;
433     dst_uv += dst_stride_uv;
434   }
435   return 0;
436 }
437
438 LIBYUV_API
439 int I420ToNV21(const uint8* src_y, int src_stride_y,
440                const uint8* src_u, int src_stride_u,
441                const uint8* src_v, int src_stride_v,
442                uint8* dst_y, int dst_stride_y,
443                uint8* dst_vu, int dst_stride_vu,
444                int width, int height) {
445   return I420ToNV12(src_y, src_stride_y,
446                     src_v, src_stride_v,
447                     src_u, src_stride_u,
448                     dst_y, src_stride_y,
449                     dst_vu, dst_stride_vu,
450                     width, height);
451 }
452
453 // Convert I420 to ARGB.
454 LIBYUV_API
455 int I420ToARGB(const uint8* src_y, int src_stride_y,
456                const uint8* src_u, int src_stride_u,
457                const uint8* src_v, int src_stride_v,
458                uint8* dst_argb, int dst_stride_argb,
459                int width, int height) {
460   int y;
461   void (*I422ToARGBRow)(const uint8* y_buf,
462                         const uint8* u_buf,
463                         const uint8* v_buf,
464                         uint8* rgb_buf,
465                         int width) = I422ToARGBRow_C;
466   if (!src_y || !src_u || !src_v || !dst_argb ||
467       width <= 0 || height == 0) {
468     return -1;
469   }
470   // Negative height means invert the image.
471   if (height < 0) {
472     height = -height;
473     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
474     dst_stride_argb = -dst_stride_argb;
475   }
476 #if defined(HAS_I422TOARGBROW_SSSE3)
477   if (TestCpuFlag(kCpuHasSSSE3)) {
478     I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
479     if (IS_ALIGNED(width, 8)) {
480       I422ToARGBRow = I422ToARGBRow_SSSE3;
481     }
482   }
483 #endif
484 #if defined(HAS_I422TOARGBROW_AVX2)
485   if (TestCpuFlag(kCpuHasAVX2)) {
486     I422ToARGBRow = I422ToARGBRow_Any_AVX2;
487     if (IS_ALIGNED(width, 16)) {
488       I422ToARGBRow = I422ToARGBRow_AVX2;
489     }
490   }
491 #endif
492 #if defined(HAS_I422TOARGBROW_NEON)
493   if (TestCpuFlag(kCpuHasNEON)) {
494     I422ToARGBRow = I422ToARGBRow_Any_NEON;
495     if (IS_ALIGNED(width, 8)) {
496       I422ToARGBRow = I422ToARGBRow_NEON;
497     }
498   }
499 #endif
500 #if defined(HAS_I422TOARGBROW_MIPS_DSPR2)
501   if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) &&
502       IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
503       IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
504       IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
505       IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
506     I422ToARGBRow = I422ToARGBRow_MIPS_DSPR2;
507   }
508 #endif
509
510   for (y = 0; y < height; ++y) {
511     I422ToARGBRow(src_y, src_u, src_v, dst_argb, width);
512     dst_argb += dst_stride_argb;
513     src_y += src_stride_y;
514     if (y & 1) {
515       src_u += src_stride_u;
516       src_v += src_stride_v;
517     }
518   }
519   return 0;
520 }
521
522 // Convert I420 to BGRA.
523 LIBYUV_API
524 int I420ToBGRA(const uint8* src_y, int src_stride_y,
525                const uint8* src_u, int src_stride_u,
526                const uint8* src_v, int src_stride_v,
527                uint8* dst_bgra, int dst_stride_bgra,
528                int width, int height) {
529   int y;
530   void (*I422ToBGRARow)(const uint8* y_buf,
531                         const uint8* u_buf,
532                         const uint8* v_buf,
533                         uint8* rgb_buf,
534                         int width) = I422ToBGRARow_C;
535   if (!src_y || !src_u || !src_v || !dst_bgra ||
536       width <= 0 || height == 0) {
537     return -1;
538   }
539   // Negative height means invert the image.
540   if (height < 0) {
541     height = -height;
542     dst_bgra = dst_bgra + (height - 1) * dst_stride_bgra;
543     dst_stride_bgra = -dst_stride_bgra;
544   }
545 #if defined(HAS_I422TOBGRAROW_SSSE3)
546   if (TestCpuFlag(kCpuHasSSSE3)) {
547     I422ToBGRARow = I422ToBGRARow_Any_SSSE3;
548     if (IS_ALIGNED(width, 8)) {
549       I422ToBGRARow = I422ToBGRARow_SSSE3;
550     }
551   }
552 #endif
553 #if defined(HAS_I422TOBGRAROW_AVX2)
554   if (TestCpuFlag(kCpuHasAVX2)) {
555     I422ToBGRARow = I422ToBGRARow_Any_AVX2;
556     if (IS_ALIGNED(width, 16)) {
557       I422ToBGRARow = I422ToBGRARow_AVX2;
558     }
559   }
560 #endif
561 #if defined(HAS_I422TOBGRAROW_NEON)
562   if (TestCpuFlag(kCpuHasNEON)) {
563     I422ToBGRARow = I422ToBGRARow_Any_NEON;
564     if (IS_ALIGNED(width, 8)) {
565       I422ToBGRARow = I422ToBGRARow_NEON;
566     }
567   }
568 #endif
569 #if defined(HAS_I422TOBGRAROW_MIPS_DSPR2)
570   if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) &&
571       IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
572       IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
573       IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
574       IS_ALIGNED(dst_bgra, 4) && IS_ALIGNED(dst_stride_bgra, 4)) {
575     I422ToBGRARow = I422ToBGRARow_MIPS_DSPR2;
576   }
577 #endif
578
579   for (y = 0; y < height; ++y) {
580     I422ToBGRARow(src_y, src_u, src_v, dst_bgra, width);
581     dst_bgra += dst_stride_bgra;
582     src_y += src_stride_y;
583     if (y & 1) {
584       src_u += src_stride_u;
585       src_v += src_stride_v;
586     }
587   }
588   return 0;
589 }
590
591 // Convert I420 to ABGR.
592 LIBYUV_API
593 int I420ToABGR(const uint8* src_y, int src_stride_y,
594                const uint8* src_u, int src_stride_u,
595                const uint8* src_v, int src_stride_v,
596                uint8* dst_abgr, int dst_stride_abgr,
597                int width, int height) {
598   int y;
599   void (*I422ToABGRRow)(const uint8* y_buf,
600                         const uint8* u_buf,
601                         const uint8* v_buf,
602                         uint8* rgb_buf,
603                         int width) = I422ToABGRRow_C;
604   if (!src_y || !src_u || !src_v || !dst_abgr ||
605       width <= 0 || height == 0) {
606     return -1;
607   }
608   // Negative height means invert the image.
609   if (height < 0) {
610     height = -height;
611     dst_abgr = dst_abgr + (height - 1) * dst_stride_abgr;
612     dst_stride_abgr = -dst_stride_abgr;
613   }
614 #if defined(HAS_I422TOABGRROW_SSSE3)
615   if (TestCpuFlag(kCpuHasSSSE3)) {
616     I422ToABGRRow = I422ToABGRRow_Any_SSSE3;
617     if (IS_ALIGNED(width, 8)) {
618       I422ToABGRRow = I422ToABGRRow_SSSE3;
619     }
620   }
621 #endif
622 #if defined(HAS_I422TOABGRROW_AVX2)
623   if (TestCpuFlag(kCpuHasAVX2)) {
624     I422ToABGRRow = I422ToABGRRow_Any_AVX2;
625     if (IS_ALIGNED(width, 16)) {
626       I422ToABGRRow = I422ToABGRRow_AVX2;
627     }
628   }
629 #endif
630 #if defined(HAS_I422TOABGRROW_NEON)
631   if (TestCpuFlag(kCpuHasNEON)) {
632     I422ToABGRRow = I422ToABGRRow_Any_NEON;
633     if (IS_ALIGNED(width, 8)) {
634       I422ToABGRRow = I422ToABGRRow_NEON;
635     }
636   }
637 #endif
638
639   for (y = 0; y < height; ++y) {
640     I422ToABGRRow(src_y, src_u, src_v, dst_abgr, width);
641     dst_abgr += dst_stride_abgr;
642     src_y += src_stride_y;
643     if (y & 1) {
644       src_u += src_stride_u;
645       src_v += src_stride_v;
646     }
647   }
648   return 0;
649 }
650
651 // Convert I420 to RGBA.
652 LIBYUV_API
653 int I420ToRGBA(const uint8* src_y, int src_stride_y,
654                const uint8* src_u, int src_stride_u,
655                const uint8* src_v, int src_stride_v,
656                uint8* dst_rgba, int dst_stride_rgba,
657                int width, int height) {
658   int y;
659   void (*I422ToRGBARow)(const uint8* y_buf,
660                         const uint8* u_buf,
661                         const uint8* v_buf,
662                         uint8* rgb_buf,
663                         int width) = I422ToRGBARow_C;
664   if (!src_y || !src_u || !src_v || !dst_rgba ||
665       width <= 0 || height == 0) {
666     return -1;
667   }
668   // Negative height means invert the image.
669   if (height < 0) {
670     height = -height;
671     dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
672     dst_stride_rgba = -dst_stride_rgba;
673   }
674 #if defined(HAS_I422TORGBAROW_SSSE3)
675   if (TestCpuFlag(kCpuHasSSSE3)) {
676     I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
677     if (IS_ALIGNED(width, 8)) {
678       I422ToRGBARow = I422ToRGBARow_SSSE3;
679     }
680   }
681 #endif
682 #if defined(HAS_I422TORGBAROW_AVX2)
683   if (TestCpuFlag(kCpuHasAVX2)) {
684     I422ToRGBARow = I422ToRGBARow_Any_AVX2;
685     if (IS_ALIGNED(width, 16)) {
686       I422ToRGBARow = I422ToRGBARow_AVX2;
687     }
688   }
689 #endif
690 #if defined(HAS_I422TORGBAROW_NEON)
691   if (TestCpuFlag(kCpuHasNEON)) {
692     I422ToRGBARow = I422ToRGBARow_Any_NEON;
693     if (IS_ALIGNED(width, 8)) {
694       I422ToRGBARow = I422ToRGBARow_NEON;
695     }
696   }
697 #endif
698
699   for (y = 0; y < height; ++y) {
700     I422ToRGBARow(src_y, src_u, src_v, dst_rgba, width);
701     dst_rgba += dst_stride_rgba;
702     src_y += src_stride_y;
703     if (y & 1) {
704       src_u += src_stride_u;
705       src_v += src_stride_v;
706     }
707   }
708   return 0;
709 }
710
711 // Convert I420 to RGB24.
712 LIBYUV_API
713 int I420ToRGB24(const uint8* src_y, int src_stride_y,
714                 const uint8* src_u, int src_stride_u,
715                 const uint8* src_v, int src_stride_v,
716                 uint8* dst_rgb24, int dst_stride_rgb24,
717                 int width, int height) {
718   int y;
719   void (*I422ToRGB24Row)(const uint8* y_buf,
720                          const uint8* u_buf,
721                          const uint8* v_buf,
722                          uint8* rgb_buf,
723                          int width) = I422ToRGB24Row_C;
724   if (!src_y || !src_u || !src_v || !dst_rgb24 ||
725       width <= 0 || height == 0) {
726     return -1;
727   }
728   // Negative height means invert the image.
729   if (height < 0) {
730     height = -height;
731     dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
732     dst_stride_rgb24 = -dst_stride_rgb24;
733   }
734 #if defined(HAS_I422TORGB24ROW_SSSE3)
735   if (TestCpuFlag(kCpuHasSSSE3)) {
736     I422ToRGB24Row = I422ToRGB24Row_Any_SSSE3;
737     if (IS_ALIGNED(width, 8)) {
738       I422ToRGB24Row = I422ToRGB24Row_SSSE3;
739     }
740   }
741 #endif
742 #if defined(HAS_I422TORGB24ROW_NEON)
743   if (TestCpuFlag(kCpuHasNEON)) {
744     I422ToRGB24Row = I422ToRGB24Row_Any_NEON;
745     if (IS_ALIGNED(width, 8)) {
746       I422ToRGB24Row = I422ToRGB24Row_NEON;
747     }
748   }
749 #endif
750
751   for (y = 0; y < height; ++y) {
752     I422ToRGB24Row(src_y, src_u, src_v, dst_rgb24, width);
753     dst_rgb24 += dst_stride_rgb24;
754     src_y += src_stride_y;
755     if (y & 1) {
756       src_u += src_stride_u;
757       src_v += src_stride_v;
758     }
759   }
760   return 0;
761 }
762
763 // Convert I420 to RAW.
764 LIBYUV_API
765 int I420ToRAW(const uint8* src_y, int src_stride_y,
766                 const uint8* src_u, int src_stride_u,
767                 const uint8* src_v, int src_stride_v,
768                 uint8* dst_raw, int dst_stride_raw,
769                 int width, int height) {
770   int y;
771   void (*I422ToRAWRow)(const uint8* y_buf,
772                        const uint8* u_buf,
773                        const uint8* v_buf,
774                        uint8* rgb_buf,
775                        int width) = I422ToRAWRow_C;
776   if (!src_y || !src_u || !src_v || !dst_raw ||
777       width <= 0 || height == 0) {
778     return -1;
779   }
780   // Negative height means invert the image.
781   if (height < 0) {
782     height = -height;
783     dst_raw = dst_raw + (height - 1) * dst_stride_raw;
784     dst_stride_raw = -dst_stride_raw;
785   }
786 #if defined(HAS_I422TORAWROW_SSSE3)
787   if (TestCpuFlag(kCpuHasSSSE3)) {
788     I422ToRAWRow = I422ToRAWRow_Any_SSSE3;
789     if (IS_ALIGNED(width, 8)) {
790       I422ToRAWRow = I422ToRAWRow_SSSE3;
791     }
792   }
793 #endif
794 #if defined(HAS_I422TORAWROW_NEON)
795   if (TestCpuFlag(kCpuHasNEON)) {
796     I422ToRAWRow = I422ToRAWRow_Any_NEON;
797     if (IS_ALIGNED(width, 8)) {
798       I422ToRAWRow = I422ToRAWRow_NEON;
799     }
800   }
801 #endif
802
803   for (y = 0; y < height; ++y) {
804     I422ToRAWRow(src_y, src_u, src_v, dst_raw, width);
805     dst_raw += dst_stride_raw;
806     src_y += src_stride_y;
807     if (y & 1) {
808       src_u += src_stride_u;
809       src_v += src_stride_v;
810     }
811   }
812   return 0;
813 }
814
815 // Convert I420 to ARGB1555.
816 LIBYUV_API
817 int I420ToARGB1555(const uint8* src_y, int src_stride_y,
818                    const uint8* src_u, int src_stride_u,
819                    const uint8* src_v, int src_stride_v,
820                    uint8* dst_argb1555, int dst_stride_argb1555,
821                    int width, int height) {
822   int y;
823   void (*I422ToARGB1555Row)(const uint8* y_buf,
824                             const uint8* u_buf,
825                             const uint8* v_buf,
826                             uint8* rgb_buf,
827                             int width) = I422ToARGB1555Row_C;
828   if (!src_y || !src_u || !src_v || !dst_argb1555 ||
829       width <= 0 || height == 0) {
830     return -1;
831   }
832   // Negative height means invert the image.
833   if (height < 0) {
834     height = -height;
835     dst_argb1555 = dst_argb1555 + (height - 1) * dst_stride_argb1555;
836     dst_stride_argb1555 = -dst_stride_argb1555;
837   }
838 #if defined(HAS_I422TOARGB1555ROW_SSSE3)
839   if (TestCpuFlag(kCpuHasSSSE3)) {
840     I422ToARGB1555Row = I422ToARGB1555Row_Any_SSSE3;
841     if (IS_ALIGNED(width, 8)) {
842       I422ToARGB1555Row = I422ToARGB1555Row_SSSE3;
843     }
844   }
845 #endif
846 #if defined(HAS_I422TOARGB1555ROW_AVX2)
847   if (TestCpuFlag(kCpuHasAVX2)) {
848     I422ToARGB1555Row = I422ToARGB1555Row_Any_AVX2;
849     if (IS_ALIGNED(width, 16)) {
850       I422ToARGB1555Row = I422ToARGB1555Row_AVX2;
851     }
852   }
853 #endif
854 #if defined(HAS_I422TOARGB1555ROW_NEON)
855   if (TestCpuFlag(kCpuHasNEON)) {
856     I422ToARGB1555Row = I422ToARGB1555Row_Any_NEON;
857     if (IS_ALIGNED(width, 8)) {
858       I422ToARGB1555Row = I422ToARGB1555Row_NEON;
859     }
860   }
861 #endif
862
863   for (y = 0; y < height; ++y) {
864     I422ToARGB1555Row(src_y, src_u, src_v, dst_argb1555, width);
865     dst_argb1555 += dst_stride_argb1555;
866     src_y += src_stride_y;
867     if (y & 1) {
868       src_u += src_stride_u;
869       src_v += src_stride_v;
870     }
871   }
872   return 0;
873 }
874
875
876 // Convert I420 to ARGB4444.
877 LIBYUV_API
878 int I420ToARGB4444(const uint8* src_y, int src_stride_y,
879                    const uint8* src_u, int src_stride_u,
880                    const uint8* src_v, int src_stride_v,
881                    uint8* dst_argb4444, int dst_stride_argb4444,
882                    int width, int height) {
883   int y;
884   void (*I422ToARGB4444Row)(const uint8* y_buf,
885                             const uint8* u_buf,
886                             const uint8* v_buf,
887                             uint8* rgb_buf,
888                             int width) = I422ToARGB4444Row_C;
889   if (!src_y || !src_u || !src_v || !dst_argb4444 ||
890       width <= 0 || height == 0) {
891     return -1;
892   }
893   // Negative height means invert the image.
894   if (height < 0) {
895     height = -height;
896     dst_argb4444 = dst_argb4444 + (height - 1) * dst_stride_argb4444;
897     dst_stride_argb4444 = -dst_stride_argb4444;
898   }
899 #if defined(HAS_I422TOARGB4444ROW_SSSE3)
900   if (TestCpuFlag(kCpuHasSSSE3)) {
901     I422ToARGB4444Row = I422ToARGB4444Row_Any_SSSE3;
902     if (IS_ALIGNED(width, 8)) {
903       I422ToARGB4444Row = I422ToARGB4444Row_SSSE3;
904     }
905   }
906 #endif
907 #if defined(HAS_I422TOARGB4444ROW_AVX2)
908   if (TestCpuFlag(kCpuHasAVX2)) {
909     I422ToARGB4444Row = I422ToARGB4444Row_Any_AVX2;
910     if (IS_ALIGNED(width, 16)) {
911       I422ToARGB4444Row = I422ToARGB4444Row_AVX2;
912     }
913   }
914 #endif
915 #if defined(HAS_I422TOARGB4444ROW_NEON)
916   if (TestCpuFlag(kCpuHasNEON)) {
917     I422ToARGB4444Row = I422ToARGB4444Row_Any_NEON;
918     if (IS_ALIGNED(width, 8)) {
919       I422ToARGB4444Row = I422ToARGB4444Row_NEON;
920     }
921   }
922 #endif
923
924   for (y = 0; y < height; ++y) {
925     I422ToARGB4444Row(src_y, src_u, src_v, dst_argb4444, width);
926     dst_argb4444 += dst_stride_argb4444;
927     src_y += src_stride_y;
928     if (y & 1) {
929       src_u += src_stride_u;
930       src_v += src_stride_v;
931     }
932   }
933   return 0;
934 }
935
936 // Convert I420 to RGB565.
937 LIBYUV_API
938 int I420ToRGB565(const uint8* src_y, int src_stride_y,
939                  const uint8* src_u, int src_stride_u,
940                  const uint8* src_v, int src_stride_v,
941                  uint8* dst_rgb565, int dst_stride_rgb565,
942                  int width, int height) {
943   int y;
944   void (*I422ToRGB565Row)(const uint8* y_buf,
945                           const uint8* u_buf,
946                           const uint8* v_buf,
947                           uint8* rgb_buf,
948                           int width) = I422ToRGB565Row_C;
949   if (!src_y || !src_u || !src_v || !dst_rgb565 ||
950       width <= 0 || height == 0) {
951     return -1;
952   }
953   // Negative height means invert the image.
954   if (height < 0) {
955     height = -height;
956     dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
957     dst_stride_rgb565 = -dst_stride_rgb565;
958   }
959 #if defined(HAS_I422TORGB565ROW_SSSE3)
960   if (TestCpuFlag(kCpuHasSSSE3)) {
961     I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
962     if (IS_ALIGNED(width, 8)) {
963       I422ToRGB565Row = I422ToRGB565Row_SSSE3;
964     }
965   }
966 #endif
967 #if defined(HAS_I422TORGB565ROW_AVX2)
968   if (TestCpuFlag(kCpuHasAVX2)) {
969     I422ToRGB565Row = I422ToRGB565Row_Any_AVX2;
970     if (IS_ALIGNED(width, 16)) {
971       I422ToRGB565Row = I422ToRGB565Row_AVX2;
972     }
973   }
974 #endif
975 #if defined(HAS_I422TORGB565ROW_NEON)
976   if (TestCpuFlag(kCpuHasNEON)) {
977     I422ToRGB565Row = I422ToRGB565Row_Any_NEON;
978     if (IS_ALIGNED(width, 8)) {
979       I422ToRGB565Row = I422ToRGB565Row_NEON;
980     }
981   }
982 #endif
983
984   for (y = 0; y < height; ++y) {
985     I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, width);
986     dst_rgb565 += dst_stride_rgb565;
987     src_y += src_stride_y;
988     if (y & 1) {
989       src_u += src_stride_u;
990       src_v += src_stride_v;
991     }
992   }
993   return 0;
994 }
995
996 // Convert I420 to specified format
997 LIBYUV_API
998 int ConvertFromI420(const uint8* y, int y_stride,
999                     const uint8* u, int u_stride,
1000                     const uint8* v, int v_stride,
1001                     uint8* dst_sample, int dst_sample_stride,
1002                     int width, int height,
1003                     uint32 fourcc) {
1004   uint32 format = CanonicalFourCC(fourcc);
1005   int r = 0;
1006   if (!y || !u|| !v || !dst_sample ||
1007       width <= 0 || height == 0) {
1008     return -1;
1009   }
1010   switch (format) {
1011     // Single plane formats
1012     case FOURCC_YUY2:
1013       r = I420ToYUY2(y, y_stride,
1014                      u, u_stride,
1015                      v, v_stride,
1016                      dst_sample,
1017                      dst_sample_stride ? dst_sample_stride : width * 2,
1018                      width, height);
1019       break;
1020     case FOURCC_UYVY:
1021       r = I420ToUYVY(y, y_stride,
1022                      u, u_stride,
1023                      v, v_stride,
1024                      dst_sample,
1025                      dst_sample_stride ? dst_sample_stride : width * 2,
1026                      width, height);
1027       break;
1028     case FOURCC_RGBP:
1029       r = I420ToRGB565(y, y_stride,
1030                        u, u_stride,
1031                        v, v_stride,
1032                        dst_sample,
1033                        dst_sample_stride ? dst_sample_stride : width * 2,
1034                        width, height);
1035       break;
1036     case FOURCC_RGBO:
1037       r = I420ToARGB1555(y, y_stride,
1038                          u, u_stride,
1039                          v, v_stride,
1040                          dst_sample,
1041                          dst_sample_stride ? dst_sample_stride : width * 2,
1042                          width, height);
1043       break;
1044     case FOURCC_R444:
1045       r = I420ToARGB4444(y, y_stride,
1046                          u, u_stride,
1047                          v, v_stride,
1048                          dst_sample,
1049                          dst_sample_stride ? dst_sample_stride : width * 2,
1050                          width, height);
1051       break;
1052     case FOURCC_24BG:
1053       r = I420ToRGB24(y, y_stride,
1054                       u, u_stride,
1055                       v, v_stride,
1056                       dst_sample,
1057                       dst_sample_stride ? dst_sample_stride : width * 3,
1058                       width, height);
1059       break;
1060     case FOURCC_RAW:
1061       r = I420ToRAW(y, y_stride,
1062                     u, u_stride,
1063                     v, v_stride,
1064                     dst_sample,
1065                     dst_sample_stride ? dst_sample_stride : width * 3,
1066                     width, height);
1067       break;
1068     case FOURCC_ARGB:
1069       r = I420ToARGB(y, y_stride,
1070                      u, u_stride,
1071                      v, v_stride,
1072                      dst_sample,
1073                      dst_sample_stride ? dst_sample_stride : width * 4,
1074                      width, height);
1075       break;
1076     case FOURCC_BGRA:
1077       r = I420ToBGRA(y, y_stride,
1078                      u, u_stride,
1079                      v, v_stride,
1080                      dst_sample,
1081                      dst_sample_stride ? dst_sample_stride : width * 4,
1082                      width, height);
1083       break;
1084     case FOURCC_ABGR:
1085       r = I420ToABGR(y, y_stride,
1086                      u, u_stride,
1087                      v, v_stride,
1088                      dst_sample,
1089                      dst_sample_stride ? dst_sample_stride : width * 4,
1090                      width, height);
1091       break;
1092     case FOURCC_RGBA:
1093       r = I420ToRGBA(y, y_stride,
1094                      u, u_stride,
1095                      v, v_stride,
1096                      dst_sample,
1097                      dst_sample_stride ? dst_sample_stride : width * 4,
1098                      width, height);
1099       break;
1100     case FOURCC_I400:
1101       r = I400Copy(y, y_stride,
1102                    dst_sample,
1103                    dst_sample_stride ? dst_sample_stride : width,
1104                    width, height);
1105       break;
1106     case FOURCC_NV12: {
1107       uint8* dst_uv = dst_sample + width * height;
1108       r = I420ToNV12(y, y_stride,
1109                      u, u_stride,
1110                      v, v_stride,
1111                      dst_sample,
1112                      dst_sample_stride ? dst_sample_stride : width,
1113                      dst_uv,
1114                      dst_sample_stride ? dst_sample_stride : width,
1115                      width, height);
1116       break;
1117     }
1118     case FOURCC_NV21: {
1119       uint8* dst_vu = dst_sample + width * height;
1120       r = I420ToNV21(y, y_stride,
1121                      u, u_stride,
1122                      v, v_stride,
1123                      dst_sample,
1124                      dst_sample_stride ? dst_sample_stride : width,
1125                      dst_vu,
1126                      dst_sample_stride ? dst_sample_stride : width,
1127                      width, height);
1128       break;
1129     }
1130     // TODO(fbarchard): Add M420.
1131     // Triplanar formats
1132     // TODO(fbarchard): halfstride instead of halfwidth
1133     case FOURCC_I420:
1134     case FOURCC_YU12:
1135     case FOURCC_YV12: {
1136       int halfwidth = (width + 1) / 2;
1137       int halfheight = (height + 1) / 2;
1138       uint8* dst_u;
1139       uint8* dst_v;
1140       if (format == FOURCC_YV12) {
1141         dst_v = dst_sample + width * height;
1142         dst_u = dst_v + halfwidth * halfheight;
1143       } else {
1144         dst_u = dst_sample + width * height;
1145         dst_v = dst_u + halfwidth * halfheight;
1146       }
1147       r = I420Copy(y, y_stride,
1148                    u, u_stride,
1149                    v, v_stride,
1150                    dst_sample, width,
1151                    dst_u, halfwidth,
1152                    dst_v, halfwidth,
1153                    width, height);
1154       break;
1155     }
1156     case FOURCC_I422:
1157     case FOURCC_YV16: {
1158       int halfwidth = (width + 1) / 2;
1159       uint8* dst_u;
1160       uint8* dst_v;
1161       if (format == FOURCC_YV16) {
1162         dst_v = dst_sample + width * height;
1163         dst_u = dst_v + halfwidth * height;
1164       } else {
1165         dst_u = dst_sample + width * height;
1166         dst_v = dst_u + halfwidth * height;
1167       }
1168       r = I420ToI422(y, y_stride,
1169                      u, u_stride,
1170                      v, v_stride,
1171                      dst_sample, width,
1172                      dst_u, halfwidth,
1173                      dst_v, halfwidth,
1174                      width, height);
1175       break;
1176     }
1177     case FOURCC_I444:
1178     case FOURCC_YV24: {
1179       uint8* dst_u;
1180       uint8* dst_v;
1181       if (format == FOURCC_YV24) {
1182         dst_v = dst_sample + width * height;
1183         dst_u = dst_v + width * height;
1184       } else {
1185         dst_u = dst_sample + width * height;
1186         dst_v = dst_u + width * height;
1187       }
1188       r = I420ToI444(y, y_stride,
1189                      u, u_stride,
1190                      v, v_stride,
1191                      dst_sample, width,
1192                      dst_u, width,
1193                      dst_v, width,
1194                      width, height);
1195       break;
1196     }
1197     case FOURCC_I411: {
1198       int quarterwidth = (width + 3) / 4;
1199       uint8* dst_u = dst_sample + width * height;
1200       uint8* dst_v = dst_u + quarterwidth * height;
1201       r = I420ToI411(y, y_stride,
1202                      u, u_stride,
1203                      v, v_stride,
1204                      dst_sample, width,
1205                      dst_u, quarterwidth,
1206                      dst_v, quarterwidth,
1207                      width, height);
1208       break;
1209     }
1210
1211     // Formats not supported - MJPG, biplanar, some rgb formats.
1212     default:
1213       return -1;  // unknown fourcc - return failure code.
1214   }
1215   return r;
1216 }
1217
1218 #ifdef __cplusplus
1219 }  // extern "C"
1220 }  // namespace libyuv
1221 #endif