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