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