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_argb.h"
12 
13 #include "libyuv/cpu_id.h"
14 #ifdef HAVE_JPEG
15 #include "libyuv/mjpeg_decoder.h"
16 #endif
17 #include "libyuv/planar_functions.h"  // For CopyPlane and ARGBShuffle.
18 #include "libyuv/rotate_argb.h"
19 #include "libyuv/row.h"
20 #include "libyuv/video_common.h"
21 
22 #ifdef __cplusplus
23 namespace libyuv {
24 extern "C" {
25 #endif
26 
27 // Copy ARGB with optional flipping
28 LIBYUV_API
ARGBCopy(const uint8_t * src_argb,int src_stride_argb,uint8_t * dst_argb,int dst_stride_argb,int width,int height)29 int ARGBCopy(const uint8_t* src_argb,
30              int src_stride_argb,
31              uint8_t* dst_argb,
32              int dst_stride_argb,
33              int width,
34              int height) {
35   if (!src_argb || !dst_argb || width <= 0 || height == 0) {
36     return -1;
37   }
38   // Negative height means invert the image.
39   if (height < 0) {
40     height = -height;
41     src_argb = src_argb + (height - 1) * src_stride_argb;
42     src_stride_argb = -src_stride_argb;
43   }
44 
45   CopyPlane(src_argb, src_stride_argb, dst_argb, dst_stride_argb, width * 4,
46             height);
47   return 0;
48 }
49 
50 // Convert I420 to ARGB with matrix
I420ToARGBMatrix(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_argb,int dst_stride_argb,const struct YuvConstants * yuvconstants,int width,int height)51 static int I420ToARGBMatrix(const uint8_t* src_y,
52                             int src_stride_y,
53                             const uint8_t* src_u,
54                             int src_stride_u,
55                             const uint8_t* src_v,
56                             int src_stride_v,
57                             uint8_t* dst_argb,
58                             int dst_stride_argb,
59                             const struct YuvConstants* yuvconstants,
60                             int width,
61                             int height) {
62   int y;
63   void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
64                         const uint8_t* v_buf, uint8_t* rgb_buf,
65                         const struct YuvConstants* yuvconstants, int width) =
66       I422ToARGBRow_C;
67   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
68     return -1;
69   }
70   // Negative height means invert the image.
71   if (height < 0) {
72     height = -height;
73     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
74     dst_stride_argb = -dst_stride_argb;
75   }
76 #if defined(HAS_I422TOARGBROW_SSSE3)
77   if (TestCpuFlag(kCpuHasSSSE3)) {
78     I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
79     if (IS_ALIGNED(width, 8)) {
80       I422ToARGBRow = I422ToARGBRow_SSSE3;
81     }
82   }
83 #endif
84 #if defined(HAS_I422TOARGBROW_AVX2)
85   if (TestCpuFlag(kCpuHasAVX2)) {
86     I422ToARGBRow = I422ToARGBRow_Any_AVX2;
87     if (IS_ALIGNED(width, 16)) {
88       I422ToARGBRow = I422ToARGBRow_AVX2;
89     }
90   }
91 #endif
92 #if defined(HAS_I422TOARGBROW_NEON)
93   if (TestCpuFlag(kCpuHasNEON)) {
94     I422ToARGBRow = I422ToARGBRow_Any_NEON;
95     if (IS_ALIGNED(width, 8)) {
96       I422ToARGBRow = I422ToARGBRow_NEON;
97     }
98   }
99 #endif
100 #if defined(HAS_I422TOARGBROW_MSA)
101   if (TestCpuFlag(kCpuHasMSA)) {
102     I422ToARGBRow = I422ToARGBRow_Any_MSA;
103     if (IS_ALIGNED(width, 8)) {
104       I422ToARGBRow = I422ToARGBRow_MSA;
105     }
106   }
107 #endif
108 
109   for (y = 0; y < height; ++y) {
110     I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
111     dst_argb += dst_stride_argb;
112     src_y += src_stride_y;
113     if (y & 1) {
114       src_u += src_stride_u;
115       src_v += src_stride_v;
116     }
117   }
118   return 0;
119 }
120 
121 // Convert I420 to ARGB.
122 LIBYUV_API
I420ToARGB(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_argb,int dst_stride_argb,int width,int height)123 int I420ToARGB(const uint8_t* src_y,
124                int src_stride_y,
125                const uint8_t* src_u,
126                int src_stride_u,
127                const uint8_t* src_v,
128                int src_stride_v,
129                uint8_t* dst_argb,
130                int dst_stride_argb,
131                int width,
132                int height) {
133   return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
134                           src_stride_v, dst_argb, dst_stride_argb,
135                           &kYuvI601Constants, width, height);
136 }
137 
138 // Convert I420 to ABGR.
139 LIBYUV_API
I420ToABGR(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_abgr,int dst_stride_abgr,int width,int height)140 int I420ToABGR(const uint8_t* src_y,
141                int src_stride_y,
142                const uint8_t* src_u,
143                int src_stride_u,
144                const uint8_t* src_v,
145                int src_stride_v,
146                uint8_t* dst_abgr,
147                int dst_stride_abgr,
148                int width,
149                int height) {
150   return I420ToARGBMatrix(src_y, src_stride_y, src_v,
151                           src_stride_v,  // Swap U and V
152                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
153                           &kYvuI601Constants,  // Use Yvu matrix
154                           width, height);
155 }
156 
157 // Convert J420 to ARGB.
158 LIBYUV_API
J420ToARGB(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_argb,int dst_stride_argb,int width,int height)159 int J420ToARGB(const uint8_t* src_y,
160                int src_stride_y,
161                const uint8_t* src_u,
162                int src_stride_u,
163                const uint8_t* src_v,
164                int src_stride_v,
165                uint8_t* dst_argb,
166                int dst_stride_argb,
167                int width,
168                int height) {
169   return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
170                           src_stride_v, dst_argb, dst_stride_argb,
171                           &kYuvJPEGConstants, width, height);
172 }
173 
174 // Convert J420 to ABGR.
175 LIBYUV_API
J420ToABGR(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_abgr,int dst_stride_abgr,int width,int height)176 int J420ToABGR(const uint8_t* src_y,
177                int src_stride_y,
178                const uint8_t* src_u,
179                int src_stride_u,
180                const uint8_t* src_v,
181                int src_stride_v,
182                uint8_t* dst_abgr,
183                int dst_stride_abgr,
184                int width,
185                int height) {
186   return I420ToARGBMatrix(src_y, src_stride_y, src_v,
187                           src_stride_v,  // Swap U and V
188                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
189                           &kYvuJPEGConstants,  // Use Yvu matrix
190                           width, height);
191 }
192 
193 // Convert H420 to ARGB.
194 LIBYUV_API
H420ToARGB(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_argb,int dst_stride_argb,int width,int height)195 int H420ToARGB(const uint8_t* src_y,
196                int src_stride_y,
197                const uint8_t* src_u,
198                int src_stride_u,
199                const uint8_t* src_v,
200                int src_stride_v,
201                uint8_t* dst_argb,
202                int dst_stride_argb,
203                int width,
204                int height) {
205   return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
206                           src_stride_v, dst_argb, dst_stride_argb,
207                           &kYuvH709Constants, width, height);
208 }
209 
210 // Convert H420 to ABGR.
211 LIBYUV_API
H420ToABGR(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_abgr,int dst_stride_abgr,int width,int height)212 int H420ToABGR(const uint8_t* src_y,
213                int src_stride_y,
214                const uint8_t* src_u,
215                int src_stride_u,
216                const uint8_t* src_v,
217                int src_stride_v,
218                uint8_t* dst_abgr,
219                int dst_stride_abgr,
220                int width,
221                int height) {
222   return I420ToARGBMatrix(src_y, src_stride_y, src_v,
223                           src_stride_v,  // Swap U and V
224                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
225                           &kYvuH709Constants,  // Use Yvu matrix
226                           width, height);
227 }
228 
229 // Convert I422 to ARGB with matrix
I422ToARGBMatrix(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_argb,int dst_stride_argb,const struct YuvConstants * yuvconstants,int width,int height)230 static int I422ToARGBMatrix(const uint8_t* src_y,
231                             int src_stride_y,
232                             const uint8_t* src_u,
233                             int src_stride_u,
234                             const uint8_t* src_v,
235                             int src_stride_v,
236                             uint8_t* dst_argb,
237                             int dst_stride_argb,
238                             const struct YuvConstants* yuvconstants,
239                             int width,
240                             int height) {
241   int y;
242   void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
243                         const uint8_t* v_buf, uint8_t* rgb_buf,
244                         const struct YuvConstants* yuvconstants, int width) =
245       I422ToARGBRow_C;
246   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
247     return -1;
248   }
249   // Negative height means invert the image.
250   if (height < 0) {
251     height = -height;
252     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
253     dst_stride_argb = -dst_stride_argb;
254   }
255   // Coalesce rows.
256   if (src_stride_y == width && src_stride_u * 2 == width &&
257       src_stride_v * 2 == width && dst_stride_argb == width * 4) {
258     width *= height;
259     height = 1;
260     src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
261   }
262 #if defined(HAS_I422TOARGBROW_SSSE3)
263   if (TestCpuFlag(kCpuHasSSSE3)) {
264     I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
265     if (IS_ALIGNED(width, 8)) {
266       I422ToARGBRow = I422ToARGBRow_SSSE3;
267     }
268   }
269 #endif
270 #if defined(HAS_I422TOARGBROW_AVX2)
271   if (TestCpuFlag(kCpuHasAVX2)) {
272     I422ToARGBRow = I422ToARGBRow_Any_AVX2;
273     if (IS_ALIGNED(width, 16)) {
274       I422ToARGBRow = I422ToARGBRow_AVX2;
275     }
276   }
277 #endif
278 #if defined(HAS_I422TOARGBROW_NEON)
279   if (TestCpuFlag(kCpuHasNEON)) {
280     I422ToARGBRow = I422ToARGBRow_Any_NEON;
281     if (IS_ALIGNED(width, 8)) {
282       I422ToARGBRow = I422ToARGBRow_NEON;
283     }
284   }
285 #endif
286 #if defined(HAS_I422TOARGBROW_MSA)
287   if (TestCpuFlag(kCpuHasMSA)) {
288     I422ToARGBRow = I422ToARGBRow_Any_MSA;
289     if (IS_ALIGNED(width, 8)) {
290       I422ToARGBRow = I422ToARGBRow_MSA;
291     }
292   }
293 #endif
294 
295   for (y = 0; y < height; ++y) {
296     I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
297     dst_argb += dst_stride_argb;
298     src_y += src_stride_y;
299     src_u += src_stride_u;
300     src_v += src_stride_v;
301   }
302   return 0;
303 }
304 
305 // Convert I422 to ARGB.
306 LIBYUV_API
I422ToARGB(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_argb,int dst_stride_argb,int width,int height)307 int I422ToARGB(const uint8_t* src_y,
308                int src_stride_y,
309                const uint8_t* src_u,
310                int src_stride_u,
311                const uint8_t* src_v,
312                int src_stride_v,
313                uint8_t* dst_argb,
314                int dst_stride_argb,
315                int width,
316                int height) {
317   return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
318                           src_stride_v, dst_argb, dst_stride_argb,
319                           &kYuvI601Constants, width, height);
320 }
321 
322 // Convert I422 to ABGR.
323 LIBYUV_API
I422ToABGR(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_abgr,int dst_stride_abgr,int width,int height)324 int I422ToABGR(const uint8_t* src_y,
325                int src_stride_y,
326                const uint8_t* src_u,
327                int src_stride_u,
328                const uint8_t* src_v,
329                int src_stride_v,
330                uint8_t* dst_abgr,
331                int dst_stride_abgr,
332                int width,
333                int height) {
334   return I422ToARGBMatrix(src_y, src_stride_y, src_v,
335                           src_stride_v,  // Swap U and V
336                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
337                           &kYvuI601Constants,  // Use Yvu matrix
338                           width, height);
339 }
340 
341 // Convert J422 to ARGB.
342 LIBYUV_API
J422ToARGB(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_argb,int dst_stride_argb,int width,int height)343 int J422ToARGB(const uint8_t* src_y,
344                int src_stride_y,
345                const uint8_t* src_u,
346                int src_stride_u,
347                const uint8_t* src_v,
348                int src_stride_v,
349                uint8_t* dst_argb,
350                int dst_stride_argb,
351                int width,
352                int height) {
353   return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
354                           src_stride_v, dst_argb, dst_stride_argb,
355                           &kYuvJPEGConstants, width, height);
356 }
357 
358 // Convert J422 to ABGR.
359 LIBYUV_API
J422ToABGR(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_abgr,int dst_stride_abgr,int width,int height)360 int J422ToABGR(const uint8_t* src_y,
361                int src_stride_y,
362                const uint8_t* src_u,
363                int src_stride_u,
364                const uint8_t* src_v,
365                int src_stride_v,
366                uint8_t* dst_abgr,
367                int dst_stride_abgr,
368                int width,
369                int height) {
370   return I422ToARGBMatrix(src_y, src_stride_y, src_v,
371                           src_stride_v,  // Swap U and V
372                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
373                           &kYvuJPEGConstants,  // Use Yvu matrix
374                           width, height);
375 }
376 
377 // Convert H422 to ARGB.
378 LIBYUV_API
H422ToARGB(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_argb,int dst_stride_argb,int width,int height)379 int H422ToARGB(const uint8_t* src_y,
380                int src_stride_y,
381                const uint8_t* src_u,
382                int src_stride_u,
383                const uint8_t* src_v,
384                int src_stride_v,
385                uint8_t* dst_argb,
386                int dst_stride_argb,
387                int width,
388                int height) {
389   return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
390                           src_stride_v, dst_argb, dst_stride_argb,
391                           &kYuvH709Constants, width, height);
392 }
393 
394 // Convert H422 to ABGR.
395 LIBYUV_API
H422ToABGR(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_abgr,int dst_stride_abgr,int width,int height)396 int H422ToABGR(const uint8_t* src_y,
397                int src_stride_y,
398                const uint8_t* src_u,
399                int src_stride_u,
400                const uint8_t* src_v,
401                int src_stride_v,
402                uint8_t* dst_abgr,
403                int dst_stride_abgr,
404                int width,
405                int height) {
406   return I422ToARGBMatrix(src_y, src_stride_y, src_v,
407                           src_stride_v,  // Swap U and V
408                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
409                           &kYvuH709Constants,  // Use Yvu matrix
410                           width, height);
411 }
412 
413 // Convert 10 bit YUV to ARGB with matrix
414 // TODO(fbarchard): Consider passing scale multiplier to I210ToARGB to
415 // multiply 10 bit yuv into high bits to allow any number of bits.
I010ToAR30Matrix(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_ar30,int dst_stride_ar30,const struct YuvConstants * yuvconstants,int width,int height)416 static int I010ToAR30Matrix(const uint16_t* src_y,
417                             int src_stride_y,
418                             const uint16_t* src_u,
419                             int src_stride_u,
420                             const uint16_t* src_v,
421                             int src_stride_v,
422                             uint8_t* dst_ar30,
423                             int dst_stride_ar30,
424                             const struct YuvConstants* yuvconstants,
425                             int width,
426                             int height) {
427   int y;
428   void (*I210ToAR30Row)(const uint16_t* y_buf, const uint16_t* u_buf,
429                         const uint16_t* v_buf, uint8_t* rgb_buf,
430                         const struct YuvConstants* yuvconstants, int width) =
431       I210ToAR30Row_C;
432   if (!src_y || !src_u || !src_v || !dst_ar30 || width <= 0 || height == 0) {
433     return -1;
434   }
435   // Negative height means invert the image.
436   if (height < 0) {
437     height = -height;
438     dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30;
439     dst_stride_ar30 = -dst_stride_ar30;
440   }
441 #if defined(HAS_I210TOAR30ROW_SSSE3)
442   if (TestCpuFlag(kCpuHasSSSE3)) {
443     I210ToAR30Row = I210ToAR30Row_Any_SSSE3;
444     if (IS_ALIGNED(width, 8)) {
445       I210ToAR30Row = I210ToAR30Row_SSSE3;
446     }
447   }
448 #endif
449 #if defined(HAS_I210TOAR30ROW_AVX2)
450   if (TestCpuFlag(kCpuHasAVX2)) {
451     I210ToAR30Row = I210ToAR30Row_Any_AVX2;
452     if (IS_ALIGNED(width, 16)) {
453       I210ToAR30Row = I210ToAR30Row_AVX2;
454     }
455   }
456 #endif
457   for (y = 0; y < height; ++y) {
458     I210ToAR30Row(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
459     dst_ar30 += dst_stride_ar30;
460     src_y += src_stride_y;
461     if (y & 1) {
462       src_u += src_stride_u;
463       src_v += src_stride_v;
464     }
465   }
466   return 0;
467 }
468 
469 // Convert I010 to AR30.
470 LIBYUV_API
I010ToAR30(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_ar30,int dst_stride_ar30,int width,int height)471 int I010ToAR30(const uint16_t* src_y,
472                int src_stride_y,
473                const uint16_t* src_u,
474                int src_stride_u,
475                const uint16_t* src_v,
476                int src_stride_v,
477                uint8_t* dst_ar30,
478                int dst_stride_ar30,
479                int width,
480                int height) {
481   return I010ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
482                           src_stride_v, dst_ar30, dst_stride_ar30,
483                           &kYuvI601Constants, width, height);
484 }
485 
486 // Convert H010 to AR30.
487 LIBYUV_API
H010ToAR30(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_ar30,int dst_stride_ar30,int width,int height)488 int H010ToAR30(const uint16_t* src_y,
489                int src_stride_y,
490                const uint16_t* src_u,
491                int src_stride_u,
492                const uint16_t* src_v,
493                int src_stride_v,
494                uint8_t* dst_ar30,
495                int dst_stride_ar30,
496                int width,
497                int height) {
498   return I010ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
499                           src_stride_v, dst_ar30, dst_stride_ar30,
500                           &kYuvH709Constants, width, height);
501 }
502 
503 // Convert I010 to AB30.
504 LIBYUV_API
I010ToAB30(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_ab30,int dst_stride_ab30,int width,int height)505 int I010ToAB30(const uint16_t* src_y,
506                int src_stride_y,
507                const uint16_t* src_u,
508                int src_stride_u,
509                const uint16_t* src_v,
510                int src_stride_v,
511                uint8_t* dst_ab30,
512                int dst_stride_ab30,
513                int width,
514                int height) {
515   return I010ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
516                           src_stride_u, dst_ab30, dst_stride_ab30,
517                           &kYvuI601Constants, width, height);
518 }
519 
520 // Convert H010 to AB30.
521 LIBYUV_API
H010ToAB30(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_ab30,int dst_stride_ab30,int width,int height)522 int H010ToAB30(const uint16_t* src_y,
523                int src_stride_y,
524                const uint16_t* src_u,
525                int src_stride_u,
526                const uint16_t* src_v,
527                int src_stride_v,
528                uint8_t* dst_ab30,
529                int dst_stride_ab30,
530                int width,
531                int height) {
532   return I010ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
533                           src_stride_u, dst_ab30, dst_stride_ab30,
534                           &kYvuH709Constants, width, height);
535 }
536 
537 // Convert 10 bit YUV to ARGB with matrix
I010ToARGBMatrix(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_argb,int dst_stride_argb,const struct YuvConstants * yuvconstants,int width,int height)538 static int I010ToARGBMatrix(const uint16_t* src_y,
539                             int src_stride_y,
540                             const uint16_t* src_u,
541                             int src_stride_u,
542                             const uint16_t* src_v,
543                             int src_stride_v,
544                             uint8_t* dst_argb,
545                             int dst_stride_argb,
546                             const struct YuvConstants* yuvconstants,
547                             int width,
548                             int height) {
549   int y;
550   void (*I210ToARGBRow)(const uint16_t* y_buf, const uint16_t* u_buf,
551                         const uint16_t* v_buf, uint8_t* rgb_buf,
552                         const struct YuvConstants* yuvconstants, int width) =
553       I210ToARGBRow_C;
554   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
555     return -1;
556   }
557   // Negative height means invert the image.
558   if (height < 0) {
559     height = -height;
560     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
561     dst_stride_argb = -dst_stride_argb;
562   }
563 #if defined(HAS_I210TOARGBROW_SSSE3)
564   if (TestCpuFlag(kCpuHasSSSE3)) {
565     I210ToARGBRow = I210ToARGBRow_Any_SSSE3;
566     if (IS_ALIGNED(width, 8)) {
567       I210ToARGBRow = I210ToARGBRow_SSSE3;
568     }
569   }
570 #endif
571 #if defined(HAS_I210TOARGBROW_AVX2)
572   if (TestCpuFlag(kCpuHasAVX2)) {
573     I210ToARGBRow = I210ToARGBRow_Any_AVX2;
574     if (IS_ALIGNED(width, 16)) {
575       I210ToARGBRow = I210ToARGBRow_AVX2;
576     }
577   }
578 #endif
579   for (y = 0; y < height; ++y) {
580     I210ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
581     dst_argb += dst_stride_argb;
582     src_y += src_stride_y;
583     if (y & 1) {
584       src_u += src_stride_u;
585       src_v += src_stride_v;
586     }
587   }
588   return 0;
589 }
590 
591 // Convert I010 to ARGB.
592 LIBYUV_API
I010ToARGB(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_argb,int dst_stride_argb,int width,int height)593 int I010ToARGB(const uint16_t* src_y,
594                int src_stride_y,
595                const uint16_t* src_u,
596                int src_stride_u,
597                const uint16_t* src_v,
598                int src_stride_v,
599                uint8_t* dst_argb,
600                int dst_stride_argb,
601                int width,
602                int height) {
603   return I010ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
604                           src_stride_v, dst_argb, dst_stride_argb,
605                           &kYuvI601Constants, width, height);
606 }
607 
608 // Convert I010 to ABGR.
609 LIBYUV_API
I010ToABGR(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_abgr,int dst_stride_abgr,int width,int height)610 int I010ToABGR(const uint16_t* src_y,
611                int src_stride_y,
612                const uint16_t* src_u,
613                int src_stride_u,
614                const uint16_t* src_v,
615                int src_stride_v,
616                uint8_t* dst_abgr,
617                int dst_stride_abgr,
618                int width,
619                int height) {
620   return I010ToARGBMatrix(src_y, src_stride_y, src_v,
621                           src_stride_v,  // Swap U and V
622                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
623                           &kYvuI601Constants,  // Use Yvu matrix
624                           width, height);
625 }
626 
627 // Convert H010 to ARGB.
628 LIBYUV_API
H010ToARGB(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_argb,int dst_stride_argb,int width,int height)629 int H010ToARGB(const uint16_t* src_y,
630                int src_stride_y,
631                const uint16_t* src_u,
632                int src_stride_u,
633                const uint16_t* src_v,
634                int src_stride_v,
635                uint8_t* dst_argb,
636                int dst_stride_argb,
637                int width,
638                int height) {
639   return I010ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
640                           src_stride_v, dst_argb, dst_stride_argb,
641                           &kYuvH709Constants, width, height);
642 }
643 
644 // Convert H010 to ABGR.
645 LIBYUV_API
H010ToABGR(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_abgr,int dst_stride_abgr,int width,int height)646 int H010ToABGR(const uint16_t* src_y,
647                int src_stride_y,
648                const uint16_t* src_u,
649                int src_stride_u,
650                const uint16_t* src_v,
651                int src_stride_v,
652                uint8_t* dst_abgr,
653                int dst_stride_abgr,
654                int width,
655                int height) {
656   return I010ToARGBMatrix(src_y, src_stride_y, src_v,
657                           src_stride_v,  // Swap U and V
658                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
659                           &kYvuH709Constants,  // Use Yvu matrix
660                           width, height);
661 }
662 
663 // Convert I444 to ARGB with matrix
I444ToARGBMatrix(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_argb,int dst_stride_argb,const struct YuvConstants * yuvconstants,int width,int height)664 static int I444ToARGBMatrix(const uint8_t* src_y,
665                             int src_stride_y,
666                             const uint8_t* src_u,
667                             int src_stride_u,
668                             const uint8_t* src_v,
669                             int src_stride_v,
670                             uint8_t* dst_argb,
671                             int dst_stride_argb,
672                             const struct YuvConstants* yuvconstants,
673                             int width,
674                             int height) {
675   int y;
676   void (*I444ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
677                         const uint8_t* v_buf, uint8_t* rgb_buf,
678                         const struct YuvConstants* yuvconstants, int width) =
679       I444ToARGBRow_C;
680   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
681     return -1;
682   }
683   // Negative height means invert the image.
684   if (height < 0) {
685     height = -height;
686     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
687     dst_stride_argb = -dst_stride_argb;
688   }
689   // Coalesce rows.
690   if (src_stride_y == width && src_stride_u == width && src_stride_v == width &&
691       dst_stride_argb == width * 4) {
692     width *= height;
693     height = 1;
694     src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
695   }
696 #if defined(HAS_I444TOARGBROW_SSSE3)
697   if (TestCpuFlag(kCpuHasSSSE3)) {
698     I444ToARGBRow = I444ToARGBRow_Any_SSSE3;
699     if (IS_ALIGNED(width, 8)) {
700       I444ToARGBRow = I444ToARGBRow_SSSE3;
701     }
702   }
703 #endif
704 #if defined(HAS_I444TOARGBROW_AVX2)
705   if (TestCpuFlag(kCpuHasAVX2)) {
706     I444ToARGBRow = I444ToARGBRow_Any_AVX2;
707     if (IS_ALIGNED(width, 16)) {
708       I444ToARGBRow = I444ToARGBRow_AVX2;
709     }
710   }
711 #endif
712 #if defined(HAS_I444TOARGBROW_NEON)
713   if (TestCpuFlag(kCpuHasNEON)) {
714     I444ToARGBRow = I444ToARGBRow_Any_NEON;
715     if (IS_ALIGNED(width, 8)) {
716       I444ToARGBRow = I444ToARGBRow_NEON;
717     }
718   }
719 #endif
720 #if defined(HAS_I444TOARGBROW_MSA)
721   if (TestCpuFlag(kCpuHasMSA)) {
722     I444ToARGBRow = I444ToARGBRow_Any_MSA;
723     if (IS_ALIGNED(width, 8)) {
724       I444ToARGBRow = I444ToARGBRow_MSA;
725     }
726   }
727 #endif
728 
729   for (y = 0; y < height; ++y) {
730     I444ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
731     dst_argb += dst_stride_argb;
732     src_y += src_stride_y;
733     src_u += src_stride_u;
734     src_v += src_stride_v;
735   }
736   return 0;
737 }
738 
739 // Convert I444 to ARGB.
740 LIBYUV_API
I444ToARGB(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_argb,int dst_stride_argb,int width,int height)741 int I444ToARGB(const uint8_t* src_y,
742                int src_stride_y,
743                const uint8_t* src_u,
744                int src_stride_u,
745                const uint8_t* src_v,
746                int src_stride_v,
747                uint8_t* dst_argb,
748                int dst_stride_argb,
749                int width,
750                int height) {
751   return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
752                           src_stride_v, dst_argb, dst_stride_argb,
753                           &kYuvI601Constants, width, height);
754 }
755 
756 // Convert I444 to ABGR.
757 LIBYUV_API
I444ToABGR(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_abgr,int dst_stride_abgr,int width,int height)758 int I444ToABGR(const uint8_t* src_y,
759                int src_stride_y,
760                const uint8_t* src_u,
761                int src_stride_u,
762                const uint8_t* src_v,
763                int src_stride_v,
764                uint8_t* dst_abgr,
765                int dst_stride_abgr,
766                int width,
767                int height) {
768   return I444ToARGBMatrix(src_y, src_stride_y, src_v,
769                           src_stride_v,  // Swap U and V
770                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
771                           &kYvuI601Constants,  // Use Yvu matrix
772                           width, height);
773 }
774 
775 // Convert J444 to ARGB.
776 LIBYUV_API
J444ToARGB(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_argb,int dst_stride_argb,int width,int height)777 int J444ToARGB(const uint8_t* src_y,
778                int src_stride_y,
779                const uint8_t* src_u,
780                int src_stride_u,
781                const uint8_t* src_v,
782                int src_stride_v,
783                uint8_t* dst_argb,
784                int dst_stride_argb,
785                int width,
786                int height) {
787   return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
788                           src_stride_v, dst_argb, dst_stride_argb,
789                           &kYuvJPEGConstants, width, height);
790 }
791 
792 // Convert I420 with Alpha to preattenuated ARGB.
I420AlphaToARGBMatrix(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,const uint8_t * src_a,int src_stride_a,uint8_t * dst_argb,int dst_stride_argb,const struct YuvConstants * yuvconstants,int width,int height,int attenuate)793 static int I420AlphaToARGBMatrix(const uint8_t* src_y,
794                                  int src_stride_y,
795                                  const uint8_t* src_u,
796                                  int src_stride_u,
797                                  const uint8_t* src_v,
798                                  int src_stride_v,
799                                  const uint8_t* src_a,
800                                  int src_stride_a,
801                                  uint8_t* dst_argb,
802                                  int dst_stride_argb,
803                                  const struct YuvConstants* yuvconstants,
804                                  int width,
805                                  int height,
806                                  int attenuate) {
807   int y;
808   void (*I422AlphaToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
809                              const uint8_t* v_buf, const uint8_t* a_buf,
810                              uint8_t* dst_argb,
811                              const struct YuvConstants* yuvconstants,
812                              int width) = I422AlphaToARGBRow_C;
813   void (*ARGBAttenuateRow)(const uint8_t* src_argb, uint8_t* dst_argb,
814                            int width) = ARGBAttenuateRow_C;
815   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
816     return -1;
817   }
818   // Negative height means invert the image.
819   if (height < 0) {
820     height = -height;
821     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
822     dst_stride_argb = -dst_stride_argb;
823   }
824 #if defined(HAS_I422ALPHATOARGBROW_SSSE3)
825   if (TestCpuFlag(kCpuHasSSSE3)) {
826     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_SSSE3;
827     if (IS_ALIGNED(width, 8)) {
828       I422AlphaToARGBRow = I422AlphaToARGBRow_SSSE3;
829     }
830   }
831 #endif
832 #if defined(HAS_I422ALPHATOARGBROW_AVX2)
833   if (TestCpuFlag(kCpuHasAVX2)) {
834     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_AVX2;
835     if (IS_ALIGNED(width, 16)) {
836       I422AlphaToARGBRow = I422AlphaToARGBRow_AVX2;
837     }
838   }
839 #endif
840 #if defined(HAS_I422ALPHATOARGBROW_NEON)
841   if (TestCpuFlag(kCpuHasNEON)) {
842     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_NEON;
843     if (IS_ALIGNED(width, 8)) {
844       I422AlphaToARGBRow = I422AlphaToARGBRow_NEON;
845     }
846   }
847 #endif
848 #if defined(HAS_I422ALPHATOARGBROW_MSA)
849   if (TestCpuFlag(kCpuHasMSA)) {
850     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_MSA;
851     if (IS_ALIGNED(width, 8)) {
852       I422AlphaToARGBRow = I422AlphaToARGBRow_MSA;
853     }
854   }
855 #endif
856 #if defined(HAS_ARGBATTENUATEROW_SSSE3)
857   if (TestCpuFlag(kCpuHasSSSE3)) {
858     ARGBAttenuateRow = ARGBAttenuateRow_Any_SSSE3;
859     if (IS_ALIGNED(width, 4)) {
860       ARGBAttenuateRow = ARGBAttenuateRow_SSSE3;
861     }
862   }
863 #endif
864 #if defined(HAS_ARGBATTENUATEROW_AVX2)
865   if (TestCpuFlag(kCpuHasAVX2)) {
866     ARGBAttenuateRow = ARGBAttenuateRow_Any_AVX2;
867     if (IS_ALIGNED(width, 8)) {
868       ARGBAttenuateRow = ARGBAttenuateRow_AVX2;
869     }
870   }
871 #endif
872 #if defined(HAS_ARGBATTENUATEROW_NEON)
873   if (TestCpuFlag(kCpuHasNEON)) {
874     ARGBAttenuateRow = ARGBAttenuateRow_Any_NEON;
875     if (IS_ALIGNED(width, 8)) {
876       ARGBAttenuateRow = ARGBAttenuateRow_NEON;
877     }
878   }
879 #endif
880 #if defined(HAS_ARGBATTENUATEROW_MSA)
881   if (TestCpuFlag(kCpuHasMSA)) {
882     ARGBAttenuateRow = ARGBAttenuateRow_Any_MSA;
883     if (IS_ALIGNED(width, 8)) {
884       ARGBAttenuateRow = ARGBAttenuateRow_MSA;
885     }
886   }
887 #endif
888 
889   for (y = 0; y < height; ++y) {
890     I422AlphaToARGBRow(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
891                        width);
892     if (attenuate) {
893       ARGBAttenuateRow(dst_argb, dst_argb, width);
894     }
895     dst_argb += dst_stride_argb;
896     src_a += src_stride_a;
897     src_y += src_stride_y;
898     if (y & 1) {
899       src_u += src_stride_u;
900       src_v += src_stride_v;
901     }
902   }
903   return 0;
904 }
905 
906 // Convert I420 with Alpha to ARGB.
907 LIBYUV_API
I420AlphaToARGB(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,const uint8_t * src_a,int src_stride_a,uint8_t * dst_argb,int dst_stride_argb,int width,int height,int attenuate)908 int I420AlphaToARGB(const uint8_t* src_y,
909                     int src_stride_y,
910                     const uint8_t* src_u,
911                     int src_stride_u,
912                     const uint8_t* src_v,
913                     int src_stride_v,
914                     const uint8_t* src_a,
915                     int src_stride_a,
916                     uint8_t* dst_argb,
917                     int dst_stride_argb,
918                     int width,
919                     int height,
920                     int attenuate) {
921   return I420AlphaToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
922                                src_stride_v, src_a, src_stride_a, dst_argb,
923                                dst_stride_argb, &kYuvI601Constants, width,
924                                height, attenuate);
925 }
926 
927 // Convert I420 with Alpha to ABGR.
928 LIBYUV_API
I420AlphaToABGR(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,const uint8_t * src_a,int src_stride_a,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height,int attenuate)929 int I420AlphaToABGR(const uint8_t* src_y,
930                     int src_stride_y,
931                     const uint8_t* src_u,
932                     int src_stride_u,
933                     const uint8_t* src_v,
934                     int src_stride_v,
935                     const uint8_t* src_a,
936                     int src_stride_a,
937                     uint8_t* dst_abgr,
938                     int dst_stride_abgr,
939                     int width,
940                     int height,
941                     int attenuate) {
942   return I420AlphaToARGBMatrix(
943       src_y, src_stride_y, src_v, src_stride_v,  // Swap U and V
944       src_u, src_stride_u, src_a, src_stride_a, dst_abgr, dst_stride_abgr,
945       &kYvuI601Constants,  // Use Yvu matrix
946       width, height, attenuate);
947 }
948 
949 // Convert I400 to ARGB.
950 LIBYUV_API
I400ToARGB(const uint8_t * src_y,int src_stride_y,uint8_t * dst_argb,int dst_stride_argb,int width,int height)951 int I400ToARGB(const uint8_t* src_y,
952                int src_stride_y,
953                uint8_t* dst_argb,
954                int dst_stride_argb,
955                int width,
956                int height) {
957   int y;
958   void (*I400ToARGBRow)(const uint8_t* y_buf, uint8_t* rgb_buf, int width) =
959       I400ToARGBRow_C;
960   if (!src_y || !dst_argb || width <= 0 || height == 0) {
961     return -1;
962   }
963   // Negative height means invert the image.
964   if (height < 0) {
965     height = -height;
966     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
967     dst_stride_argb = -dst_stride_argb;
968   }
969   // Coalesce rows.
970   if (src_stride_y == width && dst_stride_argb == width * 4) {
971     width *= height;
972     height = 1;
973     src_stride_y = dst_stride_argb = 0;
974   }
975 #if defined(HAS_I400TOARGBROW_SSE2)
976   if (TestCpuFlag(kCpuHasSSE2)) {
977     I400ToARGBRow = I400ToARGBRow_Any_SSE2;
978     if (IS_ALIGNED(width, 8)) {
979       I400ToARGBRow = I400ToARGBRow_SSE2;
980     }
981   }
982 #endif
983 #if defined(HAS_I400TOARGBROW_AVX2)
984   if (TestCpuFlag(kCpuHasAVX2)) {
985     I400ToARGBRow = I400ToARGBRow_Any_AVX2;
986     if (IS_ALIGNED(width, 16)) {
987       I400ToARGBRow = I400ToARGBRow_AVX2;
988     }
989   }
990 #endif
991 #if defined(HAS_I400TOARGBROW_NEON)
992   if (TestCpuFlag(kCpuHasNEON)) {
993     I400ToARGBRow = I400ToARGBRow_Any_NEON;
994     if (IS_ALIGNED(width, 8)) {
995       I400ToARGBRow = I400ToARGBRow_NEON;
996     }
997   }
998 #endif
999 #if defined(HAS_I400TOARGBROW_MSA)
1000   if (TestCpuFlag(kCpuHasMSA)) {
1001     I400ToARGBRow = I400ToARGBRow_Any_MSA;
1002     if (IS_ALIGNED(width, 16)) {
1003       I400ToARGBRow = I400ToARGBRow_MSA;
1004     }
1005   }
1006 #endif
1007 
1008   for (y = 0; y < height; ++y) {
1009     I400ToARGBRow(src_y, dst_argb, width);
1010     dst_argb += dst_stride_argb;
1011     src_y += src_stride_y;
1012   }
1013   return 0;
1014 }
1015 
1016 // Convert J400 to ARGB.
1017 LIBYUV_API
J400ToARGB(const uint8_t * src_y,int src_stride_y,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1018 int J400ToARGB(const uint8_t* src_y,
1019                int src_stride_y,
1020                uint8_t* dst_argb,
1021                int dst_stride_argb,
1022                int width,
1023                int height) {
1024   int y;
1025   void (*J400ToARGBRow)(const uint8_t* src_y, uint8_t* dst_argb, int width) =
1026       J400ToARGBRow_C;
1027   if (!src_y || !dst_argb || width <= 0 || height == 0) {
1028     return -1;
1029   }
1030   // Negative height means invert the image.
1031   if (height < 0) {
1032     height = -height;
1033     src_y = src_y + (height - 1) * src_stride_y;
1034     src_stride_y = -src_stride_y;
1035   }
1036   // Coalesce rows.
1037   if (src_stride_y == width && dst_stride_argb == width * 4) {
1038     width *= height;
1039     height = 1;
1040     src_stride_y = dst_stride_argb = 0;
1041   }
1042 #if defined(HAS_J400TOARGBROW_SSE2)
1043   if (TestCpuFlag(kCpuHasSSE2)) {
1044     J400ToARGBRow = J400ToARGBRow_Any_SSE2;
1045     if (IS_ALIGNED(width, 8)) {
1046       J400ToARGBRow = J400ToARGBRow_SSE2;
1047     }
1048   }
1049 #endif
1050 #if defined(HAS_J400TOARGBROW_AVX2)
1051   if (TestCpuFlag(kCpuHasAVX2)) {
1052     J400ToARGBRow = J400ToARGBRow_Any_AVX2;
1053     if (IS_ALIGNED(width, 16)) {
1054       J400ToARGBRow = J400ToARGBRow_AVX2;
1055     }
1056   }
1057 #endif
1058 #if defined(HAS_J400TOARGBROW_NEON)
1059   if (TestCpuFlag(kCpuHasNEON)) {
1060     J400ToARGBRow = J400ToARGBRow_Any_NEON;
1061     if (IS_ALIGNED(width, 8)) {
1062       J400ToARGBRow = J400ToARGBRow_NEON;
1063     }
1064   }
1065 #endif
1066 #if defined(HAS_J400TOARGBROW_MSA)
1067   if (TestCpuFlag(kCpuHasMSA)) {
1068     J400ToARGBRow = J400ToARGBRow_Any_MSA;
1069     if (IS_ALIGNED(width, 16)) {
1070       J400ToARGBRow = J400ToARGBRow_MSA;
1071     }
1072   }
1073 #endif
1074   for (y = 0; y < height; ++y) {
1075     J400ToARGBRow(src_y, dst_argb, width);
1076     src_y += src_stride_y;
1077     dst_argb += dst_stride_argb;
1078   }
1079   return 0;
1080 }
1081 
1082 // Shuffle table for converting BGRA to ARGB.
1083 static const uvec8 kShuffleMaskBGRAToARGB = {
1084     3u, 2u, 1u, 0u, 7u, 6u, 5u, 4u, 11u, 10u, 9u, 8u, 15u, 14u, 13u, 12u};
1085 
1086 // Shuffle table for converting ABGR to ARGB.
1087 static const uvec8 kShuffleMaskABGRToARGB = {
1088     2u, 1u, 0u, 3u, 6u, 5u, 4u, 7u, 10u, 9u, 8u, 11u, 14u, 13u, 12u, 15u};
1089 
1090 // Shuffle table for converting RGBA to ARGB.
1091 static const uvec8 kShuffleMaskRGBAToARGB = {
1092     1u, 2u, 3u, 0u, 5u, 6u, 7u, 4u, 9u, 10u, 11u, 8u, 13u, 14u, 15u, 12u};
1093 
1094 // Convert BGRA to ARGB.
1095 LIBYUV_API
BGRAToARGB(const uint8_t * src_bgra,int src_stride_bgra,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1096 int BGRAToARGB(const uint8_t* src_bgra,
1097                int src_stride_bgra,
1098                uint8_t* dst_argb,
1099                int dst_stride_argb,
1100                int width,
1101                int height) {
1102   return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb,
1103                      (const uint8_t*)(&kShuffleMaskBGRAToARGB), width, height);
1104 }
1105 
1106 // Convert ARGB to BGRA (same as BGRAToARGB).
1107 LIBYUV_API
ARGBToBGRA(const uint8_t * src_bgra,int src_stride_bgra,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1108 int ARGBToBGRA(const uint8_t* src_bgra,
1109                int src_stride_bgra,
1110                uint8_t* dst_argb,
1111                int dst_stride_argb,
1112                int width,
1113                int height) {
1114   return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb,
1115                      (const uint8_t*)(&kShuffleMaskBGRAToARGB), width, height);
1116 }
1117 
1118 // Convert ABGR to ARGB.
1119 LIBYUV_API
ABGRToARGB(const uint8_t * src_abgr,int src_stride_abgr,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1120 int ABGRToARGB(const uint8_t* src_abgr,
1121                int src_stride_abgr,
1122                uint8_t* dst_argb,
1123                int dst_stride_argb,
1124                int width,
1125                int height) {
1126   return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb,
1127                      (const uint8_t*)(&kShuffleMaskABGRToARGB), width, height);
1128 }
1129 
1130 // Convert ARGB to ABGR to (same as ABGRToARGB).
1131 LIBYUV_API
ARGBToABGR(const uint8_t * src_abgr,int src_stride_abgr,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1132 int ARGBToABGR(const uint8_t* src_abgr,
1133                int src_stride_abgr,
1134                uint8_t* dst_argb,
1135                int dst_stride_argb,
1136                int width,
1137                int height) {
1138   return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb,
1139                      (const uint8_t*)(&kShuffleMaskABGRToARGB), width, height);
1140 }
1141 
1142 // Convert RGBA to ARGB.
1143 LIBYUV_API
RGBAToARGB(const uint8_t * src_rgba,int src_stride_rgba,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1144 int RGBAToARGB(const uint8_t* src_rgba,
1145                int src_stride_rgba,
1146                uint8_t* dst_argb,
1147                int dst_stride_argb,
1148                int width,
1149                int height) {
1150   return ARGBShuffle(src_rgba, src_stride_rgba, dst_argb, dst_stride_argb,
1151                      (const uint8_t*)(&kShuffleMaskRGBAToARGB), width, height);
1152 }
1153 
1154 // Convert RGB24 to ARGB.
1155 LIBYUV_API
RGB24ToARGB(const uint8_t * src_rgb24,int src_stride_rgb24,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1156 int RGB24ToARGB(const uint8_t* src_rgb24,
1157                 int src_stride_rgb24,
1158                 uint8_t* dst_argb,
1159                 int dst_stride_argb,
1160                 int width,
1161                 int height) {
1162   int y;
1163   void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
1164       RGB24ToARGBRow_C;
1165   if (!src_rgb24 || !dst_argb || width <= 0 || height == 0) {
1166     return -1;
1167   }
1168   // Negative height means invert the image.
1169   if (height < 0) {
1170     height = -height;
1171     src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
1172     src_stride_rgb24 = -src_stride_rgb24;
1173   }
1174   // Coalesce rows.
1175   if (src_stride_rgb24 == width * 3 && dst_stride_argb == width * 4) {
1176     width *= height;
1177     height = 1;
1178     src_stride_rgb24 = dst_stride_argb = 0;
1179   }
1180 #if defined(HAS_RGB24TOARGBROW_SSSE3)
1181   if (TestCpuFlag(kCpuHasSSSE3)) {
1182     RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
1183     if (IS_ALIGNED(width, 16)) {
1184       RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
1185     }
1186   }
1187 #endif
1188 #if defined(HAS_RGB24TOARGBROW_NEON)
1189   if (TestCpuFlag(kCpuHasNEON)) {
1190     RGB24ToARGBRow = RGB24ToARGBRow_Any_NEON;
1191     if (IS_ALIGNED(width, 8)) {
1192       RGB24ToARGBRow = RGB24ToARGBRow_NEON;
1193     }
1194   }
1195 #endif
1196 #if defined(HAS_RGB24TOARGBROW_MSA)
1197   if (TestCpuFlag(kCpuHasMSA)) {
1198     RGB24ToARGBRow = RGB24ToARGBRow_Any_MSA;
1199     if (IS_ALIGNED(width, 16)) {
1200       RGB24ToARGBRow = RGB24ToARGBRow_MSA;
1201     }
1202   }
1203 #endif
1204 
1205   for (y = 0; y < height; ++y) {
1206     RGB24ToARGBRow(src_rgb24, dst_argb, width);
1207     src_rgb24 += src_stride_rgb24;
1208     dst_argb += dst_stride_argb;
1209   }
1210   return 0;
1211 }
1212 
1213 // Convert RAW to ARGB.
1214 LIBYUV_API
RAWToARGB(const uint8_t * src_raw,int src_stride_raw,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1215 int RAWToARGB(const uint8_t* src_raw,
1216               int src_stride_raw,
1217               uint8_t* dst_argb,
1218               int dst_stride_argb,
1219               int width,
1220               int height) {
1221   int y;
1222   void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
1223       RAWToARGBRow_C;
1224   if (!src_raw || !dst_argb || width <= 0 || height == 0) {
1225     return -1;
1226   }
1227   // Negative height means invert the image.
1228   if (height < 0) {
1229     height = -height;
1230     src_raw = src_raw + (height - 1) * src_stride_raw;
1231     src_stride_raw = -src_stride_raw;
1232   }
1233   // Coalesce rows.
1234   if (src_stride_raw == width * 3 && dst_stride_argb == width * 4) {
1235     width *= height;
1236     height = 1;
1237     src_stride_raw = dst_stride_argb = 0;
1238   }
1239 #if defined(HAS_RAWTOARGBROW_SSSE3)
1240   if (TestCpuFlag(kCpuHasSSSE3)) {
1241     RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
1242     if (IS_ALIGNED(width, 16)) {
1243       RAWToARGBRow = RAWToARGBRow_SSSE3;
1244     }
1245   }
1246 #endif
1247 #if defined(HAS_RAWTOARGBROW_NEON)
1248   if (TestCpuFlag(kCpuHasNEON)) {
1249     RAWToARGBRow = RAWToARGBRow_Any_NEON;
1250     if (IS_ALIGNED(width, 8)) {
1251       RAWToARGBRow = RAWToARGBRow_NEON;
1252     }
1253   }
1254 #endif
1255 #if defined(HAS_RAWTOARGBROW_MSA)
1256   if (TestCpuFlag(kCpuHasMSA)) {
1257     RAWToARGBRow = RAWToARGBRow_Any_MSA;
1258     if (IS_ALIGNED(width, 16)) {
1259       RAWToARGBRow = RAWToARGBRow_MSA;
1260     }
1261   }
1262 #endif
1263 
1264   for (y = 0; y < height; ++y) {
1265     RAWToARGBRow(src_raw, dst_argb, width);
1266     src_raw += src_stride_raw;
1267     dst_argb += dst_stride_argb;
1268   }
1269   return 0;
1270 }
1271 
1272 // Convert RGB565 to ARGB.
1273 LIBYUV_API
RGB565ToARGB(const uint8_t * src_rgb565,int src_stride_rgb565,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1274 int RGB565ToARGB(const uint8_t* src_rgb565,
1275                  int src_stride_rgb565,
1276                  uint8_t* dst_argb,
1277                  int dst_stride_argb,
1278                  int width,
1279                  int height) {
1280   int y;
1281   void (*RGB565ToARGBRow)(const uint8_t* src_rgb565, uint8_t* dst_argb,
1282                           int width) = RGB565ToARGBRow_C;
1283   if (!src_rgb565 || !dst_argb || width <= 0 || height == 0) {
1284     return -1;
1285   }
1286   // Negative height means invert the image.
1287   if (height < 0) {
1288     height = -height;
1289     src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
1290     src_stride_rgb565 = -src_stride_rgb565;
1291   }
1292   // Coalesce rows.
1293   if (src_stride_rgb565 == width * 2 && dst_stride_argb == width * 4) {
1294     width *= height;
1295     height = 1;
1296     src_stride_rgb565 = dst_stride_argb = 0;
1297   }
1298 #if defined(HAS_RGB565TOARGBROW_SSE2)
1299   if (TestCpuFlag(kCpuHasSSE2)) {
1300     RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
1301     if (IS_ALIGNED(width, 8)) {
1302       RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
1303     }
1304   }
1305 #endif
1306 #if defined(HAS_RGB565TOARGBROW_AVX2)
1307   if (TestCpuFlag(kCpuHasAVX2)) {
1308     RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
1309     if (IS_ALIGNED(width, 16)) {
1310       RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
1311     }
1312   }
1313 #endif
1314 #if defined(HAS_RGB565TOARGBROW_NEON)
1315   if (TestCpuFlag(kCpuHasNEON)) {
1316     RGB565ToARGBRow = RGB565ToARGBRow_Any_NEON;
1317     if (IS_ALIGNED(width, 8)) {
1318       RGB565ToARGBRow = RGB565ToARGBRow_NEON;
1319     }
1320   }
1321 #endif
1322 #if defined(HAS_RGB565TOARGBROW_MSA)
1323   if (TestCpuFlag(kCpuHasMSA)) {
1324     RGB565ToARGBRow = RGB565ToARGBRow_Any_MSA;
1325     if (IS_ALIGNED(width, 16)) {
1326       RGB565ToARGBRow = RGB565ToARGBRow_MSA;
1327     }
1328   }
1329 #endif
1330 
1331   for (y = 0; y < height; ++y) {
1332     RGB565ToARGBRow(src_rgb565, dst_argb, width);
1333     src_rgb565 += src_stride_rgb565;
1334     dst_argb += dst_stride_argb;
1335   }
1336   return 0;
1337 }
1338 
1339 // Convert ARGB1555 to ARGB.
1340 LIBYUV_API
ARGB1555ToARGB(const uint8_t * src_argb1555,int src_stride_argb1555,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1341 int ARGB1555ToARGB(const uint8_t* src_argb1555,
1342                    int src_stride_argb1555,
1343                    uint8_t* dst_argb,
1344                    int dst_stride_argb,
1345                    int width,
1346                    int height) {
1347   int y;
1348   void (*ARGB1555ToARGBRow)(const uint8_t* src_argb1555, uint8_t* dst_argb,
1349                             int width) = ARGB1555ToARGBRow_C;
1350   if (!src_argb1555 || !dst_argb || width <= 0 || height == 0) {
1351     return -1;
1352   }
1353   // Negative height means invert the image.
1354   if (height < 0) {
1355     height = -height;
1356     src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
1357     src_stride_argb1555 = -src_stride_argb1555;
1358   }
1359   // Coalesce rows.
1360   if (src_stride_argb1555 == width * 2 && dst_stride_argb == width * 4) {
1361     width *= height;
1362     height = 1;
1363     src_stride_argb1555 = dst_stride_argb = 0;
1364   }
1365 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
1366   if (TestCpuFlag(kCpuHasSSE2)) {
1367     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
1368     if (IS_ALIGNED(width, 8)) {
1369       ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
1370     }
1371   }
1372 #endif
1373 #if defined(HAS_ARGB1555TOARGBROW_AVX2)
1374   if (TestCpuFlag(kCpuHasAVX2)) {
1375     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
1376     if (IS_ALIGNED(width, 16)) {
1377       ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
1378     }
1379   }
1380 #endif
1381 #if defined(HAS_ARGB1555TOARGBROW_NEON)
1382   if (TestCpuFlag(kCpuHasNEON)) {
1383     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_NEON;
1384     if (IS_ALIGNED(width, 8)) {
1385       ARGB1555ToARGBRow = ARGB1555ToARGBRow_NEON;
1386     }
1387   }
1388 #endif
1389 #if defined(HAS_ARGB1555TOARGBROW_MSA)
1390   if (TestCpuFlag(kCpuHasMSA)) {
1391     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_MSA;
1392     if (IS_ALIGNED(width, 16)) {
1393       ARGB1555ToARGBRow = ARGB1555ToARGBRow_MSA;
1394     }
1395   }
1396 #endif
1397 
1398   for (y = 0; y < height; ++y) {
1399     ARGB1555ToARGBRow(src_argb1555, dst_argb, width);
1400     src_argb1555 += src_stride_argb1555;
1401     dst_argb += dst_stride_argb;
1402   }
1403   return 0;
1404 }
1405 
1406 // Convert ARGB4444 to ARGB.
1407 LIBYUV_API
ARGB4444ToARGB(const uint8_t * src_argb4444,int src_stride_argb4444,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1408 int ARGB4444ToARGB(const uint8_t* src_argb4444,
1409                    int src_stride_argb4444,
1410                    uint8_t* dst_argb,
1411                    int dst_stride_argb,
1412                    int width,
1413                    int height) {
1414   int y;
1415   void (*ARGB4444ToARGBRow)(const uint8_t* src_argb4444, uint8_t* dst_argb,
1416                             int width) = ARGB4444ToARGBRow_C;
1417   if (!src_argb4444 || !dst_argb || width <= 0 || height == 0) {
1418     return -1;
1419   }
1420   // Negative height means invert the image.
1421   if (height < 0) {
1422     height = -height;
1423     src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
1424     src_stride_argb4444 = -src_stride_argb4444;
1425   }
1426   // Coalesce rows.
1427   if (src_stride_argb4444 == width * 2 && dst_stride_argb == width * 4) {
1428     width *= height;
1429     height = 1;
1430     src_stride_argb4444 = dst_stride_argb = 0;
1431   }
1432 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
1433   if (TestCpuFlag(kCpuHasSSE2)) {
1434     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
1435     if (IS_ALIGNED(width, 8)) {
1436       ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
1437     }
1438   }
1439 #endif
1440 #if defined(HAS_ARGB4444TOARGBROW_AVX2)
1441   if (TestCpuFlag(kCpuHasAVX2)) {
1442     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
1443     if (IS_ALIGNED(width, 16)) {
1444       ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
1445     }
1446   }
1447 #endif
1448 #if defined(HAS_ARGB4444TOARGBROW_NEON)
1449   if (TestCpuFlag(kCpuHasNEON)) {
1450     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_NEON;
1451     if (IS_ALIGNED(width, 8)) {
1452       ARGB4444ToARGBRow = ARGB4444ToARGBRow_NEON;
1453     }
1454   }
1455 #endif
1456 #if defined(HAS_ARGB4444TOARGBROW_MSA)
1457   if (TestCpuFlag(kCpuHasMSA)) {
1458     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA;
1459     if (IS_ALIGNED(width, 16)) {
1460       ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA;
1461     }
1462   }
1463 #endif
1464 
1465   for (y = 0; y < height; ++y) {
1466     ARGB4444ToARGBRow(src_argb4444, dst_argb, width);
1467     src_argb4444 += src_stride_argb4444;
1468     dst_argb += dst_stride_argb;
1469   }
1470   return 0;
1471 }
1472 
1473 // Convert AR30 to ARGB.
1474 LIBYUV_API
AR30ToARGB(const uint8_t * src_ar30,int src_stride_ar30,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1475 int AR30ToARGB(const uint8_t* src_ar30,
1476                int src_stride_ar30,
1477                uint8_t* dst_argb,
1478                int dst_stride_argb,
1479                int width,
1480                int height) {
1481   int y;
1482   if (!src_ar30 || !dst_argb || width <= 0 || height == 0) {
1483     return -1;
1484   }
1485   // Negative height means invert the image.
1486   if (height < 0) {
1487     height = -height;
1488     src_ar30 = src_ar30 + (height - 1) * src_stride_ar30;
1489     src_stride_ar30 = -src_stride_ar30;
1490   }
1491   // Coalesce rows.
1492   if (src_stride_ar30 == width * 4 && dst_stride_argb == width * 4) {
1493     width *= height;
1494     height = 1;
1495     src_stride_ar30 = dst_stride_argb = 0;
1496   }
1497   for (y = 0; y < height; ++y) {
1498     AR30ToARGBRow_C(src_ar30, dst_argb, width);
1499     src_ar30 += src_stride_ar30;
1500     dst_argb += dst_stride_argb;
1501   }
1502   return 0;
1503 }
1504 
1505 // Convert AR30 to ABGR.
1506 LIBYUV_API
AR30ToABGR(const uint8_t * src_ar30,int src_stride_ar30,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height)1507 int AR30ToABGR(const uint8_t* src_ar30,
1508                int src_stride_ar30,
1509                uint8_t* dst_abgr,
1510                int dst_stride_abgr,
1511                int width,
1512                int height) {
1513   int y;
1514   if (!src_ar30 || !dst_abgr || width <= 0 || height == 0) {
1515     return -1;
1516   }
1517   // Negative height means invert the image.
1518   if (height < 0) {
1519     height = -height;
1520     src_ar30 = src_ar30 + (height - 1) * src_stride_ar30;
1521     src_stride_ar30 = -src_stride_ar30;
1522   }
1523   // Coalesce rows.
1524   if (src_stride_ar30 == width * 4 && dst_stride_abgr == width * 4) {
1525     width *= height;
1526     height = 1;
1527     src_stride_ar30 = dst_stride_abgr = 0;
1528   }
1529   for (y = 0; y < height; ++y) {
1530     AR30ToABGRRow_C(src_ar30, dst_abgr, width);
1531     src_ar30 += src_stride_ar30;
1532     dst_abgr += dst_stride_abgr;
1533   }
1534   return 0;
1535 }
1536 
1537 // Convert AR30 to AB30.
1538 LIBYUV_API
AR30ToAB30(const uint8_t * src_ar30,int src_stride_ar30,uint8_t * dst_ab30,int dst_stride_ab30,int width,int height)1539 int AR30ToAB30(const uint8_t* src_ar30,
1540                int src_stride_ar30,
1541                uint8_t* dst_ab30,
1542                int dst_stride_ab30,
1543                int width,
1544                int height) {
1545   int y;
1546   if (!src_ar30 || !dst_ab30 || width <= 0 || height == 0) {
1547     return -1;
1548   }
1549   // Negative height means invert the image.
1550   if (height < 0) {
1551     height = -height;
1552     src_ar30 = src_ar30 + (height - 1) * src_stride_ar30;
1553     src_stride_ar30 = -src_stride_ar30;
1554   }
1555   // Coalesce rows.
1556   if (src_stride_ar30 == width * 4 && dst_stride_ab30 == width * 4) {
1557     width *= height;
1558     height = 1;
1559     src_stride_ar30 = dst_stride_ab30 = 0;
1560   }
1561   for (y = 0; y < height; ++y) {
1562     AR30ToAB30Row_C(src_ar30, dst_ab30, width);
1563     src_ar30 += src_stride_ar30;
1564     dst_ab30 += dst_stride_ab30;
1565   }
1566   return 0;
1567 }
1568 
1569 // Convert NV12 to ARGB with matrix
NV12ToARGBMatrix(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,uint8_t * dst_argb,int dst_stride_argb,const struct YuvConstants * yuvconstants,int width,int height)1570 static int NV12ToARGBMatrix(const uint8_t* src_y,
1571                             int src_stride_y,
1572                             const uint8_t* src_uv,
1573                             int src_stride_uv,
1574                             uint8_t* dst_argb,
1575                             int dst_stride_argb,
1576                             const struct YuvConstants* yuvconstants,
1577                             int width,
1578                             int height) {
1579   int y;
1580   void (*NV12ToARGBRow)(
1581       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
1582       const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C;
1583   if (!src_y || !src_uv || !dst_argb || width <= 0 || height == 0) {
1584     return -1;
1585   }
1586   // Negative height means invert the image.
1587   if (height < 0) {
1588     height = -height;
1589     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1590     dst_stride_argb = -dst_stride_argb;
1591   }
1592 #if defined(HAS_NV12TOARGBROW_SSSE3)
1593   if (TestCpuFlag(kCpuHasSSSE3)) {
1594     NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
1595     if (IS_ALIGNED(width, 8)) {
1596       NV12ToARGBRow = NV12ToARGBRow_SSSE3;
1597     }
1598   }
1599 #endif
1600 #if defined(HAS_NV12TOARGBROW_AVX2)
1601   if (TestCpuFlag(kCpuHasAVX2)) {
1602     NV12ToARGBRow = NV12ToARGBRow_Any_AVX2;
1603     if (IS_ALIGNED(width, 16)) {
1604       NV12ToARGBRow = NV12ToARGBRow_AVX2;
1605     }
1606   }
1607 #endif
1608 #if defined(HAS_NV12TOARGBROW_NEON)
1609   if (TestCpuFlag(kCpuHasNEON)) {
1610     NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
1611     if (IS_ALIGNED(width, 8)) {
1612       NV12ToARGBRow = NV12ToARGBRow_NEON;
1613     }
1614   }
1615 #endif
1616 #if defined(HAS_NV12TOARGBROW_MSA)
1617   if (TestCpuFlag(kCpuHasMSA)) {
1618     NV12ToARGBRow = NV12ToARGBRow_Any_MSA;
1619     if (IS_ALIGNED(width, 8)) {
1620       NV12ToARGBRow = NV12ToARGBRow_MSA;
1621     }
1622   }
1623 #endif
1624 
1625   for (y = 0; y < height; ++y) {
1626     NV12ToARGBRow(src_y, src_uv, dst_argb, yuvconstants, width);
1627     dst_argb += dst_stride_argb;
1628     src_y += src_stride_y;
1629     if (y & 1) {
1630       src_uv += src_stride_uv;
1631     }
1632   }
1633   return 0;
1634 }
1635 
1636 // Convert NV21 to ARGB with matrix
NV21ToARGBMatrix(const uint8_t * src_y,int src_stride_y,const uint8_t * src_vu,int src_stride_vu,uint8_t * dst_argb,int dst_stride_argb,const struct YuvConstants * yuvconstants,int width,int height)1637 static int NV21ToARGBMatrix(const uint8_t* src_y,
1638                             int src_stride_y,
1639                             const uint8_t* src_vu,
1640                             int src_stride_vu,
1641                             uint8_t* dst_argb,
1642                             int dst_stride_argb,
1643                             const struct YuvConstants* yuvconstants,
1644                             int width,
1645                             int height) {
1646   int y;
1647   void (*NV21ToARGBRow)(
1648       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
1649       const struct YuvConstants* yuvconstants, int width) = NV21ToARGBRow_C;
1650   if (!src_y || !src_vu || !dst_argb || width <= 0 || height == 0) {
1651     return -1;
1652   }
1653   // Negative height means invert the image.
1654   if (height < 0) {
1655     height = -height;
1656     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1657     dst_stride_argb = -dst_stride_argb;
1658   }
1659 #if defined(HAS_NV21TOARGBROW_SSSE3)
1660   if (TestCpuFlag(kCpuHasSSSE3)) {
1661     NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3;
1662     if (IS_ALIGNED(width, 8)) {
1663       NV21ToARGBRow = NV21ToARGBRow_SSSE3;
1664     }
1665   }
1666 #endif
1667 #if defined(HAS_NV21TOARGBROW_AVX2)
1668   if (TestCpuFlag(kCpuHasAVX2)) {
1669     NV21ToARGBRow = NV21ToARGBRow_Any_AVX2;
1670     if (IS_ALIGNED(width, 16)) {
1671       NV21ToARGBRow = NV21ToARGBRow_AVX2;
1672     }
1673   }
1674 #endif
1675 #if defined(HAS_NV21TOARGBROW_NEON)
1676   if (TestCpuFlag(kCpuHasNEON)) {
1677     NV21ToARGBRow = NV21ToARGBRow_Any_NEON;
1678     if (IS_ALIGNED(width, 8)) {
1679       NV21ToARGBRow = NV21ToARGBRow_NEON;
1680     }
1681   }
1682 #endif
1683 #if defined(HAS_NV21TOARGBROW_MSA)
1684   if (TestCpuFlag(kCpuHasMSA)) {
1685     NV21ToARGBRow = NV21ToARGBRow_Any_MSA;
1686     if (IS_ALIGNED(width, 8)) {
1687       NV21ToARGBRow = NV21ToARGBRow_MSA;
1688     }
1689   }
1690 #endif
1691 
1692   for (y = 0; y < height; ++y) {
1693     NV21ToARGBRow(src_y, src_vu, dst_argb, yuvconstants, width);
1694     dst_argb += dst_stride_argb;
1695     src_y += src_stride_y;
1696     if (y & 1) {
1697       src_vu += src_stride_vu;
1698     }
1699   }
1700   return 0;
1701 }
1702 
1703 // Convert NV12 to ARGB.
1704 LIBYUV_API
NV12ToARGB(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1705 int NV12ToARGB(const uint8_t* src_y,
1706                int src_stride_y,
1707                const uint8_t* src_uv,
1708                int src_stride_uv,
1709                uint8_t* dst_argb,
1710                int dst_stride_argb,
1711                int width,
1712                int height) {
1713   return NV12ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_argb,
1714                           dst_stride_argb, &kYuvI601Constants, width, height);
1715 }
1716 
1717 // Convert NV21 to ARGB.
1718 LIBYUV_API
NV21ToARGB(const uint8_t * src_y,int src_stride_y,const uint8_t * src_vu,int src_stride_vu,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1719 int NV21ToARGB(const uint8_t* src_y,
1720                int src_stride_y,
1721                const uint8_t* src_vu,
1722                int src_stride_vu,
1723                uint8_t* dst_argb,
1724                int dst_stride_argb,
1725                int width,
1726                int height) {
1727   return NV21ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_argb,
1728                           dst_stride_argb, &kYuvI601Constants, width, height);
1729 }
1730 
1731 // Convert NV12 to ABGR.
1732 // To output ABGR instead of ARGB swap the UV and use a mirrrored yuc matrix.
1733 // To swap the UV use NV12 instead of NV21.LIBYUV_API
NV12ToABGR(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height)1734 int NV12ToABGR(const uint8_t* src_y,
1735                int src_stride_y,
1736                const uint8_t* src_uv,
1737                int src_stride_uv,
1738                uint8_t* dst_abgr,
1739                int dst_stride_abgr,
1740                int width,
1741                int height) {
1742   return NV21ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_abgr,
1743                           dst_stride_abgr, &kYvuI601Constants, width, height);
1744 }
1745 
1746 // Convert NV21 to ABGR.
1747 LIBYUV_API
NV21ToABGR(const uint8_t * src_y,int src_stride_y,const uint8_t * src_vu,int src_stride_vu,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height)1748 int NV21ToABGR(const uint8_t* src_y,
1749                int src_stride_y,
1750                const uint8_t* src_vu,
1751                int src_stride_vu,
1752                uint8_t* dst_abgr,
1753                int dst_stride_abgr,
1754                int width,
1755                int height) {
1756   return NV12ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_abgr,
1757                           dst_stride_abgr, &kYvuI601Constants, width, height);
1758 }
1759 
1760 // TODO(fbarchard): Consider SSSE3 2 step conversion.
1761 // Convert NV12 to RGB24 with matrix
NV12ToRGB24Matrix(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,uint8_t * dst_rgb24,int dst_stride_rgb24,const struct YuvConstants * yuvconstants,int width,int height)1762 static int NV12ToRGB24Matrix(const uint8_t* src_y,
1763                              int src_stride_y,
1764                              const uint8_t* src_uv,
1765                              int src_stride_uv,
1766                              uint8_t* dst_rgb24,
1767                              int dst_stride_rgb24,
1768                              const struct YuvConstants* yuvconstants,
1769                              int width,
1770                              int height) {
1771   int y;
1772   void (*NV12ToRGB24Row)(
1773       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
1774       const struct YuvConstants* yuvconstants, int width) = NV12ToRGB24Row_C;
1775   if (!src_y || !src_uv || !dst_rgb24 || width <= 0 || height == 0) {
1776     return -1;
1777   }
1778   // Negative height means invert the image.
1779   if (height < 0) {
1780     height = -height;
1781     dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
1782     dst_stride_rgb24 = -dst_stride_rgb24;
1783   }
1784 #if defined(HAS_NV12TORGB24ROW_NEON)
1785   if (TestCpuFlag(kCpuHasNEON)) {
1786     NV12ToRGB24Row = NV12ToRGB24Row_Any_NEON;
1787     if (IS_ALIGNED(width, 8)) {
1788       NV12ToRGB24Row = NV12ToRGB24Row_NEON;
1789     }
1790   }
1791 #endif
1792 #if defined(HAS_NV12TORGB24ROW_SSSE3)
1793   if (TestCpuFlag(kCpuHasSSSE3)) {
1794     NV12ToRGB24Row = NV12ToRGB24Row_Any_SSSE3;
1795     if (IS_ALIGNED(width, 16)) {
1796       NV12ToRGB24Row = NV12ToRGB24Row_SSSE3;
1797     }
1798   }
1799 #endif
1800 #if defined(HAS_NV12TORGB24ROW_AVX2)
1801   if (TestCpuFlag(kCpuHasAVX2)) {
1802     NV12ToRGB24Row = NV12ToRGB24Row_Any_AVX2;
1803     if (IS_ALIGNED(width, 32)) {
1804       NV12ToRGB24Row = NV12ToRGB24Row_AVX2;
1805     }
1806   }
1807 #endif
1808 
1809   for (y = 0; y < height; ++y) {
1810     NV12ToRGB24Row(src_y, src_uv, dst_rgb24, yuvconstants, width);
1811     dst_rgb24 += dst_stride_rgb24;
1812     src_y += src_stride_y;
1813     if (y & 1) {
1814       src_uv += src_stride_uv;
1815     }
1816   }
1817   return 0;
1818 }
1819 
1820 // Convert NV21 to RGB24 with matrix
NV21ToRGB24Matrix(const uint8_t * src_y,int src_stride_y,const uint8_t * src_vu,int src_stride_vu,uint8_t * dst_rgb24,int dst_stride_rgb24,const struct YuvConstants * yuvconstants,int width,int height)1821 static int NV21ToRGB24Matrix(const uint8_t* src_y,
1822                              int src_stride_y,
1823                              const uint8_t* src_vu,
1824                              int src_stride_vu,
1825                              uint8_t* dst_rgb24,
1826                              int dst_stride_rgb24,
1827                              const struct YuvConstants* yuvconstants,
1828                              int width,
1829                              int height) {
1830   int y;
1831   void (*NV21ToRGB24Row)(
1832       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
1833       const struct YuvConstants* yuvconstants, int width) = NV21ToRGB24Row_C;
1834   if (!src_y || !src_vu || !dst_rgb24 || width <= 0 || height == 0) {
1835     return -1;
1836   }
1837   // Negative height means invert the image.
1838   if (height < 0) {
1839     height = -height;
1840     dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
1841     dst_stride_rgb24 = -dst_stride_rgb24;
1842   }
1843 #if defined(HAS_NV21TORGB24ROW_NEON)
1844   if (TestCpuFlag(kCpuHasNEON)) {
1845     NV21ToRGB24Row = NV21ToRGB24Row_Any_NEON;
1846     if (IS_ALIGNED(width, 8)) {
1847       NV21ToRGB24Row = NV21ToRGB24Row_NEON;
1848     }
1849   }
1850 #endif
1851 #if defined(HAS_NV21TORGB24ROW_SSSE3)
1852   if (TestCpuFlag(kCpuHasSSSE3)) {
1853     NV21ToRGB24Row = NV21ToRGB24Row_Any_SSSE3;
1854     if (IS_ALIGNED(width, 16)) {
1855       NV21ToRGB24Row = NV21ToRGB24Row_SSSE3;
1856     }
1857   }
1858 #endif
1859 #if defined(HAS_NV21TORGB24ROW_AVX2)
1860   if (TestCpuFlag(kCpuHasAVX2)) {
1861     NV21ToRGB24Row = NV21ToRGB24Row_Any_AVX2;
1862     if (IS_ALIGNED(width, 32)) {
1863       NV21ToRGB24Row = NV21ToRGB24Row_AVX2;
1864     }
1865   }
1866 #endif
1867 
1868   for (y = 0; y < height; ++y) {
1869     NV21ToRGB24Row(src_y, src_vu, dst_rgb24, yuvconstants, width);
1870     dst_rgb24 += dst_stride_rgb24;
1871     src_y += src_stride_y;
1872     if (y & 1) {
1873       src_vu += src_stride_vu;
1874     }
1875   }
1876   return 0;
1877 }
1878 
1879 // TODO(fbarchard): NV12ToRAW can be implemented by mirrored matrix.
1880 // Convert NV12 to RGB24.
1881 LIBYUV_API
NV12ToRGB24(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,uint8_t * dst_rgb24,int dst_stride_rgb24,int width,int height)1882 int NV12ToRGB24(const uint8_t* src_y,
1883                 int src_stride_y,
1884                 const uint8_t* src_uv,
1885                 int src_stride_uv,
1886                 uint8_t* dst_rgb24,
1887                 int dst_stride_rgb24,
1888                 int width,
1889                 int height) {
1890   return NV12ToRGB24Matrix(src_y, src_stride_y, src_uv, src_stride_uv,
1891                            dst_rgb24, dst_stride_rgb24, &kYuvI601Constants,
1892                            width, height);
1893 }
1894 
1895 // Convert NV21 to RGB24.
1896 LIBYUV_API
NV21ToRGB24(const uint8_t * src_y,int src_stride_y,const uint8_t * src_vu,int src_stride_vu,uint8_t * dst_rgb24,int dst_stride_rgb24,int width,int height)1897 int NV21ToRGB24(const uint8_t* src_y,
1898                 int src_stride_y,
1899                 const uint8_t* src_vu,
1900                 int src_stride_vu,
1901                 uint8_t* dst_rgb24,
1902                 int dst_stride_rgb24,
1903                 int width,
1904                 int height) {
1905   return NV21ToRGB24Matrix(src_y, src_stride_y, src_vu, src_stride_vu,
1906                            dst_rgb24, dst_stride_rgb24, &kYuvI601Constants,
1907                            width, height);
1908 }
1909 
1910 // Convert M420 to ARGB.
1911 LIBYUV_API
M420ToARGB(const uint8_t * src_m420,int src_stride_m420,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1912 int M420ToARGB(const uint8_t* src_m420,
1913                int src_stride_m420,
1914                uint8_t* dst_argb,
1915                int dst_stride_argb,
1916                int width,
1917                int height) {
1918   int y;
1919   void (*NV12ToARGBRow)(
1920       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
1921       const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C;
1922   if (!src_m420 || !dst_argb || width <= 0 || height == 0) {
1923     return -1;
1924   }
1925   // Negative height means invert the image.
1926   if (height < 0) {
1927     height = -height;
1928     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1929     dst_stride_argb = -dst_stride_argb;
1930   }
1931 #if defined(HAS_NV12TOARGBROW_SSSE3)
1932   if (TestCpuFlag(kCpuHasSSSE3)) {
1933     NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
1934     if (IS_ALIGNED(width, 8)) {
1935       NV12ToARGBRow = NV12ToARGBRow_SSSE3;
1936     }
1937   }
1938 #endif
1939 #if defined(HAS_NV12TOARGBROW_AVX2)
1940   if (TestCpuFlag(kCpuHasAVX2)) {
1941     NV12ToARGBRow = NV12ToARGBRow_Any_AVX2;
1942     if (IS_ALIGNED(width, 16)) {
1943       NV12ToARGBRow = NV12ToARGBRow_AVX2;
1944     }
1945   }
1946 #endif
1947 #if defined(HAS_NV12TOARGBROW_NEON)
1948   if (TestCpuFlag(kCpuHasNEON)) {
1949     NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
1950     if (IS_ALIGNED(width, 8)) {
1951       NV12ToARGBRow = NV12ToARGBRow_NEON;
1952     }
1953   }
1954 #endif
1955 #if defined(HAS_NV12TOARGBROW_MSA)
1956   if (TestCpuFlag(kCpuHasMSA)) {
1957     NV12ToARGBRow = NV12ToARGBRow_Any_MSA;
1958     if (IS_ALIGNED(width, 8)) {
1959       NV12ToARGBRow = NV12ToARGBRow_MSA;
1960     }
1961   }
1962 #endif
1963 
1964   for (y = 0; y < height - 1; y += 2) {
1965     NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb,
1966                   &kYuvI601Constants, width);
1967     NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2,
1968                   dst_argb + dst_stride_argb, &kYuvI601Constants, width);
1969     dst_argb += dst_stride_argb * 2;
1970     src_m420 += src_stride_m420 * 3;
1971   }
1972   if (height & 1) {
1973     NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb,
1974                   &kYuvI601Constants, width);
1975   }
1976   return 0;
1977 }
1978 
1979 // Convert YUY2 to ARGB.
1980 LIBYUV_API
YUY2ToARGB(const uint8_t * src_yuy2,int src_stride_yuy2,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1981 int YUY2ToARGB(const uint8_t* src_yuy2,
1982                int src_stride_yuy2,
1983                uint8_t* dst_argb,
1984                int dst_stride_argb,
1985                int width,
1986                int height) {
1987   int y;
1988   void (*YUY2ToARGBRow)(const uint8_t* src_yuy2, uint8_t* dst_argb,
1989                         const struct YuvConstants* yuvconstants, int width) =
1990       YUY2ToARGBRow_C;
1991   if (!src_yuy2 || !dst_argb || width <= 0 || height == 0) {
1992     return -1;
1993   }
1994   // Negative height means invert the image.
1995   if (height < 0) {
1996     height = -height;
1997     src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
1998     src_stride_yuy2 = -src_stride_yuy2;
1999   }
2000   // Coalesce rows.
2001   if (src_stride_yuy2 == width * 2 && dst_stride_argb == width * 4) {
2002     width *= height;
2003     height = 1;
2004     src_stride_yuy2 = dst_stride_argb = 0;
2005   }
2006 #if defined(HAS_YUY2TOARGBROW_SSSE3)
2007   if (TestCpuFlag(kCpuHasSSSE3)) {
2008     YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3;
2009     if (IS_ALIGNED(width, 16)) {
2010       YUY2ToARGBRow = YUY2ToARGBRow_SSSE3;
2011     }
2012   }
2013 #endif
2014 #if defined(HAS_YUY2TOARGBROW_AVX2)
2015   if (TestCpuFlag(kCpuHasAVX2)) {
2016     YUY2ToARGBRow = YUY2ToARGBRow_Any_AVX2;
2017     if (IS_ALIGNED(width, 32)) {
2018       YUY2ToARGBRow = YUY2ToARGBRow_AVX2;
2019     }
2020   }
2021 #endif
2022 #if defined(HAS_YUY2TOARGBROW_NEON)
2023   if (TestCpuFlag(kCpuHasNEON)) {
2024     YUY2ToARGBRow = YUY2ToARGBRow_Any_NEON;
2025     if (IS_ALIGNED(width, 8)) {
2026       YUY2ToARGBRow = YUY2ToARGBRow_NEON;
2027     }
2028   }
2029 #endif
2030 #if defined(HAS_YUY2TOARGBROW_MSA)
2031   if (TestCpuFlag(kCpuHasMSA)) {
2032     YUY2ToARGBRow = YUY2ToARGBRow_Any_MSA;
2033     if (IS_ALIGNED(width, 8)) {
2034       YUY2ToARGBRow = YUY2ToARGBRow_MSA;
2035     }
2036   }
2037 #endif
2038   for (y = 0; y < height; ++y) {
2039     YUY2ToARGBRow(src_yuy2, dst_argb, &kYuvI601Constants, width);
2040     src_yuy2 += src_stride_yuy2;
2041     dst_argb += dst_stride_argb;
2042   }
2043   return 0;
2044 }
2045 
2046 // Convert UYVY to ARGB.
2047 LIBYUV_API
UYVYToARGB(const uint8_t * src_uyvy,int src_stride_uyvy,uint8_t * dst_argb,int dst_stride_argb,int width,int height)2048 int UYVYToARGB(const uint8_t* src_uyvy,
2049                int src_stride_uyvy,
2050                uint8_t* dst_argb,
2051                int dst_stride_argb,
2052                int width,
2053                int height) {
2054   int y;
2055   void (*UYVYToARGBRow)(const uint8_t* src_uyvy, uint8_t* dst_argb,
2056                         const struct YuvConstants* yuvconstants, int width) =
2057       UYVYToARGBRow_C;
2058   if (!src_uyvy || !dst_argb || width <= 0 || height == 0) {
2059     return -1;
2060   }
2061   // Negative height means invert the image.
2062   if (height < 0) {
2063     height = -height;
2064     src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
2065     src_stride_uyvy = -src_stride_uyvy;
2066   }
2067   // Coalesce rows.
2068   if (src_stride_uyvy == width * 2 && dst_stride_argb == width * 4) {
2069     width *= height;
2070     height = 1;
2071     src_stride_uyvy = dst_stride_argb = 0;
2072   }
2073 #if defined(HAS_UYVYTOARGBROW_SSSE3)
2074   if (TestCpuFlag(kCpuHasSSSE3)) {
2075     UYVYToARGBRow = UYVYToARGBRow_Any_SSSE3;
2076     if (IS_ALIGNED(width, 16)) {
2077       UYVYToARGBRow = UYVYToARGBRow_SSSE3;
2078     }
2079   }
2080 #endif
2081 #if defined(HAS_UYVYTOARGBROW_AVX2)
2082   if (TestCpuFlag(kCpuHasAVX2)) {
2083     UYVYToARGBRow = UYVYToARGBRow_Any_AVX2;
2084     if (IS_ALIGNED(width, 32)) {
2085       UYVYToARGBRow = UYVYToARGBRow_AVX2;
2086     }
2087   }
2088 #endif
2089 #if defined(HAS_UYVYTOARGBROW_NEON)
2090   if (TestCpuFlag(kCpuHasNEON)) {
2091     UYVYToARGBRow = UYVYToARGBRow_Any_NEON;
2092     if (IS_ALIGNED(width, 8)) {
2093       UYVYToARGBRow = UYVYToARGBRow_NEON;
2094     }
2095   }
2096 #endif
2097 #if defined(HAS_UYVYTOARGBROW_MSA)
2098   if (TestCpuFlag(kCpuHasMSA)) {
2099     UYVYToARGBRow = UYVYToARGBRow_Any_MSA;
2100     if (IS_ALIGNED(width, 8)) {
2101       UYVYToARGBRow = UYVYToARGBRow_MSA;
2102     }
2103   }
2104 #endif
2105   for (y = 0; y < height; ++y) {
2106     UYVYToARGBRow(src_uyvy, dst_argb, &kYuvI601Constants, width);
2107     src_uyvy += src_stride_uyvy;
2108     dst_argb += dst_stride_argb;
2109   }
2110   return 0;
2111 }
WeavePixels(const uint8_t * src_u,const uint8_t * src_v,int src_pixel_stride_uv,uint8_t * dst_uv,int width)2112 static void WeavePixels(const uint8_t* src_u,
2113                         const uint8_t* src_v,
2114                         int src_pixel_stride_uv,
2115                         uint8_t* dst_uv,
2116                         int width) {
2117   int i;
2118   for (i = 0; i < width; ++i) {
2119     dst_uv[0] = *src_u;
2120     dst_uv[1] = *src_v;
2121     dst_uv += 2;
2122     src_u += src_pixel_stride_uv;
2123     src_v += src_pixel_stride_uv;
2124   }
2125 }
2126 
2127 // Convert Android420 to ARGB.
2128 LIBYUV_API
Android420ToARGBMatrix(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_argb,int dst_stride_argb,const struct YuvConstants * yuvconstants,int width,int height)2129 int Android420ToARGBMatrix(const uint8_t* src_y,
2130                            int src_stride_y,
2131                            const uint8_t* src_u,
2132                            int src_stride_u,
2133                            const uint8_t* src_v,
2134                            int src_stride_v,
2135                            int src_pixel_stride_uv,
2136                            uint8_t* dst_argb,
2137                            int dst_stride_argb,
2138                            const struct YuvConstants* yuvconstants,
2139                            int width,
2140                            int height) {
2141   int y;
2142   uint8_t* dst_uv;
2143   const ptrdiff_t vu_off = src_v - src_u;
2144   int halfwidth = (width + 1) >> 1;
2145   int halfheight = (height + 1) >> 1;
2146   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
2147     return -1;
2148   }
2149   // Negative height means invert the image.
2150   if (height < 0) {
2151     height = -height;
2152     halfheight = (height + 1) >> 1;
2153     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
2154     dst_stride_argb = -dst_stride_argb;
2155   }
2156 
2157   // I420
2158   if (src_pixel_stride_uv == 1) {
2159     return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
2160                             src_stride_v, dst_argb, dst_stride_argb,
2161                             yuvconstants, width, height);
2162     // NV21
2163   }
2164   if (src_pixel_stride_uv == 2 && vu_off == -1 &&
2165       src_stride_u == src_stride_v) {
2166     return NV21ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, dst_argb,
2167                             dst_stride_argb, yuvconstants, width, height);
2168     // NV12
2169   }
2170   if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) {
2171     return NV12ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, dst_argb,
2172                             dst_stride_argb, yuvconstants, width, height);
2173   }
2174 
2175   // General case fallback creates NV12
2176   align_buffer_64(plane_uv, halfwidth * 2 * halfheight);
2177   dst_uv = plane_uv;
2178   for (y = 0; y < halfheight; ++y) {
2179     WeavePixels(src_u, src_v, src_pixel_stride_uv, dst_uv, halfwidth);
2180     src_u += src_stride_u;
2181     src_v += src_stride_v;
2182     dst_uv += halfwidth * 2;
2183   }
2184   NV12ToARGBMatrix(src_y, src_stride_y, plane_uv, halfwidth * 2, dst_argb,
2185                    dst_stride_argb, yuvconstants, width, height);
2186   free_aligned_buffer_64(plane_uv);
2187   return 0;
2188 }
2189 
2190 // Convert Android420 to ARGB.
2191 LIBYUV_API
Android420ToARGB(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_argb,int dst_stride_argb,int width,int height)2192 int Android420ToARGB(const uint8_t* src_y,
2193                      int src_stride_y,
2194                      const uint8_t* src_u,
2195                      int src_stride_u,
2196                      const uint8_t* src_v,
2197                      int src_stride_v,
2198                      int src_pixel_stride_uv,
2199                      uint8_t* dst_argb,
2200                      int dst_stride_argb,
2201                      int width,
2202                      int height) {
2203   return Android420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
2204                                 src_stride_v, src_pixel_stride_uv, dst_argb,
2205                                 dst_stride_argb, &kYuvI601Constants, width,
2206                                 height);
2207 }
2208 
2209 // Convert Android420 to ABGR.
2210 LIBYUV_API
Android420ToABGR(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_abgr,int dst_stride_abgr,int width,int height)2211 int Android420ToABGR(const uint8_t* src_y,
2212                      int src_stride_y,
2213                      const uint8_t* src_u,
2214                      int src_stride_u,
2215                      const uint8_t* src_v,
2216                      int src_stride_v,
2217                      int src_pixel_stride_uv,
2218                      uint8_t* dst_abgr,
2219                      int dst_stride_abgr,
2220                      int width,
2221                      int height) {
2222   return Android420ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
2223                                 src_stride_u, src_pixel_stride_uv, dst_abgr,
2224                                 dst_stride_abgr, &kYvuI601Constants, width,
2225                                 height);
2226 }
2227 
2228 #ifdef __cplusplus
2229 }  // extern "C"
2230 }  // namespace libyuv
2231 #endif
2232