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