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 #if defined(HAS_I422TOARGBROW_MMI)
109   if (TestCpuFlag(kCpuHasMMI)) {
110     I422ToARGBRow = I422ToARGBRow_Any_MMI;
111     if (IS_ALIGNED(width, 4)) {
112       I422ToARGBRow = I422ToARGBRow_MMI;
113     }
114   }
115 #endif
116 
117   for (y = 0; y < height; ++y) {
118     I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
119     dst_argb += dst_stride_argb;
120     src_y += src_stride_y;
121     if (y & 1) {
122       src_u += src_stride_u;
123       src_v += src_stride_v;
124     }
125   }
126   return 0;
127 }
128 
129 // Convert I420 to ARGB.
130 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)131 int I420ToARGB(const uint8_t* src_y,
132                int src_stride_y,
133                const uint8_t* src_u,
134                int src_stride_u,
135                const uint8_t* src_v,
136                int src_stride_v,
137                uint8_t* dst_argb,
138                int dst_stride_argb,
139                int width,
140                int height) {
141   return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
142                           src_stride_v, dst_argb, dst_stride_argb,
143                           &kYuvI601Constants, width, height);
144 }
145 
146 // Convert I420 to ABGR.
147 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)148 int I420ToABGR(const uint8_t* src_y,
149                int src_stride_y,
150                const uint8_t* src_u,
151                int src_stride_u,
152                const uint8_t* src_v,
153                int src_stride_v,
154                uint8_t* dst_abgr,
155                int dst_stride_abgr,
156                int width,
157                int height) {
158   return I420ToARGBMatrix(src_y, src_stride_y, src_v,
159                           src_stride_v,  // Swap U and V
160                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
161                           &kYvuI601Constants,  // Use Yvu matrix
162                           width, height);
163 }
164 
165 // Convert J420 to ARGB.
166 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)167 int J420ToARGB(const uint8_t* src_y,
168                int src_stride_y,
169                const uint8_t* src_u,
170                int src_stride_u,
171                const uint8_t* src_v,
172                int src_stride_v,
173                uint8_t* dst_argb,
174                int dst_stride_argb,
175                int width,
176                int height) {
177   return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
178                           src_stride_v, dst_argb, dst_stride_argb,
179                           &kYuvJPEGConstants, width, height);
180 }
181 
182 // Convert J420 to ABGR.
183 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)184 int J420ToABGR(const uint8_t* src_y,
185                int src_stride_y,
186                const uint8_t* src_u,
187                int src_stride_u,
188                const uint8_t* src_v,
189                int src_stride_v,
190                uint8_t* dst_abgr,
191                int dst_stride_abgr,
192                int width,
193                int height) {
194   return I420ToARGBMatrix(src_y, src_stride_y, src_v,
195                           src_stride_v,  // Swap U and V
196                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
197                           &kYvuJPEGConstants,  // Use Yvu matrix
198                           width, height);
199 }
200 
201 // Convert H420 to ARGB.
202 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)203 int H420ToARGB(const uint8_t* src_y,
204                int src_stride_y,
205                const uint8_t* src_u,
206                int src_stride_u,
207                const uint8_t* src_v,
208                int src_stride_v,
209                uint8_t* dst_argb,
210                int dst_stride_argb,
211                int width,
212                int height) {
213   return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
214                           src_stride_v, dst_argb, dst_stride_argb,
215                           &kYuvH709Constants, width, height);
216 }
217 
218 // Convert H420 to ABGR.
219 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)220 int H420ToABGR(const uint8_t* src_y,
221                int src_stride_y,
222                const uint8_t* src_u,
223                int src_stride_u,
224                const uint8_t* src_v,
225                int src_stride_v,
226                uint8_t* dst_abgr,
227                int dst_stride_abgr,
228                int width,
229                int height) {
230   return I420ToARGBMatrix(src_y, src_stride_y, src_v,
231                           src_stride_v,  // Swap U and V
232                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
233                           &kYvuH709Constants,  // Use Yvu matrix
234                           width, height);
235 }
236 
237 // Convert U420 to ARGB.
238 LIBYUV_API
U420ToARGB(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)239 int U420ToARGB(const uint8_t* src_y,
240                int src_stride_y,
241                const uint8_t* src_u,
242                int src_stride_u,
243                const uint8_t* src_v,
244                int src_stride_v,
245                uint8_t* dst_argb,
246                int dst_stride_argb,
247                int width,
248                int height) {
249   return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
250                           src_stride_v, dst_argb, dst_stride_argb,
251                           &kYuv2020Constants, width, height);
252 }
253 
254 // Convert U420 to ABGR.
255 LIBYUV_API
U420ToABGR(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)256 int U420ToABGR(const uint8_t* src_y,
257                int src_stride_y,
258                const uint8_t* src_u,
259                int src_stride_u,
260                const uint8_t* src_v,
261                int src_stride_v,
262                uint8_t* dst_abgr,
263                int dst_stride_abgr,
264                int width,
265                int height) {
266   return I420ToARGBMatrix(src_y, src_stride_y, src_v,
267                           src_stride_v,  // Swap U and V
268                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
269                           &kYvu2020Constants,  // Use Yvu matrix
270                           width, height);
271 }
272 
273 // 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)274 static int I422ToARGBMatrix(const uint8_t* src_y,
275                             int src_stride_y,
276                             const uint8_t* src_u,
277                             int src_stride_u,
278                             const uint8_t* src_v,
279                             int src_stride_v,
280                             uint8_t* dst_argb,
281                             int dst_stride_argb,
282                             const struct YuvConstants* yuvconstants,
283                             int width,
284                             int height) {
285   int y;
286   void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
287                         const uint8_t* v_buf, uint8_t* rgb_buf,
288                         const struct YuvConstants* yuvconstants, int width) =
289       I422ToARGBRow_C;
290   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
291     return -1;
292   }
293   // Negative height means invert the image.
294   if (height < 0) {
295     height = -height;
296     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
297     dst_stride_argb = -dst_stride_argb;
298   }
299   // Coalesce rows.
300   if (src_stride_y == width && src_stride_u * 2 == width &&
301       src_stride_v * 2 == width && dst_stride_argb == width * 4) {
302     width *= height;
303     height = 1;
304     src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
305   }
306 #if defined(HAS_I422TOARGBROW_SSSE3)
307   if (TestCpuFlag(kCpuHasSSSE3)) {
308     I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
309     if (IS_ALIGNED(width, 8)) {
310       I422ToARGBRow = I422ToARGBRow_SSSE3;
311     }
312   }
313 #endif
314 #if defined(HAS_I422TOARGBROW_AVX2)
315   if (TestCpuFlag(kCpuHasAVX2)) {
316     I422ToARGBRow = I422ToARGBRow_Any_AVX2;
317     if (IS_ALIGNED(width, 16)) {
318       I422ToARGBRow = I422ToARGBRow_AVX2;
319     }
320   }
321 #endif
322 #if defined(HAS_I422TOARGBROW_NEON)
323   if (TestCpuFlag(kCpuHasNEON)) {
324     I422ToARGBRow = I422ToARGBRow_Any_NEON;
325     if (IS_ALIGNED(width, 8)) {
326       I422ToARGBRow = I422ToARGBRow_NEON;
327     }
328   }
329 #endif
330 #if defined(HAS_I422TOARGBROW_MSA)
331   if (TestCpuFlag(kCpuHasMSA)) {
332     I422ToARGBRow = I422ToARGBRow_Any_MSA;
333     if (IS_ALIGNED(width, 8)) {
334       I422ToARGBRow = I422ToARGBRow_MSA;
335     }
336   }
337 #endif
338 #if defined(HAS_I422TOARGBROW_MMI)
339   if (TestCpuFlag(kCpuHasMMI)) {
340     I422ToARGBRow = I422ToARGBRow_Any_MMI;
341     if (IS_ALIGNED(width, 4)) {
342       I422ToARGBRow = I422ToARGBRow_MMI;
343     }
344   }
345 #endif
346 
347   for (y = 0; y < height; ++y) {
348     I422ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
349     dst_argb += dst_stride_argb;
350     src_y += src_stride_y;
351     src_u += src_stride_u;
352     src_v += src_stride_v;
353   }
354   return 0;
355 }
356 
357 // Convert I422 to ARGB.
358 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)359 int I422ToARGB(const uint8_t* src_y,
360                int src_stride_y,
361                const uint8_t* src_u,
362                int src_stride_u,
363                const uint8_t* src_v,
364                int src_stride_v,
365                uint8_t* dst_argb,
366                int dst_stride_argb,
367                int width,
368                int height) {
369   return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
370                           src_stride_v, dst_argb, dst_stride_argb,
371                           &kYuvI601Constants, width, height);
372 }
373 
374 // Convert I422 to ABGR.
375 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)376 int I422ToABGR(const uint8_t* src_y,
377                int src_stride_y,
378                const uint8_t* src_u,
379                int src_stride_u,
380                const uint8_t* src_v,
381                int src_stride_v,
382                uint8_t* dst_abgr,
383                int dst_stride_abgr,
384                int width,
385                int height) {
386   return I422ToARGBMatrix(src_y, src_stride_y, src_v,
387                           src_stride_v,  // Swap U and V
388                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
389                           &kYvuI601Constants,  // Use Yvu matrix
390                           width, height);
391 }
392 
393 // Convert J422 to ARGB.
394 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)395 int J422ToARGB(const uint8_t* src_y,
396                int src_stride_y,
397                const uint8_t* src_u,
398                int src_stride_u,
399                const uint8_t* src_v,
400                int src_stride_v,
401                uint8_t* dst_argb,
402                int dst_stride_argb,
403                int width,
404                int height) {
405   return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
406                           src_stride_v, dst_argb, dst_stride_argb,
407                           &kYuvJPEGConstants, width, height);
408 }
409 
410 // Convert J422 to ABGR.
411 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)412 int J422ToABGR(const uint8_t* src_y,
413                int src_stride_y,
414                const uint8_t* src_u,
415                int src_stride_u,
416                const uint8_t* src_v,
417                int src_stride_v,
418                uint8_t* dst_abgr,
419                int dst_stride_abgr,
420                int width,
421                int height) {
422   return I422ToARGBMatrix(src_y, src_stride_y, src_v,
423                           src_stride_v,  // Swap U and V
424                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
425                           &kYvuJPEGConstants,  // Use Yvu matrix
426                           width, height);
427 }
428 
429 // Convert H422 to ARGB.
430 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)431 int H422ToARGB(const uint8_t* src_y,
432                int src_stride_y,
433                const uint8_t* src_u,
434                int src_stride_u,
435                const uint8_t* src_v,
436                int src_stride_v,
437                uint8_t* dst_argb,
438                int dst_stride_argb,
439                int width,
440                int height) {
441   return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
442                           src_stride_v, dst_argb, dst_stride_argb,
443                           &kYuvH709Constants, width, height);
444 }
445 
446 // Convert H422 to ABGR.
447 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)448 int H422ToABGR(const uint8_t* src_y,
449                int src_stride_y,
450                const uint8_t* src_u,
451                int src_stride_u,
452                const uint8_t* src_v,
453                int src_stride_v,
454                uint8_t* dst_abgr,
455                int dst_stride_abgr,
456                int width,
457                int height) {
458   return I422ToARGBMatrix(src_y, src_stride_y, src_v,
459                           src_stride_v,  // Swap U and V
460                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
461                           &kYvuH709Constants,  // Use Yvu matrix
462                           width, height);
463 }
464 
465 // Convert U422 to ARGB.
466 LIBYUV_API
U422ToARGB(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)467 int U422ToARGB(const uint8_t* src_y,
468                int src_stride_y,
469                const uint8_t* src_u,
470                int src_stride_u,
471                const uint8_t* src_v,
472                int src_stride_v,
473                uint8_t* dst_argb,
474                int dst_stride_argb,
475                int width,
476                int height) {
477   return I422ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
478                           src_stride_v, dst_argb, dst_stride_argb,
479                           &kYuv2020Constants, width, height);
480 }
481 
482 // Convert U422 to ABGR.
483 LIBYUV_API
U422ToABGR(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)484 int U422ToABGR(const uint8_t* src_y,
485                int src_stride_y,
486                const uint8_t* src_u,
487                int src_stride_u,
488                const uint8_t* src_v,
489                int src_stride_v,
490                uint8_t* dst_abgr,
491                int dst_stride_abgr,
492                int width,
493                int height) {
494   return I422ToARGBMatrix(src_y, src_stride_y, src_v,
495                           src_stride_v,  // Swap U and V
496                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
497                           &kYvu2020Constants,  // Use Yvu matrix
498                           width, height);
499 }
500 
501 // 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)502 static int I444ToARGBMatrix(const uint8_t* src_y,
503                             int src_stride_y,
504                             const uint8_t* src_u,
505                             int src_stride_u,
506                             const uint8_t* src_v,
507                             int src_stride_v,
508                             uint8_t* dst_argb,
509                             int dst_stride_argb,
510                             const struct YuvConstants* yuvconstants,
511                             int width,
512                             int height) {
513   int y;
514   void (*I444ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
515                         const uint8_t* v_buf, uint8_t* rgb_buf,
516                         const struct YuvConstants* yuvconstants, int width) =
517       I444ToARGBRow_C;
518   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
519     return -1;
520   }
521   // Negative height means invert the image.
522   if (height < 0) {
523     height = -height;
524     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
525     dst_stride_argb = -dst_stride_argb;
526   }
527   // Coalesce rows.
528   if (src_stride_y == width && src_stride_u == width && src_stride_v == width &&
529       dst_stride_argb == width * 4) {
530     width *= height;
531     height = 1;
532     src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0;
533   }
534 #if defined(HAS_I444TOARGBROW_SSSE3)
535   if (TestCpuFlag(kCpuHasSSSE3)) {
536     I444ToARGBRow = I444ToARGBRow_Any_SSSE3;
537     if (IS_ALIGNED(width, 8)) {
538       I444ToARGBRow = I444ToARGBRow_SSSE3;
539     }
540   }
541 #endif
542 #if defined(HAS_I444TOARGBROW_AVX2)
543   if (TestCpuFlag(kCpuHasAVX2)) {
544     I444ToARGBRow = I444ToARGBRow_Any_AVX2;
545     if (IS_ALIGNED(width, 16)) {
546       I444ToARGBRow = I444ToARGBRow_AVX2;
547     }
548   }
549 #endif
550 #if defined(HAS_I444TOARGBROW_NEON)
551   if (TestCpuFlag(kCpuHasNEON)) {
552     I444ToARGBRow = I444ToARGBRow_Any_NEON;
553     if (IS_ALIGNED(width, 8)) {
554       I444ToARGBRow = I444ToARGBRow_NEON;
555     }
556   }
557 #endif
558 #if defined(HAS_I444TOARGBROW_MSA)
559   if (TestCpuFlag(kCpuHasMSA)) {
560     I444ToARGBRow = I444ToARGBRow_Any_MSA;
561     if (IS_ALIGNED(width, 8)) {
562       I444ToARGBRow = I444ToARGBRow_MSA;
563     }
564   }
565 #endif
566 #if defined(HAS_I444TOARGBROW_MMI)
567   if (TestCpuFlag(kCpuHasMMI)) {
568     I444ToARGBRow = I444ToARGBRow_Any_MMI;
569     if (IS_ALIGNED(width, 4)) {
570       I444ToARGBRow = I444ToARGBRow_MMI;
571     }
572   }
573 #endif
574 
575   for (y = 0; y < height; ++y) {
576     I444ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
577     dst_argb += dst_stride_argb;
578     src_y += src_stride_y;
579     src_u += src_stride_u;
580     src_v += src_stride_v;
581   }
582   return 0;
583 }
584 
585 // Convert I444 to ARGB.
586 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)587 int I444ToARGB(const uint8_t* src_y,
588                int src_stride_y,
589                const uint8_t* src_u,
590                int src_stride_u,
591                const uint8_t* src_v,
592                int src_stride_v,
593                uint8_t* dst_argb,
594                int dst_stride_argb,
595                int width,
596                int height) {
597   return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
598                           src_stride_v, dst_argb, dst_stride_argb,
599                           &kYuvI601Constants, width, height);
600 }
601 
602 // Convert I444 to ABGR.
603 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)604 int I444ToABGR(const uint8_t* src_y,
605                int src_stride_y,
606                const uint8_t* src_u,
607                int src_stride_u,
608                const uint8_t* src_v,
609                int src_stride_v,
610                uint8_t* dst_abgr,
611                int dst_stride_abgr,
612                int width,
613                int height) {
614   return I444ToARGBMatrix(src_y, src_stride_y, src_v,
615                           src_stride_v,  // Swap U and V
616                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
617                           &kYvuI601Constants,  // Use Yvu matrix
618                           width, height);
619 }
620 
621 // Convert J444 to ARGB.
622 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)623 int J444ToARGB(const uint8_t* src_y,
624                int src_stride_y,
625                const uint8_t* src_u,
626                int src_stride_u,
627                const uint8_t* src_v,
628                int src_stride_v,
629                uint8_t* dst_argb,
630                int dst_stride_argb,
631                int width,
632                int height) {
633   return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
634                           src_stride_v, dst_argb, dst_stride_argb,
635                           &kYuvJPEGConstants, width, height);
636 }
637 
638 // Convert J444 to ABGR.
639 LIBYUV_API
J444ToABGR(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)640 int J444ToABGR(const uint8_t* src_y,
641                int src_stride_y,
642                const uint8_t* src_u,
643                int src_stride_u,
644                const uint8_t* src_v,
645                int src_stride_v,
646                uint8_t* dst_abgr,
647                int dst_stride_abgr,
648                int width,
649                int height) {
650   return I444ToARGBMatrix(src_y, src_stride_y, src_v,
651                           src_stride_v,  // Swap U and V
652                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
653                           &kYvuJPEGConstants,  // Use Yvu matrix
654                           width, height);
655 }
656 
657 // Convert H444 to ARGB.
658 LIBYUV_API
H444ToARGB(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)659 int H444ToARGB(const uint8_t* src_y,
660                int src_stride_y,
661                const uint8_t* src_u,
662                int src_stride_u,
663                const uint8_t* src_v,
664                int src_stride_v,
665                uint8_t* dst_argb,
666                int dst_stride_argb,
667                int width,
668                int height) {
669   return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
670                           src_stride_v, dst_argb, dst_stride_argb,
671                           &kYuvH709Constants, width, height);
672 }
673 
674 // Convert H444 to ABGR.
675 LIBYUV_API
H444ToABGR(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)676 int H444ToABGR(const uint8_t* src_y,
677                int src_stride_y,
678                const uint8_t* src_u,
679                int src_stride_u,
680                const uint8_t* src_v,
681                int src_stride_v,
682                uint8_t* dst_abgr,
683                int dst_stride_abgr,
684                int width,
685                int height) {
686   return I444ToARGBMatrix(src_y, src_stride_y, src_v,
687                           src_stride_v,  // Swap U and V
688                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
689                           &kYvuH709Constants,  // Use Yvu matrix
690                           width, height);
691 }
692 
693 // Convert U444 to ARGB.
694 LIBYUV_API
U444ToARGB(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)695 int U444ToARGB(const uint8_t* src_y,
696                int src_stride_y,
697                const uint8_t* src_u,
698                int src_stride_u,
699                const uint8_t* src_v,
700                int src_stride_v,
701                uint8_t* dst_argb,
702                int dst_stride_argb,
703                int width,
704                int height) {
705   return I444ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
706                           src_stride_v, dst_argb, dst_stride_argb,
707                           &kYuv2020Constants, width, height);
708 }
709 
710 // Convert U444 to ABGR.
711 LIBYUV_API
U444ToABGR(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)712 int U444ToABGR(const uint8_t* src_y,
713                int src_stride_y,
714                const uint8_t* src_u,
715                int src_stride_u,
716                const uint8_t* src_v,
717                int src_stride_v,
718                uint8_t* dst_abgr,
719                int dst_stride_abgr,
720                int width,
721                int height) {
722   return I444ToARGBMatrix(src_y, src_stride_y, src_v,
723                           src_stride_v,  // Swap U and V
724                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
725                           &kYvu2020Constants,  // Use Yvu matrix
726                           width, height);
727 }
728 
729 // Convert 10 bit YUV to ARGB with matrix
730 // TODO(fbarchard): Consider passing scale multiplier to I210ToARGB to
731 // 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)732 static int I010ToAR30Matrix(const uint16_t* src_y,
733                             int src_stride_y,
734                             const uint16_t* src_u,
735                             int src_stride_u,
736                             const uint16_t* src_v,
737                             int src_stride_v,
738                             uint8_t* dst_ar30,
739                             int dst_stride_ar30,
740                             const struct YuvConstants* yuvconstants,
741                             int width,
742                             int height) {
743   int y;
744   void (*I210ToAR30Row)(const uint16_t* y_buf, const uint16_t* u_buf,
745                         const uint16_t* v_buf, uint8_t* rgb_buf,
746                         const struct YuvConstants* yuvconstants, int width) =
747       I210ToAR30Row_C;
748   if (!src_y || !src_u || !src_v || !dst_ar30 || width <= 0 || height == 0) {
749     return -1;
750   }
751   // Negative height means invert the image.
752   if (height < 0) {
753     height = -height;
754     dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30;
755     dst_stride_ar30 = -dst_stride_ar30;
756   }
757 #if defined(HAS_I210TOAR30ROW_SSSE3)
758   if (TestCpuFlag(kCpuHasSSSE3)) {
759     I210ToAR30Row = I210ToAR30Row_Any_SSSE3;
760     if (IS_ALIGNED(width, 8)) {
761       I210ToAR30Row = I210ToAR30Row_SSSE3;
762     }
763   }
764 #endif
765 #if defined(HAS_I210TOAR30ROW_AVX2)
766   if (TestCpuFlag(kCpuHasAVX2)) {
767     I210ToAR30Row = I210ToAR30Row_Any_AVX2;
768     if (IS_ALIGNED(width, 16)) {
769       I210ToAR30Row = I210ToAR30Row_AVX2;
770     }
771   }
772 #endif
773   for (y = 0; y < height; ++y) {
774     I210ToAR30Row(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
775     dst_ar30 += dst_stride_ar30;
776     src_y += src_stride_y;
777     if (y & 1) {
778       src_u += src_stride_u;
779       src_v += src_stride_v;
780     }
781   }
782   return 0;
783 }
784 
785 // Convert I010 to AR30.
786 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)787 int I010ToAR30(const uint16_t* src_y,
788                int src_stride_y,
789                const uint16_t* src_u,
790                int src_stride_u,
791                const uint16_t* src_v,
792                int src_stride_v,
793                uint8_t* dst_ar30,
794                int dst_stride_ar30,
795                int width,
796                int height) {
797   return I010ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
798                           src_stride_v, dst_ar30, dst_stride_ar30,
799                           &kYuvI601Constants, width, height);
800 }
801 
802 // Convert H010 to AR30.
803 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)804 int H010ToAR30(const uint16_t* src_y,
805                int src_stride_y,
806                const uint16_t* src_u,
807                int src_stride_u,
808                const uint16_t* src_v,
809                int src_stride_v,
810                uint8_t* dst_ar30,
811                int dst_stride_ar30,
812                int width,
813                int height) {
814   return I010ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
815                           src_stride_v, dst_ar30, dst_stride_ar30,
816                           &kYuvH709Constants, width, height);
817 }
818 
819 // Convert U010 to AR30.
820 LIBYUV_API
U010ToAR30(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)821 int U010ToAR30(const uint16_t* src_y,
822                int src_stride_y,
823                const uint16_t* src_u,
824                int src_stride_u,
825                const uint16_t* src_v,
826                int src_stride_v,
827                uint8_t* dst_ar30,
828                int dst_stride_ar30,
829                int width,
830                int height) {
831   return I010ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
832                           src_stride_v, dst_ar30, dst_stride_ar30,
833                           &kYuv2020Constants, width, height);
834 }
835 
836 // Convert I010 to AB30.
837 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)838 int I010ToAB30(const uint16_t* src_y,
839                int src_stride_y,
840                const uint16_t* src_u,
841                int src_stride_u,
842                const uint16_t* src_v,
843                int src_stride_v,
844                uint8_t* dst_ab30,
845                int dst_stride_ab30,
846                int width,
847                int height) {
848   return I010ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
849                           src_stride_u, dst_ab30, dst_stride_ab30,
850                           &kYvuI601Constants, width, height);
851 }
852 
853 // Convert H010 to AB30.
854 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)855 int H010ToAB30(const uint16_t* src_y,
856                int src_stride_y,
857                const uint16_t* src_u,
858                int src_stride_u,
859                const uint16_t* src_v,
860                int src_stride_v,
861                uint8_t* dst_ab30,
862                int dst_stride_ab30,
863                int width,
864                int height) {
865   return I010ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
866                           src_stride_u, dst_ab30, dst_stride_ab30,
867                           &kYvuH709Constants, width, height);
868 }
869 
870 // Convert U010 to AB30.
871 LIBYUV_API
U010ToAB30(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)872 int U010ToAB30(const uint16_t* src_y,
873                int src_stride_y,
874                const uint16_t* src_u,
875                int src_stride_u,
876                const uint16_t* src_v,
877                int src_stride_v,
878                uint8_t* dst_ab30,
879                int dst_stride_ab30,
880                int width,
881                int height) {
882   return I010ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
883                           src_stride_u, dst_ab30, dst_stride_ab30,
884                           &kYuv2020Constants, width, height);
885 }
886 
887 // Convert 10 bit YUV to ARGB with matrix
888 // TODO(fbarchard): Consider passing scale multiplier to I210ToARGB to
889 // multiply 10 bit yuv into high bits to allow any number of bits.
I210ToAR30Matrix(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)890 static int I210ToAR30Matrix(const uint16_t* src_y,
891                             int src_stride_y,
892                             const uint16_t* src_u,
893                             int src_stride_u,
894                             const uint16_t* src_v,
895                             int src_stride_v,
896                             uint8_t* dst_ar30,
897                             int dst_stride_ar30,
898                             const struct YuvConstants* yuvconstants,
899                             int width,
900                             int height) {
901   int y;
902   void (*I210ToAR30Row)(const uint16_t* y_buf, const uint16_t* u_buf,
903                         const uint16_t* v_buf, uint8_t* rgb_buf,
904                         const struct YuvConstants* yuvconstants, int width) =
905       I210ToAR30Row_C;
906   if (!src_y || !src_u || !src_v || !dst_ar30 || width <= 0 || height == 0) {
907     return -1;
908   }
909   // Negative height means invert the image.
910   if (height < 0) {
911     height = -height;
912     dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30;
913     dst_stride_ar30 = -dst_stride_ar30;
914   }
915 #if defined(HAS_I210TOAR30ROW_SSSE3)
916   if (TestCpuFlag(kCpuHasSSSE3)) {
917     I210ToAR30Row = I210ToAR30Row_Any_SSSE3;
918     if (IS_ALIGNED(width, 8)) {
919       I210ToAR30Row = I210ToAR30Row_SSSE3;
920     }
921   }
922 #endif
923 #if defined(HAS_I210TOAR30ROW_AVX2)
924   if (TestCpuFlag(kCpuHasAVX2)) {
925     I210ToAR30Row = I210ToAR30Row_Any_AVX2;
926     if (IS_ALIGNED(width, 16)) {
927       I210ToAR30Row = I210ToAR30Row_AVX2;
928     }
929   }
930 #endif
931   for (y = 0; y < height; ++y) {
932     I210ToAR30Row(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
933     dst_ar30 += dst_stride_ar30;
934     src_y += src_stride_y;
935     src_u += src_stride_u;
936     src_v += src_stride_v;
937   }
938   return 0;
939 }
940 
941 // Convert I210 to AR30.
942 LIBYUV_API
I210ToAR30(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)943 int I210ToAR30(const uint16_t* src_y,
944                int src_stride_y,
945                const uint16_t* src_u,
946                int src_stride_u,
947                const uint16_t* src_v,
948                int src_stride_v,
949                uint8_t* dst_ar30,
950                int dst_stride_ar30,
951                int width,
952                int height) {
953   return I210ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
954                           src_stride_v, dst_ar30, dst_stride_ar30,
955                           &kYuvI601Constants, width, height);
956 }
957 
958 // Convert H210 to AR30.
959 LIBYUV_API
H210ToAR30(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)960 int H210ToAR30(const uint16_t* src_y,
961                int src_stride_y,
962                const uint16_t* src_u,
963                int src_stride_u,
964                const uint16_t* src_v,
965                int src_stride_v,
966                uint8_t* dst_ar30,
967                int dst_stride_ar30,
968                int width,
969                int height) {
970   return I210ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
971                           src_stride_v, dst_ar30, dst_stride_ar30,
972                           &kYuvH709Constants, width, height);
973 }
974 
975 // Convert U210 to AR30.
976 LIBYUV_API
U210ToAR30(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)977 int U210ToAR30(const uint16_t* src_y,
978                int src_stride_y,
979                const uint16_t* src_u,
980                int src_stride_u,
981                const uint16_t* src_v,
982                int src_stride_v,
983                uint8_t* dst_ar30,
984                int dst_stride_ar30,
985                int width,
986                int height) {
987   return I210ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
988                           src_stride_v, dst_ar30, dst_stride_ar30,
989                           &kYuv2020Constants, width, height);
990 }
991 
992 // Convert I210 to AB30.
993 LIBYUV_API
I210ToAB30(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)994 int I210ToAB30(const uint16_t* src_y,
995                int src_stride_y,
996                const uint16_t* src_u,
997                int src_stride_u,
998                const uint16_t* src_v,
999                int src_stride_v,
1000                uint8_t* dst_ab30,
1001                int dst_stride_ab30,
1002                int width,
1003                int height) {
1004   return I210ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
1005                           src_stride_u, dst_ab30, dst_stride_ab30,
1006                           &kYvuI601Constants, width, height);
1007 }
1008 
1009 // Convert H210 to AB30.
1010 LIBYUV_API
H210ToAB30(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)1011 int H210ToAB30(const uint16_t* src_y,
1012                int src_stride_y,
1013                const uint16_t* src_u,
1014                int src_stride_u,
1015                const uint16_t* src_v,
1016                int src_stride_v,
1017                uint8_t* dst_ab30,
1018                int dst_stride_ab30,
1019                int width,
1020                int height) {
1021   return I210ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
1022                           src_stride_u, dst_ab30, dst_stride_ab30,
1023                           &kYvuH709Constants, width, height);
1024 }
1025 
1026 // Convert U210 to AB30.
1027 LIBYUV_API
U210ToAB30(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)1028 int U210ToAB30(const uint16_t* src_y,
1029                int src_stride_y,
1030                const uint16_t* src_u,
1031                int src_stride_u,
1032                const uint16_t* src_v,
1033                int src_stride_v,
1034                uint8_t* dst_ab30,
1035                int dst_stride_ab30,
1036                int width,
1037                int height) {
1038   return I210ToAR30Matrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
1039                           src_stride_u, dst_ab30, dst_stride_ab30,
1040                           &kYuv2020Constants, width, height);
1041 }
1042 
1043 // 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)1044 static int I010ToARGBMatrix(const uint16_t* src_y,
1045                             int src_stride_y,
1046                             const uint16_t* src_u,
1047                             int src_stride_u,
1048                             const uint16_t* src_v,
1049                             int src_stride_v,
1050                             uint8_t* dst_argb,
1051                             int dst_stride_argb,
1052                             const struct YuvConstants* yuvconstants,
1053                             int width,
1054                             int height) {
1055   int y;
1056   void (*I210ToARGBRow)(const uint16_t* y_buf, const uint16_t* u_buf,
1057                         const uint16_t* v_buf, uint8_t* rgb_buf,
1058                         const struct YuvConstants* yuvconstants, int width) =
1059       I210ToARGBRow_C;
1060   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
1061     return -1;
1062   }
1063   // Negative height means invert the image.
1064   if (height < 0) {
1065     height = -height;
1066     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1067     dst_stride_argb = -dst_stride_argb;
1068   }
1069 #if defined(HAS_I210TOARGBROW_SSSE3)
1070   if (TestCpuFlag(kCpuHasSSSE3)) {
1071     I210ToARGBRow = I210ToARGBRow_Any_SSSE3;
1072     if (IS_ALIGNED(width, 8)) {
1073       I210ToARGBRow = I210ToARGBRow_SSSE3;
1074     }
1075   }
1076 #endif
1077 #if defined(HAS_I210TOARGBROW_AVX2)
1078   if (TestCpuFlag(kCpuHasAVX2)) {
1079     I210ToARGBRow = I210ToARGBRow_Any_AVX2;
1080     if (IS_ALIGNED(width, 16)) {
1081       I210ToARGBRow = I210ToARGBRow_AVX2;
1082     }
1083   }
1084 #endif
1085 #if defined(HAS_I210TOARGBROW_MMI)
1086   if (TestCpuFlag(kCpuHasMMI)) {
1087     I210ToARGBRow = I210ToARGBRow_Any_MMI;
1088     if (IS_ALIGNED(width, 4)) {
1089       I210ToARGBRow = I210ToARGBRow_MMI;
1090     }
1091   }
1092 #endif
1093   for (y = 0; y < height; ++y) {
1094     I210ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
1095     dst_argb += dst_stride_argb;
1096     src_y += src_stride_y;
1097     if (y & 1) {
1098       src_u += src_stride_u;
1099       src_v += src_stride_v;
1100     }
1101   }
1102   return 0;
1103 }
1104 
1105 // Convert I010 to ARGB.
1106 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)1107 int I010ToARGB(const uint16_t* src_y,
1108                int src_stride_y,
1109                const uint16_t* src_u,
1110                int src_stride_u,
1111                const uint16_t* src_v,
1112                int src_stride_v,
1113                uint8_t* dst_argb,
1114                int dst_stride_argb,
1115                int width,
1116                int height) {
1117   return I010ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1118                           src_stride_v, dst_argb, dst_stride_argb,
1119                           &kYuvI601Constants, width, height);
1120 }
1121 
1122 // Convert I010 to ABGR.
1123 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)1124 int I010ToABGR(const uint16_t* src_y,
1125                int src_stride_y,
1126                const uint16_t* src_u,
1127                int src_stride_u,
1128                const uint16_t* src_v,
1129                int src_stride_v,
1130                uint8_t* dst_abgr,
1131                int dst_stride_abgr,
1132                int width,
1133                int height) {
1134   return I010ToARGBMatrix(src_y, src_stride_y, src_v,
1135                           src_stride_v,  // Swap U and V
1136                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
1137                           &kYvuI601Constants,  // Use Yvu matrix
1138                           width, height);
1139 }
1140 
1141 // Convert H010 to ARGB.
1142 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)1143 int H010ToARGB(const uint16_t* src_y,
1144                int src_stride_y,
1145                const uint16_t* src_u,
1146                int src_stride_u,
1147                const uint16_t* src_v,
1148                int src_stride_v,
1149                uint8_t* dst_argb,
1150                int dst_stride_argb,
1151                int width,
1152                int height) {
1153   return I010ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1154                           src_stride_v, dst_argb, dst_stride_argb,
1155                           &kYuvH709Constants, width, height);
1156 }
1157 
1158 // Convert H010 to ABGR.
1159 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)1160 int H010ToABGR(const uint16_t* src_y,
1161                int src_stride_y,
1162                const uint16_t* src_u,
1163                int src_stride_u,
1164                const uint16_t* src_v,
1165                int src_stride_v,
1166                uint8_t* dst_abgr,
1167                int dst_stride_abgr,
1168                int width,
1169                int height) {
1170   return I010ToARGBMatrix(src_y, src_stride_y, src_v,
1171                           src_stride_v,  // Swap U and V
1172                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
1173                           &kYvuH709Constants,  // Use Yvu matrix
1174                           width, height);
1175 }
1176 
1177 // Convert U010 to ARGB.
1178 LIBYUV_API
U010ToARGB(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)1179 int U010ToARGB(const uint16_t* src_y,
1180                int src_stride_y,
1181                const uint16_t* src_u,
1182                int src_stride_u,
1183                const uint16_t* src_v,
1184                int src_stride_v,
1185                uint8_t* dst_argb,
1186                int dst_stride_argb,
1187                int width,
1188                int height) {
1189   return I010ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1190                           src_stride_v, dst_argb, dst_stride_argb,
1191                           &kYuv2020Constants, width, height);
1192 }
1193 
1194 // Convert U010 to ABGR.
1195 LIBYUV_API
U010ToABGR(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)1196 int U010ToABGR(const uint16_t* src_y,
1197                int src_stride_y,
1198                const uint16_t* src_u,
1199                int src_stride_u,
1200                const uint16_t* src_v,
1201                int src_stride_v,
1202                uint8_t* dst_abgr,
1203                int dst_stride_abgr,
1204                int width,
1205                int height) {
1206   return I010ToARGBMatrix(src_y, src_stride_y, src_v,
1207                           src_stride_v,  // Swap U and V
1208                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
1209                           &kYvu2020Constants,  // Use Yvu matrix
1210                           width, height);
1211 }
1212 
1213 // Convert 10 bit 422 YUV to ARGB with matrix
I210ToARGBMatrix(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)1214 static int I210ToARGBMatrix(const uint16_t* src_y,
1215                             int src_stride_y,
1216                             const uint16_t* src_u,
1217                             int src_stride_u,
1218                             const uint16_t* src_v,
1219                             int src_stride_v,
1220                             uint8_t* dst_argb,
1221                             int dst_stride_argb,
1222                             const struct YuvConstants* yuvconstants,
1223                             int width,
1224                             int height) {
1225   int y;
1226   void (*I210ToARGBRow)(const uint16_t* y_buf, const uint16_t* u_buf,
1227                         const uint16_t* v_buf, uint8_t* rgb_buf,
1228                         const struct YuvConstants* yuvconstants, int width) =
1229       I210ToARGBRow_C;
1230   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
1231     return -1;
1232   }
1233   // Negative height means invert the image.
1234   if (height < 0) {
1235     height = -height;
1236     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1237     dst_stride_argb = -dst_stride_argb;
1238   }
1239 #if defined(HAS_I210TOARGBROW_SSSE3)
1240   if (TestCpuFlag(kCpuHasSSSE3)) {
1241     I210ToARGBRow = I210ToARGBRow_Any_SSSE3;
1242     if (IS_ALIGNED(width, 8)) {
1243       I210ToARGBRow = I210ToARGBRow_SSSE3;
1244     }
1245   }
1246 #endif
1247 #if defined(HAS_I210TOARGBROW_AVX2)
1248   if (TestCpuFlag(kCpuHasAVX2)) {
1249     I210ToARGBRow = I210ToARGBRow_Any_AVX2;
1250     if (IS_ALIGNED(width, 16)) {
1251       I210ToARGBRow = I210ToARGBRow_AVX2;
1252     }
1253   }
1254 #endif
1255 #if defined(HAS_I210TOARGBROW_MMI)
1256   if (TestCpuFlag(kCpuHasMMI)) {
1257     I210ToARGBRow = I210ToARGBRow_Any_MMI;
1258     if (IS_ALIGNED(width, 4)) {
1259       I210ToARGBRow = I210ToARGBRow_MMI;
1260     }
1261   }
1262 #endif
1263   for (y = 0; y < height; ++y) {
1264     I210ToARGBRow(src_y, src_u, src_v, dst_argb, yuvconstants, width);
1265     dst_argb += dst_stride_argb;
1266     src_y += src_stride_y;
1267     src_u += src_stride_u;
1268     src_v += src_stride_v;
1269   }
1270   return 0;
1271 }
1272 
1273 
1274 
1275 
1276 // Convert I210 to ARGB.
1277 LIBYUV_API
I210ToARGB(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)1278 int I210ToARGB(const uint16_t* src_y,
1279                int src_stride_y,
1280                const uint16_t* src_u,
1281                int src_stride_u,
1282                const uint16_t* src_v,
1283                int src_stride_v,
1284                uint8_t* dst_argb,
1285                int dst_stride_argb,
1286                int width,
1287                int height) {
1288   return I210ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1289                           src_stride_v, dst_argb, dst_stride_argb,
1290                           &kYuvI601Constants, width, height);
1291 }
1292 
1293 // Convert I210 to ABGR.
1294 LIBYUV_API
I210ToABGR(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)1295 int I210ToABGR(const uint16_t* src_y,
1296                int src_stride_y,
1297                const uint16_t* src_u,
1298                int src_stride_u,
1299                const uint16_t* src_v,
1300                int src_stride_v,
1301                uint8_t* dst_abgr,
1302                int dst_stride_abgr,
1303                int width,
1304                int height) {
1305   return I210ToARGBMatrix(src_y, src_stride_y, src_v,
1306                           src_stride_v,  // Swap U and V
1307                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
1308                           &kYvuI601Constants,  // Use Yvu matrix
1309                           width, height);
1310 }
1311 
1312 // Convert H210 to ARGB.
1313 LIBYUV_API
H210ToARGB(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)1314 int H210ToARGB(const uint16_t* src_y,
1315                int src_stride_y,
1316                const uint16_t* src_u,
1317                int src_stride_u,
1318                const uint16_t* src_v,
1319                int src_stride_v,
1320                uint8_t* dst_argb,
1321                int dst_stride_argb,
1322                int width,
1323                int height) {
1324   return I210ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1325                           src_stride_v, dst_argb, dst_stride_argb,
1326                           &kYuvH709Constants, width, height);
1327 }
1328 
1329 // Convert H210 to ABGR.
1330 LIBYUV_API
H210ToABGR(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)1331 int H210ToABGR(const uint16_t* src_y,
1332                int src_stride_y,
1333                const uint16_t* src_u,
1334                int src_stride_u,
1335                const uint16_t* src_v,
1336                int src_stride_v,
1337                uint8_t* dst_abgr,
1338                int dst_stride_abgr,
1339                int width,
1340                int height) {
1341   return I210ToARGBMatrix(src_y, src_stride_y, src_v,
1342                           src_stride_v,  // Swap U and V
1343                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
1344                           &kYvuH709Constants,  // Use Yvu matrix
1345                           width, height);
1346 }
1347 
1348 // Convert U210 to ARGB.
1349 LIBYUV_API
U210ToARGB(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)1350 int U210ToARGB(const uint16_t* src_y,
1351                int src_stride_y,
1352                const uint16_t* src_u,
1353                int src_stride_u,
1354                const uint16_t* src_v,
1355                int src_stride_v,
1356                uint8_t* dst_argb,
1357                int dst_stride_argb,
1358                int width,
1359                int height) {
1360   return I210ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1361                           src_stride_v, dst_argb, dst_stride_argb,
1362                           &kYuv2020Constants, width, height);
1363 }
1364 
1365 // Convert U210 to ABGR.
1366 LIBYUV_API
U210ToABGR(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)1367 int U210ToABGR(const uint16_t* src_y,
1368                int src_stride_y,
1369                const uint16_t* src_u,
1370                int src_stride_u,
1371                const uint16_t* src_v,
1372                int src_stride_v,
1373                uint8_t* dst_abgr,
1374                int dst_stride_abgr,
1375                int width,
1376                int height) {
1377   return I210ToARGBMatrix(src_y, src_stride_y, src_v,
1378                           src_stride_v,  // Swap U and V
1379                           src_u, src_stride_u, dst_abgr, dst_stride_abgr,
1380                           &kYvu2020Constants,  // Use Yvu matrix
1381                           width, height);
1382 }
1383 
1384 // 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)1385 static int I420AlphaToARGBMatrix(const uint8_t* src_y,
1386                                  int src_stride_y,
1387                                  const uint8_t* src_u,
1388                                  int src_stride_u,
1389                                  const uint8_t* src_v,
1390                                  int src_stride_v,
1391                                  const uint8_t* src_a,
1392                                  int src_stride_a,
1393                                  uint8_t* dst_argb,
1394                                  int dst_stride_argb,
1395                                  const struct YuvConstants* yuvconstants,
1396                                  int width,
1397                                  int height,
1398                                  int attenuate) {
1399   int y;
1400   void (*I422AlphaToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
1401                              const uint8_t* v_buf, const uint8_t* a_buf,
1402                              uint8_t* dst_argb,
1403                              const struct YuvConstants* yuvconstants,
1404                              int width) = I422AlphaToARGBRow_C;
1405   void (*ARGBAttenuateRow)(const uint8_t* src_argb, uint8_t* dst_argb,
1406                            int width) = ARGBAttenuateRow_C;
1407   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
1408     return -1;
1409   }
1410   // Negative height means invert the image.
1411   if (height < 0) {
1412     height = -height;
1413     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1414     dst_stride_argb = -dst_stride_argb;
1415   }
1416 #if defined(HAS_I422ALPHATOARGBROW_SSSE3)
1417   if (TestCpuFlag(kCpuHasSSSE3)) {
1418     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_SSSE3;
1419     if (IS_ALIGNED(width, 8)) {
1420       I422AlphaToARGBRow = I422AlphaToARGBRow_SSSE3;
1421     }
1422   }
1423 #endif
1424 #if defined(HAS_I422ALPHATOARGBROW_AVX2)
1425   if (TestCpuFlag(kCpuHasAVX2)) {
1426     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_AVX2;
1427     if (IS_ALIGNED(width, 16)) {
1428       I422AlphaToARGBRow = I422AlphaToARGBRow_AVX2;
1429     }
1430   }
1431 #endif
1432 #if defined(HAS_I422ALPHATOARGBROW_NEON)
1433   if (TestCpuFlag(kCpuHasNEON)) {
1434     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_NEON;
1435     if (IS_ALIGNED(width, 8)) {
1436       I422AlphaToARGBRow = I422AlphaToARGBRow_NEON;
1437     }
1438   }
1439 #endif
1440 #if defined(HAS_I422ALPHATOARGBROW_MSA)
1441   if (TestCpuFlag(kCpuHasMSA)) {
1442     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_MSA;
1443     if (IS_ALIGNED(width, 8)) {
1444       I422AlphaToARGBRow = I422AlphaToARGBRow_MSA;
1445     }
1446   }
1447 #endif
1448 #if defined(HAS_I422ALPHATOARGBROW_MMI)
1449   if (TestCpuFlag(kCpuHasMMI)) {
1450     I422AlphaToARGBRow = I422AlphaToARGBRow_Any_MMI;
1451     if (IS_ALIGNED(width, 4)) {
1452       I422AlphaToARGBRow = I422AlphaToARGBRow_MMI;
1453     }
1454   }
1455 #endif
1456 #if defined(HAS_ARGBATTENUATEROW_SSSE3)
1457   if (TestCpuFlag(kCpuHasSSSE3)) {
1458     ARGBAttenuateRow = ARGBAttenuateRow_Any_SSSE3;
1459     if (IS_ALIGNED(width, 4)) {
1460       ARGBAttenuateRow = ARGBAttenuateRow_SSSE3;
1461     }
1462   }
1463 #endif
1464 #if defined(HAS_ARGBATTENUATEROW_AVX2)
1465   if (TestCpuFlag(kCpuHasAVX2)) {
1466     ARGBAttenuateRow = ARGBAttenuateRow_Any_AVX2;
1467     if (IS_ALIGNED(width, 8)) {
1468       ARGBAttenuateRow = ARGBAttenuateRow_AVX2;
1469     }
1470   }
1471 #endif
1472 #if defined(HAS_ARGBATTENUATEROW_NEON)
1473   if (TestCpuFlag(kCpuHasNEON)) {
1474     ARGBAttenuateRow = ARGBAttenuateRow_Any_NEON;
1475     if (IS_ALIGNED(width, 8)) {
1476       ARGBAttenuateRow = ARGBAttenuateRow_NEON;
1477     }
1478   }
1479 #endif
1480 #if defined(HAS_ARGBATTENUATEROW_MSA)
1481   if (TestCpuFlag(kCpuHasMSA)) {
1482     ARGBAttenuateRow = ARGBAttenuateRow_Any_MSA;
1483     if (IS_ALIGNED(width, 8)) {
1484       ARGBAttenuateRow = ARGBAttenuateRow_MSA;
1485     }
1486   }
1487 #endif
1488 #if defined(HAS_ARGBATTENUATEROW_MMI)
1489   if (TestCpuFlag(kCpuHasMMI)) {
1490     ARGBAttenuateRow = ARGBAttenuateRow_Any_MMI;
1491     if (IS_ALIGNED(width, 2)) {
1492       ARGBAttenuateRow = ARGBAttenuateRow_MMI;
1493     }
1494   }
1495 #endif
1496 
1497   for (y = 0; y < height; ++y) {
1498     I422AlphaToARGBRow(src_y, src_u, src_v, src_a, dst_argb, yuvconstants,
1499                        width);
1500     if (attenuate) {
1501       ARGBAttenuateRow(dst_argb, dst_argb, width);
1502     }
1503     dst_argb += dst_stride_argb;
1504     src_a += src_stride_a;
1505     src_y += src_stride_y;
1506     if (y & 1) {
1507       src_u += src_stride_u;
1508       src_v += src_stride_v;
1509     }
1510   }
1511   return 0;
1512 }
1513 
1514 // Convert I420 with Alpha to ARGB.
1515 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)1516 int I420AlphaToARGB(const uint8_t* src_y,
1517                     int src_stride_y,
1518                     const uint8_t* src_u,
1519                     int src_stride_u,
1520                     const uint8_t* src_v,
1521                     int src_stride_v,
1522                     const uint8_t* src_a,
1523                     int src_stride_a,
1524                     uint8_t* dst_argb,
1525                     int dst_stride_argb,
1526                     int width,
1527                     int height,
1528                     int attenuate) {
1529   return I420AlphaToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1530                                src_stride_v, src_a, src_stride_a, dst_argb,
1531                                dst_stride_argb, &kYuvI601Constants, width,
1532                                height, attenuate);
1533 }
1534 
1535 // Convert I420 with Alpha to ABGR.
1536 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)1537 int I420AlphaToABGR(const uint8_t* src_y,
1538                     int src_stride_y,
1539                     const uint8_t* src_u,
1540                     int src_stride_u,
1541                     const uint8_t* src_v,
1542                     int src_stride_v,
1543                     const uint8_t* src_a,
1544                     int src_stride_a,
1545                     uint8_t* dst_abgr,
1546                     int dst_stride_abgr,
1547                     int width,
1548                     int height,
1549                     int attenuate) {
1550   return I420AlphaToARGBMatrix(
1551       src_y, src_stride_y, src_v, src_stride_v,  // Swap U and V
1552       src_u, src_stride_u, src_a, src_stride_a, dst_abgr, dst_stride_abgr,
1553       &kYvuI601Constants,  // Use Yvu matrix
1554       width, height, attenuate);
1555 }
1556 
1557 // Convert I400 to ARGB.
1558 LIBYUV_API
I400ToARGB(const uint8_t * src_y,int src_stride_y,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1559 int I400ToARGB(const uint8_t* src_y,
1560                int src_stride_y,
1561                uint8_t* dst_argb,
1562                int dst_stride_argb,
1563                int width,
1564                int height) {
1565   int y;
1566   void (*I400ToARGBRow)(const uint8_t* y_buf, uint8_t* rgb_buf, int width) =
1567       I400ToARGBRow_C;
1568   if (!src_y || !dst_argb || width <= 0 || height == 0) {
1569     return -1;
1570   }
1571   // Negative height means invert the image.
1572   if (height < 0) {
1573     height = -height;
1574     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1575     dst_stride_argb = -dst_stride_argb;
1576   }
1577   // Coalesce rows.
1578   if (src_stride_y == width && dst_stride_argb == width * 4) {
1579     width *= height;
1580     height = 1;
1581     src_stride_y = dst_stride_argb = 0;
1582   }
1583 #if defined(HAS_I400TOARGBROW_SSE2)
1584   if (TestCpuFlag(kCpuHasSSE2)) {
1585     I400ToARGBRow = I400ToARGBRow_Any_SSE2;
1586     if (IS_ALIGNED(width, 8)) {
1587       I400ToARGBRow = I400ToARGBRow_SSE2;
1588     }
1589   }
1590 #endif
1591 #if defined(HAS_I400TOARGBROW_AVX2)
1592   if (TestCpuFlag(kCpuHasAVX2)) {
1593     I400ToARGBRow = I400ToARGBRow_Any_AVX2;
1594     if (IS_ALIGNED(width, 16)) {
1595       I400ToARGBRow = I400ToARGBRow_AVX2;
1596     }
1597   }
1598 #endif
1599 #if defined(HAS_I400TOARGBROW_NEON)
1600   if (TestCpuFlag(kCpuHasNEON)) {
1601     I400ToARGBRow = I400ToARGBRow_Any_NEON;
1602     if (IS_ALIGNED(width, 8)) {
1603       I400ToARGBRow = I400ToARGBRow_NEON;
1604     }
1605   }
1606 #endif
1607 #if defined(HAS_I400TOARGBROW_MSA)
1608   if (TestCpuFlag(kCpuHasMSA)) {
1609     I400ToARGBRow = I400ToARGBRow_Any_MSA;
1610     if (IS_ALIGNED(width, 16)) {
1611       I400ToARGBRow = I400ToARGBRow_MSA;
1612     }
1613   }
1614 #endif
1615 #if defined(HAS_I400TOARGBROW_MMI)
1616   if (TestCpuFlag(kCpuHasMMI)) {
1617     I400ToARGBRow = I400ToARGBRow_Any_MMI;
1618     if (IS_ALIGNED(width, 8)) {
1619       I400ToARGBRow = I400ToARGBRow_MMI;
1620     }
1621   }
1622 #endif
1623 
1624   for (y = 0; y < height; ++y) {
1625     I400ToARGBRow(src_y, dst_argb, width);
1626     dst_argb += dst_stride_argb;
1627     src_y += src_stride_y;
1628   }
1629   return 0;
1630 }
1631 
1632 // Convert J400 to ARGB.
1633 LIBYUV_API
J400ToARGB(const uint8_t * src_y,int src_stride_y,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1634 int J400ToARGB(const uint8_t* src_y,
1635                int src_stride_y,
1636                uint8_t* dst_argb,
1637                int dst_stride_argb,
1638                int width,
1639                int height) {
1640   int y;
1641   void (*J400ToARGBRow)(const uint8_t* src_y, uint8_t* dst_argb, int width) =
1642       J400ToARGBRow_C;
1643   if (!src_y || !dst_argb || width <= 0 || height == 0) {
1644     return -1;
1645   }
1646   // Negative height means invert the image.
1647   if (height < 0) {
1648     height = -height;
1649     src_y = src_y + (height - 1) * src_stride_y;
1650     src_stride_y = -src_stride_y;
1651   }
1652   // Coalesce rows.
1653   if (src_stride_y == width && dst_stride_argb == width * 4) {
1654     width *= height;
1655     height = 1;
1656     src_stride_y = dst_stride_argb = 0;
1657   }
1658 #if defined(HAS_J400TOARGBROW_SSE2)
1659   if (TestCpuFlag(kCpuHasSSE2)) {
1660     J400ToARGBRow = J400ToARGBRow_Any_SSE2;
1661     if (IS_ALIGNED(width, 8)) {
1662       J400ToARGBRow = J400ToARGBRow_SSE2;
1663     }
1664   }
1665 #endif
1666 #if defined(HAS_J400TOARGBROW_AVX2)
1667   if (TestCpuFlag(kCpuHasAVX2)) {
1668     J400ToARGBRow = J400ToARGBRow_Any_AVX2;
1669     if (IS_ALIGNED(width, 16)) {
1670       J400ToARGBRow = J400ToARGBRow_AVX2;
1671     }
1672   }
1673 #endif
1674 #if defined(HAS_J400TOARGBROW_NEON)
1675   if (TestCpuFlag(kCpuHasNEON)) {
1676     J400ToARGBRow = J400ToARGBRow_Any_NEON;
1677     if (IS_ALIGNED(width, 8)) {
1678       J400ToARGBRow = J400ToARGBRow_NEON;
1679     }
1680   }
1681 #endif
1682 #if defined(HAS_J400TOARGBROW_MSA)
1683   if (TestCpuFlag(kCpuHasMSA)) {
1684     J400ToARGBRow = J400ToARGBRow_Any_MSA;
1685     if (IS_ALIGNED(width, 16)) {
1686       J400ToARGBRow = J400ToARGBRow_MSA;
1687     }
1688   }
1689 #endif
1690 #if defined(HAS_J400TOARGBROW_MMI)
1691   if (TestCpuFlag(kCpuHasMMI)) {
1692     J400ToARGBRow = J400ToARGBRow_Any_MMI;
1693     if (IS_ALIGNED(width, 4)) {
1694       J400ToARGBRow = J400ToARGBRow_MMI;
1695     }
1696   }
1697 #endif
1698   for (y = 0; y < height; ++y) {
1699     J400ToARGBRow(src_y, dst_argb, width);
1700     src_y += src_stride_y;
1701     dst_argb += dst_stride_argb;
1702   }
1703   return 0;
1704 }
1705 
1706 // Shuffle table for converting BGRA to ARGB.
1707 static const uvec8 kShuffleMaskBGRAToARGB = {
1708     3u, 2u, 1u, 0u, 7u, 6u, 5u, 4u, 11u, 10u, 9u, 8u, 15u, 14u, 13u, 12u};
1709 
1710 // Shuffle table for converting ABGR to ARGB.
1711 static const uvec8 kShuffleMaskABGRToARGB = {
1712     2u, 1u, 0u, 3u, 6u, 5u, 4u, 7u, 10u, 9u, 8u, 11u, 14u, 13u, 12u, 15u};
1713 
1714 // Shuffle table for converting RGBA to ARGB.
1715 static const uvec8 kShuffleMaskRGBAToARGB = {
1716     1u, 2u, 3u, 0u, 5u, 6u, 7u, 4u, 9u, 10u, 11u, 8u, 13u, 14u, 15u, 12u};
1717 
1718 // Convert BGRA to ARGB.
1719 LIBYUV_API
BGRAToARGB(const uint8_t * src_bgra,int src_stride_bgra,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1720 int BGRAToARGB(const uint8_t* src_bgra,
1721                int src_stride_bgra,
1722                uint8_t* dst_argb,
1723                int dst_stride_argb,
1724                int width,
1725                int height) {
1726   return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb,
1727                      (const uint8_t*)(&kShuffleMaskBGRAToARGB), width, height);
1728 }
1729 
1730 // Convert ARGB to BGRA (same as BGRAToARGB).
1731 LIBYUV_API
ARGBToBGRA(const uint8_t * src_bgra,int src_stride_bgra,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1732 int ARGBToBGRA(const uint8_t* src_bgra,
1733                int src_stride_bgra,
1734                uint8_t* dst_argb,
1735                int dst_stride_argb,
1736                int width,
1737                int height) {
1738   return ARGBShuffle(src_bgra, src_stride_bgra, dst_argb, dst_stride_argb,
1739                      (const uint8_t*)(&kShuffleMaskBGRAToARGB), width, height);
1740 }
1741 
1742 // Convert ABGR to ARGB.
1743 LIBYUV_API
ABGRToARGB(const uint8_t * src_abgr,int src_stride_abgr,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1744 int ABGRToARGB(const uint8_t* src_abgr,
1745                int src_stride_abgr,
1746                uint8_t* dst_argb,
1747                int dst_stride_argb,
1748                int width,
1749                int height) {
1750   return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb,
1751                      (const uint8_t*)(&kShuffleMaskABGRToARGB), width, height);
1752 }
1753 
1754 // Convert ARGB to ABGR to (same as ABGRToARGB).
1755 LIBYUV_API
ARGBToABGR(const uint8_t * src_abgr,int src_stride_abgr,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1756 int ARGBToABGR(const uint8_t* src_abgr,
1757                int src_stride_abgr,
1758                uint8_t* dst_argb,
1759                int dst_stride_argb,
1760                int width,
1761                int height) {
1762   return ARGBShuffle(src_abgr, src_stride_abgr, dst_argb, dst_stride_argb,
1763                      (const uint8_t*)(&kShuffleMaskABGRToARGB), width, height);
1764 }
1765 
1766 // Convert RGBA to ARGB.
1767 LIBYUV_API
RGBAToARGB(const uint8_t * src_rgba,int src_stride_rgba,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1768 int RGBAToARGB(const uint8_t* src_rgba,
1769                int src_stride_rgba,
1770                uint8_t* dst_argb,
1771                int dst_stride_argb,
1772                int width,
1773                int height) {
1774   return ARGBShuffle(src_rgba, src_stride_rgba, dst_argb, dst_stride_argb,
1775                      (const uint8_t*)(&kShuffleMaskRGBAToARGB), width, height);
1776 }
1777 
1778 // Convert RGB24 to ARGB.
1779 LIBYUV_API
RGB24ToARGB(const uint8_t * src_rgb24,int src_stride_rgb24,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1780 int RGB24ToARGB(const uint8_t* src_rgb24,
1781                 int src_stride_rgb24,
1782                 uint8_t* dst_argb,
1783                 int dst_stride_argb,
1784                 int width,
1785                 int height) {
1786   int y;
1787   void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
1788       RGB24ToARGBRow_C;
1789   if (!src_rgb24 || !dst_argb || width <= 0 || height == 0) {
1790     return -1;
1791   }
1792   // Negative height means invert the image.
1793   if (height < 0) {
1794     height = -height;
1795     src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
1796     src_stride_rgb24 = -src_stride_rgb24;
1797   }
1798   // Coalesce rows.
1799   if (src_stride_rgb24 == width * 3 && dst_stride_argb == width * 4) {
1800     width *= height;
1801     height = 1;
1802     src_stride_rgb24 = dst_stride_argb = 0;
1803   }
1804 #if defined(HAS_RGB24TOARGBROW_SSSE3)
1805   if (TestCpuFlag(kCpuHasSSSE3)) {
1806     RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
1807     if (IS_ALIGNED(width, 16)) {
1808       RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
1809     }
1810   }
1811 #endif
1812 #if defined(HAS_RGB24TOARGBROW_NEON)
1813   if (TestCpuFlag(kCpuHasNEON)) {
1814     RGB24ToARGBRow = RGB24ToARGBRow_Any_NEON;
1815     if (IS_ALIGNED(width, 8)) {
1816       RGB24ToARGBRow = RGB24ToARGBRow_NEON;
1817     }
1818   }
1819 #endif
1820 #if defined(HAS_RGB24TOARGBROW_MSA)
1821   if (TestCpuFlag(kCpuHasMSA)) {
1822     RGB24ToARGBRow = RGB24ToARGBRow_Any_MSA;
1823     if (IS_ALIGNED(width, 16)) {
1824       RGB24ToARGBRow = RGB24ToARGBRow_MSA;
1825     }
1826   }
1827 #endif
1828 #if defined(HAS_RGB24TOARGBROW_MMI)
1829   if (TestCpuFlag(kCpuHasMMI)) {
1830     RGB24ToARGBRow = RGB24ToARGBRow_Any_MMI;
1831     if (IS_ALIGNED(width, 4)) {
1832       RGB24ToARGBRow = RGB24ToARGBRow_MMI;
1833     }
1834   }
1835 #endif
1836 
1837   for (y = 0; y < height; ++y) {
1838     RGB24ToARGBRow(src_rgb24, dst_argb, width);
1839     src_rgb24 += src_stride_rgb24;
1840     dst_argb += dst_stride_argb;
1841   }
1842   return 0;
1843 }
1844 
1845 // Convert RAW to ARGB.
1846 LIBYUV_API
RAWToARGB(const uint8_t * src_raw,int src_stride_raw,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1847 int RAWToARGB(const uint8_t* src_raw,
1848               int src_stride_raw,
1849               uint8_t* dst_argb,
1850               int dst_stride_argb,
1851               int width,
1852               int height) {
1853   int y;
1854   void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
1855       RAWToARGBRow_C;
1856   if (!src_raw || !dst_argb || width <= 0 || height == 0) {
1857     return -1;
1858   }
1859   // Negative height means invert the image.
1860   if (height < 0) {
1861     height = -height;
1862     src_raw = src_raw + (height - 1) * src_stride_raw;
1863     src_stride_raw = -src_stride_raw;
1864   }
1865   // Coalesce rows.
1866   if (src_stride_raw == width * 3 && dst_stride_argb == width * 4) {
1867     width *= height;
1868     height = 1;
1869     src_stride_raw = dst_stride_argb = 0;
1870   }
1871 #if defined(HAS_RAWTOARGBROW_SSSE3)
1872   if (TestCpuFlag(kCpuHasSSSE3)) {
1873     RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
1874     if (IS_ALIGNED(width, 16)) {
1875       RAWToARGBRow = RAWToARGBRow_SSSE3;
1876     }
1877   }
1878 #endif
1879 #if defined(HAS_RAWTOARGBROW_NEON)
1880   if (TestCpuFlag(kCpuHasNEON)) {
1881     RAWToARGBRow = RAWToARGBRow_Any_NEON;
1882     if (IS_ALIGNED(width, 8)) {
1883       RAWToARGBRow = RAWToARGBRow_NEON;
1884     }
1885   }
1886 #endif
1887 #if defined(HAS_RAWTOARGBROW_MSA)
1888   if (TestCpuFlag(kCpuHasMSA)) {
1889     RAWToARGBRow = RAWToARGBRow_Any_MSA;
1890     if (IS_ALIGNED(width, 16)) {
1891       RAWToARGBRow = RAWToARGBRow_MSA;
1892     }
1893   }
1894 #endif
1895 #if defined(HAS_RAWTOARGBROW_MMI)
1896   if (TestCpuFlag(kCpuHasMMI)) {
1897     RAWToARGBRow = RAWToARGBRow_Any_MMI;
1898     if (IS_ALIGNED(width, 4)) {
1899       RAWToARGBRow = RAWToARGBRow_MMI;
1900     }
1901   }
1902 #endif
1903 
1904   for (y = 0; y < height; ++y) {
1905     RAWToARGBRow(src_raw, dst_argb, width);
1906     src_raw += src_stride_raw;
1907     dst_argb += dst_stride_argb;
1908   }
1909   return 0;
1910 }
1911 
1912 // Convert RAW to RGBA.
1913 LIBYUV_API
RAWToRGBA(const uint8_t * src_raw,int src_stride_raw,uint8_t * dst_rgba,int dst_stride_rgba,int width,int height)1914 int RAWToRGBA(const uint8_t* src_raw,
1915               int src_stride_raw,
1916               uint8_t* dst_rgba,
1917               int dst_stride_rgba,
1918               int width,
1919               int height) {
1920   int y;
1921   void (*RAWToRGBARow)(const uint8_t* src_rgb, uint8_t* dst_rgba, int width) =
1922       RAWToRGBARow_C;
1923   if (!src_raw || !dst_rgba || width <= 0 || height == 0) {
1924     return -1;
1925   }
1926   // Negative height means invert the image.
1927   if (height < 0) {
1928     height = -height;
1929     src_raw = src_raw + (height - 1) * src_stride_raw;
1930     src_stride_raw = -src_stride_raw;
1931   }
1932   // Coalesce rows.
1933   if (src_stride_raw == width * 3 && dst_stride_rgba == width * 4) {
1934     width *= height;
1935     height = 1;
1936     src_stride_raw = dst_stride_rgba = 0;
1937   }
1938 #if defined(HAS_RAWTORGBAROW_SSSE3)
1939   if (TestCpuFlag(kCpuHasSSSE3)) {
1940     RAWToRGBARow = RAWToRGBARow_Any_SSSE3;
1941     if (IS_ALIGNED(width, 16)) {
1942       RAWToRGBARow = RAWToRGBARow_SSSE3;
1943     }
1944   }
1945 #endif
1946 #if defined(HAS_RAWTORGBAROW_NEON)
1947   if (TestCpuFlag(kCpuHasNEON)) {
1948     RAWToRGBARow = RAWToRGBARow_Any_NEON;
1949     if (IS_ALIGNED(width, 8)) {
1950       RAWToRGBARow = RAWToRGBARow_NEON;
1951     }
1952   }
1953 #endif
1954 
1955   for (y = 0; y < height; ++y) {
1956     RAWToRGBARow(src_raw, dst_rgba, width);
1957     src_raw += src_stride_raw;
1958     dst_rgba += dst_stride_rgba;
1959   }
1960   return 0;
1961 }
1962 
1963 // Convert RGB565 to ARGB.
1964 LIBYUV_API
RGB565ToARGB(const uint8_t * src_rgb565,int src_stride_rgb565,uint8_t * dst_argb,int dst_stride_argb,int width,int height)1965 int RGB565ToARGB(const uint8_t* src_rgb565,
1966                  int src_stride_rgb565,
1967                  uint8_t* dst_argb,
1968                  int dst_stride_argb,
1969                  int width,
1970                  int height) {
1971   int y;
1972   void (*RGB565ToARGBRow)(const uint8_t* src_rgb565, uint8_t* dst_argb,
1973                           int width) = RGB565ToARGBRow_C;
1974   if (!src_rgb565 || !dst_argb || width <= 0 || height == 0) {
1975     return -1;
1976   }
1977   // Negative height means invert the image.
1978   if (height < 0) {
1979     height = -height;
1980     src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
1981     src_stride_rgb565 = -src_stride_rgb565;
1982   }
1983   // Coalesce rows.
1984   if (src_stride_rgb565 == width * 2 && dst_stride_argb == width * 4) {
1985     width *= height;
1986     height = 1;
1987     src_stride_rgb565 = dst_stride_argb = 0;
1988   }
1989 #if defined(HAS_RGB565TOARGBROW_SSE2)
1990   if (TestCpuFlag(kCpuHasSSE2)) {
1991     RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
1992     if (IS_ALIGNED(width, 8)) {
1993       RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
1994     }
1995   }
1996 #endif
1997 #if defined(HAS_RGB565TOARGBROW_AVX2)
1998   if (TestCpuFlag(kCpuHasAVX2)) {
1999     RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
2000     if (IS_ALIGNED(width, 16)) {
2001       RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
2002     }
2003   }
2004 #endif
2005 #if defined(HAS_RGB565TOARGBROW_NEON)
2006   if (TestCpuFlag(kCpuHasNEON)) {
2007     RGB565ToARGBRow = RGB565ToARGBRow_Any_NEON;
2008     if (IS_ALIGNED(width, 8)) {
2009       RGB565ToARGBRow = RGB565ToARGBRow_NEON;
2010     }
2011   }
2012 #endif
2013 #if defined(HAS_RGB565TOARGBROW_MSA)
2014   if (TestCpuFlag(kCpuHasMSA)) {
2015     RGB565ToARGBRow = RGB565ToARGBRow_Any_MSA;
2016     if (IS_ALIGNED(width, 16)) {
2017       RGB565ToARGBRow = RGB565ToARGBRow_MSA;
2018     }
2019   }
2020 #endif
2021 #if defined(HAS_RGB565TOARGBROW_MMI)
2022   if (TestCpuFlag(kCpuHasMMI)) {
2023     RGB565ToARGBRow = RGB565ToARGBRow_Any_MMI;
2024     if (IS_ALIGNED(width, 4)) {
2025       RGB565ToARGBRow = RGB565ToARGBRow_MMI;
2026     }
2027   }
2028 #endif
2029 
2030   for (y = 0; y < height; ++y) {
2031     RGB565ToARGBRow(src_rgb565, dst_argb, width);
2032     src_rgb565 += src_stride_rgb565;
2033     dst_argb += dst_stride_argb;
2034   }
2035   return 0;
2036 }
2037 
2038 // Convert ARGB1555 to ARGB.
2039 LIBYUV_API
ARGB1555ToARGB(const uint8_t * src_argb1555,int src_stride_argb1555,uint8_t * dst_argb,int dst_stride_argb,int width,int height)2040 int ARGB1555ToARGB(const uint8_t* src_argb1555,
2041                    int src_stride_argb1555,
2042                    uint8_t* dst_argb,
2043                    int dst_stride_argb,
2044                    int width,
2045                    int height) {
2046   int y;
2047   void (*ARGB1555ToARGBRow)(const uint8_t* src_argb1555, uint8_t* dst_argb,
2048                             int width) = ARGB1555ToARGBRow_C;
2049   if (!src_argb1555 || !dst_argb || width <= 0 || height == 0) {
2050     return -1;
2051   }
2052   // Negative height means invert the image.
2053   if (height < 0) {
2054     height = -height;
2055     src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
2056     src_stride_argb1555 = -src_stride_argb1555;
2057   }
2058   // Coalesce rows.
2059   if (src_stride_argb1555 == width * 2 && dst_stride_argb == width * 4) {
2060     width *= height;
2061     height = 1;
2062     src_stride_argb1555 = dst_stride_argb = 0;
2063   }
2064 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
2065   if (TestCpuFlag(kCpuHasSSE2)) {
2066     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
2067     if (IS_ALIGNED(width, 8)) {
2068       ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
2069     }
2070   }
2071 #endif
2072 #if defined(HAS_ARGB1555TOARGBROW_AVX2)
2073   if (TestCpuFlag(kCpuHasAVX2)) {
2074     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
2075     if (IS_ALIGNED(width, 16)) {
2076       ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
2077     }
2078   }
2079 #endif
2080 #if defined(HAS_ARGB1555TOARGBROW_NEON)
2081   if (TestCpuFlag(kCpuHasNEON)) {
2082     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_NEON;
2083     if (IS_ALIGNED(width, 8)) {
2084       ARGB1555ToARGBRow = ARGB1555ToARGBRow_NEON;
2085     }
2086   }
2087 #endif
2088 #if defined(HAS_ARGB1555TOARGBROW_MSA)
2089   if (TestCpuFlag(kCpuHasMSA)) {
2090     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_MSA;
2091     if (IS_ALIGNED(width, 16)) {
2092       ARGB1555ToARGBRow = ARGB1555ToARGBRow_MSA;
2093     }
2094   }
2095 #endif
2096 #if defined(HAS_ARGB1555TOARGBROW_MMI)
2097   if (TestCpuFlag(kCpuHasMMI)) {
2098     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_MMI;
2099     if (IS_ALIGNED(width, 4)) {
2100       ARGB1555ToARGBRow = ARGB1555ToARGBRow_MMI;
2101     }
2102   }
2103 #endif
2104 
2105   for (y = 0; y < height; ++y) {
2106     ARGB1555ToARGBRow(src_argb1555, dst_argb, width);
2107     src_argb1555 += src_stride_argb1555;
2108     dst_argb += dst_stride_argb;
2109   }
2110   return 0;
2111 }
2112 
2113 // Convert ARGB4444 to ARGB.
2114 LIBYUV_API
ARGB4444ToARGB(const uint8_t * src_argb4444,int src_stride_argb4444,uint8_t * dst_argb,int dst_stride_argb,int width,int height)2115 int ARGB4444ToARGB(const uint8_t* src_argb4444,
2116                    int src_stride_argb4444,
2117                    uint8_t* dst_argb,
2118                    int dst_stride_argb,
2119                    int width,
2120                    int height) {
2121   int y;
2122   void (*ARGB4444ToARGBRow)(const uint8_t* src_argb4444, uint8_t* dst_argb,
2123                             int width) = ARGB4444ToARGBRow_C;
2124   if (!src_argb4444 || !dst_argb || width <= 0 || height == 0) {
2125     return -1;
2126   }
2127   // Negative height means invert the image.
2128   if (height < 0) {
2129     height = -height;
2130     src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
2131     src_stride_argb4444 = -src_stride_argb4444;
2132   }
2133   // Coalesce rows.
2134   if (src_stride_argb4444 == width * 2 && dst_stride_argb == width * 4) {
2135     width *= height;
2136     height = 1;
2137     src_stride_argb4444 = dst_stride_argb = 0;
2138   }
2139 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
2140   if (TestCpuFlag(kCpuHasSSE2)) {
2141     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
2142     if (IS_ALIGNED(width, 8)) {
2143       ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
2144     }
2145   }
2146 #endif
2147 #if defined(HAS_ARGB4444TOARGBROW_AVX2)
2148   if (TestCpuFlag(kCpuHasAVX2)) {
2149     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
2150     if (IS_ALIGNED(width, 16)) {
2151       ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
2152     }
2153   }
2154 #endif
2155 #if defined(HAS_ARGB4444TOARGBROW_NEON)
2156   if (TestCpuFlag(kCpuHasNEON)) {
2157     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_NEON;
2158     if (IS_ALIGNED(width, 8)) {
2159       ARGB4444ToARGBRow = ARGB4444ToARGBRow_NEON;
2160     }
2161   }
2162 #endif
2163 #if defined(HAS_ARGB4444TOARGBROW_MSA)
2164   if (TestCpuFlag(kCpuHasMSA)) {
2165     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA;
2166     if (IS_ALIGNED(width, 16)) {
2167       ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA;
2168     }
2169   }
2170 #endif
2171 #if defined(HAS_ARGB4444TOARGBROW_MMI)
2172   if (TestCpuFlag(kCpuHasMMI)) {
2173     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MMI;
2174     if (IS_ALIGNED(width, 4)) {
2175       ARGB4444ToARGBRow = ARGB4444ToARGBRow_MMI;
2176     }
2177   }
2178 #endif
2179 
2180   for (y = 0; y < height; ++y) {
2181     ARGB4444ToARGBRow(src_argb4444, dst_argb, width);
2182     src_argb4444 += src_stride_argb4444;
2183     dst_argb += dst_stride_argb;
2184   }
2185   return 0;
2186 }
2187 
2188 // Convert AR30 to ARGB.
2189 LIBYUV_API
AR30ToARGB(const uint8_t * src_ar30,int src_stride_ar30,uint8_t * dst_argb,int dst_stride_argb,int width,int height)2190 int AR30ToARGB(const uint8_t* src_ar30,
2191                int src_stride_ar30,
2192                uint8_t* dst_argb,
2193                int dst_stride_argb,
2194                int width,
2195                int height) {
2196   int y;
2197   if (!src_ar30 || !dst_argb || width <= 0 || height == 0) {
2198     return -1;
2199   }
2200   // Negative height means invert the image.
2201   if (height < 0) {
2202     height = -height;
2203     src_ar30 = src_ar30 + (height - 1) * src_stride_ar30;
2204     src_stride_ar30 = -src_stride_ar30;
2205   }
2206   // Coalesce rows.
2207   if (src_stride_ar30 == width * 4 && dst_stride_argb == width * 4) {
2208     width *= height;
2209     height = 1;
2210     src_stride_ar30 = dst_stride_argb = 0;
2211   }
2212   for (y = 0; y < height; ++y) {
2213     AR30ToARGBRow_C(src_ar30, dst_argb, width);
2214     src_ar30 += src_stride_ar30;
2215     dst_argb += dst_stride_argb;
2216   }
2217   return 0;
2218 }
2219 
2220 // Convert AR30 to ABGR.
2221 LIBYUV_API
AR30ToABGR(const uint8_t * src_ar30,int src_stride_ar30,uint8_t * dst_abgr,int dst_stride_abgr,int width,int height)2222 int AR30ToABGR(const uint8_t* src_ar30,
2223                int src_stride_ar30,
2224                uint8_t* dst_abgr,
2225                int dst_stride_abgr,
2226                int width,
2227                int height) {
2228   int y;
2229   if (!src_ar30 || !dst_abgr || width <= 0 || height == 0) {
2230     return -1;
2231   }
2232   // Negative height means invert the image.
2233   if (height < 0) {
2234     height = -height;
2235     src_ar30 = src_ar30 + (height - 1) * src_stride_ar30;
2236     src_stride_ar30 = -src_stride_ar30;
2237   }
2238   // Coalesce rows.
2239   if (src_stride_ar30 == width * 4 && dst_stride_abgr == width * 4) {
2240     width *= height;
2241     height = 1;
2242     src_stride_ar30 = dst_stride_abgr = 0;
2243   }
2244   for (y = 0; y < height; ++y) {
2245     AR30ToABGRRow_C(src_ar30, dst_abgr, width);
2246     src_ar30 += src_stride_ar30;
2247     dst_abgr += dst_stride_abgr;
2248   }
2249   return 0;
2250 }
2251 
2252 // Convert AR30 to AB30.
2253 LIBYUV_API
AR30ToAB30(const uint8_t * src_ar30,int src_stride_ar30,uint8_t * dst_ab30,int dst_stride_ab30,int width,int height)2254 int AR30ToAB30(const uint8_t* src_ar30,
2255                int src_stride_ar30,
2256                uint8_t* dst_ab30,
2257                int dst_stride_ab30,
2258                int width,
2259                int height) {
2260   int y;
2261   if (!src_ar30 || !dst_ab30 || width <= 0 || height == 0) {
2262     return -1;
2263   }
2264   // Negative height means invert the image.
2265   if (height < 0) {
2266     height = -height;
2267     src_ar30 = src_ar30 + (height - 1) * src_stride_ar30;
2268     src_stride_ar30 = -src_stride_ar30;
2269   }
2270   // Coalesce rows.
2271   if (src_stride_ar30 == width * 4 && dst_stride_ab30 == width * 4) {
2272     width *= height;
2273     height = 1;
2274     src_stride_ar30 = dst_stride_ab30 = 0;
2275   }
2276   for (y = 0; y < height; ++y) {
2277     AR30ToAB30Row_C(src_ar30, dst_ab30, width);
2278     src_ar30 += src_stride_ar30;
2279     dst_ab30 += dst_stride_ab30;
2280   }
2281   return 0;
2282 }
2283 
2284 // 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)2285 static int NV12ToARGBMatrix(const uint8_t* src_y,
2286                             int src_stride_y,
2287                             const uint8_t* src_uv,
2288                             int src_stride_uv,
2289                             uint8_t* dst_argb,
2290                             int dst_stride_argb,
2291                             const struct YuvConstants* yuvconstants,
2292                             int width,
2293                             int height) {
2294   int y;
2295   void (*NV12ToARGBRow)(
2296       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
2297       const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C;
2298   if (!src_y || !src_uv || !dst_argb || width <= 0 || height == 0) {
2299     return -1;
2300   }
2301   // Negative height means invert the image.
2302   if (height < 0) {
2303     height = -height;
2304     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
2305     dst_stride_argb = -dst_stride_argb;
2306   }
2307 #if defined(HAS_NV12TOARGBROW_SSSE3)
2308   if (TestCpuFlag(kCpuHasSSSE3)) {
2309     NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
2310     if (IS_ALIGNED(width, 8)) {
2311       NV12ToARGBRow = NV12ToARGBRow_SSSE3;
2312     }
2313   }
2314 #endif
2315 #if defined(HAS_NV12TOARGBROW_AVX2)
2316   if (TestCpuFlag(kCpuHasAVX2)) {
2317     NV12ToARGBRow = NV12ToARGBRow_Any_AVX2;
2318     if (IS_ALIGNED(width, 16)) {
2319       NV12ToARGBRow = NV12ToARGBRow_AVX2;
2320     }
2321   }
2322 #endif
2323 #if defined(HAS_NV12TOARGBROW_NEON)
2324   if (TestCpuFlag(kCpuHasNEON)) {
2325     NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
2326     if (IS_ALIGNED(width, 8)) {
2327       NV12ToARGBRow = NV12ToARGBRow_NEON;
2328     }
2329   }
2330 #endif
2331 #if defined(HAS_NV12TOARGBROW_MSA)
2332   if (TestCpuFlag(kCpuHasMSA)) {
2333     NV12ToARGBRow = NV12ToARGBRow_Any_MSA;
2334     if (IS_ALIGNED(width, 8)) {
2335       NV12ToARGBRow = NV12ToARGBRow_MSA;
2336     }
2337   }
2338 #endif
2339 #if defined(HAS_NV12TOARGBROW_MMI)
2340   if (TestCpuFlag(kCpuHasMMI)) {
2341     NV12ToARGBRow = NV12ToARGBRow_Any_MMI;
2342     if (IS_ALIGNED(width, 4)) {
2343       NV12ToARGBRow = NV12ToARGBRow_MMI;
2344     }
2345   }
2346 #endif
2347 
2348   for (y = 0; y < height; ++y) {
2349     NV12ToARGBRow(src_y, src_uv, dst_argb, yuvconstants, width);
2350     dst_argb += dst_stride_argb;
2351     src_y += src_stride_y;
2352     if (y & 1) {
2353       src_uv += src_stride_uv;
2354     }
2355   }
2356   return 0;
2357 }
2358 
2359 // 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)2360 static int NV21ToARGBMatrix(const uint8_t* src_y,
2361                             int src_stride_y,
2362                             const uint8_t* src_vu,
2363                             int src_stride_vu,
2364                             uint8_t* dst_argb,
2365                             int dst_stride_argb,
2366                             const struct YuvConstants* yuvconstants,
2367                             int width,
2368                             int height) {
2369   int y;
2370   void (*NV21ToARGBRow)(
2371       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
2372       const struct YuvConstants* yuvconstants, int width) = NV21ToARGBRow_C;
2373   if (!src_y || !src_vu || !dst_argb || width <= 0 || height == 0) {
2374     return -1;
2375   }
2376   // Negative height means invert the image.
2377   if (height < 0) {
2378     height = -height;
2379     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
2380     dst_stride_argb = -dst_stride_argb;
2381   }
2382 #if defined(HAS_NV21TOARGBROW_SSSE3)
2383   if (TestCpuFlag(kCpuHasSSSE3)) {
2384     NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3;
2385     if (IS_ALIGNED(width, 8)) {
2386       NV21ToARGBRow = NV21ToARGBRow_SSSE3;
2387     }
2388   }
2389 #endif
2390 #if defined(HAS_NV21TOARGBROW_AVX2)
2391   if (TestCpuFlag(kCpuHasAVX2)) {
2392     NV21ToARGBRow = NV21ToARGBRow_Any_AVX2;
2393     if (IS_ALIGNED(width, 16)) {
2394       NV21ToARGBRow = NV21ToARGBRow_AVX2;
2395     }
2396   }
2397 #endif
2398 #if defined(HAS_NV21TOARGBROW_NEON)
2399   if (TestCpuFlag(kCpuHasNEON)) {
2400     NV21ToARGBRow = NV21ToARGBRow_Any_NEON;
2401     if (IS_ALIGNED(width, 8)) {
2402       NV21ToARGBRow = NV21ToARGBRow_NEON;
2403     }
2404   }
2405 #endif
2406 #if defined(HAS_NV21TOARGBROW_MSA)
2407   if (TestCpuFlag(kCpuHasMSA)) {
2408     NV21ToARGBRow = NV21ToARGBRow_Any_MSA;
2409     if (IS_ALIGNED(width, 8)) {
2410       NV21ToARGBRow = NV21ToARGBRow_MSA;
2411     }
2412   }
2413 #endif
2414 #if defined(HAS_NV21TOARGBROW_MMI)
2415   if (TestCpuFlag(kCpuHasMMI)) {
2416     NV21ToARGBRow = NV21ToARGBRow_Any_MMI;
2417     if (IS_ALIGNED(width, 4)) {
2418       NV21ToARGBRow = NV21ToARGBRow_MMI;
2419     }
2420   }
2421 #endif
2422 
2423   for (y = 0; y < height; ++y) {
2424     NV21ToARGBRow(src_y, src_vu, dst_argb, yuvconstants, width);
2425     dst_argb += dst_stride_argb;
2426     src_y += src_stride_y;
2427     if (y & 1) {
2428       src_vu += src_stride_vu;
2429     }
2430   }
2431   return 0;
2432 }
2433 
2434 // Convert NV12 to ARGB.
2435 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)2436 int NV12ToARGB(const uint8_t* src_y,
2437                int src_stride_y,
2438                const uint8_t* src_uv,
2439                int src_stride_uv,
2440                uint8_t* dst_argb,
2441                int dst_stride_argb,
2442                int width,
2443                int height) {
2444   return NV12ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_argb,
2445                           dst_stride_argb, &kYuvI601Constants, width, height);
2446 }
2447 
2448 // Convert NV21 to ARGB.
2449 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)2450 int NV21ToARGB(const uint8_t* src_y,
2451                int src_stride_y,
2452                const uint8_t* src_vu,
2453                int src_stride_vu,
2454                uint8_t* dst_argb,
2455                int dst_stride_argb,
2456                int width,
2457                int height) {
2458   return NV21ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_argb,
2459                           dst_stride_argb, &kYuvI601Constants, width, height);
2460 }
2461 
2462 // Convert NV12 to ABGR.
2463 // To output ABGR instead of ARGB swap the UV and use a mirrored yuv matrix.
2464 // To swap the UV use NV12 instead of NV21.LIBYUV_API
2465 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)2466 int NV12ToABGR(const uint8_t* src_y,
2467                int src_stride_y,
2468                const uint8_t* src_uv,
2469                int src_stride_uv,
2470                uint8_t* dst_abgr,
2471                int dst_stride_abgr,
2472                int width,
2473                int height) {
2474   return NV21ToARGBMatrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_abgr,
2475                           dst_stride_abgr, &kYvuI601Constants, width, height);
2476 }
2477 
2478 // Convert NV21 to ABGR.
2479 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)2480 int NV21ToABGR(const uint8_t* src_y,
2481                int src_stride_y,
2482                const uint8_t* src_vu,
2483                int src_stride_vu,
2484                uint8_t* dst_abgr,
2485                int dst_stride_abgr,
2486                int width,
2487                int height) {
2488   return NV12ToARGBMatrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_abgr,
2489                           dst_stride_abgr, &kYvuI601Constants, width, height);
2490 }
2491 
2492 // TODO(fbarchard): Consider SSSE3 2 step conversion.
2493 // 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)2494 static int NV12ToRGB24Matrix(const uint8_t* src_y,
2495                              int src_stride_y,
2496                              const uint8_t* src_uv,
2497                              int src_stride_uv,
2498                              uint8_t* dst_rgb24,
2499                              int dst_stride_rgb24,
2500                              const struct YuvConstants* yuvconstants,
2501                              int width,
2502                              int height) {
2503   int y;
2504   void (*NV12ToRGB24Row)(
2505       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
2506       const struct YuvConstants* yuvconstants, int width) = NV12ToRGB24Row_C;
2507   if (!src_y || !src_uv || !dst_rgb24 || width <= 0 || height == 0) {
2508     return -1;
2509   }
2510   // Negative height means invert the image.
2511   if (height < 0) {
2512     height = -height;
2513     dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
2514     dst_stride_rgb24 = -dst_stride_rgb24;
2515   }
2516 #if defined(HAS_NV12TORGB24ROW_NEON)
2517   if (TestCpuFlag(kCpuHasNEON)) {
2518     NV12ToRGB24Row = NV12ToRGB24Row_Any_NEON;
2519     if (IS_ALIGNED(width, 8)) {
2520       NV12ToRGB24Row = NV12ToRGB24Row_NEON;
2521     }
2522   }
2523 #endif
2524 #if defined(HAS_NV12TORGB24ROW_SSSE3)
2525   if (TestCpuFlag(kCpuHasSSSE3)) {
2526     NV12ToRGB24Row = NV12ToRGB24Row_Any_SSSE3;
2527     if (IS_ALIGNED(width, 16)) {
2528       NV12ToRGB24Row = NV12ToRGB24Row_SSSE3;
2529     }
2530   }
2531 #endif
2532 #if defined(HAS_NV12TORGB24ROW_AVX2)
2533   if (TestCpuFlag(kCpuHasAVX2)) {
2534     NV12ToRGB24Row = NV12ToRGB24Row_Any_AVX2;
2535     if (IS_ALIGNED(width, 32)) {
2536       NV12ToRGB24Row = NV12ToRGB24Row_AVX2;
2537     }
2538   }
2539 #endif
2540 #if defined(HAS_NV12TORGB24ROW_MMI)
2541   if (TestCpuFlag(kCpuHasMMI)) {
2542     NV12ToRGB24Row = NV12ToRGB24Row_Any_MMI;
2543     if (IS_ALIGNED(width, 8)) {
2544       NV12ToRGB24Row = NV12ToRGB24Row_MMI;
2545     }
2546   }
2547 #endif
2548 
2549   for (y = 0; y < height; ++y) {
2550     NV12ToRGB24Row(src_y, src_uv, dst_rgb24, yuvconstants, width);
2551     dst_rgb24 += dst_stride_rgb24;
2552     src_y += src_stride_y;
2553     if (y & 1) {
2554       src_uv += src_stride_uv;
2555     }
2556   }
2557   return 0;
2558 }
2559 
2560 // 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)2561 static int NV21ToRGB24Matrix(const uint8_t* src_y,
2562                              int src_stride_y,
2563                              const uint8_t* src_vu,
2564                              int src_stride_vu,
2565                              uint8_t* dst_rgb24,
2566                              int dst_stride_rgb24,
2567                              const struct YuvConstants* yuvconstants,
2568                              int width,
2569                              int height) {
2570   int y;
2571   void (*NV21ToRGB24Row)(
2572       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
2573       const struct YuvConstants* yuvconstants, int width) = NV21ToRGB24Row_C;
2574   if (!src_y || !src_vu || !dst_rgb24 || width <= 0 || height == 0) {
2575     return -1;
2576   }
2577   // Negative height means invert the image.
2578   if (height < 0) {
2579     height = -height;
2580     dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
2581     dst_stride_rgb24 = -dst_stride_rgb24;
2582   }
2583 #if defined(HAS_NV21TORGB24ROW_NEON)
2584   if (TestCpuFlag(kCpuHasNEON)) {
2585     NV21ToRGB24Row = NV21ToRGB24Row_Any_NEON;
2586     if (IS_ALIGNED(width, 8)) {
2587       NV21ToRGB24Row = NV21ToRGB24Row_NEON;
2588     }
2589   }
2590 #endif
2591 #if defined(HAS_NV21TORGB24ROW_SSSE3)
2592   if (TestCpuFlag(kCpuHasSSSE3)) {
2593     NV21ToRGB24Row = NV21ToRGB24Row_Any_SSSE3;
2594     if (IS_ALIGNED(width, 16)) {
2595       NV21ToRGB24Row = NV21ToRGB24Row_SSSE3;
2596     }
2597   }
2598 #endif
2599 #if defined(HAS_NV21TORGB24ROW_AVX2)
2600   if (TestCpuFlag(kCpuHasAVX2)) {
2601     NV21ToRGB24Row = NV21ToRGB24Row_Any_AVX2;
2602     if (IS_ALIGNED(width, 32)) {
2603       NV21ToRGB24Row = NV21ToRGB24Row_AVX2;
2604     }
2605   }
2606 #endif
2607 #if defined(HAS_NV21TORGB24ROW_MMI)
2608   if (TestCpuFlag(kCpuHasMMI)) {
2609     NV21ToRGB24Row = NV21ToRGB24Row_Any_MMI;
2610     if (IS_ALIGNED(width, 8)) {
2611       NV21ToRGB24Row = NV21ToRGB24Row_MMI;
2612     }
2613   }
2614 #endif
2615 
2616   for (y = 0; y < height; ++y) {
2617     NV21ToRGB24Row(src_y, src_vu, dst_rgb24, yuvconstants, width);
2618     dst_rgb24 += dst_stride_rgb24;
2619     src_y += src_stride_y;
2620     if (y & 1) {
2621       src_vu += src_stride_vu;
2622     }
2623   }
2624   return 0;
2625 }
2626 
2627 // Convert NV12 to RGB24.
2628 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)2629 int NV12ToRGB24(const uint8_t* src_y,
2630                 int src_stride_y,
2631                 const uint8_t* src_uv,
2632                 int src_stride_uv,
2633                 uint8_t* dst_rgb24,
2634                 int dst_stride_rgb24,
2635                 int width,
2636                 int height) {
2637   return NV12ToRGB24Matrix(src_y, src_stride_y, src_uv, src_stride_uv,
2638                            dst_rgb24, dst_stride_rgb24, &kYuvI601Constants,
2639                            width, height);
2640 }
2641 
2642 // Convert NV21 to RGB24.
2643 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)2644 int NV21ToRGB24(const uint8_t* src_y,
2645                 int src_stride_y,
2646                 const uint8_t* src_vu,
2647                 int src_stride_vu,
2648                 uint8_t* dst_rgb24,
2649                 int dst_stride_rgb24,
2650                 int width,
2651                 int height) {
2652   return NV21ToRGB24Matrix(src_y, src_stride_y, src_vu, src_stride_vu,
2653                            dst_rgb24, dst_stride_rgb24, &kYuvI601Constants,
2654                            width, height);
2655 }
2656 
2657 // Convert NV12 to RAW.
2658 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)2659 int NV12ToRAW(const uint8_t* src_y,
2660               int src_stride_y,
2661               const uint8_t* src_uv,
2662               int src_stride_uv,
2663               uint8_t* dst_raw,
2664               int dst_stride_raw,
2665               int width,
2666               int height) {
2667   return NV21ToRGB24Matrix(src_y, src_stride_y, src_uv, src_stride_uv, dst_raw,
2668                            dst_stride_raw, &kYvuI601Constants, width, height);
2669 }
2670 
2671 // Convert NV21 to RAW.
2672 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)2673 int NV21ToRAW(const uint8_t* src_y,
2674               int src_stride_y,
2675               const uint8_t* src_vu,
2676               int src_stride_vu,
2677               uint8_t* dst_raw,
2678               int dst_stride_raw,
2679               int width,
2680               int height) {
2681   return NV12ToRGB24Matrix(src_y, src_stride_y, src_vu, src_stride_vu, dst_raw,
2682                            dst_stride_raw, &kYvuI601Constants, width, height);
2683 }
2684 
2685 // 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)2686 int NV21ToYUV24(const uint8_t* src_y,
2687                 int src_stride_y,
2688                 const uint8_t* src_vu,
2689                 int src_stride_vu,
2690                 uint8_t* dst_yuv24,
2691                 int dst_stride_yuv24,
2692                 int width,
2693                 int height) {
2694   int y;
2695   void (*NV21ToYUV24Row)(const uint8_t* src_y, const uint8_t* src_vu,
2696                          uint8_t* dst_yuv24, int width) = NV21ToYUV24Row_C;
2697   if (!src_y || !src_vu || !dst_yuv24 || width <= 0 || height == 0) {
2698     return -1;
2699   }
2700   // Negative height means invert the image.
2701   if (height < 0) {
2702     height = -height;
2703     dst_yuv24 = dst_yuv24 + (height - 1) * dst_stride_yuv24;
2704     dst_stride_yuv24 = -dst_stride_yuv24;
2705   }
2706 #if defined(HAS_NV21TOYUV24ROW_NEON)
2707   if (TestCpuFlag(kCpuHasNEON)) {
2708     NV21ToYUV24Row = NV21ToYUV24Row_Any_NEON;
2709     if (IS_ALIGNED(width, 16)) {
2710       NV21ToYUV24Row = NV21ToYUV24Row_NEON;
2711     }
2712   }
2713 #endif
2714 #if defined(HAS_NV21TOYUV24ROW_AVX2)
2715   if (TestCpuFlag(kCpuHasAVX2)) {
2716     NV21ToYUV24Row = NV21ToYUV24Row_Any_AVX2;
2717     if (IS_ALIGNED(width, 32)) {
2718       NV21ToYUV24Row = NV21ToYUV24Row_AVX2;
2719     }
2720   }
2721 #endif
2722   for (y = 0; y < height; ++y) {
2723     NV21ToYUV24Row(src_y, src_vu, dst_yuv24, width);
2724     dst_yuv24 += dst_stride_yuv24;
2725     src_y += src_stride_y;
2726     if (y & 1) {
2727       src_vu += src_stride_vu;
2728     }
2729   }
2730   return 0;
2731 }
2732 
2733 // Convert M420 to ARGB.
2734 LIBYUV_API
M420ToARGB(const uint8_t * src_m420,int src_stride_m420,uint8_t * dst_argb,int dst_stride_argb,int width,int height)2735 int M420ToARGB(const uint8_t* src_m420,
2736                int src_stride_m420,
2737                uint8_t* dst_argb,
2738                int dst_stride_argb,
2739                int width,
2740                int height) {
2741   int y;
2742   void (*NV12ToARGBRow)(
2743       const uint8_t* y_buf, const uint8_t* uv_buf, uint8_t* rgb_buf,
2744       const struct YuvConstants* yuvconstants, int width) = NV12ToARGBRow_C;
2745   if (!src_m420 || !dst_argb || width <= 0 || height == 0) {
2746     return -1;
2747   }
2748   // Negative height means invert the image.
2749   if (height < 0) {
2750     height = -height;
2751     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
2752     dst_stride_argb = -dst_stride_argb;
2753   }
2754 #if defined(HAS_NV12TOARGBROW_SSSE3)
2755   if (TestCpuFlag(kCpuHasSSSE3)) {
2756     NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3;
2757     if (IS_ALIGNED(width, 8)) {
2758       NV12ToARGBRow = NV12ToARGBRow_SSSE3;
2759     }
2760   }
2761 #endif
2762 #if defined(HAS_NV12TOARGBROW_AVX2)
2763   if (TestCpuFlag(kCpuHasAVX2)) {
2764     NV12ToARGBRow = NV12ToARGBRow_Any_AVX2;
2765     if (IS_ALIGNED(width, 16)) {
2766       NV12ToARGBRow = NV12ToARGBRow_AVX2;
2767     }
2768   }
2769 #endif
2770 #if defined(HAS_NV12TOARGBROW_NEON)
2771   if (TestCpuFlag(kCpuHasNEON)) {
2772     NV12ToARGBRow = NV12ToARGBRow_Any_NEON;
2773     if (IS_ALIGNED(width, 8)) {
2774       NV12ToARGBRow = NV12ToARGBRow_NEON;
2775     }
2776   }
2777 #endif
2778 #if defined(HAS_NV12TOARGBROW_MSA)
2779   if (TestCpuFlag(kCpuHasMSA)) {
2780     NV12ToARGBRow = NV12ToARGBRow_Any_MSA;
2781     if (IS_ALIGNED(width, 8)) {
2782       NV12ToARGBRow = NV12ToARGBRow_MSA;
2783     }
2784   }
2785 #endif
2786 #if defined(HAS_NV12TOARGBROW_MMI)
2787   if (TestCpuFlag(kCpuHasMMI)) {
2788     NV12ToARGBRow = NV12ToARGBRow_Any_MMI;
2789     if (IS_ALIGNED(width, 4)) {
2790       NV12ToARGBRow = NV12ToARGBRow_MMI;
2791     }
2792   }
2793 #endif
2794 
2795   for (y = 0; y < height - 1; y += 2) {
2796     NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb,
2797                   &kYuvI601Constants, width);
2798     NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2,
2799                   dst_argb + dst_stride_argb, &kYuvI601Constants, width);
2800     dst_argb += dst_stride_argb * 2;
2801     src_m420 += src_stride_m420 * 3;
2802   }
2803   if (height & 1) {
2804     NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb,
2805                   &kYuvI601Constants, width);
2806   }
2807   return 0;
2808 }
2809 
2810 // Convert YUY2 to ARGB.
2811 LIBYUV_API
YUY2ToARGB(const uint8_t * src_yuy2,int src_stride_yuy2,uint8_t * dst_argb,int dst_stride_argb,int width,int height)2812 int YUY2ToARGB(const uint8_t* src_yuy2,
2813                int src_stride_yuy2,
2814                uint8_t* dst_argb,
2815                int dst_stride_argb,
2816                int width,
2817                int height) {
2818   int y;
2819   void (*YUY2ToARGBRow)(const uint8_t* src_yuy2, uint8_t* dst_argb,
2820                         const struct YuvConstants* yuvconstants, int width) =
2821       YUY2ToARGBRow_C;
2822   if (!src_yuy2 || !dst_argb || width <= 0 || height == 0) {
2823     return -1;
2824   }
2825   // Negative height means invert the image.
2826   if (height < 0) {
2827     height = -height;
2828     src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
2829     src_stride_yuy2 = -src_stride_yuy2;
2830   }
2831   // Coalesce rows.
2832   if (src_stride_yuy2 == width * 2 && dst_stride_argb == width * 4) {
2833     width *= height;
2834     height = 1;
2835     src_stride_yuy2 = dst_stride_argb = 0;
2836   }
2837 #if defined(HAS_YUY2TOARGBROW_SSSE3)
2838   if (TestCpuFlag(kCpuHasSSSE3)) {
2839     YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3;
2840     if (IS_ALIGNED(width, 16)) {
2841       YUY2ToARGBRow = YUY2ToARGBRow_SSSE3;
2842     }
2843   }
2844 #endif
2845 #if defined(HAS_YUY2TOARGBROW_AVX2)
2846   if (TestCpuFlag(kCpuHasAVX2)) {
2847     YUY2ToARGBRow = YUY2ToARGBRow_Any_AVX2;
2848     if (IS_ALIGNED(width, 32)) {
2849       YUY2ToARGBRow = YUY2ToARGBRow_AVX2;
2850     }
2851   }
2852 #endif
2853 #if defined(HAS_YUY2TOARGBROW_NEON)
2854   if (TestCpuFlag(kCpuHasNEON)) {
2855     YUY2ToARGBRow = YUY2ToARGBRow_Any_NEON;
2856     if (IS_ALIGNED(width, 8)) {
2857       YUY2ToARGBRow = YUY2ToARGBRow_NEON;
2858     }
2859   }
2860 #endif
2861 #if defined(HAS_YUY2TOARGBROW_MSA)
2862   if (TestCpuFlag(kCpuHasMSA)) {
2863     YUY2ToARGBRow = YUY2ToARGBRow_Any_MSA;
2864     if (IS_ALIGNED(width, 8)) {
2865       YUY2ToARGBRow = YUY2ToARGBRow_MSA;
2866     }
2867   }
2868 #endif
2869 #if defined(HAS_YUY2TOARGBROW_MMI)
2870   if (TestCpuFlag(kCpuHasMMI)) {
2871     YUY2ToARGBRow = YUY2ToARGBRow_Any_MMI;
2872     if (IS_ALIGNED(width, 4)) {
2873       YUY2ToARGBRow = YUY2ToARGBRow_MMI;
2874     }
2875   }
2876 #endif
2877   for (y = 0; y < height; ++y) {
2878     YUY2ToARGBRow(src_yuy2, dst_argb, &kYuvI601Constants, width);
2879     src_yuy2 += src_stride_yuy2;
2880     dst_argb += dst_stride_argb;
2881   }
2882   return 0;
2883 }
2884 
2885 // Convert UYVY to ARGB.
2886 LIBYUV_API
UYVYToARGB(const uint8_t * src_uyvy,int src_stride_uyvy,uint8_t * dst_argb,int dst_stride_argb,int width,int height)2887 int UYVYToARGB(const uint8_t* src_uyvy,
2888                int src_stride_uyvy,
2889                uint8_t* dst_argb,
2890                int dst_stride_argb,
2891                int width,
2892                int height) {
2893   int y;
2894   void (*UYVYToARGBRow)(const uint8_t* src_uyvy, uint8_t* dst_argb,
2895                         const struct YuvConstants* yuvconstants, int width) =
2896       UYVYToARGBRow_C;
2897   if (!src_uyvy || !dst_argb || width <= 0 || height == 0) {
2898     return -1;
2899   }
2900   // Negative height means invert the image.
2901   if (height < 0) {
2902     height = -height;
2903     src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
2904     src_stride_uyvy = -src_stride_uyvy;
2905   }
2906   // Coalesce rows.
2907   if (src_stride_uyvy == width * 2 && dst_stride_argb == width * 4) {
2908     width *= height;
2909     height = 1;
2910     src_stride_uyvy = dst_stride_argb = 0;
2911   }
2912 #if defined(HAS_UYVYTOARGBROW_SSSE3)
2913   if (TestCpuFlag(kCpuHasSSSE3)) {
2914     UYVYToARGBRow = UYVYToARGBRow_Any_SSSE3;
2915     if (IS_ALIGNED(width, 16)) {
2916       UYVYToARGBRow = UYVYToARGBRow_SSSE3;
2917     }
2918   }
2919 #endif
2920 #if defined(HAS_UYVYTOARGBROW_AVX2)
2921   if (TestCpuFlag(kCpuHasAVX2)) {
2922     UYVYToARGBRow = UYVYToARGBRow_Any_AVX2;
2923     if (IS_ALIGNED(width, 32)) {
2924       UYVYToARGBRow = UYVYToARGBRow_AVX2;
2925     }
2926   }
2927 #endif
2928 #if defined(HAS_UYVYTOARGBROW_NEON)
2929   if (TestCpuFlag(kCpuHasNEON)) {
2930     UYVYToARGBRow = UYVYToARGBRow_Any_NEON;
2931     if (IS_ALIGNED(width, 8)) {
2932       UYVYToARGBRow = UYVYToARGBRow_NEON;
2933     }
2934   }
2935 #endif
2936 #if defined(HAS_UYVYTOARGBROW_MSA)
2937   if (TestCpuFlag(kCpuHasMSA)) {
2938     UYVYToARGBRow = UYVYToARGBRow_Any_MSA;
2939     if (IS_ALIGNED(width, 8)) {
2940       UYVYToARGBRow = UYVYToARGBRow_MSA;
2941     }
2942   }
2943 #endif
2944 #if defined(HAS_UYVYTOARGBROW_MMI)
2945   if (TestCpuFlag(kCpuHasMMI)) {
2946     UYVYToARGBRow = UYVYToARGBRow_Any_MMI;
2947     if (IS_ALIGNED(width, 4)) {
2948       UYVYToARGBRow = UYVYToARGBRow_MMI;
2949     }
2950   }
2951 #endif
2952   for (y = 0; y < height; ++y) {
2953     UYVYToARGBRow(src_uyvy, dst_argb, &kYuvI601Constants, width);
2954     src_uyvy += src_stride_uyvy;
2955     dst_argb += dst_stride_argb;
2956   }
2957   return 0;
2958 }
WeavePixels(const uint8_t * src_u,const uint8_t * src_v,int src_pixel_stride_uv,uint8_t * dst_uv,int width)2959 static void WeavePixels(const uint8_t* src_u,
2960                         const uint8_t* src_v,
2961                         int src_pixel_stride_uv,
2962                         uint8_t* dst_uv,
2963                         int width) {
2964   int i;
2965   for (i = 0; i < width; ++i) {
2966     dst_uv[0] = *src_u;
2967     dst_uv[1] = *src_v;
2968     dst_uv += 2;
2969     src_u += src_pixel_stride_uv;
2970     src_v += src_pixel_stride_uv;
2971   }
2972 }
2973 
2974 // Convert Android420 to ARGB.
2975 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)2976 int Android420ToARGBMatrix(const uint8_t* src_y,
2977                            int src_stride_y,
2978                            const uint8_t* src_u,
2979                            int src_stride_u,
2980                            const uint8_t* src_v,
2981                            int src_stride_v,
2982                            int src_pixel_stride_uv,
2983                            uint8_t* dst_argb,
2984                            int dst_stride_argb,
2985                            const struct YuvConstants* yuvconstants,
2986                            int width,
2987                            int height) {
2988   int y;
2989   uint8_t* dst_uv;
2990   const ptrdiff_t vu_off = src_v - src_u;
2991   int halfwidth = (width + 1) >> 1;
2992   int halfheight = (height + 1) >> 1;
2993   if (!src_y || !src_u || !src_v || !dst_argb || width <= 0 || height == 0) {
2994     return -1;
2995   }
2996   // Negative height means invert the image.
2997   if (height < 0) {
2998     height = -height;
2999     halfheight = (height + 1) >> 1;
3000     dst_argb = dst_argb + (height - 1) * dst_stride_argb;
3001     dst_stride_argb = -dst_stride_argb;
3002   }
3003 
3004   // I420
3005   if (src_pixel_stride_uv == 1) {
3006     return I420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
3007                             src_stride_v, dst_argb, dst_stride_argb,
3008                             yuvconstants, width, height);
3009     // NV21
3010   }
3011   if (src_pixel_stride_uv == 2 && vu_off == -1 &&
3012       src_stride_u == src_stride_v) {
3013     return NV21ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, dst_argb,
3014                             dst_stride_argb, yuvconstants, width, height);
3015     // NV12
3016   }
3017   if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) {
3018     return NV12ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, dst_argb,
3019                             dst_stride_argb, yuvconstants, width, height);
3020   }
3021 
3022   // General case fallback creates NV12
3023   align_buffer_64(plane_uv, halfwidth * 2 * halfheight);
3024   dst_uv = plane_uv;
3025   for (y = 0; y < halfheight; ++y) {
3026     WeavePixels(src_u, src_v, src_pixel_stride_uv, dst_uv, halfwidth);
3027     src_u += src_stride_u;
3028     src_v += src_stride_v;
3029     dst_uv += halfwidth * 2;
3030   }
3031   NV12ToARGBMatrix(src_y, src_stride_y, plane_uv, halfwidth * 2, dst_argb,
3032                    dst_stride_argb, yuvconstants, width, height);
3033   free_aligned_buffer_64(plane_uv);
3034   return 0;
3035 }
3036 
3037 // Convert Android420 to ARGB.
3038 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)3039 int Android420ToARGB(const uint8_t* src_y,
3040                      int src_stride_y,
3041                      const uint8_t* src_u,
3042                      int src_stride_u,
3043                      const uint8_t* src_v,
3044                      int src_stride_v,
3045                      int src_pixel_stride_uv,
3046                      uint8_t* dst_argb,
3047                      int dst_stride_argb,
3048                      int width,
3049                      int height) {
3050   return Android420ToARGBMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
3051                                 src_stride_v, src_pixel_stride_uv, dst_argb,
3052                                 dst_stride_argb, &kYuvI601Constants, width,
3053                                 height);
3054 }
3055 
3056 // Convert Android420 to ABGR.
3057 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)3058 int Android420ToABGR(const uint8_t* src_y,
3059                      int src_stride_y,
3060                      const uint8_t* src_u,
3061                      int src_stride_u,
3062                      const uint8_t* src_v,
3063                      int src_stride_v,
3064                      int src_pixel_stride_uv,
3065                      uint8_t* dst_abgr,
3066                      int dst_stride_abgr,
3067                      int width,
3068                      int height) {
3069   return Android420ToARGBMatrix(src_y, src_stride_y, src_v, src_stride_v, src_u,
3070                                 src_stride_u, src_pixel_stride_uv, dst_abgr,
3071                                 dst_stride_abgr, &kYvuI601Constants, width,
3072                                 height);
3073 }
3074 
3075 #ifdef __cplusplus
3076 }  // extern "C"
3077 }  // namespace libyuv
3078 #endif
3079