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