• 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_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 #if defined(HAS_ARGBATTENUATEROW_MMI)
889   if (TestCpuFlag(kCpuHasMMI)) {
890     ARGBAttenuateRow = ARGBAttenuateRow_Any_MMI;
891     if (IS_ALIGNED(width, 2)) {
892       ARGBAttenuateRow = ARGBAttenuateRow_MMI;
893     }
894   }
895 #endif
896 
897   for (y = 0; y < height; ++y) {
898     I422AlphaToARGBRow(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
899                        width);
900     if (attenuate) {
901       ARGBAttenuateRow(dst_argb, dst_argb, width);
902     }
903     dst_argb += dst_stride_argb;
904     src_a += src_stride_a;
905     src_y += src_stride_y;
906     if (y & 1) {
907       src_u += src_stride_u;
908       src_v += src_stride_v;
909     }
910   }
911   return 0;
912 }
913 
914 // Convert I420 with Alpha to ARGB.
915 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)916 int I420AlphaToARGB(const uint8_t* src_y,
917                     int src_stride_y,
918                     const uint8_t* src_u,
919                     int src_stride_u,
920                     const uint8_t* src_v,
921                     int src_stride_v,
922                     const uint8_t* src_a,
923                     int src_stride_a,
924                     uint8_t* dst_argb,
925                     int dst_stride_argb,
926                     int width,
927                     int height,
928                     int attenuate) {
929   return I420AlphaToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
930                                src_stride_v, src_a, src_stride_a, dst_argb,
931                                dst_stride_argb, &kYuvI601Constants, width,
932                                height, attenuate);
933 }
934 
935 // Convert I420 with Alpha to ABGR.
936 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)937 int I420AlphaToABGR(const uint8_t* src_y,
938                     int src_stride_y,
939                     const uint8_t* src_u,
940                     int src_stride_u,
941                     const uint8_t* src_v,
942                     int src_stride_v,
943                     const uint8_t* src_a,
944                     int src_stride_a,
945                     uint8_t* dst_abgr,
946                     int dst_stride_abgr,
947                     int width,
948                     int height,
949                     int attenuate) {
950   return I420AlphaToARGBMatrix(
951       src_y, src_stride_y, src_v, src_stride_v,  // Swap U and V
952       src_u, src_stride_u, src_a, src_stride_a, dst_abgr, dst_stride_abgr,
953       &kYvuI601Constants,  // Use Yvu matrix
954       width, height, attenuate);
955 }
956 
957 // Convert I400 to ARGB.
958 LIBYUV_API
I400ToARGB(const uint8_t * src_y,int src_stride_y,uint8_t * dst_argb,int dst_stride_argb,int width,int height)959 int I400ToARGB(const uint8_t* src_y,
960                int src_stride_y,
961                uint8_t* dst_argb,
962                int dst_stride_argb,
963                int width,
964                int height) {
965   int y;
966   void (*I400ToARGBRow)(const uint8_t* y_buf, uint8_t* rgb_buf, int width) =
967       I400ToARGBRow_C;
968   if (!src_y || !dst_argb || width <= 0 || height == 0) {
969     return -1;
970   }
971   // Negative height means invert the image.
972   if (height < 0) {
973     height = -height;
974     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
975     dst_stride_argb = -dst_stride_argb;
976   }
977   // Coalesce rows.
978   if (src_stride_y == width && dst_stride_argb == width * 4) {
979     width *= height;
980     height = 1;
981     src_stride_y = dst_stride_argb = 0;
982   }
983 #if defined(HAS_I400TOARGBROW_SSE2)
984   if (TestCpuFlag(kCpuHasSSE2)) {
985     I400ToARGBRow = I400ToARGBRow_Any_SSE2;
986     if (IS_ALIGNED(width, 8)) {
987       I400ToARGBRow = I400ToARGBRow_SSE2;
988     }
989   }
990 #endif
991 #if defined(HAS_I400TOARGBROW_AVX2)
992   if (TestCpuFlag(kCpuHasAVX2)) {
993     I400ToARGBRow = I400ToARGBRow_Any_AVX2;
994     if (IS_ALIGNED(width, 16)) {
995       I400ToARGBRow = I400ToARGBRow_AVX2;
996     }
997   }
998 #endif
999 #if defined(HAS_I400TOARGBROW_NEON)
1000   if (TestCpuFlag(kCpuHasNEON)) {
1001     I400ToARGBRow = I400ToARGBRow_Any_NEON;
1002     if (IS_ALIGNED(width, 8)) {
1003       I400ToARGBRow = I400ToARGBRow_NEON;
1004     }
1005   }
1006 #endif
1007 #if defined(HAS_I400TOARGBROW_MSA)
1008   if (TestCpuFlag(kCpuHasMSA)) {
1009     I400ToARGBRow = I400ToARGBRow_Any_MSA;
1010     if (IS_ALIGNED(width, 16)) {
1011       I400ToARGBRow = I400ToARGBRow_MSA;
1012     }
1013   }
1014 #endif
1015 #if defined(HAS_I400TOARGBROW_MMI)
1016   if (TestCpuFlag(kCpuHasMMI)) {
1017     I400ToARGBRow = I400ToARGBRow_Any_MMI;
1018     if (IS_ALIGNED(width, 8)) {
1019       I400ToARGBRow = I400ToARGBRow_MMI;
1020     }
1021   }
1022 #endif
1023 
1024   for (y = 0; y < height; ++y) {
1025     I400ToARGBRow(src_y, dst_argb, width);
1026     dst_argb += dst_stride_argb;
1027     src_y += src_stride_y;
1028   }
1029   return 0;
1030 }
1031 
1032 // Convert J400 to ARGB.
1033 LIBYUV_API
J400ToARGB(const uint8_t * src_y,int src_stride_y,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1034 int J400ToARGB(const uint8_t* src_y,
1035                int src_stride_y,
1036                uint8_t* dst_argb,
1037                int dst_stride_argb,
1038                int width,
1039                int height) {
1040   int y;
1041   void (*J400ToARGBRow)(const uint8_t* src_y, uint8_t* dst_argb, int width) =
1042       J400ToARGBRow_C;
1043   if (!src_y || !dst_argb || width <= 0 || height == 0) {
1044     return -1;
1045   }
1046   // Negative height means invert the image.
1047   if (height < 0) {
1048     height = -height;
1049     src_y = src_y + (height - 1) * src_stride_y;
1050     src_stride_y = -src_stride_y;
1051   }
1052   // Coalesce rows.
1053   if (src_stride_y == width && dst_stride_argb == width * 4) {
1054     width *= height;
1055     height = 1;
1056     src_stride_y = dst_stride_argb = 0;
1057   }
1058 #if defined(HAS_J400TOARGBROW_SSE2)
1059   if (TestCpuFlag(kCpuHasSSE2)) {
1060     J400ToARGBRow = J400ToARGBRow_Any_SSE2;
1061     if (IS_ALIGNED(width, 8)) {
1062       J400ToARGBRow = J400ToARGBRow_SSE2;
1063     }
1064   }
1065 #endif
1066 #if defined(HAS_J400TOARGBROW_AVX2)
1067   if (TestCpuFlag(kCpuHasAVX2)) {
1068     J400ToARGBRow = J400ToARGBRow_Any_AVX2;
1069     if (IS_ALIGNED(width, 16)) {
1070       J400ToARGBRow = J400ToARGBRow_AVX2;
1071     }
1072   }
1073 #endif
1074 #if defined(HAS_J400TOARGBROW_NEON)
1075   if (TestCpuFlag(kCpuHasNEON)) {
1076     J400ToARGBRow = J400ToARGBRow_Any_NEON;
1077     if (IS_ALIGNED(width, 8)) {
1078       J400ToARGBRow = J400ToARGBRow_NEON;
1079     }
1080   }
1081 #endif
1082 #if defined(HAS_J400TOARGBROW_MSA)
1083   if (TestCpuFlag(kCpuHasMSA)) {
1084     J400ToARGBRow = J400ToARGBRow_Any_MSA;
1085     if (IS_ALIGNED(width, 16)) {
1086       J400ToARGBRow = J400ToARGBRow_MSA;
1087     }
1088   }
1089 #endif
1090 #if defined(HAS_J400TOARGBROW_MMI)
1091   if (TestCpuFlag(kCpuHasMMI)) {
1092     J400ToARGBRow = J400ToARGBRow_Any_MMI;
1093     if (IS_ALIGNED(width, 4)) {
1094       J400ToARGBRow = J400ToARGBRow_MMI;
1095     }
1096   }
1097 #endif
1098   for (y = 0; y < height; ++y) {
1099     J400ToARGBRow(src_y, dst_argb, width);
1100     src_y += src_stride_y;
1101     dst_argb += dst_stride_argb;
1102   }
1103   return 0;
1104 }
1105 
1106 // Shuffle table for converting BGRA to ARGB.
1107 static const uvec8 kShuffleMaskBGRAToARGB = {
1108     3u, 2u, 1u, 0u, 7u, 6u, 5u, 4u, 11u, 10u, 9u, 8u, 15u, 14u, 13u, 12u};
1109 
1110 // Shuffle table for converting ABGR to ARGB.
1111 static const uvec8 kShuffleMaskABGRToARGB = {
1112     2u, 1u, 0u, 3u, 6u, 5u, 4u, 7u, 10u, 9u, 8u, 11u, 14u, 13u, 12u, 15u};
1113 
1114 // Shuffle table for converting RGBA to ARGB.
1115 static const uvec8 kShuffleMaskRGBAToARGB = {
1116     1u, 2u, 3u, 0u, 5u, 6u, 7u, 4u, 9u, 10u, 11u, 8u, 13u, 14u, 15u, 12u};
1117 
1118 // Convert BGRA to ARGB.
1119 LIBYUV_API
BGRAToARGB(const uint8_t * src_bgra,int src_stride_bgra,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1120 int BGRAToARGB(const uint8_t* src_bgra,
1121                int src_stride_bgra,
1122                uint8_t* dst_argb,
1123                int dst_stride_argb,
1124                int width,
1125                int height) {
1126   return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb,
1127                      (const uint8_t*)(&kShuffleMaskBGRAToARGB), width, height);
1128 }
1129 
1130 // Convert ARGB to BGRA (same as BGRAToARGB).
1131 LIBYUV_API
ARGBToBGRA(const uint8_t * src_bgra,int src_stride_bgra,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1132 int ARGBToBGRA(const uint8_t* src_bgra,
1133                int src_stride_bgra,
1134                uint8_t* dst_argb,
1135                int dst_stride_argb,
1136                int width,
1137                int height) {
1138   return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb,
1139                      (const uint8_t*)(&kShuffleMaskBGRAToARGB), width, height);
1140 }
1141 
1142 // Convert ABGR to ARGB.
1143 LIBYUV_API
ABGRToARGB(const uint8_t * src_abgr,int src_stride_abgr,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1144 int ABGRToARGB(const uint8_t* src_abgr,
1145                int src_stride_abgr,
1146                uint8_t* dst_argb,
1147                int dst_stride_argb,
1148                int width,
1149                int height) {
1150   return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb,
1151                      (const uint8_t*)(&kShuffleMaskABGRToARGB), width, height);
1152 }
1153 
1154 // Convert ARGB to ABGR to (same as ABGRToARGB).
1155 LIBYUV_API
ARGBToABGR(const uint8_t * src_abgr,int src_stride_abgr,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1156 int ARGBToABGR(const uint8_t* src_abgr,
1157                int src_stride_abgr,
1158                uint8_t* dst_argb,
1159                int dst_stride_argb,
1160                int width,
1161                int height) {
1162   return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb,
1163                      (const uint8_t*)(&kShuffleMaskABGRToARGB), width, height);
1164 }
1165 
1166 // Convert RGBA to ARGB.
1167 LIBYUV_API
RGBAToARGB(const uint8_t * src_rgba,int src_stride_rgba,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1168 int RGBAToARGB(const uint8_t* src_rgba,
1169                int src_stride_rgba,
1170                uint8_t* dst_argb,
1171                int dst_stride_argb,
1172                int width,
1173                int height) {
1174   return ARGBShuffle(src_rgba, src_stride_rgba, dst_argb, dst_stride_argb,
1175                      (const uint8_t*)(&kShuffleMaskRGBAToARGB), width, height);
1176 }
1177 
1178 // Convert RGB24 to ARGB.
1179 LIBYUV_API
RGB24ToARGB(const uint8_t * src_rgb24,int src_stride_rgb24,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1180 int RGB24ToARGB(const uint8_t* src_rgb24,
1181                 int src_stride_rgb24,
1182                 uint8_t* dst_argb,
1183                 int dst_stride_argb,
1184                 int width,
1185                 int height) {
1186   int y;
1187   void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
1188       RGB24ToARGBRow_C;
1189   if (!src_rgb24 || !dst_argb || width <= 0 || height == 0) {
1190     return -1;
1191   }
1192   // Negative height means invert the image.
1193   if (height < 0) {
1194     height = -height;
1195     src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
1196     src_stride_rgb24 = -src_stride_rgb24;
1197   }
1198   // Coalesce rows.
1199   if (src_stride_rgb24 == width * 3 && dst_stride_argb == width * 4) {
1200     width *= height;
1201     height = 1;
1202     src_stride_rgb24 = dst_stride_argb = 0;
1203   }
1204 #if defined(HAS_RGB24TOARGBROW_SSSE3)
1205   if (TestCpuFlag(kCpuHasSSSE3)) {
1206     RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
1207     if (IS_ALIGNED(width, 16)) {
1208       RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
1209     }
1210   }
1211 #endif
1212 #if defined(HAS_RGB24TOARGBROW_NEON)
1213   if (TestCpuFlag(kCpuHasNEON)) {
1214     RGB24ToARGBRow = RGB24ToARGBRow_Any_NEON;
1215     if (IS_ALIGNED(width, 8)) {
1216       RGB24ToARGBRow = RGB24ToARGBRow_NEON;
1217     }
1218   }
1219 #endif
1220 #if defined(HAS_RGB24TOARGBROW_MSA)
1221   if (TestCpuFlag(kCpuHasMSA)) {
1222     RGB24ToARGBRow = RGB24ToARGBRow_Any_MSA;
1223     if (IS_ALIGNED(width, 16)) {
1224       RGB24ToARGBRow = RGB24ToARGBRow_MSA;
1225     }
1226   }
1227 #endif
1228 #if defined(HAS_RGB24TOARGBROW_MMI)
1229   if (TestCpuFlag(kCpuHasMMI)) {
1230     RGB24ToARGBRow = RGB24ToARGBRow_Any_MMI;
1231     if (IS_ALIGNED(width, 4)) {
1232       RGB24ToARGBRow = RGB24ToARGBRow_MMI;
1233     }
1234   }
1235 #endif
1236 
1237   for (y = 0; y < height; ++y) {
1238     RGB24ToARGBRow(src_rgb24, dst_argb, width);
1239     src_rgb24 += src_stride_rgb24;
1240     dst_argb += dst_stride_argb;
1241   }
1242   return 0;
1243 }
1244 
1245 // Convert RAW to ARGB.
1246 LIBYUV_API
RAWToARGB(const uint8_t * src_raw,int src_stride_raw,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1247 int RAWToARGB(const uint8_t* src_raw,
1248               int src_stride_raw,
1249               uint8_t* dst_argb,
1250               int dst_stride_argb,
1251               int width,
1252               int height) {
1253   int y;
1254   void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
1255       RAWToARGBRow_C;
1256   if (!src_raw || !dst_argb || width <= 0 || height == 0) {
1257     return -1;
1258   }
1259   // Negative height means invert the image.
1260   if (height < 0) {
1261     height = -height;
1262     src_raw = src_raw + (height - 1) * src_stride_raw;
1263     src_stride_raw = -src_stride_raw;
1264   }
1265   // Coalesce rows.
1266   if (src_stride_raw == width * 3 && dst_stride_argb == width * 4) {
1267     width *= height;
1268     height = 1;
1269     src_stride_raw = dst_stride_argb = 0;
1270   }
1271 #if defined(HAS_RAWTOARGBROW_SSSE3)
1272   if (TestCpuFlag(kCpuHasSSSE3)) {
1273     RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
1274     if (IS_ALIGNED(width, 16)) {
1275       RAWToARGBRow = RAWToARGBRow_SSSE3;
1276     }
1277   }
1278 #endif
1279 #if defined(HAS_RAWTOARGBROW_NEON)
1280   if (TestCpuFlag(kCpuHasNEON)) {
1281     RAWToARGBRow = RAWToARGBRow_Any_NEON;
1282     if (IS_ALIGNED(width, 8)) {
1283       RAWToARGBRow = RAWToARGBRow_NEON;
1284     }
1285   }
1286 #endif
1287 #if defined(HAS_RAWTOARGBROW_MSA)
1288   if (TestCpuFlag(kCpuHasMSA)) {
1289     RAWToARGBRow = RAWToARGBRow_Any_MSA;
1290     if (IS_ALIGNED(width, 16)) {
1291       RAWToARGBRow = RAWToARGBRow_MSA;
1292     }
1293   }
1294 #endif
1295 #if defined(HAS_RAWTOARGBROW_MMI)
1296   if (TestCpuFlag(kCpuHasMMI)) {
1297     RAWToARGBRow = RAWToARGBRow_Any_MMI;
1298     if (IS_ALIGNED(width, 4)) {
1299       RAWToARGBRow = RAWToARGBRow_MMI;
1300     }
1301   }
1302 #endif
1303 
1304   for (y = 0; y < height; ++y) {
1305     RAWToARGBRow(src_raw, dst_argb, width);
1306     src_raw += src_stride_raw;
1307     dst_argb += dst_stride_argb;
1308   }
1309   return 0;
1310 }
1311 
1312 // Convert RGB565 to ARGB.
1313 LIBYUV_API
RGB565ToARGB(const uint8_t * src_rgb565,int src_stride_rgb565,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1314 int RGB565ToARGB(const uint8_t* src_rgb565,
1315                  int src_stride_rgb565,
1316                  uint8_t* dst_argb,
1317                  int dst_stride_argb,
1318                  int width,
1319                  int height) {
1320   int y;
1321   void (*RGB565ToARGBRow)(const uint8_t* src_rgb565, uint8_t* dst_argb,
1322                           int width) = RGB565ToARGBRow_C;
1323   if (!src_rgb565 || !dst_argb || width <= 0 || height == 0) {
1324     return -1;
1325   }
1326   // Negative height means invert the image.
1327   if (height < 0) {
1328     height = -height;
1329     src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
1330     src_stride_rgb565 = -src_stride_rgb565;
1331   }
1332   // Coalesce rows.
1333   if (src_stride_rgb565 == width * 2 && dst_stride_argb == width * 4) {
1334     width *= height;
1335     height = 1;
1336     src_stride_rgb565 = dst_stride_argb = 0;
1337   }
1338 #if defined(HAS_RGB565TOARGBROW_SSE2)
1339   if (TestCpuFlag(kCpuHasSSE2)) {
1340     RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
1341     if (IS_ALIGNED(width, 8)) {
1342       RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
1343     }
1344   }
1345 #endif
1346 #if defined(HAS_RGB565TOARGBROW_AVX2)
1347   if (TestCpuFlag(kCpuHasAVX2)) {
1348     RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
1349     if (IS_ALIGNED(width, 16)) {
1350       RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
1351     }
1352   }
1353 #endif
1354 #if defined(HAS_RGB565TOARGBROW_NEON)
1355   if (TestCpuFlag(kCpuHasNEON)) {
1356     RGB565ToARGBRow = RGB565ToARGBRow_Any_NEON;
1357     if (IS_ALIGNED(width, 8)) {
1358       RGB565ToARGBRow = RGB565ToARGBRow_NEON;
1359     }
1360   }
1361 #endif
1362 #if defined(HAS_RGB565TOARGBROW_MSA)
1363   if (TestCpuFlag(kCpuHasMSA)) {
1364     RGB565ToARGBRow = RGB565ToARGBRow_Any_MSA;
1365     if (IS_ALIGNED(width, 16)) {
1366       RGB565ToARGBRow = RGB565ToARGBRow_MSA;
1367     }
1368   }
1369 #endif
1370 #if defined(HAS_RGB565TOARGBROW_MMI)
1371   if (TestCpuFlag(kCpuHasMMI)) {
1372     RGB565ToARGBRow = RGB565ToARGBRow_Any_MMI;
1373     if (IS_ALIGNED(width, 4)) {
1374       RGB565ToARGBRow = RGB565ToARGBRow_MMI;
1375     }
1376   }
1377 #endif
1378 
1379   for (y = 0; y < height; ++y) {
1380     RGB565ToARGBRow(src_rgb565, dst_argb, width);
1381     src_rgb565 += src_stride_rgb565;
1382     dst_argb += dst_stride_argb;
1383   }
1384   return 0;
1385 }
1386 
1387 // Convert ARGB1555 to ARGB.
1388 LIBYUV_API
ARGB1555ToARGB(const uint8_t * src_argb1555,int src_stride_argb1555,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1389 int ARGB1555ToARGB(const uint8_t* src_argb1555,
1390                    int src_stride_argb1555,
1391                    uint8_t* dst_argb,
1392                    int dst_stride_argb,
1393                    int width,
1394                    int height) {
1395   int y;
1396   void (*ARGB1555ToARGBRow)(const uint8_t* src_argb1555, uint8_t* dst_argb,
1397                             int width) = ARGB1555ToARGBRow_C;
1398   if (!src_argb1555 || !dst_argb || width <= 0 || height == 0) {
1399     return -1;
1400   }
1401   // Negative height means invert the image.
1402   if (height < 0) {
1403     height = -height;
1404     src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
1405     src_stride_argb1555 = -src_stride_argb1555;
1406   }
1407   // Coalesce rows.
1408   if (src_stride_argb1555 == width * 2 && dst_stride_argb == width * 4) {
1409     width *= height;
1410     height = 1;
1411     src_stride_argb1555 = dst_stride_argb = 0;
1412   }
1413 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
1414   if (TestCpuFlag(kCpuHasSSE2)) {
1415     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
1416     if (IS_ALIGNED(width, 8)) {
1417       ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
1418     }
1419   }
1420 #endif
1421 #if defined(HAS_ARGB1555TOARGBROW_AVX2)
1422   if (TestCpuFlag(kCpuHasAVX2)) {
1423     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
1424     if (IS_ALIGNED(width, 16)) {
1425       ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
1426     }
1427   }
1428 #endif
1429 #if defined(HAS_ARGB1555TOARGBROW_NEON)
1430   if (TestCpuFlag(kCpuHasNEON)) {
1431     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_NEON;
1432     if (IS_ALIGNED(width, 8)) {
1433       ARGB1555ToARGBRow = ARGB1555ToARGBRow_NEON;
1434     }
1435   }
1436 #endif
1437 #if defined(HAS_ARGB1555TOARGBROW_MSA)
1438   if (TestCpuFlag(kCpuHasMSA)) {
1439     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_MSA;
1440     if (IS_ALIGNED(width, 16)) {
1441       ARGB1555ToARGBRow = ARGB1555ToARGBRow_MSA;
1442     }
1443   }
1444 #endif
1445 #if defined(HAS_ARGB1555TOARGBROW_MMI)
1446   if (TestCpuFlag(kCpuHasMMI)) {
1447     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_MMI;
1448     if (IS_ALIGNED(width, 4)) {
1449       ARGB1555ToARGBRow = ARGB1555ToARGBRow_MMI;
1450     }
1451   }
1452 #endif
1453 
1454   for (y = 0; y < height; ++y) {
1455     ARGB1555ToARGBRow(src_argb1555, dst_argb, width);
1456     src_argb1555 += src_stride_argb1555;
1457     dst_argb += dst_stride_argb;
1458   }
1459   return 0;
1460 }
1461 
1462 // Convert ARGB4444 to ARGB.
1463 LIBYUV_API
ARGB4444ToARGB(const uint8_t * src_argb4444,int src_stride_argb4444,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1464 int ARGB4444ToARGB(const uint8_t* src_argb4444,
1465                    int src_stride_argb4444,
1466                    uint8_t* dst_argb,
1467                    int dst_stride_argb,
1468                    int width,
1469                    int height) {
1470   int y;
1471   void (*ARGB4444ToARGBRow)(const uint8_t* src_argb4444, uint8_t* dst_argb,
1472                             int width) = ARGB4444ToARGBRow_C;
1473   if (!src_argb4444 || !dst_argb || width <= 0 || height == 0) {
1474     return -1;
1475   }
1476   // Negative height means invert the image.
1477   if (height < 0) {
1478     height = -height;
1479     src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
1480     src_stride_argb4444 = -src_stride_argb4444;
1481   }
1482   // Coalesce rows.
1483   if (src_stride_argb4444 == width * 2 && dst_stride_argb == width * 4) {
1484     width *= height;
1485     height = 1;
1486     src_stride_argb4444 = dst_stride_argb = 0;
1487   }
1488 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
1489   if (TestCpuFlag(kCpuHasSSE2)) {
1490     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
1491     if (IS_ALIGNED(width, 8)) {
1492       ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
1493     }
1494   }
1495 #endif
1496 #if defined(HAS_ARGB4444TOARGBROW_AVX2)
1497   if (TestCpuFlag(kCpuHasAVX2)) {
1498     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
1499     if (IS_ALIGNED(width, 16)) {
1500       ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
1501     }
1502   }
1503 #endif
1504 #if defined(HAS_ARGB4444TOARGBROW_NEON)
1505   if (TestCpuFlag(kCpuHasNEON)) {
1506     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_NEON;
1507     if (IS_ALIGNED(width, 8)) {
1508       ARGB4444ToARGBRow = ARGB4444ToARGBRow_NEON;
1509     }
1510   }
1511 #endif
1512 #if defined(HAS_ARGB4444TOARGBROW_MSA)
1513   if (TestCpuFlag(kCpuHasMSA)) {
1514     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA;
1515     if (IS_ALIGNED(width, 16)) {
1516       ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA;
1517     }
1518   }
1519 #endif
1520 #if defined(HAS_ARGB4444TOARGBROW_MMI)
1521   if (TestCpuFlag(kCpuHasMMI)) {
1522     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MMI;
1523     if (IS_ALIGNED(width, 4)) {
1524       ARGB4444ToARGBRow = ARGB4444ToARGBRow_MMI;
1525     }
1526   }
1527 #endif
1528 
1529   for (y = 0; y < height; ++y) {
1530     ARGB4444ToARGBRow(src_argb4444, dst_argb, width);
1531     src_argb4444 += src_stride_argb4444;
1532     dst_argb += dst_stride_argb;
1533   }
1534   return 0;
1535 }
1536 
1537 // Convert AR30 to ARGB.
1538 LIBYUV_API
AR30ToARGB(const uint8_t * src_ar30,int src_stride_ar30,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1539 int AR30ToARGB(const uint8_t* src_ar30,
1540                int src_stride_ar30,
1541                uint8_t* dst_argb,
1542                int dst_stride_argb,
1543                int width,
1544                int height) {
1545   int y;
1546   if (!src_ar30 || !dst_argb || 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_argb == width * 4) {
1557     width *= height;
1558     height = 1;
1559     src_stride_ar30 = dst_stride_argb = 0;
1560   }
1561   for (y = 0; y < height; ++y) {
1562     AR30ToARGBRow_C(src_ar30, dst_argb, width);
1563     src_ar30 += src_stride_ar30;
1564     dst_argb += dst_stride_argb;
1565   }
1566   return 0;
1567 }
1568 
1569 // Convert AR30 to ABGR.
1570 LIBYUV_API
AR30ToABGR(const uint8_t * src_ar30,int src_stride_ar30,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height)1571 int AR30ToABGR(const uint8_t* src_ar30,
1572                int src_stride_ar30,
1573                uint8_t* dst_abgr,
1574                int dst_stride_abgr,
1575                int width,
1576                int height) {
1577   int y;
1578   if (!src_ar30 || !dst_abgr || width <= 0 || height == 0) {
1579     return -1;
1580   }
1581   // Negative height means invert the image.
1582   if (height < 0) {
1583     height = -height;
1584     src_ar30 = src_ar30 + (height - 1) * src_stride_ar30;
1585     src_stride_ar30 = -src_stride_ar30;
1586   }
1587   // Coalesce rows.
1588   if (src_stride_ar30 == width * 4 && dst_stride_abgr == width * 4) {
1589     width *= height;
1590     height = 1;
1591     src_stride_ar30 = dst_stride_abgr = 0;
1592   }
1593   for (y = 0; y < height; ++y) {
1594     AR30ToABGRRow_C(src_ar30, dst_abgr, width);
1595     src_ar30 += src_stride_ar30;
1596     dst_abgr += dst_stride_abgr;
1597   }
1598   return 0;
1599 }
1600 
1601 // Convert AR30 to AB30.
1602 LIBYUV_API
AR30ToAB30(const uint8_t * src_ar30,int src_stride_ar30,uint8_t * dst_ab30,int dst_stride_ab30,int width,int height)1603 int AR30ToAB30(const uint8_t* src_ar30,
1604                int src_stride_ar30,
1605                uint8_t* dst_ab30,
1606                int dst_stride_ab30,
1607                int width,
1608                int height) {
1609   int y;
1610   if (!src_ar30 || !dst_ab30 || width <= 0 || height == 0) {
1611     return -1;
1612   }
1613   // Negative height means invert the image.
1614   if (height < 0) {
1615     height = -height;
1616     src_ar30 = src_ar30 + (height - 1) * src_stride_ar30;
1617     src_stride_ar30 = -src_stride_ar30;
1618   }
1619   // Coalesce rows.
1620   if (src_stride_ar30 == width * 4 && dst_stride_ab30 == width * 4) {
1621     width *= height;
1622     height = 1;
1623     src_stride_ar30 = dst_stride_ab30 = 0;
1624   }
1625   for (y = 0; y < height; ++y) {
1626     AR30ToAB30Row_C(src_ar30, dst_ab30, width);
1627     src_ar30 += src_stride_ar30;
1628     dst_ab30 += dst_stride_ab30;
1629   }
1630   return 0;
1631 }
1632 
1633 // 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)1634 static int NV12ToARGBMatrix(const uint8_t* src_y,
1635                             int src_stride_y,
1636                             const uint8_t* src_uv,
1637                             int src_stride_uv,
1638                             uint8_t* dst_argb,
1639                             int dst_stride_argb,
1640                             const struct YuvConstants* yuvconstants,
1641                             int width,
1642                             int height) {
1643   int y;
1644   void (*NV12ToARGBRow)(
1645       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
1646       const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C;
1647   if (!src_y || !src_uv || !dst_argb || width <= 0 || height == 0) {
1648     return -1;
1649   }
1650   // Negative height means invert the image.
1651   if (height < 0) {
1652     height = -height;
1653     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1654     dst_stride_argb = -dst_stride_argb;
1655   }
1656 #if defined(HAS_NV12TOARGBROW_SSSE3)
1657   if (TestCpuFlag(kCpuHasSSSE3)) {
1658     NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
1659     if (IS_ALIGNED(width, 8)) {
1660       NV12ToARGBRow = NV12ToARGBRow_SSSE3;
1661     }
1662   }
1663 #endif
1664 #if defined(HAS_NV12TOARGBROW_AVX2)
1665   if (TestCpuFlag(kCpuHasAVX2)) {
1666     NV12ToARGBRow = NV12ToARGBRow_Any_AVX2;
1667     if (IS_ALIGNED(width, 16)) {
1668       NV12ToARGBRow = NV12ToARGBRow_AVX2;
1669     }
1670   }
1671 #endif
1672 #if defined(HAS_NV12TOARGBROW_NEON)
1673   if (TestCpuFlag(kCpuHasNEON)) {
1674     NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
1675     if (IS_ALIGNED(width, 8)) {
1676       NV12ToARGBRow = NV12ToARGBRow_NEON;
1677     }
1678   }
1679 #endif
1680 #if defined(HAS_NV12TOARGBROW_MSA)
1681   if (TestCpuFlag(kCpuHasMSA)) {
1682     NV12ToARGBRow = NV12ToARGBRow_Any_MSA;
1683     if (IS_ALIGNED(width, 8)) {
1684       NV12ToARGBRow = NV12ToARGBRow_MSA;
1685     }
1686   }
1687 #endif
1688 
1689   for (y = 0; y < height; ++y) {
1690     NV12ToARGBRow(src_y, src_uv, dst_argb, yuvconstants, width);
1691     dst_argb += dst_stride_argb;
1692     src_y += src_stride_y;
1693     if (y & 1) {
1694       src_uv += src_stride_uv;
1695     }
1696   }
1697   return 0;
1698 }
1699 
1700 // 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)1701 static int NV21ToARGBMatrix(const uint8_t* src_y,
1702                             int src_stride_y,
1703                             const uint8_t* src_vu,
1704                             int src_stride_vu,
1705                             uint8_t* dst_argb,
1706                             int dst_stride_argb,
1707                             const struct YuvConstants* yuvconstants,
1708                             int width,
1709                             int height) {
1710   int y;
1711   void (*NV21ToARGBRow)(
1712       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
1713       const struct YuvConstants* yuvconstants, int width) = NV21ToARGBRow_C;
1714   if (!src_y || !src_vu || !dst_argb || width <= 0 || height == 0) {
1715     return -1;
1716   }
1717   // Negative height means invert the image.
1718   if (height < 0) {
1719     height = -height;
1720     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1721     dst_stride_argb = -dst_stride_argb;
1722   }
1723 #if defined(HAS_NV21TOARGBROW_SSSE3)
1724   if (TestCpuFlag(kCpuHasSSSE3)) {
1725     NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3;
1726     if (IS_ALIGNED(width, 8)) {
1727       NV21ToARGBRow = NV21ToARGBRow_SSSE3;
1728     }
1729   }
1730 #endif
1731 #if defined(HAS_NV21TOARGBROW_AVX2)
1732   if (TestCpuFlag(kCpuHasAVX2)) {
1733     NV21ToARGBRow = NV21ToARGBRow_Any_AVX2;
1734     if (IS_ALIGNED(width, 16)) {
1735       NV21ToARGBRow = NV21ToARGBRow_AVX2;
1736     }
1737   }
1738 #endif
1739 #if defined(HAS_NV21TOARGBROW_NEON)
1740   if (TestCpuFlag(kCpuHasNEON)) {
1741     NV21ToARGBRow = NV21ToARGBRow_Any_NEON;
1742     if (IS_ALIGNED(width, 8)) {
1743       NV21ToARGBRow = NV21ToARGBRow_NEON;
1744     }
1745   }
1746 #endif
1747 #if defined(HAS_NV21TOARGBROW_MSA)
1748   if (TestCpuFlag(kCpuHasMSA)) {
1749     NV21ToARGBRow = NV21ToARGBRow_Any_MSA;
1750     if (IS_ALIGNED(width, 8)) {
1751       NV21ToARGBRow = NV21ToARGBRow_MSA;
1752     }
1753   }
1754 #endif
1755 
1756   for (y = 0; y < height; ++y) {
1757     NV21ToARGBRow(src_y, src_vu, dst_argb, yuvconstants, width);
1758     dst_argb += dst_stride_argb;
1759     src_y += src_stride_y;
1760     if (y & 1) {
1761       src_vu += src_stride_vu;
1762     }
1763   }
1764   return 0;
1765 }
1766 
1767 // Convert NV12 to ARGB.
1768 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)1769 int NV12ToARGB(const uint8_t* src_y,
1770                int src_stride_y,
1771                const uint8_t* src_uv,
1772                int src_stride_uv,
1773                uint8_t* dst_argb,
1774                int dst_stride_argb,
1775                int width,
1776                int height) {
1777   return NV12ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_argb,
1778                           dst_stride_argb, &kYuvI601Constants, width, height);
1779 }
1780 
1781 // Convert NV21 to ARGB.
1782 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)1783 int NV21ToARGB(const uint8_t* src_y,
1784                int src_stride_y,
1785                const uint8_t* src_vu,
1786                int src_stride_vu,
1787                uint8_t* dst_argb,
1788                int dst_stride_argb,
1789                int width,
1790                int height) {
1791   return NV21ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_argb,
1792                           dst_stride_argb, &kYuvI601Constants, width, height);
1793 }
1794 
1795 // Convert NV12 to ABGR.
1796 // To output ABGR instead of ARGB swap the UV and use a mirrored yuv matrix.
1797 // To swap the UV use NV12 instead of NV21.LIBYUV_API
1798 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)1799 int NV12ToABGR(const uint8_t* src_y,
1800                int src_stride_y,
1801                const uint8_t* src_uv,
1802                int src_stride_uv,
1803                uint8_t* dst_abgr,
1804                int dst_stride_abgr,
1805                int width,
1806                int height) {
1807   return NV21ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_abgr,
1808                           dst_stride_abgr, &kYvuI601Constants, width, height);
1809 }
1810 
1811 // Convert NV21 to ABGR.
1812 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)1813 int NV21ToABGR(const uint8_t* src_y,
1814                int src_stride_y,
1815                const uint8_t* src_vu,
1816                int src_stride_vu,
1817                uint8_t* dst_abgr,
1818                int dst_stride_abgr,
1819                int width,
1820                int height) {
1821   return NV12ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_abgr,
1822                           dst_stride_abgr, &kYvuI601Constants, width, height);
1823 }
1824 
1825 // TODO(fbarchard): Consider SSSE3 2 step conversion.
1826 // 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)1827 static int NV12ToRGB24Matrix(const uint8_t* src_y,
1828                              int src_stride_y,
1829                              const uint8_t* src_uv,
1830                              int src_stride_uv,
1831                              uint8_t* dst_rgb24,
1832                              int dst_stride_rgb24,
1833                              const struct YuvConstants* yuvconstants,
1834                              int width,
1835                              int height) {
1836   int y;
1837   void (*NV12ToRGB24Row)(
1838       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
1839       const struct YuvConstants* yuvconstants, int width) = NV12ToRGB24Row_C;
1840   if (!src_y || !src_uv || !dst_rgb24 || width <= 0 || height == 0) {
1841     return -1;
1842   }
1843   // Negative height means invert the image.
1844   if (height < 0) {
1845     height = -height;
1846     dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
1847     dst_stride_rgb24 = -dst_stride_rgb24;
1848   }
1849 #if defined(HAS_NV12TORGB24ROW_NEON)
1850   if (TestCpuFlag(kCpuHasNEON)) {
1851     NV12ToRGB24Row = NV12ToRGB24Row_Any_NEON;
1852     if (IS_ALIGNED(width, 8)) {
1853       NV12ToRGB24Row = NV12ToRGB24Row_NEON;
1854     }
1855   }
1856 #endif
1857 #if defined(HAS_NV12TORGB24ROW_SSSE3)
1858   if (TestCpuFlag(kCpuHasSSSE3)) {
1859     NV12ToRGB24Row = NV12ToRGB24Row_Any_SSSE3;
1860     if (IS_ALIGNED(width, 16)) {
1861       NV12ToRGB24Row = NV12ToRGB24Row_SSSE3;
1862     }
1863   }
1864 #endif
1865 #if defined(HAS_NV12TORGB24ROW_AVX2)
1866   if (TestCpuFlag(kCpuHasAVX2)) {
1867     NV12ToRGB24Row = NV12ToRGB24Row_Any_AVX2;
1868     if (IS_ALIGNED(width, 32)) {
1869       NV12ToRGB24Row = NV12ToRGB24Row_AVX2;
1870     }
1871   }
1872 #endif
1873 
1874   for (y = 0; y < height; ++y) {
1875     NV12ToRGB24Row(src_y, src_uv, dst_rgb24, yuvconstants, width);
1876     dst_rgb24 += dst_stride_rgb24;
1877     src_y += src_stride_y;
1878     if (y & 1) {
1879       src_uv += src_stride_uv;
1880     }
1881   }
1882   return 0;
1883 }
1884 
1885 // 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)1886 static int NV21ToRGB24Matrix(const uint8_t* src_y,
1887                              int src_stride_y,
1888                              const uint8_t* src_vu,
1889                              int src_stride_vu,
1890                              uint8_t* dst_rgb24,
1891                              int dst_stride_rgb24,
1892                              const struct YuvConstants* yuvconstants,
1893                              int width,
1894                              int height) {
1895   int y;
1896   void (*NV21ToRGB24Row)(
1897       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
1898       const struct YuvConstants* yuvconstants, int width) = NV21ToRGB24Row_C;
1899   if (!src_y || !src_vu || !dst_rgb24 || width <= 0 || height == 0) {
1900     return -1;
1901   }
1902   // Negative height means invert the image.
1903   if (height < 0) {
1904     height = -height;
1905     dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
1906     dst_stride_rgb24 = -dst_stride_rgb24;
1907   }
1908 #if defined(HAS_NV21TORGB24ROW_NEON)
1909   if (TestCpuFlag(kCpuHasNEON)) {
1910     NV21ToRGB24Row = NV21ToRGB24Row_Any_NEON;
1911     if (IS_ALIGNED(width, 8)) {
1912       NV21ToRGB24Row = NV21ToRGB24Row_NEON;
1913     }
1914   }
1915 #endif
1916 #if defined(HAS_NV21TORGB24ROW_SSSE3)
1917   if (TestCpuFlag(kCpuHasSSSE3)) {
1918     NV21ToRGB24Row = NV21ToRGB24Row_Any_SSSE3;
1919     if (IS_ALIGNED(width, 16)) {
1920       NV21ToRGB24Row = NV21ToRGB24Row_SSSE3;
1921     }
1922   }
1923 #endif
1924 #if defined(HAS_NV21TORGB24ROW_AVX2)
1925   if (TestCpuFlag(kCpuHasAVX2)) {
1926     NV21ToRGB24Row = NV21ToRGB24Row_Any_AVX2;
1927     if (IS_ALIGNED(width, 32)) {
1928       NV21ToRGB24Row = NV21ToRGB24Row_AVX2;
1929     }
1930   }
1931 #endif
1932 
1933   for (y = 0; y < height; ++y) {
1934     NV21ToRGB24Row(src_y, src_vu, dst_rgb24, yuvconstants, width);
1935     dst_rgb24 += dst_stride_rgb24;
1936     src_y += src_stride_y;
1937     if (y & 1) {
1938       src_vu += src_stride_vu;
1939     }
1940   }
1941   return 0;
1942 }
1943 
1944 // Convert NV12 to RGB24.
1945 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)1946 int NV12ToRGB24(const uint8_t* src_y,
1947                 int src_stride_y,
1948                 const uint8_t* src_uv,
1949                 int src_stride_uv,
1950                 uint8_t* dst_rgb24,
1951                 int dst_stride_rgb24,
1952                 int width,
1953                 int height) {
1954   return NV12ToRGB24Matrix(src_y, src_stride_y, src_uv, src_stride_uv,
1955                            dst_rgb24, dst_stride_rgb24, &kYuvI601Constants,
1956                            width, height);
1957 }
1958 
1959 // Convert NV21 to RGB24.
1960 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)1961 int NV21ToRGB24(const uint8_t* src_y,
1962                 int src_stride_y,
1963                 const uint8_t* src_vu,
1964                 int src_stride_vu,
1965                 uint8_t* dst_rgb24,
1966                 int dst_stride_rgb24,
1967                 int width,
1968                 int height) {
1969   return NV21ToRGB24Matrix(src_y, src_stride_y, src_vu, src_stride_vu,
1970                            dst_rgb24, dst_stride_rgb24, &kYuvI601Constants,
1971                            width, height);
1972 }
1973 
1974 // Convert NV12 to RAW.
1975 LIBYUV_API
NV12ToRAW(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,uint8_t * dst_raw,int dst_stride_raw,int width,int height)1976 int NV12ToRAW(const uint8_t* src_y,
1977               int src_stride_y,
1978               const uint8_t* src_uv,
1979               int src_stride_uv,
1980               uint8_t* dst_raw,
1981               int dst_stride_raw,
1982               int width,
1983               int height) {
1984   return NV21ToRGB24Matrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_raw,
1985                            dst_stride_raw, &kYvuI601Constants, width, height);
1986 }
1987 
1988 // Convert NV21 to RAW.
1989 LIBYUV_API
NV21ToRAW(const uint8_t * src_y,int src_stride_y,const uint8_t * src_vu,int src_stride_vu,uint8_t * dst_raw,int dst_stride_raw,int width,int height)1990 int NV21ToRAW(const uint8_t* src_y,
1991               int src_stride_y,
1992               const uint8_t* src_vu,
1993               int src_stride_vu,
1994               uint8_t* dst_raw,
1995               int dst_stride_raw,
1996               int width,
1997               int height) {
1998   return NV12ToRGB24Matrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_raw,
1999                            dst_stride_raw, &kYvuI601Constants, width, height);
2000 }
2001 
2002 // Convert NV21 to YUV24
NV21ToYUV24(const uint8_t * src_y,int src_stride_y,const uint8_t * src_vu,int src_stride_vu,uint8_t * dst_yuv24,int dst_stride_yuv24,int width,int height)2003 int NV21ToYUV24(const uint8_t* src_y,
2004                 int src_stride_y,
2005                 const uint8_t* src_vu,
2006                 int src_stride_vu,
2007                 uint8_t* dst_yuv24,
2008                 int dst_stride_yuv24,
2009                 int width,
2010                 int height) {
2011   int y;
2012   void (*NV21ToYUV24Row)(const uint8_t* src_y, const uint8_t* src_vu,
2013                          uint8_t* dst_yuv24, int width) = NV21ToYUV24Row_C;
2014   if (!src_y || !src_vu || !dst_yuv24 || width <= 0 || height == 0) {
2015     return -1;
2016   }
2017   // Negative height means invert the image.
2018   if (height < 0) {
2019     height = -height;
2020     dst_yuv24 = dst_yuv24 + (height - 1) * dst_stride_yuv24;
2021     dst_stride_yuv24 = -dst_stride_yuv24;
2022   }
2023 #if defined(HAS_NV21TOYUV24ROW_NEON)
2024   if (TestCpuFlag(kCpuHasNEON)) {
2025     NV21ToYUV24Row = NV21ToYUV24Row_Any_NEON;
2026     if (IS_ALIGNED(width, 16)) {
2027       NV21ToYUV24Row = NV21ToYUV24Row_NEON;
2028     }
2029   }
2030 #endif
2031 #if defined(HAS_NV21TOYUV24ROW_AVX2)
2032   if (TestCpuFlag(kCpuHasAVX2)) {
2033     NV21ToYUV24Row = NV21ToYUV24Row_Any_AVX2;
2034     if (IS_ALIGNED(width, 32)) {
2035       NV21ToYUV24Row = NV21ToYUV24Row_AVX2;
2036     }
2037   }
2038 #endif
2039   for (y = 0; y < height; ++y) {
2040     NV21ToYUV24Row(src_y, src_vu, dst_yuv24, width);
2041     dst_yuv24 += dst_stride_yuv24;
2042     src_y += src_stride_y;
2043     if (y & 1) {
2044       src_vu += src_stride_vu;
2045     }
2046   }
2047   return 0;
2048 }
2049 
2050 // Convert M420 to ARGB.
2051 LIBYUV_API
M420ToARGB(const uint8_t * src_m420,int src_stride_m420,uint8_t * dst_argb,int dst_stride_argb,int width,int height)2052 int M420ToARGB(const uint8_t* src_m420,
2053                int src_stride_m420,
2054                uint8_t* dst_argb,
2055                int dst_stride_argb,
2056                int width,
2057                int height) {
2058   int y;
2059   void (*NV12ToARGBRow)(
2060       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
2061       const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C;
2062   if (!src_m420 || !dst_argb || width <= 0 || height == 0) {
2063     return -1;
2064   }
2065   // Negative height means invert the image.
2066   if (height < 0) {
2067     height = -height;
2068     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
2069     dst_stride_argb = -dst_stride_argb;
2070   }
2071 #if defined(HAS_NV12TOARGBROW_SSSE3)
2072   if (TestCpuFlag(kCpuHasSSSE3)) {
2073     NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
2074     if (IS_ALIGNED(width, 8)) {
2075       NV12ToARGBRow = NV12ToARGBRow_SSSE3;
2076     }
2077   }
2078 #endif
2079 #if defined(HAS_NV12TOARGBROW_AVX2)
2080   if (TestCpuFlag(kCpuHasAVX2)) {
2081     NV12ToARGBRow = NV12ToARGBRow_Any_AVX2;
2082     if (IS_ALIGNED(width, 16)) {
2083       NV12ToARGBRow = NV12ToARGBRow_AVX2;
2084     }
2085   }
2086 #endif
2087 #if defined(HAS_NV12TOARGBROW_NEON)
2088   if (TestCpuFlag(kCpuHasNEON)) {
2089     NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
2090     if (IS_ALIGNED(width, 8)) {
2091       NV12ToARGBRow = NV12ToARGBRow_NEON;
2092     }
2093   }
2094 #endif
2095 #if defined(HAS_NV12TOARGBROW_MSA)
2096   if (TestCpuFlag(kCpuHasMSA)) {
2097     NV12ToARGBRow = NV12ToARGBRow_Any_MSA;
2098     if (IS_ALIGNED(width, 8)) {
2099       NV12ToARGBRow = NV12ToARGBRow_MSA;
2100     }
2101   }
2102 #endif
2103 
2104   for (y = 0; y < height - 1; y += 2) {
2105     NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb,
2106                   &kYuvI601Constants, width);
2107     NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2,
2108                   dst_argb + dst_stride_argb, &kYuvI601Constants, width);
2109     dst_argb += dst_stride_argb * 2;
2110     src_m420 += src_stride_m420 * 3;
2111   }
2112   if (height & 1) {
2113     NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb,
2114                   &kYuvI601Constants, width);
2115   }
2116   return 0;
2117 }
2118 
2119 // Convert YUY2 to ARGB.
2120 LIBYUV_API
YUY2ToARGB(const uint8_t * src_yuy2,int src_stride_yuy2,uint8_t * dst_argb,int dst_stride_argb,int width,int height)2121 int YUY2ToARGB(const uint8_t* src_yuy2,
2122                int src_stride_yuy2,
2123                uint8_t* dst_argb,
2124                int dst_stride_argb,
2125                int width,
2126                int height) {
2127   int y;
2128   void (*YUY2ToARGBRow)(const uint8_t* src_yuy2, uint8_t* dst_argb,
2129                         const struct YuvConstants* yuvconstants, int width) =
2130       YUY2ToARGBRow_C;
2131   if (!src_yuy2 || !dst_argb || width <= 0 || height == 0) {
2132     return -1;
2133   }
2134   // Negative height means invert the image.
2135   if (height < 0) {
2136     height = -height;
2137     src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
2138     src_stride_yuy2 = -src_stride_yuy2;
2139   }
2140   // Coalesce rows.
2141   if (src_stride_yuy2 == width * 2 && dst_stride_argb == width * 4) {
2142     width *= height;
2143     height = 1;
2144     src_stride_yuy2 = dst_stride_argb = 0;
2145   }
2146 #if defined(HAS_YUY2TOARGBROW_SSSE3)
2147   if (TestCpuFlag(kCpuHasSSSE3)) {
2148     YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3;
2149     if (IS_ALIGNED(width, 16)) {
2150       YUY2ToARGBRow = YUY2ToARGBRow_SSSE3;
2151     }
2152   }
2153 #endif
2154 #if defined(HAS_YUY2TOARGBROW_AVX2)
2155   if (TestCpuFlag(kCpuHasAVX2)) {
2156     YUY2ToARGBRow = YUY2ToARGBRow_Any_AVX2;
2157     if (IS_ALIGNED(width, 32)) {
2158       YUY2ToARGBRow = YUY2ToARGBRow_AVX2;
2159     }
2160   }
2161 #endif
2162 #if defined(HAS_YUY2TOARGBROW_NEON)
2163   if (TestCpuFlag(kCpuHasNEON)) {
2164     YUY2ToARGBRow = YUY2ToARGBRow_Any_NEON;
2165     if (IS_ALIGNED(width, 8)) {
2166       YUY2ToARGBRow = YUY2ToARGBRow_NEON;
2167     }
2168   }
2169 #endif
2170 #if defined(HAS_YUY2TOARGBROW_MSA)
2171   if (TestCpuFlag(kCpuHasMSA)) {
2172     YUY2ToARGBRow = YUY2ToARGBRow_Any_MSA;
2173     if (IS_ALIGNED(width, 8)) {
2174       YUY2ToARGBRow = YUY2ToARGBRow_MSA;
2175     }
2176   }
2177 #endif
2178   for (y = 0; y < height; ++y) {
2179     YUY2ToARGBRow(src_yuy2, dst_argb, &kYuvI601Constants, width);
2180     src_yuy2 += src_stride_yuy2;
2181     dst_argb += dst_stride_argb;
2182   }
2183   return 0;
2184 }
2185 
2186 // Convert UYVY to ARGB.
2187 LIBYUV_API
UYVYToARGB(const uint8_t * src_uyvy,int src_stride_uyvy,uint8_t * dst_argb,int dst_stride_argb,int width,int height)2188 int UYVYToARGB(const uint8_t* src_uyvy,
2189                int src_stride_uyvy,
2190                uint8_t* dst_argb,
2191                int dst_stride_argb,
2192                int width,
2193                int height) {
2194   int y;
2195   void (*UYVYToARGBRow)(const uint8_t* src_uyvy, uint8_t* dst_argb,
2196                         const struct YuvConstants* yuvconstants, int width) =
2197       UYVYToARGBRow_C;
2198   if (!src_uyvy || !dst_argb || width <= 0 || height == 0) {
2199     return -1;
2200   }
2201   // Negative height means invert the image.
2202   if (height < 0) {
2203     height = -height;
2204     src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
2205     src_stride_uyvy = -src_stride_uyvy;
2206   }
2207   // Coalesce rows.
2208   if (src_stride_uyvy == width * 2 && dst_stride_argb == width * 4) {
2209     width *= height;
2210     height = 1;
2211     src_stride_uyvy = dst_stride_argb = 0;
2212   }
2213 #if defined(HAS_UYVYTOARGBROW_SSSE3)
2214   if (TestCpuFlag(kCpuHasSSSE3)) {
2215     UYVYToARGBRow = UYVYToARGBRow_Any_SSSE3;
2216     if (IS_ALIGNED(width, 16)) {
2217       UYVYToARGBRow = UYVYToARGBRow_SSSE3;
2218     }
2219   }
2220 #endif
2221 #if defined(HAS_UYVYTOARGBROW_AVX2)
2222   if (TestCpuFlag(kCpuHasAVX2)) {
2223     UYVYToARGBRow = UYVYToARGBRow_Any_AVX2;
2224     if (IS_ALIGNED(width, 32)) {
2225       UYVYToARGBRow = UYVYToARGBRow_AVX2;
2226     }
2227   }
2228 #endif
2229 #if defined(HAS_UYVYTOARGBROW_NEON)
2230   if (TestCpuFlag(kCpuHasNEON)) {
2231     UYVYToARGBRow = UYVYToARGBRow_Any_NEON;
2232     if (IS_ALIGNED(width, 8)) {
2233       UYVYToARGBRow = UYVYToARGBRow_NEON;
2234     }
2235   }
2236 #endif
2237 #if defined(HAS_UYVYTOARGBROW_MSA)
2238   if (TestCpuFlag(kCpuHasMSA)) {
2239     UYVYToARGBRow = UYVYToARGBRow_Any_MSA;
2240     if (IS_ALIGNED(width, 8)) {
2241       UYVYToARGBRow = UYVYToARGBRow_MSA;
2242     }
2243   }
2244 #endif
2245   for (y = 0; y < height; ++y) {
2246     UYVYToARGBRow(src_uyvy, dst_argb, &kYuvI601Constants, width);
2247     src_uyvy += src_stride_uyvy;
2248     dst_argb += dst_stride_argb;
2249   }
2250   return 0;
2251 }
WeavePixels(const uint8_t * src_u,const uint8_t * src_v,int src_pixel_stride_uv,uint8_t * dst_uv,int width)2252 static void WeavePixels(const uint8_t* src_u,
2253                         const uint8_t* src_v,
2254                         int src_pixel_stride_uv,
2255                         uint8_t* dst_uv,
2256                         int width) {
2257   int i;
2258   for (i = 0; i < width; ++i) {
2259     dst_uv[0] = *src_u;
2260     dst_uv[1] = *src_v;
2261     dst_uv += 2;
2262     src_u += src_pixel_stride_uv;
2263     src_v += src_pixel_stride_uv;
2264   }
2265 }
2266 
2267 // Convert Android420 to ARGB.
2268 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)2269 int Android420ToARGBMatrix(const uint8_t* src_y,
2270                            int src_stride_y,
2271                            const uint8_t* src_u,
2272                            int src_stride_u,
2273                            const uint8_t* src_v,
2274                            int src_stride_v,
2275                            int src_pixel_stride_uv,
2276                            uint8_t* dst_argb,
2277                            int dst_stride_argb,
2278                            const struct YuvConstants* yuvconstants,
2279                            int width,
2280                            int height) {
2281   int y;
2282   uint8_t* dst_uv;
2283   const ptrdiff_t vu_off = src_v - src_u;
2284   int halfwidth = (width + 1) >> 1;
2285   int halfheight = (height + 1) >> 1;
2286   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
2287     return -1;
2288   }
2289   // Negative height means invert the image.
2290   if (height < 0) {
2291     height = -height;
2292     halfheight = (height + 1) >> 1;
2293     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
2294     dst_stride_argb = -dst_stride_argb;
2295   }
2296 
2297   // I420
2298   if (src_pixel_stride_uv == 1) {
2299     return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
2300                             src_stride_v, dst_argb, dst_stride_argb,
2301                             yuvconstants, width, height);
2302     // NV21
2303   }
2304   if (src_pixel_stride_uv == 2 && vu_off == -1 &&
2305       src_stride_u == src_stride_v) {
2306     return NV21ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, dst_argb,
2307                             dst_stride_argb, yuvconstants, width, height);
2308     // NV12
2309   }
2310   if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) {
2311     return NV12ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, dst_argb,
2312                             dst_stride_argb, yuvconstants, width, height);
2313   }
2314 
2315   // General case fallback creates NV12
2316   align_buffer_64(plane_uv, halfwidth * 2 * halfheight);
2317   dst_uv = plane_uv;
2318   for (y = 0; y < halfheight; ++y) {
2319     WeavePixels(src_u, src_v, src_pixel_stride_uv, dst_uv, halfwidth);
2320     src_u += src_stride_u;
2321     src_v += src_stride_v;
2322     dst_uv += halfwidth * 2;
2323   }
2324   NV12ToARGBMatrix(src_y, src_stride_y, plane_uv, halfwidth * 2, dst_argb,
2325                    dst_stride_argb, yuvconstants, width, height);
2326   free_aligned_buffer_64(plane_uv);
2327   return 0;
2328 }
2329 
2330 // Convert Android420 to ARGB.
2331 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)2332 int Android420ToARGB(const uint8_t* src_y,
2333                      int src_stride_y,
2334                      const uint8_t* src_u,
2335                      int src_stride_u,
2336                      const uint8_t* src_v,
2337                      int src_stride_v,
2338                      int src_pixel_stride_uv,
2339                      uint8_t* dst_argb,
2340                      int dst_stride_argb,
2341                      int width,
2342                      int height) {
2343   return Android420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
2344                                 src_stride_v, src_pixel_stride_uv, dst_argb,
2345                                 dst_stride_argb, &kYuvI601Constants, width,
2346                                 height);
2347 }
2348 
2349 // Convert Android420 to ABGR.
2350 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)2351 int Android420ToABGR(const uint8_t* src_y,
2352                      int src_stride_y,
2353                      const uint8_t* src_u,
2354                      int src_stride_u,
2355                      const uint8_t* src_v,
2356                      int src_stride_v,
2357                      int src_pixel_stride_uv,
2358                      uint8_t* dst_abgr,
2359                      int dst_stride_abgr,
2360                      int width,
2361                      int height) {
2362   return Android420ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
2363                                 src_stride_u, src_pixel_stride_uv, dst_abgr,
2364                                 dst_stride_abgr, &kYvuI601Constants, width,
2365                                 height);
2366 }
2367 
2368 #ifdef __cplusplus
2369 }  // extern "C"
2370 }  // namespace libyuv
2371 #endif
2372