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