• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2012 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_from_argb.h"
12 
13 #include "libyuv/basic_types.h"
14 #include "libyuv/cpu_id.h"
15 #include "libyuv/planar_functions.h"
16 #include "libyuv/row.h"
17 
18 #ifdef __cplusplus
19 namespace libyuv {
20 extern "C" {
21 #endif
22 
23 // ARGB little endian (bgra in memory) to I444
24 LIBYUV_API
ARGBToI444(const uint8 * src_argb,int src_stride_argb,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)25 int ARGBToI444(const uint8* src_argb,
26                int src_stride_argb,
27                uint8* dst_y,
28                int dst_stride_y,
29                uint8* dst_u,
30                int dst_stride_u,
31                uint8* dst_v,
32                int dst_stride_v,
33                int width,
34                int height) {
35   int y;
36   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
37       ARGBToYRow_C;
38   void (*ARGBToUV444Row)(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
39                          int width) = ARGBToUV444Row_C;
40   if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
41     return -1;
42   }
43   if (height < 0) {
44     height = -height;
45     src_argb = src_argb + (height - 1) * src_stride_argb;
46     src_stride_argb = -src_stride_argb;
47   }
48   // Coalesce rows.
49   if (src_stride_argb == width * 4 && dst_stride_y == width &&
50       dst_stride_u == width && dst_stride_v == width) {
51     width *= height;
52     height = 1;
53     src_stride_argb = dst_stride_y = dst_stride_u = dst_stride_v = 0;
54   }
55 #if defined(HAS_ARGBTOUV444ROW_SSSE3)
56   if (TestCpuFlag(kCpuHasSSSE3)) {
57     ARGBToUV444Row = ARGBToUV444Row_Any_SSSE3;
58     if (IS_ALIGNED(width, 16)) {
59       ARGBToUV444Row = ARGBToUV444Row_SSSE3;
60     }
61   }
62 #endif
63 #if defined(HAS_ARGBTOUV444ROW_NEON)
64   if (TestCpuFlag(kCpuHasNEON)) {
65     ARGBToUV444Row = ARGBToUV444Row_Any_NEON;
66     if (IS_ALIGNED(width, 8)) {
67       ARGBToUV444Row = ARGBToUV444Row_NEON;
68     }
69   }
70 #endif
71 #if defined(HAS_ARGBTOUV444ROW_MSA)
72   if (TestCpuFlag(kCpuHasMSA)) {
73     ARGBToUV444Row = ARGBToUV444Row_Any_MSA;
74     if (IS_ALIGNED(width, 16)) {
75       ARGBToUV444Row = ARGBToUV444Row_MSA;
76     }
77   }
78 #endif
79 #if defined(HAS_ARGBTOYROW_SSSE3)
80   if (TestCpuFlag(kCpuHasSSSE3)) {
81     ARGBToYRow = ARGBToYRow_Any_SSSE3;
82     if (IS_ALIGNED(width, 16)) {
83       ARGBToYRow = ARGBToYRow_SSSE3;
84     }
85   }
86 #endif
87 #if defined(HAS_ARGBTOYROW_AVX2)
88   if (TestCpuFlag(kCpuHasAVX2)) {
89     ARGBToYRow = ARGBToYRow_Any_AVX2;
90     if (IS_ALIGNED(width, 32)) {
91       ARGBToYRow = ARGBToYRow_AVX2;
92     }
93   }
94 #endif
95 #if defined(HAS_ARGBTOYROW_NEON)
96   if (TestCpuFlag(kCpuHasNEON)) {
97     ARGBToYRow = ARGBToYRow_Any_NEON;
98     if (IS_ALIGNED(width, 8)) {
99       ARGBToYRow = ARGBToYRow_NEON;
100     }
101   }
102 #endif
103 #if defined(HAS_ARGBTOYROW_DSPR2)
104   if (TestCpuFlag(kCpuHasDSPR2)) {
105     ARGBToYRow = ARGBToYRow_Any_DSPR2;
106     if (IS_ALIGNED(width, 8)) {
107       ARGBToYRow = ARGBToYRow_DSPR2;
108     }
109   }
110 #endif
111 #if defined(HAS_ARGBTOYROW_MSA)
112   if (TestCpuFlag(kCpuHasMSA)) {
113     ARGBToYRow = ARGBToYRow_Any_MSA;
114     if (IS_ALIGNED(width, 16)) {
115       ARGBToYRow = ARGBToYRow_MSA;
116     }
117   }
118 #endif
119 
120   for (y = 0; y < height; ++y) {
121     ARGBToUV444Row(src_argb, dst_u, dst_v, width);
122     ARGBToYRow(src_argb, dst_y, width);
123     src_argb += src_stride_argb;
124     dst_y += dst_stride_y;
125     dst_u += dst_stride_u;
126     dst_v += dst_stride_v;
127   }
128   return 0;
129 }
130 
131 // ARGB little endian (bgra in memory) to I422
132 LIBYUV_API
ARGBToI422(const uint8 * src_argb,int src_stride_argb,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)133 int ARGBToI422(const uint8* src_argb,
134                int src_stride_argb,
135                uint8* dst_y,
136                int dst_stride_y,
137                uint8* dst_u,
138                int dst_stride_u,
139                uint8* dst_v,
140                int dst_stride_v,
141                int width,
142                int height) {
143   int y;
144   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u,
145                       uint8* dst_v, int width) = ARGBToUVRow_C;
146   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
147       ARGBToYRow_C;
148   if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
149     return -1;
150   }
151   // Negative height means invert the image.
152   if (height < 0) {
153     height = -height;
154     src_argb = src_argb + (height - 1) * src_stride_argb;
155     src_stride_argb = -src_stride_argb;
156   }
157   // Coalesce rows.
158   if (src_stride_argb == width * 4 && dst_stride_y == width &&
159       dst_stride_u * 2 == width && dst_stride_v * 2 == width) {
160     width *= height;
161     height = 1;
162     src_stride_argb = dst_stride_y = dst_stride_u = dst_stride_v = 0;
163   }
164 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
165   if (TestCpuFlag(kCpuHasSSSE3)) {
166     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
167     ARGBToYRow = ARGBToYRow_Any_SSSE3;
168     if (IS_ALIGNED(width, 16)) {
169       ARGBToUVRow = ARGBToUVRow_SSSE3;
170       ARGBToYRow = ARGBToYRow_SSSE3;
171     }
172   }
173 #endif
174 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
175   if (TestCpuFlag(kCpuHasAVX2)) {
176     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
177     ARGBToYRow = ARGBToYRow_Any_AVX2;
178     if (IS_ALIGNED(width, 32)) {
179       ARGBToUVRow = ARGBToUVRow_AVX2;
180       ARGBToYRow = ARGBToYRow_AVX2;
181     }
182   }
183 #endif
184 #if defined(HAS_ARGBTOYROW_NEON)
185   if (TestCpuFlag(kCpuHasNEON)) {
186     ARGBToYRow = ARGBToYRow_Any_NEON;
187     if (IS_ALIGNED(width, 8)) {
188       ARGBToYRow = ARGBToYRow_NEON;
189     }
190   }
191 #endif
192 #if defined(HAS_ARGBTOUVROW_NEON)
193   if (TestCpuFlag(kCpuHasNEON)) {
194     ARGBToUVRow = ARGBToUVRow_Any_NEON;
195     if (IS_ALIGNED(width, 16)) {
196       ARGBToUVRow = ARGBToUVRow_NEON;
197     }
198   }
199 #endif
200 #if defined(HAS_ARGBTOYROW_DSPR2)
201   if (TestCpuFlag(kCpuHasDSPR2)) {
202     ARGBToYRow = ARGBToYRow_Any_DSPR2;
203     if (IS_ALIGNED(width, 8)) {
204       ARGBToYRow = ARGBToYRow_DSPR2;
205     }
206   }
207 #endif
208 #if defined(HAS_ARGBTOUVROW_DSPR2)
209   if (TestCpuFlag(kCpuHasDSPR2)) {
210     ARGBToUVRow = ARGBToUVRow_Any_DSPR2;
211     if (IS_ALIGNED(width, 16)) {
212       ARGBToUVRow = ARGBToUVRow_DSPR2;
213     }
214   }
215 #endif
216 
217 #if defined(HAS_ARGBTOYROW_MSA)
218   if (TestCpuFlag(kCpuHasMSA)) {
219     ARGBToYRow = ARGBToYRow_Any_MSA;
220     if (IS_ALIGNED(width, 16)) {
221       ARGBToYRow = ARGBToYRow_MSA;
222     }
223   }
224 #endif
225 #if defined(HAS_ARGBTOUVROW_MSA)
226   if (TestCpuFlag(kCpuHasMSA)) {
227     ARGBToUVRow = ARGBToUVRow_Any_MSA;
228     if (IS_ALIGNED(width, 32)) {
229       ARGBToUVRow = ARGBToUVRow_MSA;
230     }
231   }
232 #endif
233 
234   for (y = 0; y < height; ++y) {
235     ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
236     ARGBToYRow(src_argb, dst_y, width);
237     src_argb += src_stride_argb;
238     dst_y += dst_stride_y;
239     dst_u += dst_stride_u;
240     dst_v += dst_stride_v;
241   }
242   return 0;
243 }
244 
245 LIBYUV_API
ARGBToNV12(const uint8 * src_argb,int src_stride_argb,uint8 * dst_y,int dst_stride_y,uint8 * dst_uv,int dst_stride_uv,int width,int height)246 int ARGBToNV12(const uint8* src_argb,
247                int src_stride_argb,
248                uint8* dst_y,
249                int dst_stride_y,
250                uint8* dst_uv,
251                int dst_stride_uv,
252                int width,
253                int height) {
254   int y;
255   int halfwidth = (width + 1) >> 1;
256   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u,
257                       uint8* dst_v, int width) = ARGBToUVRow_C;
258   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
259       ARGBToYRow_C;
260   void (*MergeUVRow_)(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
261                       int width) = MergeUVRow_C;
262   if (!src_argb || !dst_y || !dst_uv || width <= 0 || height == 0) {
263     return -1;
264   }
265   // Negative height means invert the image.
266   if (height < 0) {
267     height = -height;
268     src_argb = src_argb + (height - 1) * src_stride_argb;
269     src_stride_argb = -src_stride_argb;
270   }
271 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
272   if (TestCpuFlag(kCpuHasSSSE3)) {
273     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
274     ARGBToYRow = ARGBToYRow_Any_SSSE3;
275     if (IS_ALIGNED(width, 16)) {
276       ARGBToUVRow = ARGBToUVRow_SSSE3;
277       ARGBToYRow = ARGBToYRow_SSSE3;
278     }
279   }
280 #endif
281 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
282   if (TestCpuFlag(kCpuHasAVX2)) {
283     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
284     ARGBToYRow = ARGBToYRow_Any_AVX2;
285     if (IS_ALIGNED(width, 32)) {
286       ARGBToUVRow = ARGBToUVRow_AVX2;
287       ARGBToYRow = ARGBToYRow_AVX2;
288     }
289   }
290 #endif
291 #if defined(HAS_ARGBTOYROW_NEON)
292   if (TestCpuFlag(kCpuHasNEON)) {
293     ARGBToYRow = ARGBToYRow_Any_NEON;
294     if (IS_ALIGNED(width, 8)) {
295       ARGBToYRow = ARGBToYRow_NEON;
296     }
297   }
298 #endif
299 #if defined(HAS_ARGBTOUVROW_NEON)
300   if (TestCpuFlag(kCpuHasNEON)) {
301     ARGBToUVRow = ARGBToUVRow_Any_NEON;
302     if (IS_ALIGNED(width, 16)) {
303       ARGBToUVRow = ARGBToUVRow_NEON;
304     }
305   }
306 #endif
307 #if defined(HAS_ARGBTOYROW_MSA)
308   if (TestCpuFlag(kCpuHasMSA)) {
309     ARGBToYRow = ARGBToYRow_Any_MSA;
310     if (IS_ALIGNED(width, 16)) {
311       ARGBToYRow = ARGBToYRow_MSA;
312     }
313   }
314 #endif
315 #if defined(HAS_ARGBTOUVROW_MSA)
316   if (TestCpuFlag(kCpuHasMSA)) {
317     ARGBToUVRow = ARGBToUVRow_Any_MSA;
318     if (IS_ALIGNED(width, 32)) {
319       ARGBToUVRow = ARGBToUVRow_MSA;
320     }
321   }
322 #endif
323 #if defined(HAS_MERGEUVROW_SSE2)
324   if (TestCpuFlag(kCpuHasSSE2)) {
325     MergeUVRow_ = MergeUVRow_Any_SSE2;
326     if (IS_ALIGNED(halfwidth, 16)) {
327       MergeUVRow_ = MergeUVRow_SSE2;
328     }
329   }
330 #endif
331 #if defined(HAS_MERGEUVROW_AVX2)
332   if (TestCpuFlag(kCpuHasAVX2)) {
333     MergeUVRow_ = MergeUVRow_Any_AVX2;
334     if (IS_ALIGNED(halfwidth, 32)) {
335       MergeUVRow_ = MergeUVRow_AVX2;
336     }
337   }
338 #endif
339 #if defined(HAS_MERGEUVROW_NEON)
340   if (TestCpuFlag(kCpuHasNEON)) {
341     MergeUVRow_ = MergeUVRow_Any_NEON;
342     if (IS_ALIGNED(halfwidth, 16)) {
343       MergeUVRow_ = MergeUVRow_NEON;
344     }
345   }
346 #endif
347 #if defined(HAS_ARGBTOYROW_DSPR2)
348   if (TestCpuFlag(kCpuHasDSPR2)) {
349     ARGBToYRow = ARGBToYRow_Any_DSPR2;
350     if (IS_ALIGNED(width, 8)) {
351       ARGBToYRow = ARGBToYRow_DSPR2;
352     }
353   }
354 #endif
355 #if defined(HAS_ARGBTOUVROW_DSPR2)
356   if (TestCpuFlag(kCpuHasDSPR2)) {
357     ARGBToUVRow = ARGBToUVRow_Any_DSPR2;
358     if (IS_ALIGNED(width, 16)) {
359       ARGBToUVRow = ARGBToUVRow_DSPR2;
360     }
361   }
362 #endif
363 #if defined(HAS_MERGEUVROW_MSA)
364   if (TestCpuFlag(kCpuHasMSA)) {
365     MergeUVRow_ = MergeUVRow_Any_MSA;
366     if (IS_ALIGNED(halfwidth, 16)) {
367       MergeUVRow_ = MergeUVRow_MSA;
368     }
369   }
370 #endif
371   {
372     // Allocate a rows of uv.
373     align_buffer_64(row_u, ((halfwidth + 31) & ~31) * 2);
374     uint8* row_v = row_u + ((halfwidth + 31) & ~31);
375 
376     for (y = 0; y < height - 1; y += 2) {
377       ARGBToUVRow(src_argb, src_stride_argb, row_u, row_v, width);
378       MergeUVRow_(row_u, row_v, dst_uv, halfwidth);
379       ARGBToYRow(src_argb, dst_y, width);
380       ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
381       src_argb += src_stride_argb * 2;
382       dst_y += dst_stride_y * 2;
383       dst_uv += dst_stride_uv;
384     }
385     if (height & 1) {
386       ARGBToUVRow(src_argb, 0, row_u, row_v, width);
387       MergeUVRow_(row_u, row_v, dst_uv, halfwidth);
388       ARGBToYRow(src_argb, dst_y, width);
389     }
390     free_aligned_buffer_64(row_u);
391   }
392   return 0;
393 }
394 
395 // Same as NV12 but U and V swapped.
396 LIBYUV_API
ARGBToNV21(const uint8 * src_argb,int src_stride_argb,uint8 * dst_y,int dst_stride_y,uint8 * dst_uv,int dst_stride_uv,int width,int height)397 int ARGBToNV21(const uint8* src_argb,
398                int src_stride_argb,
399                uint8* dst_y,
400                int dst_stride_y,
401                uint8* dst_uv,
402                int dst_stride_uv,
403                int width,
404                int height) {
405   int y;
406   int halfwidth = (width + 1) >> 1;
407   void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u,
408                       uint8* dst_v, int width) = ARGBToUVRow_C;
409   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
410       ARGBToYRow_C;
411   void (*MergeUVRow_)(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
412                       int width) = MergeUVRow_C;
413   if (!src_argb || !dst_y || !dst_uv || width <= 0 || height == 0) {
414     return -1;
415   }
416   // Negative height means invert the image.
417   if (height < 0) {
418     height = -height;
419     src_argb = src_argb + (height - 1) * src_stride_argb;
420     src_stride_argb = -src_stride_argb;
421   }
422 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
423   if (TestCpuFlag(kCpuHasSSSE3)) {
424     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
425     ARGBToYRow = ARGBToYRow_Any_SSSE3;
426     if (IS_ALIGNED(width, 16)) {
427       ARGBToUVRow = ARGBToUVRow_SSSE3;
428       ARGBToYRow = ARGBToYRow_SSSE3;
429     }
430   }
431 #endif
432 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
433   if (TestCpuFlag(kCpuHasAVX2)) {
434     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
435     ARGBToYRow = ARGBToYRow_Any_AVX2;
436     if (IS_ALIGNED(width, 32)) {
437       ARGBToUVRow = ARGBToUVRow_AVX2;
438       ARGBToYRow = ARGBToYRow_AVX2;
439     }
440   }
441 #endif
442 #if defined(HAS_ARGBTOYROW_NEON)
443   if (TestCpuFlag(kCpuHasNEON)) {
444     ARGBToYRow = ARGBToYRow_Any_NEON;
445     if (IS_ALIGNED(width, 8)) {
446       ARGBToYRow = ARGBToYRow_NEON;
447     }
448   }
449 #endif
450 #if defined(HAS_ARGBTOUVROW_NEON)
451   if (TestCpuFlag(kCpuHasNEON)) {
452     ARGBToUVRow = ARGBToUVRow_Any_NEON;
453     if (IS_ALIGNED(width, 16)) {
454       ARGBToUVRow = ARGBToUVRow_NEON;
455     }
456   }
457 #endif
458 #if defined(HAS_ARGBTOYROW_MSA)
459   if (TestCpuFlag(kCpuHasMSA)) {
460     ARGBToYRow = ARGBToYRow_Any_MSA;
461     if (IS_ALIGNED(width, 16)) {
462       ARGBToYRow = ARGBToYRow_MSA;
463     }
464   }
465 #endif
466 #if defined(HAS_ARGBTOUVROW_MSA)
467   if (TestCpuFlag(kCpuHasMSA)) {
468     ARGBToUVRow = ARGBToUVRow_Any_MSA;
469     if (IS_ALIGNED(width, 32)) {
470       ARGBToUVRow = ARGBToUVRow_MSA;
471     }
472   }
473 #endif
474 #if defined(HAS_MERGEUVROW_SSE2)
475   if (TestCpuFlag(kCpuHasSSE2)) {
476     MergeUVRow_ = MergeUVRow_Any_SSE2;
477     if (IS_ALIGNED(halfwidth, 16)) {
478       MergeUVRow_ = MergeUVRow_SSE2;
479     }
480   }
481 #endif
482 #if defined(HAS_MERGEUVROW_AVX2)
483   if (TestCpuFlag(kCpuHasAVX2)) {
484     MergeUVRow_ = MergeUVRow_Any_AVX2;
485     if (IS_ALIGNED(halfwidth, 32)) {
486       MergeUVRow_ = MergeUVRow_AVX2;
487     }
488   }
489 #endif
490 #if defined(HAS_MERGEUVROW_NEON)
491   if (TestCpuFlag(kCpuHasNEON)) {
492     MergeUVRow_ = MergeUVRow_Any_NEON;
493     if (IS_ALIGNED(halfwidth, 16)) {
494       MergeUVRow_ = MergeUVRow_NEON;
495     }
496   }
497 #endif
498 #if defined(HAS_ARGBTOYROW_DSPR2)
499   if (TestCpuFlag(kCpuHasDSPR2)) {
500     ARGBToYRow = ARGBToYRow_Any_DSPR2;
501     if (IS_ALIGNED(width, 8)) {
502       ARGBToYRow = ARGBToYRow_DSPR2;
503     }
504   }
505 #endif
506 #if defined(HAS_ARGBTOUVROW_DSPR2)
507   if (TestCpuFlag(kCpuHasDSPR2)) {
508     ARGBToUVRow = ARGBToUVRow_Any_DSPR2;
509     if (IS_ALIGNED(width, 16)) {
510       ARGBToUVRow = ARGBToUVRow_DSPR2;
511     }
512   }
513 #endif
514 #if defined(HAS_MERGEUVROW_MSA)
515   if (TestCpuFlag(kCpuHasMSA)) {
516     MergeUVRow_ = MergeUVRow_Any_MSA;
517     if (IS_ALIGNED(halfwidth, 16)) {
518       MergeUVRow_ = MergeUVRow_MSA;
519     }
520   }
521 #endif
522   {
523     // Allocate a rows of uv.
524     align_buffer_64(row_u, ((halfwidth + 31) & ~31) * 2);
525     uint8* row_v = row_u + ((halfwidth + 31) & ~31);
526 
527     for (y = 0; y < height - 1; y += 2) {
528       ARGBToUVRow(src_argb, src_stride_argb, row_u, row_v, width);
529       MergeUVRow_(row_v, row_u, dst_uv, halfwidth);
530       ARGBToYRow(src_argb, dst_y, width);
531       ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
532       src_argb += src_stride_argb * 2;
533       dst_y += dst_stride_y * 2;
534       dst_uv += dst_stride_uv;
535     }
536     if (height & 1) {
537       ARGBToUVRow(src_argb, 0, row_u, row_v, width);
538       MergeUVRow_(row_v, row_u, dst_uv, halfwidth);
539       ARGBToYRow(src_argb, dst_y, width);
540     }
541     free_aligned_buffer_64(row_u);
542   }
543   return 0;
544 }
545 
546 // Convert ARGB to YUY2.
547 LIBYUV_API
ARGBToYUY2(const uint8 * src_argb,int src_stride_argb,uint8 * dst_yuy2,int dst_stride_yuy2,int width,int height)548 int ARGBToYUY2(const uint8* src_argb,
549                int src_stride_argb,
550                uint8* dst_yuy2,
551                int dst_stride_yuy2,
552                int width,
553                int height) {
554   int y;
555   void (*ARGBToUVRow)(const uint8* src_argb, int src_stride_argb, uint8* dst_u,
556                       uint8* dst_v, int width) = ARGBToUVRow_C;
557   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
558       ARGBToYRow_C;
559   void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u,
560                         const uint8* src_v, uint8* dst_yuy2, int width) =
561       I422ToYUY2Row_C;
562 
563   if (!src_argb || !dst_yuy2 || width <= 0 || height == 0) {
564     return -1;
565   }
566   // Negative height means invert the image.
567   if (height < 0) {
568     height = -height;
569     dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
570     dst_stride_yuy2 = -dst_stride_yuy2;
571   }
572   // Coalesce rows.
573   if (src_stride_argb == width * 4 && dst_stride_yuy2 == width * 2) {
574     width *= height;
575     height = 1;
576     src_stride_argb = dst_stride_yuy2 = 0;
577   }
578 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
579   if (TestCpuFlag(kCpuHasSSSE3)) {
580     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
581     ARGBToYRow = ARGBToYRow_Any_SSSE3;
582     if (IS_ALIGNED(width, 16)) {
583       ARGBToUVRow = ARGBToUVRow_SSSE3;
584       ARGBToYRow = ARGBToYRow_SSSE3;
585     }
586   }
587 #endif
588 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
589   if (TestCpuFlag(kCpuHasAVX2)) {
590     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
591     ARGBToYRow = ARGBToYRow_Any_AVX2;
592     if (IS_ALIGNED(width, 32)) {
593       ARGBToUVRow = ARGBToUVRow_AVX2;
594       ARGBToYRow = ARGBToYRow_AVX2;
595     }
596   }
597 #endif
598 #if defined(HAS_ARGBTOYROW_NEON)
599   if (TestCpuFlag(kCpuHasNEON)) {
600     ARGBToYRow = ARGBToYRow_Any_NEON;
601     if (IS_ALIGNED(width, 8)) {
602       ARGBToYRow = ARGBToYRow_NEON;
603     }
604   }
605 #endif
606 #if defined(HAS_ARGBTOUVROW_NEON)
607   if (TestCpuFlag(kCpuHasNEON)) {
608     ARGBToUVRow = ARGBToUVRow_Any_NEON;
609     if (IS_ALIGNED(width, 16)) {
610       ARGBToUVRow = ARGBToUVRow_NEON;
611     }
612   }
613 #endif
614 #if defined(HAS_ARGBTOYROW_MSA)
615   if (TestCpuFlag(kCpuHasMSA)) {
616     ARGBToYRow = ARGBToYRow_Any_MSA;
617     if (IS_ALIGNED(width, 16)) {
618       ARGBToYRow = ARGBToYRow_MSA;
619     }
620   }
621 #endif
622 #if defined(HAS_ARGBTOUVROW_MSA)
623   if (TestCpuFlag(kCpuHasMSA)) {
624     ARGBToUVRow = ARGBToUVRow_Any_MSA;
625     if (IS_ALIGNED(width, 32)) {
626       ARGBToUVRow = ARGBToUVRow_MSA;
627     }
628   }
629 #endif
630 #if defined(HAS_I422TOYUY2ROW_SSE2)
631   if (TestCpuFlag(kCpuHasSSE2)) {
632     I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
633     if (IS_ALIGNED(width, 16)) {
634       I422ToYUY2Row = I422ToYUY2Row_SSE2;
635     }
636   }
637 #endif
638 #if defined(HAS_I422TOYUY2ROW_NEON)
639   if (TestCpuFlag(kCpuHasNEON)) {
640     I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
641     if (IS_ALIGNED(width, 16)) {
642       I422ToYUY2Row = I422ToYUY2Row_NEON;
643     }
644   }
645 #endif
646 #if defined(HAS_ARGBTOYROW_DSPR2)
647   if (TestCpuFlag(kCpuHasDSPR2)) {
648     ARGBToYRow = ARGBToYRow_Any_DSPR2;
649     if (IS_ALIGNED(width, 8)) {
650       ARGBToYRow = ARGBToYRow_DSPR2;
651     }
652   }
653 #endif
654 #if defined(HAS_ARGBTOUVROW_DSPR2)
655   if (TestCpuFlag(kCpuHasDSPR2)) {
656     ARGBToUVRow = ARGBToUVRow_Any_DSPR2;
657     if (IS_ALIGNED(width, 16)) {
658       ARGBToUVRow = ARGBToUVRow_DSPR2;
659     }
660   }
661 #endif
662 #if defined(HAS_I422TOYUY2ROW_MSA)
663   if (TestCpuFlag(kCpuHasMSA)) {
664     I422ToYUY2Row = I422ToYUY2Row_Any_MSA;
665     if (IS_ALIGNED(width, 32)) {
666       I422ToYUY2Row = I422ToYUY2Row_MSA;
667     }
668   }
669 #endif
670 
671   {
672     // Allocate a rows of yuv.
673     align_buffer_64(row_y, ((width + 63) & ~63) * 2);
674     uint8* row_u = row_y + ((width + 63) & ~63);
675     uint8* row_v = row_u + ((width + 63) & ~63) / 2;
676 
677     for (y = 0; y < height; ++y) {
678       ARGBToUVRow(src_argb, 0, row_u, row_v, width);
679       ARGBToYRow(src_argb, row_y, width);
680       I422ToYUY2Row(row_y, row_u, row_v, dst_yuy2, width);
681       src_argb += src_stride_argb;
682       dst_yuy2 += dst_stride_yuy2;
683     }
684 
685     free_aligned_buffer_64(row_y);
686   }
687   return 0;
688 }
689 
690 // Convert ARGB to UYVY.
691 LIBYUV_API
ARGBToUYVY(const uint8 * src_argb,int src_stride_argb,uint8 * dst_uyvy,int dst_stride_uyvy,int width,int height)692 int ARGBToUYVY(const uint8* src_argb,
693                int src_stride_argb,
694                uint8* dst_uyvy,
695                int dst_stride_uyvy,
696                int width,
697                int height) {
698   int y;
699   void (*ARGBToUVRow)(const uint8* src_argb, int src_stride_argb, uint8* dst_u,
700                       uint8* dst_v, int width) = ARGBToUVRow_C;
701   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
702       ARGBToYRow_C;
703   void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u,
704                         const uint8* src_v, uint8* dst_uyvy, int width) =
705       I422ToUYVYRow_C;
706 
707   if (!src_argb || !dst_uyvy || width <= 0 || height == 0) {
708     return -1;
709   }
710   // Negative height means invert the image.
711   if (height < 0) {
712     height = -height;
713     dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
714     dst_stride_uyvy = -dst_stride_uyvy;
715   }
716   // Coalesce rows.
717   if (src_stride_argb == width * 4 && dst_stride_uyvy == width * 2) {
718     width *= height;
719     height = 1;
720     src_stride_argb = dst_stride_uyvy = 0;
721   }
722 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
723   if (TestCpuFlag(kCpuHasSSSE3)) {
724     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
725     ARGBToYRow = ARGBToYRow_Any_SSSE3;
726     if (IS_ALIGNED(width, 16)) {
727       ARGBToUVRow = ARGBToUVRow_SSSE3;
728       ARGBToYRow = ARGBToYRow_SSSE3;
729     }
730   }
731 #endif
732 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
733   if (TestCpuFlag(kCpuHasAVX2)) {
734     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
735     ARGBToYRow = ARGBToYRow_Any_AVX2;
736     if (IS_ALIGNED(width, 32)) {
737       ARGBToUVRow = ARGBToUVRow_AVX2;
738       ARGBToYRow = ARGBToYRow_AVX2;
739     }
740   }
741 #endif
742 #if defined(HAS_ARGBTOYROW_NEON)
743   if (TestCpuFlag(kCpuHasNEON)) {
744     ARGBToYRow = ARGBToYRow_Any_NEON;
745     if (IS_ALIGNED(width, 8)) {
746       ARGBToYRow = ARGBToYRow_NEON;
747     }
748   }
749 #endif
750 #if defined(HAS_ARGBTOUVROW_NEON)
751   if (TestCpuFlag(kCpuHasNEON)) {
752     ARGBToUVRow = ARGBToUVRow_Any_NEON;
753     if (IS_ALIGNED(width, 16)) {
754       ARGBToUVRow = ARGBToUVRow_NEON;
755     }
756   }
757 #endif
758 #if defined(HAS_ARGBTOYROW_MSA)
759   if (TestCpuFlag(kCpuHasMSA)) {
760     ARGBToYRow = ARGBToYRow_Any_MSA;
761     if (IS_ALIGNED(width, 16)) {
762       ARGBToYRow = ARGBToYRow_MSA;
763     }
764   }
765 #endif
766 #if defined(HAS_ARGBTOUVROW_MSA)
767   if (TestCpuFlag(kCpuHasMSA)) {
768     ARGBToUVRow = ARGBToUVRow_Any_MSA;
769     if (IS_ALIGNED(width, 32)) {
770       ARGBToUVRow = ARGBToUVRow_MSA;
771     }
772   }
773 #endif
774 #if defined(HAS_I422TOUYVYROW_SSE2)
775   if (TestCpuFlag(kCpuHasSSE2)) {
776     I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
777     if (IS_ALIGNED(width, 16)) {
778       I422ToUYVYRow = I422ToUYVYRow_SSE2;
779     }
780   }
781 #endif
782 #if defined(HAS_I422TOUYVYROW_NEON)
783   if (TestCpuFlag(kCpuHasNEON)) {
784     I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
785     if (IS_ALIGNED(width, 16)) {
786       I422ToUYVYRow = I422ToUYVYRow_NEON;
787     }
788   }
789 #endif
790 #if defined(HAS_ARGBTOYROW_DSPR2)
791   if (TestCpuFlag(kCpuHasDSPR2)) {
792     ARGBToYRow = ARGBToYRow_Any_DSPR2;
793     if (IS_ALIGNED(width, 8)) {
794       ARGBToYRow = ARGBToYRow_DSPR2;
795     }
796   }
797 #endif
798 #if defined(HAS_ARGBTOUVROW_DSPR2)
799   if (TestCpuFlag(kCpuHasDSPR2)) {
800     ARGBToUVRow = ARGBToUVRow_Any_DSPR2;
801     if (IS_ALIGNED(width, 16)) {
802       ARGBToUVRow = ARGBToUVRow_DSPR2;
803     }
804   }
805 #endif
806 #if defined(HAS_I422TOUYVYROW_MSA)
807   if (TestCpuFlag(kCpuHasMSA)) {
808     I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
809     if (IS_ALIGNED(width, 32)) {
810       I422ToUYVYRow = I422ToUYVYRow_MSA;
811     }
812   }
813 #endif
814 
815   {
816     // Allocate a rows of yuv.
817     align_buffer_64(row_y, ((width + 63) & ~63) * 2);
818     uint8* row_u = row_y + ((width + 63) & ~63);
819     uint8* row_v = row_u + ((width + 63) & ~63) / 2;
820 
821     for (y = 0; y < height; ++y) {
822       ARGBToUVRow(src_argb, 0, row_u, row_v, width);
823       ARGBToYRow(src_argb, row_y, width);
824       I422ToUYVYRow(row_y, row_u, row_v, dst_uyvy, width);
825       src_argb += src_stride_argb;
826       dst_uyvy += dst_stride_uyvy;
827     }
828 
829     free_aligned_buffer_64(row_y);
830   }
831   return 0;
832 }
833 
834 // Convert ARGB to I400.
835 LIBYUV_API
ARGBToI400(const uint8 * src_argb,int src_stride_argb,uint8 * dst_y,int dst_stride_y,int width,int height)836 int ARGBToI400(const uint8* src_argb,
837                int src_stride_argb,
838                uint8* dst_y,
839                int dst_stride_y,
840                int width,
841                int height) {
842   int y;
843   void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
844       ARGBToYRow_C;
845   if (!src_argb || !dst_y || width <= 0 || height == 0) {
846     return -1;
847   }
848   if (height < 0) {
849     height = -height;
850     src_argb = src_argb + (height - 1) * src_stride_argb;
851     src_stride_argb = -src_stride_argb;
852   }
853   // Coalesce rows.
854   if (src_stride_argb == width * 4 && dst_stride_y == width) {
855     width *= height;
856     height = 1;
857     src_stride_argb = dst_stride_y = 0;
858   }
859 #if defined(HAS_ARGBTOYROW_SSSE3)
860   if (TestCpuFlag(kCpuHasSSSE3)) {
861     ARGBToYRow = ARGBToYRow_Any_SSSE3;
862     if (IS_ALIGNED(width, 16)) {
863       ARGBToYRow = ARGBToYRow_SSSE3;
864     }
865   }
866 #endif
867 #if defined(HAS_ARGBTOYROW_AVX2)
868   if (TestCpuFlag(kCpuHasAVX2)) {
869     ARGBToYRow = ARGBToYRow_Any_AVX2;
870     if (IS_ALIGNED(width, 32)) {
871       ARGBToYRow = ARGBToYRow_AVX2;
872     }
873   }
874 #endif
875 #if defined(HAS_ARGBTOYROW_NEON)
876   if (TestCpuFlag(kCpuHasNEON)) {
877     ARGBToYRow = ARGBToYRow_Any_NEON;
878     if (IS_ALIGNED(width, 8)) {
879       ARGBToYRow = ARGBToYRow_NEON;
880     }
881   }
882 #endif
883 #if defined(HAS_ARGBTOYROW_DSPR2)
884   if (TestCpuFlag(kCpuHasDSPR2)) {
885     ARGBToYRow = ARGBToYRow_Any_DSPR2;
886     if (IS_ALIGNED(width, 8)) {
887       ARGBToYRow = ARGBToYRow_DSPR2;
888     }
889   }
890 #endif
891 #if defined(HAS_ARGBTOYROW_MSA)
892   if (TestCpuFlag(kCpuHasMSA)) {
893     ARGBToYRow = ARGBToYRow_Any_MSA;
894     if (IS_ALIGNED(width, 16)) {
895       ARGBToYRow = ARGBToYRow_MSA;
896     }
897   }
898 #endif
899 
900   for (y = 0; y < height; ++y) {
901     ARGBToYRow(src_argb, dst_y, width);
902     src_argb += src_stride_argb;
903     dst_y += dst_stride_y;
904   }
905   return 0;
906 }
907 
908 // Shuffle table for converting ARGB to RGBA.
909 static uvec8 kShuffleMaskARGBToRGBA = {3u,  0u, 1u, 2u,  7u,  4u,  5u,  6u,
910                                        11u, 8u, 9u, 10u, 15u, 12u, 13u, 14u};
911 
912 // Convert ARGB to RGBA.
913 LIBYUV_API
ARGBToRGBA(const uint8 * src_argb,int src_stride_argb,uint8 * dst_rgba,int dst_stride_rgba,int width,int height)914 int ARGBToRGBA(const uint8* src_argb,
915                int src_stride_argb,
916                uint8* dst_rgba,
917                int dst_stride_rgba,
918                int width,
919                int height) {
920   return ARGBShuffle(src_argb, src_stride_argb, dst_rgba, dst_stride_rgba,
921                      (const uint8*)(&kShuffleMaskARGBToRGBA), width, height);
922 }
923 
924 // Convert ARGB To RGB24.
925 LIBYUV_API
ARGBToRGB24(const uint8 * src_argb,int src_stride_argb,uint8 * dst_rgb24,int dst_stride_rgb24,int width,int height)926 int ARGBToRGB24(const uint8* src_argb,
927                 int src_stride_argb,
928                 uint8* dst_rgb24,
929                 int dst_stride_rgb24,
930                 int width,
931                 int height) {
932   int y;
933   void (*ARGBToRGB24Row)(const uint8* src_argb, uint8* dst_rgb, int width) =
934       ARGBToRGB24Row_C;
935   if (!src_argb || !dst_rgb24 || width <= 0 || height == 0) {
936     return -1;
937   }
938   if (height < 0) {
939     height = -height;
940     src_argb = src_argb + (height - 1) * src_stride_argb;
941     src_stride_argb = -src_stride_argb;
942   }
943   // Coalesce rows.
944   if (src_stride_argb == width * 4 && dst_stride_rgb24 == width * 3) {
945     width *= height;
946     height = 1;
947     src_stride_argb = dst_stride_rgb24 = 0;
948   }
949 #if defined(HAS_ARGBTORGB24ROW_SSSE3)
950   if (TestCpuFlag(kCpuHasSSSE3)) {
951     ARGBToRGB24Row = ARGBToRGB24Row_Any_SSSE3;
952     if (IS_ALIGNED(width, 16)) {
953       ARGBToRGB24Row = ARGBToRGB24Row_SSSE3;
954     }
955   }
956 #endif
957 #if defined(HAS_ARGBTORGB24ROW_NEON)
958   if (TestCpuFlag(kCpuHasNEON)) {
959     ARGBToRGB24Row = ARGBToRGB24Row_Any_NEON;
960     if (IS_ALIGNED(width, 8)) {
961       ARGBToRGB24Row = ARGBToRGB24Row_NEON;
962     }
963   }
964 #endif
965 #if defined(HAS_ARGBTORGB24ROW_MSA)
966   if (TestCpuFlag(kCpuHasMSA)) {
967     ARGBToRGB24Row = ARGBToRGB24Row_Any_MSA;
968     if (IS_ALIGNED(width, 16)) {
969       ARGBToRGB24Row = ARGBToRGB24Row_MSA;
970     }
971   }
972 #endif
973 
974   for (y = 0; y < height; ++y) {
975     ARGBToRGB24Row(src_argb, dst_rgb24, width);
976     src_argb += src_stride_argb;
977     dst_rgb24 += dst_stride_rgb24;
978   }
979   return 0;
980 }
981 
982 // Convert ARGB To RAW.
983 LIBYUV_API
ARGBToRAW(const uint8 * src_argb,int src_stride_argb,uint8 * dst_raw,int dst_stride_raw,int width,int height)984 int ARGBToRAW(const uint8* src_argb,
985               int src_stride_argb,
986               uint8* dst_raw,
987               int dst_stride_raw,
988               int width,
989               int height) {
990   int y;
991   void (*ARGBToRAWRow)(const uint8* src_argb, uint8* dst_rgb, int width) =
992       ARGBToRAWRow_C;
993   if (!src_argb || !dst_raw || width <= 0 || height == 0) {
994     return -1;
995   }
996   if (height < 0) {
997     height = -height;
998     src_argb = src_argb + (height - 1) * src_stride_argb;
999     src_stride_argb = -src_stride_argb;
1000   }
1001   // Coalesce rows.
1002   if (src_stride_argb == width * 4 && dst_stride_raw == width * 3) {
1003     width *= height;
1004     height = 1;
1005     src_stride_argb = dst_stride_raw = 0;
1006   }
1007 #if defined(HAS_ARGBTORAWROW_SSSE3)
1008   if (TestCpuFlag(kCpuHasSSSE3)) {
1009     ARGBToRAWRow = ARGBToRAWRow_Any_SSSE3;
1010     if (IS_ALIGNED(width, 16)) {
1011       ARGBToRAWRow = ARGBToRAWRow_SSSE3;
1012     }
1013   }
1014 #endif
1015 #if defined(HAS_ARGBTORAWROW_NEON)
1016   if (TestCpuFlag(kCpuHasNEON)) {
1017     ARGBToRAWRow = ARGBToRAWRow_Any_NEON;
1018     if (IS_ALIGNED(width, 8)) {
1019       ARGBToRAWRow = ARGBToRAWRow_NEON;
1020     }
1021   }
1022 #endif
1023 #if defined(HAS_ARGBTORAWROW_MSA)
1024   if (TestCpuFlag(kCpuHasMSA)) {
1025     ARGBToRAWRow = ARGBToRAWRow_Any_MSA;
1026     if (IS_ALIGNED(width, 16)) {
1027       ARGBToRAWRow = ARGBToRAWRow_MSA;
1028     }
1029   }
1030 #endif
1031 
1032   for (y = 0; y < height; ++y) {
1033     ARGBToRAWRow(src_argb, dst_raw, width);
1034     src_argb += src_stride_argb;
1035     dst_raw += dst_stride_raw;
1036   }
1037   return 0;
1038 }
1039 
1040 // Ordered 8x8 dither for 888 to 565.  Values from 0 to 7.
1041 static const uint8 kDither565_4x4[16] = {
1042     0, 4, 1, 5, 6, 2, 7, 3, 1, 5, 0, 4, 7, 3, 6, 2,
1043 };
1044 
1045 // Convert ARGB To RGB565 with 4x4 dither matrix (16 bytes).
1046 LIBYUV_API
ARGBToRGB565Dither(const uint8 * src_argb,int src_stride_argb,uint8 * dst_rgb565,int dst_stride_rgb565,const uint8 * dither4x4,int width,int height)1047 int ARGBToRGB565Dither(const uint8* src_argb,
1048                        int src_stride_argb,
1049                        uint8* dst_rgb565,
1050                        int dst_stride_rgb565,
1051                        const uint8* dither4x4,
1052                        int width,
1053                        int height) {
1054   int y;
1055   void (*ARGBToRGB565DitherRow)(const uint8* src_argb, uint8* dst_rgb,
1056                                 const uint32 dither4, int width) =
1057       ARGBToRGB565DitherRow_C;
1058   if (!src_argb || !dst_rgb565 || width <= 0 || height == 0) {
1059     return -1;
1060   }
1061   if (height < 0) {
1062     height = -height;
1063     src_argb = src_argb + (height - 1) * src_stride_argb;
1064     src_stride_argb = -src_stride_argb;
1065   }
1066   if (!dither4x4) {
1067     dither4x4 = kDither565_4x4;
1068   }
1069 #if defined(HAS_ARGBTORGB565DITHERROW_SSE2)
1070   if (TestCpuFlag(kCpuHasSSE2)) {
1071     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_SSE2;
1072     if (IS_ALIGNED(width, 4)) {
1073       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_SSE2;
1074     }
1075   }
1076 #endif
1077 #if defined(HAS_ARGBTORGB565DITHERROW_AVX2)
1078   if (TestCpuFlag(kCpuHasAVX2)) {
1079     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_AVX2;
1080     if (IS_ALIGNED(width, 8)) {
1081       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_AVX2;
1082     }
1083   }
1084 #endif
1085 #if defined(HAS_ARGBTORGB565DITHERROW_NEON)
1086   if (TestCpuFlag(kCpuHasNEON)) {
1087     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_NEON;
1088     if (IS_ALIGNED(width, 8)) {
1089       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_NEON;
1090     }
1091   }
1092 #endif
1093 #if defined(HAS_ARGBTORGB565DITHERROW_MSA)
1094   if (TestCpuFlag(kCpuHasMSA)) {
1095     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_MSA;
1096     if (IS_ALIGNED(width, 8)) {
1097       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_MSA;
1098     }
1099   }
1100 #endif
1101 
1102   for (y = 0; y < height; ++y) {
1103     ARGBToRGB565DitherRow(src_argb, dst_rgb565,
1104                           *(uint32*)(dither4x4 + ((y & 3) << 2)),
1105                           width); /* NOLINT */
1106     src_argb += src_stride_argb;
1107     dst_rgb565 += dst_stride_rgb565;
1108   }
1109   return 0;
1110 }
1111 
1112 // Convert ARGB To RGB565.
1113 // TODO(fbarchard): Consider using dither function low level with zeros.
1114 LIBYUV_API
ARGBToRGB565(const uint8 * src_argb,int src_stride_argb,uint8 * dst_rgb565,int dst_stride_rgb565,int width,int height)1115 int ARGBToRGB565(const uint8* src_argb,
1116                  int src_stride_argb,
1117                  uint8* dst_rgb565,
1118                  int dst_stride_rgb565,
1119                  int width,
1120                  int height) {
1121   int y;
1122   void (*ARGBToRGB565Row)(const uint8* src_argb, uint8* dst_rgb, int width) =
1123       ARGBToRGB565Row_C;
1124   if (!src_argb || !dst_rgb565 || width <= 0 || height == 0) {
1125     return -1;
1126   }
1127   if (height < 0) {
1128     height = -height;
1129     src_argb = src_argb + (height - 1) * src_stride_argb;
1130     src_stride_argb = -src_stride_argb;
1131   }
1132   // Coalesce rows.
1133   if (src_stride_argb == width * 4 && dst_stride_rgb565 == width * 2) {
1134     width *= height;
1135     height = 1;
1136     src_stride_argb = dst_stride_rgb565 = 0;
1137   }
1138 #if defined(HAS_ARGBTORGB565ROW_SSE2)
1139   if (TestCpuFlag(kCpuHasSSE2)) {
1140     ARGBToRGB565Row = ARGBToRGB565Row_Any_SSE2;
1141     if (IS_ALIGNED(width, 4)) {
1142       ARGBToRGB565Row = ARGBToRGB565Row_SSE2;
1143     }
1144   }
1145 #endif
1146 #if defined(HAS_ARGBTORGB565ROW_AVX2)
1147   if (TestCpuFlag(kCpuHasAVX2)) {
1148     ARGBToRGB565Row = ARGBToRGB565Row_Any_AVX2;
1149     if (IS_ALIGNED(width, 8)) {
1150       ARGBToRGB565Row = ARGBToRGB565Row_AVX2;
1151     }
1152   }
1153 #endif
1154 #if defined(HAS_ARGBTORGB565ROW_NEON)
1155   if (TestCpuFlag(kCpuHasNEON)) {
1156     ARGBToRGB565Row = ARGBToRGB565Row_Any_NEON;
1157     if (IS_ALIGNED(width, 8)) {
1158       ARGBToRGB565Row = ARGBToRGB565Row_NEON;
1159     }
1160   }
1161 #endif
1162 #if defined(HAS_ARGBTORGB565ROW_MSA)
1163   if (TestCpuFlag(kCpuHasMSA)) {
1164     ARGBToRGB565Row = ARGBToRGB565Row_Any_MSA;
1165     if (IS_ALIGNED(width, 8)) {
1166       ARGBToRGB565Row = ARGBToRGB565Row_MSA;
1167     }
1168   }
1169 #endif
1170 
1171   for (y = 0; y < height; ++y) {
1172     ARGBToRGB565Row(src_argb, dst_rgb565, width);
1173     src_argb += src_stride_argb;
1174     dst_rgb565 += dst_stride_rgb565;
1175   }
1176   return 0;
1177 }
1178 
1179 // Convert ARGB To ARGB1555.
1180 LIBYUV_API
ARGBToARGB1555(const uint8 * src_argb,int src_stride_argb,uint8 * dst_argb1555,int dst_stride_argb1555,int width,int height)1181 int ARGBToARGB1555(const uint8* src_argb,
1182                    int src_stride_argb,
1183                    uint8* dst_argb1555,
1184                    int dst_stride_argb1555,
1185                    int width,
1186                    int height) {
1187   int y;
1188   void (*ARGBToARGB1555Row)(const uint8* src_argb, uint8* dst_rgb, int width) =
1189       ARGBToARGB1555Row_C;
1190   if (!src_argb || !dst_argb1555 || width <= 0 || height == 0) {
1191     return -1;
1192   }
1193   if (height < 0) {
1194     height = -height;
1195     src_argb = src_argb + (height - 1) * src_stride_argb;
1196     src_stride_argb = -src_stride_argb;
1197   }
1198   // Coalesce rows.
1199   if (src_stride_argb == width * 4 && dst_stride_argb1555 == width * 2) {
1200     width *= height;
1201     height = 1;
1202     src_stride_argb = dst_stride_argb1555 = 0;
1203   }
1204 #if defined(HAS_ARGBTOARGB1555ROW_SSE2)
1205   if (TestCpuFlag(kCpuHasSSE2)) {
1206     ARGBToARGB1555Row = ARGBToARGB1555Row_Any_SSE2;
1207     if (IS_ALIGNED(width, 4)) {
1208       ARGBToARGB1555Row = ARGBToARGB1555Row_SSE2;
1209     }
1210   }
1211 #endif
1212 #if defined(HAS_ARGBTOARGB1555ROW_AVX2)
1213   if (TestCpuFlag(kCpuHasAVX2)) {
1214     ARGBToARGB1555Row = ARGBToARGB1555Row_Any_AVX2;
1215     if (IS_ALIGNED(width, 8)) {
1216       ARGBToARGB1555Row = ARGBToARGB1555Row_AVX2;
1217     }
1218   }
1219 #endif
1220 #if defined(HAS_ARGBTOARGB1555ROW_NEON)
1221   if (TestCpuFlag(kCpuHasNEON)) {
1222     ARGBToARGB1555Row = ARGBToARGB1555Row_Any_NEON;
1223     if (IS_ALIGNED(width, 8)) {
1224       ARGBToARGB1555Row = ARGBToARGB1555Row_NEON;
1225     }
1226   }
1227 #endif
1228 #if defined(HAS_ARGBTOARGB1555ROW_MSA)
1229   if (TestCpuFlag(kCpuHasMSA)) {
1230     ARGBToARGB1555Row = ARGBToARGB1555Row_Any_MSA;
1231     if (IS_ALIGNED(width, 8)) {
1232       ARGBToARGB1555Row = ARGBToARGB1555Row_MSA;
1233     }
1234   }
1235 #endif
1236 
1237   for (y = 0; y < height; ++y) {
1238     ARGBToARGB1555Row(src_argb, dst_argb1555, width);
1239     src_argb += src_stride_argb;
1240     dst_argb1555 += dst_stride_argb1555;
1241   }
1242   return 0;
1243 }
1244 
1245 // Convert ARGB To ARGB4444.
1246 LIBYUV_API
ARGBToARGB4444(const uint8 * src_argb,int src_stride_argb,uint8 * dst_argb4444,int dst_stride_argb4444,int width,int height)1247 int ARGBToARGB4444(const uint8* src_argb,
1248                    int src_stride_argb,
1249                    uint8* dst_argb4444,
1250                    int dst_stride_argb4444,
1251                    int width,
1252                    int height) {
1253   int y;
1254   void (*ARGBToARGB4444Row)(const uint8* src_argb, uint8* dst_rgb, int width) =
1255       ARGBToARGB4444Row_C;
1256   if (!src_argb || !dst_argb4444 || width <= 0 || height == 0) {
1257     return -1;
1258   }
1259   if (height < 0) {
1260     height = -height;
1261     src_argb = src_argb + (height - 1) * src_stride_argb;
1262     src_stride_argb = -src_stride_argb;
1263   }
1264   // Coalesce rows.
1265   if (src_stride_argb == width * 4 && dst_stride_argb4444 == width * 2) {
1266     width *= height;
1267     height = 1;
1268     src_stride_argb = dst_stride_argb4444 = 0;
1269   }
1270 #if defined(HAS_ARGBTOARGB4444ROW_SSE2)
1271   if (TestCpuFlag(kCpuHasSSE2)) {
1272     ARGBToARGB4444Row = ARGBToARGB4444Row_Any_SSE2;
1273     if (IS_ALIGNED(width, 4)) {
1274       ARGBToARGB4444Row = ARGBToARGB4444Row_SSE2;
1275     }
1276   }
1277 #endif
1278 #if defined(HAS_ARGBTOARGB4444ROW_AVX2)
1279   if (TestCpuFlag(kCpuHasAVX2)) {
1280     ARGBToARGB4444Row = ARGBToARGB4444Row_Any_AVX2;
1281     if (IS_ALIGNED(width, 8)) {
1282       ARGBToARGB4444Row = ARGBToARGB4444Row_AVX2;
1283     }
1284   }
1285 #endif
1286 #if defined(HAS_ARGBTOARGB4444ROW_NEON)
1287   if (TestCpuFlag(kCpuHasNEON)) {
1288     ARGBToARGB4444Row = ARGBToARGB4444Row_Any_NEON;
1289     if (IS_ALIGNED(width, 8)) {
1290       ARGBToARGB4444Row = ARGBToARGB4444Row_NEON;
1291     }
1292   }
1293 #endif
1294 #if defined(HAS_ARGBTOARGB4444ROW_MSA)
1295   if (TestCpuFlag(kCpuHasMSA)) {
1296     ARGBToARGB4444Row = ARGBToARGB4444Row_Any_MSA;
1297     if (IS_ALIGNED(width, 8)) {
1298       ARGBToARGB4444Row = ARGBToARGB4444Row_MSA;
1299     }
1300   }
1301 #endif
1302 
1303   for (y = 0; y < height; ++y) {
1304     ARGBToARGB4444Row(src_argb, dst_argb4444, width);
1305     src_argb += src_stride_argb;
1306     dst_argb4444 += dst_stride_argb4444;
1307   }
1308   return 0;
1309 }
1310 
1311 // Convert ARGB to J420. (JPeg full range I420).
1312 LIBYUV_API
ARGBToJ420(const uint8 * src_argb,int src_stride_argb,uint8 * dst_yj,int dst_stride_yj,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)1313 int ARGBToJ420(const uint8* src_argb,
1314                int src_stride_argb,
1315                uint8* dst_yj,
1316                int dst_stride_yj,
1317                uint8* dst_u,
1318                int dst_stride_u,
1319                uint8* dst_v,
1320                int dst_stride_v,
1321                int width,
1322                int height) {
1323   int y;
1324   void (*ARGBToUVJRow)(const uint8* src_argb0, int src_stride_argb,
1325                        uint8* dst_u, uint8* dst_v, int width) = ARGBToUVJRow_C;
1326   void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_yj, int width) =
1327       ARGBToYJRow_C;
1328   if (!src_argb || !dst_yj || !dst_u || !dst_v || width <= 0 || height == 0) {
1329     return -1;
1330   }
1331   // Negative height means invert the image.
1332   if (height < 0) {
1333     height = -height;
1334     src_argb = src_argb + (height - 1) * src_stride_argb;
1335     src_stride_argb = -src_stride_argb;
1336   }
1337 #if defined(HAS_ARGBTOYJROW_SSSE3) && defined(HAS_ARGBTOUVJROW_SSSE3)
1338   if (TestCpuFlag(kCpuHasSSSE3)) {
1339     ARGBToUVJRow = ARGBToUVJRow_Any_SSSE3;
1340     ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
1341     if (IS_ALIGNED(width, 16)) {
1342       ARGBToUVJRow = ARGBToUVJRow_SSSE3;
1343       ARGBToYJRow = ARGBToYJRow_SSSE3;
1344     }
1345   }
1346 #endif
1347 #if defined(HAS_ARGBTOYJROW_AVX2)
1348   if (TestCpuFlag(kCpuHasAVX2)) {
1349     ARGBToYJRow = ARGBToYJRow_Any_AVX2;
1350     if (IS_ALIGNED(width, 32)) {
1351       ARGBToYJRow = ARGBToYJRow_AVX2;
1352     }
1353   }
1354 #endif
1355 #if defined(HAS_ARGBTOYJROW_NEON)
1356   if (TestCpuFlag(kCpuHasNEON)) {
1357     ARGBToYJRow = ARGBToYJRow_Any_NEON;
1358     if (IS_ALIGNED(width, 8)) {
1359       ARGBToYJRow = ARGBToYJRow_NEON;
1360     }
1361   }
1362 #endif
1363 #if defined(HAS_ARGBTOUVJROW_NEON)
1364   if (TestCpuFlag(kCpuHasNEON)) {
1365     ARGBToUVJRow = ARGBToUVJRow_Any_NEON;
1366     if (IS_ALIGNED(width, 16)) {
1367       ARGBToUVJRow = ARGBToUVJRow_NEON;
1368     }
1369   }
1370 #endif
1371 #if defined(HAS_ARGBTOYJROW_MSA)
1372   if (TestCpuFlag(kCpuHasMSA)) {
1373     ARGBToYJRow = ARGBToYJRow_Any_MSA;
1374     if (IS_ALIGNED(width, 16)) {
1375       ARGBToYJRow = ARGBToYJRow_MSA;
1376     }
1377   }
1378 #endif
1379 #if defined(HAS_ARGBTOUVJROW_MSA)
1380   if (TestCpuFlag(kCpuHasMSA)) {
1381     ARGBToUVJRow = ARGBToUVJRow_Any_MSA;
1382     if (IS_ALIGNED(width, 32)) {
1383       ARGBToUVJRow = ARGBToUVJRow_MSA;
1384     }
1385   }
1386 #endif
1387 
1388   for (y = 0; y < height - 1; y += 2) {
1389     ARGBToUVJRow(src_argb, src_stride_argb, dst_u, dst_v, width);
1390     ARGBToYJRow(src_argb, dst_yj, width);
1391     ARGBToYJRow(src_argb + src_stride_argb, dst_yj + dst_stride_yj, width);
1392     src_argb += src_stride_argb * 2;
1393     dst_yj += dst_stride_yj * 2;
1394     dst_u += dst_stride_u;
1395     dst_v += dst_stride_v;
1396   }
1397   if (height & 1) {
1398     ARGBToUVJRow(src_argb, 0, dst_u, dst_v, width);
1399     ARGBToYJRow(src_argb, dst_yj, width);
1400   }
1401   return 0;
1402 }
1403 
1404 // Convert ARGB to J422. (JPeg full range I422).
1405 LIBYUV_API
ARGBToJ422(const uint8 * src_argb,int src_stride_argb,uint8 * dst_yj,int dst_stride_yj,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)1406 int ARGBToJ422(const uint8* src_argb,
1407                int src_stride_argb,
1408                uint8* dst_yj,
1409                int dst_stride_yj,
1410                uint8* dst_u,
1411                int dst_stride_u,
1412                uint8* dst_v,
1413                int dst_stride_v,
1414                int width,
1415                int height) {
1416   int y;
1417   void (*ARGBToUVJRow)(const uint8* src_argb0, int src_stride_argb,
1418                        uint8* dst_u, uint8* dst_v, int width) = ARGBToUVJRow_C;
1419   void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_yj, int width) =
1420       ARGBToYJRow_C;
1421   if (!src_argb || !dst_yj || !dst_u || !dst_v || width <= 0 || height == 0) {
1422     return -1;
1423   }
1424   // Negative height means invert the image.
1425   if (height < 0) {
1426     height = -height;
1427     src_argb = src_argb + (height - 1) * src_stride_argb;
1428     src_stride_argb = -src_stride_argb;
1429   }
1430   // Coalesce rows.
1431   if (src_stride_argb == width * 4 && dst_stride_yj == width &&
1432       dst_stride_u * 2 == width && dst_stride_v * 2 == width) {
1433     width *= height;
1434     height = 1;
1435     src_stride_argb = dst_stride_yj = dst_stride_u = dst_stride_v = 0;
1436   }
1437 #if defined(HAS_ARGBTOYJROW_SSSE3) && defined(HAS_ARGBTOUVJROW_SSSE3)
1438   if (TestCpuFlag(kCpuHasSSSE3)) {
1439     ARGBToUVJRow = ARGBToUVJRow_Any_SSSE3;
1440     ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
1441     if (IS_ALIGNED(width, 16)) {
1442       ARGBToUVJRow = ARGBToUVJRow_SSSE3;
1443       ARGBToYJRow = ARGBToYJRow_SSSE3;
1444     }
1445   }
1446 #endif
1447 #if defined(HAS_ARGBTOYJROW_AVX2)
1448   if (TestCpuFlag(kCpuHasAVX2)) {
1449     ARGBToYJRow = ARGBToYJRow_Any_AVX2;
1450     if (IS_ALIGNED(width, 32)) {
1451       ARGBToYJRow = ARGBToYJRow_AVX2;
1452     }
1453   }
1454 #endif
1455 #if defined(HAS_ARGBTOYJROW_NEON)
1456   if (TestCpuFlag(kCpuHasNEON)) {
1457     ARGBToYJRow = ARGBToYJRow_Any_NEON;
1458     if (IS_ALIGNED(width, 8)) {
1459       ARGBToYJRow = ARGBToYJRow_NEON;
1460     }
1461   }
1462 #endif
1463 #if defined(HAS_ARGBTOUVJROW_NEON)
1464   if (TestCpuFlag(kCpuHasNEON)) {
1465     ARGBToUVJRow = ARGBToUVJRow_Any_NEON;
1466     if (IS_ALIGNED(width, 16)) {
1467       ARGBToUVJRow = ARGBToUVJRow_NEON;
1468     }
1469   }
1470 #endif
1471 #if defined(HAS_ARGBTOYJROW_MSA)
1472   if (TestCpuFlag(kCpuHasMSA)) {
1473     ARGBToYJRow = ARGBToYJRow_Any_MSA;
1474     if (IS_ALIGNED(width, 16)) {
1475       ARGBToYJRow = ARGBToYJRow_MSA;
1476     }
1477   }
1478 #endif
1479 #if defined(HAS_ARGBTOUVJROW_MSA)
1480   if (TestCpuFlag(kCpuHasMSA)) {
1481     ARGBToUVJRow = ARGBToUVJRow_Any_MSA;
1482     if (IS_ALIGNED(width, 32)) {
1483       ARGBToUVJRow = ARGBToUVJRow_MSA;
1484     }
1485   }
1486 #endif
1487 
1488   for (y = 0; y < height; ++y) {
1489     ARGBToUVJRow(src_argb, 0, dst_u, dst_v, width);
1490     ARGBToYJRow(src_argb, dst_yj, width);
1491     src_argb += src_stride_argb;
1492     dst_yj += dst_stride_yj;
1493     dst_u += dst_stride_u;
1494     dst_v += dst_stride_v;
1495   }
1496   return 0;
1497 }
1498 
1499 // Convert ARGB to J400.
1500 LIBYUV_API
ARGBToJ400(const uint8 * src_argb,int src_stride_argb,uint8 * dst_yj,int dst_stride_yj,int width,int height)1501 int ARGBToJ400(const uint8* src_argb,
1502                int src_stride_argb,
1503                uint8* dst_yj,
1504                int dst_stride_yj,
1505                int width,
1506                int height) {
1507   int y;
1508   void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_yj, int width) =
1509       ARGBToYJRow_C;
1510   if (!src_argb || !dst_yj || width <= 0 || height == 0) {
1511     return -1;
1512   }
1513   if (height < 0) {
1514     height = -height;
1515     src_argb = src_argb + (height - 1) * src_stride_argb;
1516     src_stride_argb = -src_stride_argb;
1517   }
1518   // Coalesce rows.
1519   if (src_stride_argb == width * 4 && dst_stride_yj == width) {
1520     width *= height;
1521     height = 1;
1522     src_stride_argb = dst_stride_yj = 0;
1523   }
1524 #if defined(HAS_ARGBTOYJROW_SSSE3)
1525   if (TestCpuFlag(kCpuHasSSSE3)) {
1526     ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
1527     if (IS_ALIGNED(width, 16)) {
1528       ARGBToYJRow = ARGBToYJRow_SSSE3;
1529     }
1530   }
1531 #endif
1532 #if defined(HAS_ARGBTOYJROW_AVX2)
1533   if (TestCpuFlag(kCpuHasAVX2)) {
1534     ARGBToYJRow = ARGBToYJRow_Any_AVX2;
1535     if (IS_ALIGNED(width, 32)) {
1536       ARGBToYJRow = ARGBToYJRow_AVX2;
1537     }
1538   }
1539 #endif
1540 #if defined(HAS_ARGBTOYJROW_NEON)
1541   if (TestCpuFlag(kCpuHasNEON)) {
1542     ARGBToYJRow = ARGBToYJRow_Any_NEON;
1543     if (IS_ALIGNED(width, 8)) {
1544       ARGBToYJRow = ARGBToYJRow_NEON;
1545     }
1546   }
1547 #endif
1548 #if defined(HAS_ARGBTOYJROW_MSA)
1549   if (TestCpuFlag(kCpuHasMSA)) {
1550     ARGBToYJRow = ARGBToYJRow_Any_MSA;
1551     if (IS_ALIGNED(width, 16)) {
1552       ARGBToYJRow = ARGBToYJRow_MSA;
1553     }
1554   }
1555 #endif
1556 
1557   for (y = 0; y < height; ++y) {
1558     ARGBToYJRow(src_argb, dst_yj, width);
1559     src_argb += src_stride_argb;
1560     dst_yj += dst_stride_yj;
1561   }
1562   return 0;
1563 }
1564 
1565 #ifdef __cplusplus
1566 }  // extern "C"
1567 }  // namespace libyuv
1568 #endif
1569