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