Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / libyuv / source / convert.cc
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/convert.h"
12
13 #include "libyuv/basic_types.h"
14 #include "libyuv/cpu_id.h"
15 #include "libyuv/planar_functions.h"
16 #include "libyuv/rotate.h"
17 #include "libyuv/scale.h"  // For ScalePlane()
18 #include "libyuv/row.h"
19
20 #ifdef __cplusplus
21 namespace libyuv {
22 extern "C" {
23 #endif
24
25 #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
26 static __inline int Abs(int v) {
27   return v >= 0 ? v : -v;
28 }
29
30 // Any I4xx To I420 format with mirroring.
31 static int I4xxToI420(const uint8* src_y, int src_stride_y,
32                       const uint8* src_u, int src_stride_u,
33                       const uint8* src_v, int src_stride_v,
34                       uint8* dst_y, int dst_stride_y,
35                       uint8* dst_u, int dst_stride_u,
36                       uint8* dst_v, int dst_stride_v,
37                       int src_y_width, int src_y_height,
38                       int src_uv_width, int src_uv_height) {
39   const int dst_y_width = Abs(src_y_width);
40   const int dst_y_height = Abs(src_y_height);
41   const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
42   const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
43   if (src_y_width == 0 || src_y_height == 0 ||
44       src_uv_width == 0 || src_uv_height == 0) {
45     return -1;
46   }
47   ScalePlane(src_y, src_stride_y, src_y_width, src_y_height,
48              dst_y, dst_stride_y, dst_y_width, dst_y_height,
49              kFilterBilinear);
50   ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height,
51              dst_u, dst_stride_u, dst_uv_width, dst_uv_height,
52              kFilterBilinear);
53   ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height,
54              dst_v, dst_stride_v, dst_uv_width, dst_uv_height,
55              kFilterBilinear);
56   return 0;
57 }
58
59 // Copy I420 with optional flipping
60 // TODO(fbarchard): Use Scale plane which supports mirroring, but ensure
61 // is does row coalescing.
62 LIBYUV_API
63 int I420Copy(const uint8* src_y, int src_stride_y,
64              const uint8* src_u, int src_stride_u,
65              const uint8* src_v, int src_stride_v,
66              uint8* dst_y, int dst_stride_y,
67              uint8* dst_u, int dst_stride_u,
68              uint8* dst_v, int dst_stride_v,
69              int width, int height) {
70   int halfwidth = (width + 1) >> 1;
71   int halfheight = (height + 1) >> 1;
72   if (!src_y || !src_u || !src_v ||
73       !dst_y || !dst_u || !dst_v ||
74       width <= 0 || height == 0) {
75     return -1;
76   }
77   // Negative height means invert the image.
78   if (height < 0) {
79     height = -height;
80     halfheight = (height + 1) >> 1;
81     src_y = src_y + (height - 1) * src_stride_y;
82     src_u = src_u + (halfheight - 1) * src_stride_u;
83     src_v = src_v + (halfheight - 1) * src_stride_v;
84     src_stride_y = -src_stride_y;
85     src_stride_u = -src_stride_u;
86     src_stride_v = -src_stride_v;
87   }
88
89   if (dst_y) {
90     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
91   }
92   // Copy UV planes.
93   CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
94   CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
95   return 0;
96 }
97
98 // 422 chroma is 1/2 width, 1x height
99 // 420 chroma is 1/2 width, 1/2 height
100 LIBYUV_API
101 int I422ToI420(const uint8* src_y, int src_stride_y,
102                const uint8* src_u, int src_stride_u,
103                const uint8* src_v, int src_stride_v,
104                uint8* dst_y, int dst_stride_y,
105                uint8* dst_u, int dst_stride_u,
106                uint8* dst_v, int dst_stride_v,
107                int width, int height) {
108   const int src_uv_width = SUBSAMPLE(width, 1, 1);
109   return I4xxToI420(src_y, src_stride_y,
110                     src_u, src_stride_u,
111                     src_v, src_stride_v,
112                     dst_y, dst_stride_y,
113                     dst_u, dst_stride_u,
114                     dst_v, dst_stride_v,
115                     width, height,
116                     src_uv_width, height);
117 }
118
119 // 444 chroma is 1x width, 1x height
120 // 420 chroma is 1/2 width, 1/2 height
121 LIBYUV_API
122 int I444ToI420(const uint8* src_y, int src_stride_y,
123                const uint8* src_u, int src_stride_u,
124                const uint8* src_v, int src_stride_v,
125                uint8* dst_y, int dst_stride_y,
126                uint8* dst_u, int dst_stride_u,
127                uint8* dst_v, int dst_stride_v,
128                int width, int height) {
129   return I4xxToI420(src_y, src_stride_y,
130                     src_u, src_stride_u,
131                     src_v, src_stride_v,
132                     dst_y, dst_stride_y,
133                     dst_u, dst_stride_u,
134                     dst_v, dst_stride_v,
135                     width, height,
136                     width, height);
137 }
138
139 // 411 chroma is 1/4 width, 1x height
140 // 420 chroma is 1/2 width, 1/2 height
141 LIBYUV_API
142 int I411ToI420(const uint8* src_y, int src_stride_y,
143                const uint8* src_u, int src_stride_u,
144                const uint8* src_v, int src_stride_v,
145                uint8* dst_y, int dst_stride_y,
146                uint8* dst_u, int dst_stride_u,
147                uint8* dst_v, int dst_stride_v,
148                int width, int height) {
149   const int src_uv_width = SUBSAMPLE(width, 3, 2);
150   return I4xxToI420(src_y, src_stride_y,
151                     src_u, src_stride_u,
152                     src_v, src_stride_v,
153                     dst_y, dst_stride_y,
154                     dst_u, dst_stride_u,
155                     dst_v, dst_stride_v,
156                     width, height,
157                     src_uv_width, height);
158 }
159
160 // I400 is greyscale typically used in MJPG
161 LIBYUV_API
162 int I400ToI420(const uint8* src_y, int src_stride_y,
163                uint8* dst_y, int dst_stride_y,
164                uint8* dst_u, int dst_stride_u,
165                uint8* dst_v, int dst_stride_v,
166                int width, int height) {
167   int halfwidth = (width + 1) >> 1;
168   int halfheight = (height + 1) >> 1;
169   if (!src_y || !dst_y || !dst_u || !dst_v ||
170       width <= 0 || height == 0) {
171     return -1;
172   }
173   // Negative height means invert the image.
174   if (height < 0) {
175     height = -height;
176     halfheight = (height + 1) >> 1;
177     src_y = src_y + (height - 1) * src_stride_y;
178     src_stride_y = -src_stride_y;
179   }
180   CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
181   SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128);
182   SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128);
183   return 0;
184 }
185
186 static void CopyPlane2(const uint8* src, int src_stride_0, int src_stride_1,
187                        uint8* dst, int dst_stride,
188                        int width, int height) {
189   int y;
190   void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
191 #if defined(HAS_COPYROW_X86)
192   if (TestCpuFlag(kCpuHasX86) && IS_ALIGNED(width, 4)) {
193     CopyRow = CopyRow_X86;
194   }
195 #endif
196 #if defined(HAS_COPYROW_SSE2)
197   if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
198       IS_ALIGNED(src, 16) &&
199       IS_ALIGNED(src_stride_0, 16) && IS_ALIGNED(src_stride_1, 16) &&
200       IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) {
201     CopyRow = CopyRow_SSE2;
202   }
203 #endif
204 #if defined(HAS_COPYROW_ERMS)
205   if (TestCpuFlag(kCpuHasERMS)) {
206     CopyRow = CopyRow_ERMS;
207   }
208 #endif
209 #if defined(HAS_COPYROW_NEON)
210   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
211     CopyRow = CopyRow_NEON;
212   }
213 #endif
214 #if defined(HAS_COPYROW_MIPS)
215   if (TestCpuFlag(kCpuHasMIPS)) {
216     CopyRow = CopyRow_MIPS;
217   }
218 #endif
219
220   // Copy plane
221   for (y = 0; y < height - 1; y += 2) {
222     CopyRow(src, dst, width);
223     CopyRow(src + src_stride_0, dst + dst_stride, width);
224     src += src_stride_0 + src_stride_1;
225     dst += dst_stride * 2;
226   }
227   if (height & 1) {
228     CopyRow(src, dst, width);
229   }
230 }
231
232 // Support converting from FOURCC_M420
233 // Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for
234 // easy conversion to I420.
235 // M420 format description:
236 // M420 is row biplanar 420: 2 rows of Y and 1 row of UV.
237 // Chroma is half width / half height. (420)
238 // src_stride_m420 is row planar. Normally this will be the width in pixels.
239 //   The UV plane is half width, but 2 values, so src_stride_m420 applies to
240 //   this as well as the two Y planes.
241 static int X420ToI420(const uint8* src_y,
242                       int src_stride_y0, int src_stride_y1,
243                       const uint8* src_uv, int src_stride_uv,
244                       uint8* dst_y, int dst_stride_y,
245                       uint8* dst_u, int dst_stride_u,
246                       uint8* dst_v, int dst_stride_v,
247                       int width, int height) {
248   int y;
249   int halfwidth = (width + 1) >> 1;
250   int halfheight = (height + 1) >> 1;
251   void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix) =
252       SplitUVRow_C;
253   if (!src_y || !src_uv ||
254       !dst_y || !dst_u || !dst_v ||
255       width <= 0 || height == 0) {
256     return -1;
257   }
258   // Negative height means invert the image.
259   if (height < 0) {
260     height = -height;
261     halfheight = (height + 1) >> 1;
262     dst_y = dst_y + (height - 1) * dst_stride_y;
263     dst_u = dst_u + (halfheight - 1) * dst_stride_u;
264     dst_v = dst_v + (halfheight - 1) * dst_stride_v;
265     dst_stride_y = -dst_stride_y;
266     dst_stride_u = -dst_stride_u;
267     dst_stride_v = -dst_stride_v;
268   }
269   // Coalesce rows.
270   if (src_stride_y0 == width &&
271       src_stride_y1 == width &&
272       dst_stride_y == width) {
273     width *= height;
274     height = 1;
275     src_stride_y0 = src_stride_y1 = dst_stride_y = 0;
276   }
277   // Coalesce rows.
278   if (src_stride_uv == halfwidth * 2 &&
279       dst_stride_u == halfwidth &&
280       dst_stride_v == halfwidth) {
281     halfwidth *= halfheight;
282     halfheight = 1;
283     src_stride_uv = dst_stride_u = dst_stride_v = 0;
284   }
285 #if defined(HAS_SPLITUVROW_SSE2)
286   if (TestCpuFlag(kCpuHasSSE2) && halfwidth >= 16) {
287     SplitUVRow = SplitUVRow_Any_SSE2;
288     if (IS_ALIGNED(halfwidth, 16)) {
289       SplitUVRow = SplitUVRow_Unaligned_SSE2;
290       if (IS_ALIGNED(src_uv, 16) && IS_ALIGNED(src_stride_uv, 16) &&
291           IS_ALIGNED(dst_u, 16) && IS_ALIGNED(dst_stride_u, 16) &&
292           IS_ALIGNED(dst_v, 16) && IS_ALIGNED(dst_stride_v, 16)) {
293         SplitUVRow = SplitUVRow_SSE2;
294       }
295     }
296   }
297 #endif
298 #if defined(HAS_SPLITUVROW_AVX2)
299   if (TestCpuFlag(kCpuHasAVX2) && halfwidth >= 32) {
300     SplitUVRow = SplitUVRow_Any_AVX2;
301     if (IS_ALIGNED(halfwidth, 32)) {
302       SplitUVRow = SplitUVRow_AVX2;
303     }
304   }
305 #endif
306 #if defined(HAS_SPLITUVROW_NEON)
307   if (TestCpuFlag(kCpuHasNEON) && halfwidth >= 16) {
308     SplitUVRow = SplitUVRow_Any_NEON;
309     if (IS_ALIGNED(halfwidth, 16)) {
310       SplitUVRow = SplitUVRow_NEON;
311     }
312   }
313 #endif
314 #if defined(HAS_SPLITUVROW_MIPS_DSPR2)
315   if (TestCpuFlag(kCpuHasMIPS_DSPR2) && halfwidth >= 16) {
316     SplitUVRow = SplitUVRow_Any_MIPS_DSPR2;
317     if (IS_ALIGNED(halfwidth, 16)) {
318       SplitUVRow = SplitUVRow_Unaligned_MIPS_DSPR2;
319       if (IS_ALIGNED(src_uv, 4) && IS_ALIGNED(src_stride_uv, 4) &&
320           IS_ALIGNED(dst_u, 4) && IS_ALIGNED(dst_stride_u, 4) &&
321           IS_ALIGNED(dst_v, 4) && IS_ALIGNED(dst_stride_v, 4)) {
322         SplitUVRow = SplitUVRow_MIPS_DSPR2;
323       }
324     }
325   }
326 #endif
327
328   if (dst_y) {
329     if (src_stride_y0 == src_stride_y1) {
330       CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height);
331     } else {
332       CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y,
333                  width, height);
334     }
335   }
336
337   for (y = 0; y < halfheight; ++y) {
338     // Copy a row of UV.
339     SplitUVRow(src_uv, dst_u, dst_v, halfwidth);
340     dst_u += dst_stride_u;
341     dst_v += dst_stride_v;
342     src_uv += src_stride_uv;
343   }
344   return 0;
345 }
346
347 // Convert NV12 to I420.
348 LIBYUV_API
349 int NV12ToI420(const uint8* src_y, int src_stride_y,
350                const uint8* src_uv, int src_stride_uv,
351                uint8* dst_y, int dst_stride_y,
352                uint8* dst_u, int dst_stride_u,
353                uint8* dst_v, int dst_stride_v,
354                int width, int height) {
355   return X420ToI420(src_y, src_stride_y, src_stride_y,
356                     src_uv, src_stride_uv,
357                     dst_y, dst_stride_y,
358                     dst_u, dst_stride_u,
359                     dst_v, dst_stride_v,
360                     width, height);
361 }
362
363 // Convert NV21 to I420.  Same as NV12 but u and v pointers swapped.
364 LIBYUV_API
365 int NV21ToI420(const uint8* src_y, int src_stride_y,
366                const uint8* src_vu, int src_stride_vu,
367                uint8* dst_y, int dst_stride_y,
368                uint8* dst_u, int dst_stride_u,
369                uint8* dst_v, int dst_stride_v,
370                int width, int height) {
371   return X420ToI420(src_y, src_stride_y, src_stride_y,
372                     src_vu, src_stride_vu,
373                     dst_y, dst_stride_y,
374                     dst_v, dst_stride_v,
375                     dst_u, dst_stride_u,
376                     width, height);
377 }
378
379 // Convert M420 to I420.
380 LIBYUV_API
381 int M420ToI420(const uint8* src_m420, int src_stride_m420,
382                uint8* dst_y, int dst_stride_y,
383                uint8* dst_u, int dst_stride_u,
384                uint8* dst_v, int dst_stride_v,
385                int width, int height) {
386   return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2,
387                     src_m420 + src_stride_m420 * 2, src_stride_m420 * 3,
388                     dst_y, dst_stride_y,
389                     dst_u, dst_stride_u,
390                     dst_v, dst_stride_v,
391                     width, height);
392 }
393
394 // Convert Q420 to I420.
395 // Format is rows of YY/YUYV
396 LIBYUV_API
397 int Q420ToI420(const uint8* src_y, int src_stride_y,
398                const uint8* src_yuy2, int src_stride_yuy2,
399                uint8* dst_y, int dst_stride_y,
400                uint8* dst_u, int dst_stride_u,
401                uint8* dst_v, int dst_stride_v,
402                int width, int height) {
403   int y;
404   int halfheight = (height + 1) >> 1;
405   void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
406   void (*YUY2ToUV422Row)(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v,
407       int pix) = YUY2ToUV422Row_C;
408   void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int pix) =
409       YUY2ToYRow_C;
410   if (!src_y || !src_yuy2 ||
411       !dst_y || !dst_u || !dst_v ||
412       width <= 0 || height == 0) {
413     return -1;
414   }
415   // Negative height means invert the image.
416   if (height < 0) {
417     height = -height;
418     halfheight = (height + 1) >> 1;
419     dst_y = dst_y + (height - 1) * dst_stride_y;
420     dst_u = dst_u + (halfheight - 1) * dst_stride_u;
421     dst_v = dst_v + (halfheight - 1) * dst_stride_v;
422     dst_stride_y = -dst_stride_y;
423     dst_stride_u = -dst_stride_u;
424     dst_stride_v = -dst_stride_v;
425   }
426   // CopyRow for rows of just Y in Q420 copied to Y plane of I420.
427 #if defined(HAS_COPYROW_NEON)
428   if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
429     CopyRow = CopyRow_NEON;
430   }
431 #endif
432 #if defined(HAS_COPYROW_X86)
433   if (IS_ALIGNED(width, 4)) {
434     CopyRow = CopyRow_X86;
435   }
436 #endif
437 #if defined(HAS_COPYROW_SSE2)
438   if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
439       IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
440       IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
441     CopyRow = CopyRow_SSE2;
442   }
443 #endif
444 #if defined(HAS_COPYROW_ERMS)
445   if (TestCpuFlag(kCpuHasERMS)) {
446     CopyRow = CopyRow_ERMS;
447   }
448 #endif
449 #if defined(HAS_COPYROW_MIPS)
450   if (TestCpuFlag(kCpuHasMIPS)) {
451     CopyRow = CopyRow_MIPS;
452   }
453 #endif
454
455 #if defined(HAS_YUY2TOYROW_SSE2)
456   if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
457     YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2;
458     YUY2ToYRow = YUY2ToYRow_Any_SSE2;
459     if (IS_ALIGNED(width, 16)) {
460       YUY2ToUV422Row = YUY2ToUV422Row_Unaligned_SSE2;
461       YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
462       if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
463         YUY2ToUV422Row = YUY2ToUV422Row_SSE2;
464         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
465           YUY2ToYRow = YUY2ToYRow_SSE2;
466         }
467       }
468     }
469   }
470 #endif
471 #if defined(HAS_YUY2TOYROW_AVX2)
472   if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
473     YUY2ToUV422Row = YUY2ToUV422Row_Any_AVX2;
474     YUY2ToYRow = YUY2ToYRow_Any_AVX2;
475     if (IS_ALIGNED(width, 32)) {
476       YUY2ToUV422Row = YUY2ToUV422Row_AVX2;
477       YUY2ToYRow = YUY2ToYRow_AVX2;
478     }
479   }
480 #endif
481 #if defined(HAS_YUY2TOYROW_NEON)
482   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
483     YUY2ToYRow = YUY2ToYRow_Any_NEON;
484     if (width >= 16) {
485       YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON;
486     }
487     if (IS_ALIGNED(width, 16)) {
488       YUY2ToYRow = YUY2ToYRow_NEON;
489       YUY2ToUV422Row = YUY2ToUV422Row_NEON;
490     }
491   }
492 #endif
493
494   for (y = 0; y < height - 1; y += 2) {
495     CopyRow(src_y, dst_y, width);
496     src_y += src_stride_y;
497     dst_y += dst_stride_y;
498
499     YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
500     YUY2ToYRow(src_yuy2, dst_y, width);
501     src_yuy2 += src_stride_yuy2;
502     dst_y += dst_stride_y;
503     dst_u += dst_stride_u;
504     dst_v += dst_stride_v;
505   }
506   if (height & 1) {
507     CopyRow(src_y, dst_y, width);
508     YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
509   }
510   return 0;
511 }
512
513 // Convert YUY2 to I420.
514 LIBYUV_API
515 int YUY2ToI420(const uint8* src_yuy2, int src_stride_yuy2,
516                uint8* dst_y, int dst_stride_y,
517                uint8* dst_u, int dst_stride_u,
518                uint8* dst_v, int dst_stride_v,
519                int width, int height) {
520   int y;
521   void (*YUY2ToUVRow)(const uint8* src_yuy2, int src_stride_yuy2,
522       uint8* dst_u, uint8* dst_v, int pix) = YUY2ToUVRow_C;
523   void (*YUY2ToYRow)(const uint8* src_yuy2,
524       uint8* dst_y, int pix) = YUY2ToYRow_C;
525   // Negative height means invert the image.
526   if (height < 0) {
527     height = -height;
528     src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
529     src_stride_yuy2 = -src_stride_yuy2;
530   }
531 #if defined(HAS_YUY2TOYROW_SSE2)
532   if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
533     YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
534     YUY2ToYRow = YUY2ToYRow_Any_SSE2;
535     if (IS_ALIGNED(width, 16)) {
536       YUY2ToUVRow = YUY2ToUVRow_Unaligned_SSE2;
537       YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
538       if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
539         YUY2ToUVRow = YUY2ToUVRow_SSE2;
540         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
541           YUY2ToYRow = YUY2ToYRow_SSE2;
542         }
543       }
544     }
545   }
546 #endif
547 #if defined(HAS_YUY2TOYROW_AVX2)
548   if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
549     YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
550     YUY2ToYRow = YUY2ToYRow_Any_AVX2;
551     if (IS_ALIGNED(width, 32)) {
552       YUY2ToUVRow = YUY2ToUVRow_AVX2;
553       YUY2ToYRow = YUY2ToYRow_AVX2;
554     }
555   }
556 #endif
557 #if defined(HAS_YUY2TOYROW_NEON)
558   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
559     YUY2ToYRow = YUY2ToYRow_Any_NEON;
560     if (width >= 16) {
561       YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
562     }
563     if (IS_ALIGNED(width, 16)) {
564       YUY2ToYRow = YUY2ToYRow_NEON;
565       YUY2ToUVRow = YUY2ToUVRow_NEON;
566     }
567   }
568 #endif
569
570   for (y = 0; y < height - 1; y += 2) {
571     YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
572     YUY2ToYRow(src_yuy2, dst_y, width);
573     YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
574     src_yuy2 += src_stride_yuy2 * 2;
575     dst_y += dst_stride_y * 2;
576     dst_u += dst_stride_u;
577     dst_v += dst_stride_v;
578   }
579   if (height & 1) {
580     YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
581     YUY2ToYRow(src_yuy2, dst_y, width);
582   }
583   return 0;
584 }
585
586 // Convert UYVY to I420.
587 LIBYUV_API
588 int UYVYToI420(const uint8* src_uyvy, int src_stride_uyvy,
589                uint8* dst_y, int dst_stride_y,
590                uint8* dst_u, int dst_stride_u,
591                uint8* dst_v, int dst_stride_v,
592                int width, int height) {
593   int y;
594   void (*UYVYToUVRow)(const uint8* src_uyvy, int src_stride_uyvy,
595       uint8* dst_u, uint8* dst_v, int pix) = UYVYToUVRow_C;
596   void (*UYVYToYRow)(const uint8* src_uyvy,
597       uint8* dst_y, int pix) = UYVYToYRow_C;
598   // Negative height means invert the image.
599   if (height < 0) {
600     height = -height;
601     src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
602     src_stride_uyvy = -src_stride_uyvy;
603   }
604 #if defined(HAS_UYVYTOYROW_SSE2)
605   if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
606     UYVYToUVRow = UYVYToUVRow_Any_SSE2;
607     UYVYToYRow = UYVYToYRow_Any_SSE2;
608     if (IS_ALIGNED(width, 16)) {
609       UYVYToUVRow = UYVYToUVRow_Unaligned_SSE2;
610       UYVYToYRow = UYVYToYRow_Unaligned_SSE2;
611       if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16)) {
612         UYVYToUVRow = UYVYToUVRow_SSE2;
613         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
614           UYVYToYRow = UYVYToYRow_SSE2;
615         }
616       }
617     }
618   }
619 #endif
620 #if defined(HAS_UYVYTOYROW_AVX2)
621   if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
622     UYVYToUVRow = UYVYToUVRow_Any_AVX2;
623     UYVYToYRow = UYVYToYRow_Any_AVX2;
624     if (IS_ALIGNED(width, 32)) {
625       UYVYToUVRow = UYVYToUVRow_AVX2;
626       UYVYToYRow = UYVYToYRow_AVX2;
627     }
628   }
629 #endif
630 #if defined(HAS_UYVYTOYROW_NEON)
631   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
632     UYVYToYRow = UYVYToYRow_Any_NEON;
633     if (width >= 16) {
634       UYVYToUVRow = UYVYToUVRow_Any_NEON;
635     }
636     if (IS_ALIGNED(width, 16)) {
637       UYVYToYRow = UYVYToYRow_NEON;
638       UYVYToUVRow = UYVYToUVRow_NEON;
639     }
640   }
641 #endif
642
643   for (y = 0; y < height - 1; y += 2) {
644     UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
645     UYVYToYRow(src_uyvy, dst_y, width);
646     UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
647     src_uyvy += src_stride_uyvy * 2;
648     dst_y += dst_stride_y * 2;
649     dst_u += dst_stride_u;
650     dst_v += dst_stride_v;
651   }
652   if (height & 1) {
653     UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
654     UYVYToYRow(src_uyvy, dst_y, width);
655   }
656   return 0;
657 }
658
659 // Convert ARGB to I420.
660 LIBYUV_API
661 int ARGBToI420(const uint8* src_argb, int src_stride_argb,
662                uint8* dst_y, int dst_stride_y,
663                uint8* dst_u, int dst_stride_u,
664                uint8* dst_v, int dst_stride_v,
665                int width, int height) {
666   int y;
667   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
668       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
669   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
670       ARGBToYRow_C;
671   if (!src_argb ||
672       !dst_y || !dst_u || !dst_v ||
673       width <= 0 || height == 0) {
674     return -1;
675   }
676   // Negative height means invert the image.
677   if (height < 0) {
678     height = -height;
679     src_argb = src_argb + (height - 1) * src_stride_argb;
680     src_stride_argb = -src_stride_argb;
681   }
682 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
683   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
684     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
685     ARGBToYRow = ARGBToYRow_Any_SSSE3;
686     if (IS_ALIGNED(width, 16)) {
687       ARGBToUVRow = ARGBToUVRow_Unaligned_SSSE3;
688       ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
689       if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
690         ARGBToUVRow = ARGBToUVRow_SSSE3;
691         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
692           ARGBToYRow = ARGBToYRow_SSSE3;
693         }
694       }
695     }
696   }
697 #endif
698 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
699   if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
700     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
701     ARGBToYRow = ARGBToYRow_Any_AVX2;
702     if (IS_ALIGNED(width, 32)) {
703       ARGBToUVRow = ARGBToUVRow_AVX2;
704       ARGBToYRow = ARGBToYRow_AVX2;
705     }
706   }
707 #endif
708 #if defined(HAS_ARGBTOYROW_NEON)
709   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
710     ARGBToYRow = ARGBToYRow_Any_NEON;
711     if (IS_ALIGNED(width, 8)) {
712       ARGBToYRow = ARGBToYRow_NEON;
713     }
714     if (width >= 16) {
715       ARGBToUVRow = ARGBToUVRow_Any_NEON;
716       if (IS_ALIGNED(width, 16)) {
717         ARGBToUVRow = ARGBToUVRow_NEON;
718       }
719     }
720   }
721 #endif
722
723   for (y = 0; y < height - 1; y += 2) {
724     ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
725     ARGBToYRow(src_argb, dst_y, width);
726     ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
727     src_argb += src_stride_argb * 2;
728     dst_y += dst_stride_y * 2;
729     dst_u += dst_stride_u;
730     dst_v += dst_stride_v;
731   }
732   if (height & 1) {
733     ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
734     ARGBToYRow(src_argb, dst_y, width);
735   }
736   return 0;
737 }
738
739 // Convert BGRA to I420.
740 LIBYUV_API
741 int BGRAToI420(const uint8* src_bgra, int src_stride_bgra,
742                uint8* dst_y, int dst_stride_y,
743                uint8* dst_u, int dst_stride_u,
744                uint8* dst_v, int dst_stride_v,
745                int width, int height) {
746   int y;
747   void (*BGRAToUVRow)(const uint8* src_bgra0, int src_stride_bgra,
748       uint8* dst_u, uint8* dst_v, int width) = BGRAToUVRow_C;
749   void (*BGRAToYRow)(const uint8* src_bgra, uint8* dst_y, int pix) =
750       BGRAToYRow_C;
751   if (!src_bgra ||
752       !dst_y || !dst_u || !dst_v ||
753       width <= 0 || height == 0) {
754     return -1;
755   }
756   // Negative height means invert the image.
757   if (height < 0) {
758     height = -height;
759     src_bgra = src_bgra + (height - 1) * src_stride_bgra;
760     src_stride_bgra = -src_stride_bgra;
761   }
762 #if defined(HAS_BGRATOYROW_SSSE3)
763   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
764     BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
765     BGRAToYRow = BGRAToYRow_Any_SSSE3;
766     if (IS_ALIGNED(width, 16)) {
767       BGRAToUVRow = BGRAToUVRow_Unaligned_SSSE3;
768       BGRAToYRow = BGRAToYRow_Unaligned_SSSE3;
769       if (IS_ALIGNED(src_bgra, 16) && IS_ALIGNED(src_stride_bgra, 16)) {
770         BGRAToUVRow = BGRAToUVRow_SSSE3;
771         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
772           BGRAToYRow = BGRAToYRow_SSSE3;
773         }
774       }
775     }
776   }
777 #elif defined(HAS_BGRATOYROW_NEON)
778   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
779     BGRAToYRow = BGRAToYRow_Any_NEON;
780     if (IS_ALIGNED(width, 8)) {
781       BGRAToYRow = BGRAToYRow_NEON;
782     }
783     if (width >= 16) {
784       BGRAToUVRow = BGRAToUVRow_Any_NEON;
785       if (IS_ALIGNED(width, 16)) {
786         BGRAToUVRow = BGRAToUVRow_NEON;
787       }
788     }
789   }
790 #endif
791
792   for (y = 0; y < height - 1; y += 2) {
793     BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
794     BGRAToYRow(src_bgra, dst_y, width);
795     BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
796     src_bgra += src_stride_bgra * 2;
797     dst_y += dst_stride_y * 2;
798     dst_u += dst_stride_u;
799     dst_v += dst_stride_v;
800   }
801   if (height & 1) {
802     BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
803     BGRAToYRow(src_bgra, dst_y, width);
804   }
805   return 0;
806 }
807
808 // Convert ABGR to I420.
809 LIBYUV_API
810 int ABGRToI420(const uint8* src_abgr, int src_stride_abgr,
811                uint8* dst_y, int dst_stride_y,
812                uint8* dst_u, int dst_stride_u,
813                uint8* dst_v, int dst_stride_v,
814                int width, int height) {
815   int y;
816   void (*ABGRToUVRow)(const uint8* src_abgr0, int src_stride_abgr,
817       uint8* dst_u, uint8* dst_v, int width) = ABGRToUVRow_C;
818   void (*ABGRToYRow)(const uint8* src_abgr, uint8* dst_y, int pix) =
819       ABGRToYRow_C;
820   if (!src_abgr ||
821       !dst_y || !dst_u || !dst_v ||
822       width <= 0 || height == 0) {
823     return -1;
824   }
825   // Negative height means invert the image.
826   if (height < 0) {
827     height = -height;
828     src_abgr = src_abgr + (height - 1) * src_stride_abgr;
829     src_stride_abgr = -src_stride_abgr;
830   }
831 #if defined(HAS_ABGRTOYROW_SSSE3)
832   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
833     ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
834     ABGRToYRow = ABGRToYRow_Any_SSSE3;
835     if (IS_ALIGNED(width, 16)) {
836       ABGRToUVRow = ABGRToUVRow_Unaligned_SSSE3;
837       ABGRToYRow = ABGRToYRow_Unaligned_SSSE3;
838       if (IS_ALIGNED(src_abgr, 16) && IS_ALIGNED(src_stride_abgr, 16)) {
839         ABGRToUVRow = ABGRToUVRow_SSSE3;
840         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
841           ABGRToYRow = ABGRToYRow_SSSE3;
842         }
843       }
844     }
845   }
846 #elif defined(HAS_ABGRTOYROW_NEON)
847   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
848     ABGRToYRow = ABGRToYRow_Any_NEON;
849     if (IS_ALIGNED(width, 8)) {
850       ABGRToYRow = ABGRToYRow_NEON;
851     }
852     if (width >= 16) {
853       ABGRToUVRow = ABGRToUVRow_Any_NEON;
854       if (IS_ALIGNED(width, 16)) {
855         ABGRToUVRow = ABGRToUVRow_NEON;
856       }
857     }
858   }
859 #endif
860
861   for (y = 0; y < height - 1; y += 2) {
862     ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
863     ABGRToYRow(src_abgr, dst_y, width);
864     ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
865     src_abgr += src_stride_abgr * 2;
866     dst_y += dst_stride_y * 2;
867     dst_u += dst_stride_u;
868     dst_v += dst_stride_v;
869   }
870   if (height & 1) {
871     ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
872     ABGRToYRow(src_abgr, dst_y, width);
873   }
874   return 0;
875 }
876
877 // Convert RGBA to I420.
878 LIBYUV_API
879 int RGBAToI420(const uint8* src_rgba, int src_stride_rgba,
880                uint8* dst_y, int dst_stride_y,
881                uint8* dst_u, int dst_stride_u,
882                uint8* dst_v, int dst_stride_v,
883                int width, int height) {
884   int y;
885   void (*RGBAToUVRow)(const uint8* src_rgba0, int src_stride_rgba,
886       uint8* dst_u, uint8* dst_v, int width) = RGBAToUVRow_C;
887   void (*RGBAToYRow)(const uint8* src_rgba, uint8* dst_y, int pix) =
888       RGBAToYRow_C;
889   if (!src_rgba ||
890       !dst_y || !dst_u || !dst_v ||
891       width <= 0 || height == 0) {
892     return -1;
893   }
894   // Negative height means invert the image.
895   if (height < 0) {
896     height = -height;
897     src_rgba = src_rgba + (height - 1) * src_stride_rgba;
898     src_stride_rgba = -src_stride_rgba;
899   }
900 #if defined(HAS_RGBATOYROW_SSSE3)
901   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
902     RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
903     RGBAToYRow = RGBAToYRow_Any_SSSE3;
904     if (IS_ALIGNED(width, 16)) {
905       RGBAToUVRow = RGBAToUVRow_Unaligned_SSSE3;
906       RGBAToYRow = RGBAToYRow_Unaligned_SSSE3;
907       if (IS_ALIGNED(src_rgba, 16) && IS_ALIGNED(src_stride_rgba, 16)) {
908         RGBAToUVRow = RGBAToUVRow_SSSE3;
909         if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
910           RGBAToYRow = RGBAToYRow_SSSE3;
911         }
912       }
913     }
914   }
915 #elif defined(HAS_RGBATOYROW_NEON)
916   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
917     RGBAToYRow = RGBAToYRow_Any_NEON;
918     if (IS_ALIGNED(width, 8)) {
919       RGBAToYRow = RGBAToYRow_NEON;
920     }
921     if (width >= 16) {
922       RGBAToUVRow = RGBAToUVRow_Any_NEON;
923       if (IS_ALIGNED(width, 16)) {
924         RGBAToUVRow = RGBAToUVRow_NEON;
925       }
926     }
927   }
928 #endif
929
930   for (y = 0; y < height - 1; y += 2) {
931     RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
932     RGBAToYRow(src_rgba, dst_y, width);
933     RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
934     src_rgba += src_stride_rgba * 2;
935     dst_y += dst_stride_y * 2;
936     dst_u += dst_stride_u;
937     dst_v += dst_stride_v;
938   }
939   if (height & 1) {
940     RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
941     RGBAToYRow(src_rgba, dst_y, width);
942   }
943   return 0;
944 }
945
946 // Convert RGB24 to I420.
947 LIBYUV_API
948 int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24,
949                 uint8* dst_y, int dst_stride_y,
950                 uint8* dst_u, int dst_stride_u,
951                 uint8* dst_v, int dst_stride_v,
952                 int width, int height) {
953   int y;
954 #if defined(HAS_RGB24TOYROW_NEON)
955   void (*RGB24ToUVRow)(const uint8* src_rgb24, int src_stride_rgb24,
956       uint8* dst_u, uint8* dst_v, int width) = RGB24ToUVRow_C;
957   void (*RGB24ToYRow)(const uint8* src_rgb24, uint8* dst_y, int pix) =
958       RGB24ToYRow_C;
959 #else
960   void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
961       RGB24ToARGBRow_C;
962   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
963       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
964   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
965       ARGBToYRow_C;
966   // Allocate 2 rows of ARGB.
967   const int kRowSize = (width * 4 + 15) & ~15;
968   align_buffer_64(row, kRowSize * 2);
969 #endif
970   if (!src_rgb24 || !dst_y || !dst_u || !dst_v ||
971       width <= 0 || height == 0) {
972     return -1;
973   }
974   // Negative height means invert the image.
975   if (height < 0) {
976     height = -height;
977     src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
978     src_stride_rgb24 = -src_stride_rgb24;
979   }
980
981 #if defined(HAS_RGB24TOYROW_NEON)
982   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
983     RGB24ToYRow = RGB24ToYRow_Any_NEON;
984     if (IS_ALIGNED(width, 8)) {
985       RGB24ToYRow = RGB24ToYRow_NEON;
986     }
987     if (width >= 16) {
988       RGB24ToUVRow = RGB24ToUVRow_Any_NEON;
989       if (IS_ALIGNED(width, 16)) {
990         RGB24ToUVRow = RGB24ToUVRow_NEON;
991       }
992     }
993   }
994 #else  // HAS_RGB24TOYROW_NEON
995
996 #if defined(HAS_RGB24TOARGBROW_SSSE3)
997   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
998     RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
999     if (IS_ALIGNED(width, 16)) {
1000       RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
1001     }
1002   }
1003 #endif
1004 #if defined(HAS_ARGBTOUVROW_SSSE3)
1005   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1006     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1007     if (IS_ALIGNED(width, 16)) {
1008       ARGBToUVRow = ARGBToUVRow_SSSE3;
1009     }
1010   }
1011 #endif
1012 #if defined(HAS_ARGBTOUVROW_SSSE3)
1013   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1014     ARGBToYRow = ARGBToYRow_Any_SSSE3;
1015     if (IS_ALIGNED(width, 16)) {
1016       ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1017       if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1018         ARGBToYRow = ARGBToYRow_SSSE3;
1019       }
1020     }
1021   }
1022 #endif  // HAS_ARGBTOUVROW_SSSE3
1023 #endif  // HAS_RGB24TOYROW_NEON
1024
1025   for (y = 0; y < height - 1; y += 2) {
1026 #if defined(HAS_RGB24TOYROW_NEON)
1027     RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
1028     RGB24ToYRow(src_rgb24, dst_y, width);
1029     RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
1030 #else
1031     RGB24ToARGBRow(src_rgb24, row, width);
1032     RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
1033     ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1034     ARGBToYRow(row, dst_y, width);
1035     ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1036 #endif
1037     src_rgb24 += src_stride_rgb24 * 2;
1038     dst_y += dst_stride_y * 2;
1039     dst_u += dst_stride_u;
1040     dst_v += dst_stride_v;
1041   }
1042   if (height & 1) {
1043 #if defined(HAS_RGB24TOYROW_NEON)
1044     RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
1045     RGB24ToYRow(src_rgb24, dst_y, width);
1046 #else
1047     RGB24ToARGBRow(src_rgb24, row, width);
1048     ARGBToUVRow(row, 0, dst_u, dst_v, width);
1049     ARGBToYRow(row, dst_y, width);
1050 #endif
1051   }
1052 #if !defined(HAS_RGB24TOYROW_NEON)
1053   free_aligned_buffer_64(row);
1054 #endif
1055   return 0;
1056 }
1057
1058 // Convert RAW to I420.
1059 LIBYUV_API
1060 int RAWToI420(const uint8* src_raw, int src_stride_raw,
1061               uint8* dst_y, int dst_stride_y,
1062               uint8* dst_u, int dst_stride_u,
1063               uint8* dst_v, int dst_stride_v,
1064               int width, int height) {
1065   int y;
1066 #if defined(HAS_RAWTOYROW_NEON)
1067   void (*RAWToUVRow)(const uint8* src_raw, int src_stride_raw,
1068       uint8* dst_u, uint8* dst_v, int width) = RAWToUVRow_C;
1069   void (*RAWToYRow)(const uint8* src_raw, uint8* dst_y, int pix) =
1070       RAWToYRow_C;
1071 #else
1072   void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1073       RAWToARGBRow_C;
1074   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1075       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1076   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1077       ARGBToYRow_C;
1078   // Allocate 2 rows of ARGB.
1079   const int kRowSize = (width * 4 + 15) & ~15;
1080   align_buffer_64(row, kRowSize * 2);
1081 #endif
1082   if (!src_raw || !dst_y || !dst_u || !dst_v ||
1083       width <= 0 || height == 0) {
1084     return -1;
1085   }
1086   // Negative height means invert the image.
1087   if (height < 0) {
1088     height = -height;
1089     src_raw = src_raw + (height - 1) * src_stride_raw;
1090     src_stride_raw = -src_stride_raw;
1091   }
1092
1093 #if defined(HAS_RAWTOYROW_NEON)
1094   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
1095     RAWToYRow = RAWToYRow_Any_NEON;
1096     if (IS_ALIGNED(width, 8)) {
1097       RAWToYRow = RAWToYRow_NEON;
1098     }
1099     if (width >= 16) {
1100       RAWToUVRow = RAWToUVRow_Any_NEON;
1101       if (IS_ALIGNED(width, 16)) {
1102         RAWToUVRow = RAWToUVRow_NEON;
1103       }
1104     }
1105   }
1106 #else  // HAS_RAWTOYROW_NEON
1107
1108 #if defined(HAS_RAWTOARGBROW_SSSE3)
1109   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1110     RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
1111     if (IS_ALIGNED(width, 16)) {
1112       RAWToARGBRow = RAWToARGBRow_SSSE3;
1113     }
1114   }
1115 #endif
1116 #if defined(HAS_ARGBTOUVROW_SSSE3)
1117   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1118     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1119     if (IS_ALIGNED(width, 16)) {
1120       ARGBToUVRow = ARGBToUVRow_SSSE3;
1121     }
1122   }
1123 #endif
1124 #if defined(HAS_ARGBTOUVROW_SSSE3)
1125   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1126     ARGBToYRow = ARGBToYRow_Any_SSSE3;
1127     if (IS_ALIGNED(width, 16)) {
1128       ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1129       if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1130         ARGBToYRow = ARGBToYRow_SSSE3;
1131       }
1132     }
1133   }
1134 #endif  // HAS_ARGBTOUVROW_SSSE3
1135 #endif  // HAS_RAWTOYROW_NEON
1136
1137   for (y = 0; y < height - 1; y += 2) {
1138 #if defined(HAS_RAWTOYROW_NEON)
1139     RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width);
1140     RAWToYRow(src_raw, dst_y, width);
1141     RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
1142 #else
1143     RAWToARGBRow(src_raw, row, width);
1144     RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width);
1145     ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1146     ARGBToYRow(row, dst_y, width);
1147     ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1148 #endif
1149     src_raw += src_stride_raw * 2;
1150     dst_y += dst_stride_y * 2;
1151     dst_u += dst_stride_u;
1152     dst_v += dst_stride_v;
1153   }
1154   if (height & 1) {
1155 #if defined(HAS_RAWTOYROW_NEON)
1156     RAWToUVRow(src_raw, 0, dst_u, dst_v, width);
1157     RAWToYRow(src_raw, dst_y, width);
1158 #else
1159     RAWToARGBRow(src_raw, row, width);
1160     ARGBToUVRow(row, 0, dst_u, dst_v, width);
1161     ARGBToYRow(row, dst_y, width);
1162 #endif
1163   }
1164 #if !defined(HAS_RAWTOYROW_NEON)
1165   free_aligned_buffer_64(row);
1166 #endif
1167   return 0;
1168 }
1169
1170 // Convert RGB565 to I420.
1171 LIBYUV_API
1172 int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565,
1173                  uint8* dst_y, int dst_stride_y,
1174                  uint8* dst_u, int dst_stride_u,
1175                  uint8* dst_v, int dst_stride_v,
1176                  int width, int height) {
1177   int y;
1178 #if defined(HAS_RGB565TOYROW_NEON)
1179   void (*RGB565ToUVRow)(const uint8* src_rgb565, int src_stride_rgb565,
1180       uint8* dst_u, uint8* dst_v, int width) = RGB565ToUVRow_C;
1181   void (*RGB565ToYRow)(const uint8* src_rgb565, uint8* dst_y, int pix) =
1182       RGB565ToYRow_C;
1183 #else
1184   void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1185       RGB565ToARGBRow_C;
1186   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1187       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1188   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1189       ARGBToYRow_C;
1190   // Allocate 2 rows of ARGB.
1191   const int kRowSize = (width * 4 + 15) & ~15;
1192   align_buffer_64(row, kRowSize * 2);
1193 #endif
1194   if (!src_rgb565 || !dst_y || !dst_u || !dst_v ||
1195       width <= 0 || height == 0) {
1196     return -1;
1197   }
1198   // Negative height means invert the image.
1199   if (height < 0) {
1200     height = -height;
1201     src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
1202     src_stride_rgb565 = -src_stride_rgb565;
1203   }
1204
1205 #if defined(HAS_RGB565TOYROW_NEON)
1206   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
1207     RGB565ToYRow = RGB565ToYRow_Any_NEON;
1208     if (IS_ALIGNED(width, 8)) {
1209       RGB565ToYRow = RGB565ToYRow_NEON;
1210     }
1211     if (width >= 16) {
1212       RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
1213       if (IS_ALIGNED(width, 16)) {
1214         RGB565ToUVRow = RGB565ToUVRow_NEON;
1215       }
1216     }
1217   }
1218 #else  // HAS_RGB565TOYROW_NEON
1219
1220 #if defined(HAS_RGB565TOARGBROW_SSE2)
1221   if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
1222     RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
1223     if (IS_ALIGNED(width, 8)) {
1224       RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
1225     }
1226   }
1227 #endif
1228 #if defined(HAS_ARGBTOUVROW_SSSE3)
1229   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1230     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1231     if (IS_ALIGNED(width, 16)) {
1232       ARGBToUVRow = ARGBToUVRow_SSSE3;
1233     }
1234   }
1235 #endif
1236 #if defined(HAS_ARGBTOUVROW_SSSE3)
1237   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1238     ARGBToYRow = ARGBToYRow_Any_SSSE3;
1239     if (IS_ALIGNED(width, 16)) {
1240       ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1241       if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1242         ARGBToYRow = ARGBToYRow_SSSE3;
1243       }
1244     }
1245   }
1246 #endif  // HAS_ARGBTOUVROW_SSSE3
1247 #endif  // HAS_RGB565TOYROW_NEON
1248
1249   for (y = 0; y < height - 1; y += 2) {
1250 #if defined(HAS_RGB565TOYROW_NEON)
1251     RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width);
1252     RGB565ToYRow(src_rgb565, dst_y, width);
1253     RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
1254 #else
1255     RGB565ToARGBRow(src_rgb565, row, width);
1256     RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width);
1257     ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1258     ARGBToYRow(row, dst_y, width);
1259     ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1260 #endif
1261     src_rgb565 += src_stride_rgb565 * 2;
1262     dst_y += dst_stride_y * 2;
1263     dst_u += dst_stride_u;
1264     dst_v += dst_stride_v;
1265   }
1266   if (height & 1) {
1267 #if defined(HAS_RGB565TOYROW_NEON)
1268     RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width);
1269     RGB565ToYRow(src_rgb565, dst_y, width);
1270 #else
1271     RGB565ToARGBRow(src_rgb565, row, width);
1272     ARGBToUVRow(row, 0, dst_u, dst_v, width);
1273     ARGBToYRow(row, dst_y, width);
1274 #endif
1275   }
1276 #if !defined(HAS_RGB565TOYROW_NEON)
1277   free_aligned_buffer_64(row);
1278 #endif
1279   return 0;
1280 }
1281
1282 // Convert ARGB1555 to I420.
1283 LIBYUV_API
1284 int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555,
1285                    uint8* dst_y, int dst_stride_y,
1286                    uint8* dst_u, int dst_stride_u,
1287                    uint8* dst_v, int dst_stride_v,
1288                    int width, int height) {
1289   int y;
1290 #if defined(HAS_ARGB1555TOYROW_NEON)
1291   void (*ARGB1555ToUVRow)(const uint8* src_argb1555, int src_stride_argb1555,
1292       uint8* dst_u, uint8* dst_v, int width) = ARGB1555ToUVRow_C;
1293   void (*ARGB1555ToYRow)(const uint8* src_argb1555, uint8* dst_y, int pix) =
1294       ARGB1555ToYRow_C;
1295 #else
1296   void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1297       ARGB1555ToARGBRow_C;
1298   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1299       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1300   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1301       ARGBToYRow_C;
1302   // Allocate 2 rows of ARGB.
1303   const int kRowSize = (width * 4 + 15) & ~15;
1304   align_buffer_64(row, kRowSize * 2);
1305 #endif
1306   if (!src_argb1555 || !dst_y || !dst_u || !dst_v ||
1307       width <= 0 || height == 0) {
1308     return -1;
1309   }
1310   // Negative height means invert the image.
1311   if (height < 0) {
1312     height = -height;
1313     src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
1314     src_stride_argb1555 = -src_stride_argb1555;
1315   }
1316
1317 #if defined(HAS_ARGB1555TOYROW_NEON)
1318   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
1319     ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
1320     if (IS_ALIGNED(width, 8)) {
1321       ARGB1555ToYRow = ARGB1555ToYRow_NEON;
1322     }
1323     if (width >= 16) {
1324       ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
1325       if (IS_ALIGNED(width, 16)) {
1326         ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
1327       }
1328     }
1329   }
1330 #else  // HAS_ARGB1555TOYROW_NEON
1331
1332 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
1333   if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
1334     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
1335     if (IS_ALIGNED(width, 8)) {
1336       ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
1337     }
1338   }
1339 #endif
1340 #if defined(HAS_ARGBTOUVROW_SSSE3)
1341   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1342     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1343     if (IS_ALIGNED(width, 16)) {
1344       ARGBToUVRow = ARGBToUVRow_SSSE3;
1345     }
1346   }
1347 #endif
1348 #if defined(HAS_ARGBTOUVROW_SSSE3)
1349   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1350     ARGBToYRow = ARGBToYRow_Any_SSSE3;
1351     if (IS_ALIGNED(width, 16)) {
1352       ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1353       if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1354         ARGBToYRow = ARGBToYRow_SSSE3;
1355       }
1356     }
1357   }
1358 #endif  // HAS_ARGBTOUVROW_SSSE3
1359 #endif  // HAS_ARGB1555TOYROW_NEON
1360
1361   for (y = 0; y < height - 1; y += 2) {
1362 #if defined(HAS_ARGB1555TOYROW_NEON)
1363     ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width);
1364     ARGB1555ToYRow(src_argb1555, dst_y, width);
1365     ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y,
1366                    width);
1367 #else
1368     ARGB1555ToARGBRow(src_argb1555, row, width);
1369     ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize,
1370                       width);
1371     ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1372     ARGBToYRow(row, dst_y, width);
1373     ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1374 #endif
1375     src_argb1555 += src_stride_argb1555 * 2;
1376     dst_y += dst_stride_y * 2;
1377     dst_u += dst_stride_u;
1378     dst_v += dst_stride_v;
1379   }
1380   if (height & 1) {
1381 #if defined(HAS_ARGB1555TOYROW_NEON)
1382     ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width);
1383     ARGB1555ToYRow(src_argb1555, dst_y, width);
1384 #else
1385     ARGB1555ToARGBRow(src_argb1555, row, width);
1386     ARGBToUVRow(row, 0, dst_u, dst_v, width);
1387     ARGBToYRow(row, dst_y, width);
1388 #endif
1389   }
1390 #if !defined(HAS_ARGB1555TOYROW_NEON)
1391   free_aligned_buffer_64(row);
1392 #endif
1393   return 0;
1394 }
1395
1396 // Convert ARGB4444 to I420.
1397 LIBYUV_API
1398 int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444,
1399                    uint8* dst_y, int dst_stride_y,
1400                    uint8* dst_u, int dst_stride_u,
1401                    uint8* dst_v, int dst_stride_v,
1402                    int width, int height) {
1403   int y;
1404 #if defined(HAS_ARGB4444TOYROW_NEON)
1405   void (*ARGB4444ToUVRow)(const uint8* src_argb4444, int src_stride_argb4444,
1406       uint8* dst_u, uint8* dst_v, int width) = ARGB4444ToUVRow_C;
1407   void (*ARGB4444ToYRow)(const uint8* src_argb4444, uint8* dst_y, int pix) =
1408       ARGB4444ToYRow_C;
1409 #else
1410   void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1411       ARGB4444ToARGBRow_C;
1412   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1413       uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1414   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1415       ARGBToYRow_C;
1416   // Allocate 2 rows of ARGB.
1417   const int kRowSize = (width * 4 + 15) & ~15;
1418   align_buffer_64(row, kRowSize * 2);
1419 #endif
1420   if (!src_argb4444 || !dst_y || !dst_u || !dst_v ||
1421       width <= 0 || height == 0) {
1422     return -1;
1423   }
1424   // Negative height means invert the image.
1425   if (height < 0) {
1426     height = -height;
1427     src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
1428     src_stride_argb4444 = -src_stride_argb4444;
1429   }
1430
1431 #if defined(HAS_ARGB4444TOYROW_NEON)
1432   if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
1433     ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
1434     if (IS_ALIGNED(width, 8)) {
1435       ARGB4444ToYRow = ARGB4444ToYRow_NEON;
1436     }
1437     if (width >= 16) {
1438       ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
1439       if (IS_ALIGNED(width, 16)) {
1440         ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
1441       }
1442     }
1443   }
1444 #else  // HAS_ARGB4444TOYROW_NEON
1445
1446 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
1447   if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
1448     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
1449     if (IS_ALIGNED(width, 8)) {
1450       ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
1451     }
1452   }
1453 #endif
1454 #if defined(HAS_ARGBTOUVROW_SSSE3)
1455   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1456     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1457     if (IS_ALIGNED(width, 16)) {
1458       ARGBToUVRow = ARGBToUVRow_SSSE3;
1459     }
1460   }
1461 #endif
1462 #if defined(HAS_ARGBTOUVROW_SSSE3)
1463   if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1464     ARGBToYRow = ARGBToYRow_Any_SSSE3;
1465     if (IS_ALIGNED(width, 16)) {
1466       ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1467       if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1468         ARGBToYRow = ARGBToYRow_SSSE3;
1469       }
1470     }
1471   }
1472 #endif  // HAS_ARGBTOUVROW_SSSE3
1473 #endif  // HAS_ARGB4444TOYROW_NEON
1474
1475   for (y = 0; y < height - 1; y += 2) {
1476 #if defined(HAS_ARGB4444TOYROW_NEON)
1477     ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width);
1478     ARGB4444ToYRow(src_argb4444, dst_y, width);
1479     ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y,
1480                    width);
1481 #else
1482     ARGB4444ToARGBRow(src_argb4444, row, width);
1483     ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize,
1484                       width);
1485     ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1486     ARGBToYRow(row, dst_y, width);
1487     ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1488 #endif
1489     src_argb4444 += src_stride_argb4444 * 2;
1490     dst_y += dst_stride_y * 2;
1491     dst_u += dst_stride_u;
1492     dst_v += dst_stride_v;
1493   }
1494   if (height & 1) {
1495 #if defined(HAS_ARGB4444TOYROW_NEON)
1496     ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width);
1497     ARGB4444ToYRow(src_argb4444, dst_y, width);
1498 #else
1499     ARGB4444ToARGBRow(src_argb4444, row, width);
1500     ARGBToUVRow(row, 0, dst_u, dst_v, width);
1501     ARGBToYRow(row, dst_y, width);
1502 #endif
1503   }
1504 #if !defined(HAS_ARGB4444TOYROW_NEON)
1505   free_aligned_buffer_64(row);
1506 #endif
1507   return 0;
1508 }
1509
1510 #ifdef __cplusplus
1511 }  // extern "C"
1512 }  // namespace libyuv
1513 #endif