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
19namespace libyuv {
20extern "C" {
21#endif
22
23// ARGB little endian (bgra in memory) to I444
24LIBYUV_API
25int 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
105LIBYUV_API
106int 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
185LIBYUV_API
186int 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
257LIBYUV_API
258int 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.
366LIBYUV_API
367int 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.
475LIBYUV_API
476int 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.
577LIBYUV_API
578int 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.
679LIBYUV_API
680int 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.
735static 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.
740LIBYUV_API
741int 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.
751LIBYUV_API
752int 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.
799LIBYUV_API
800int 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.
847static 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).
855LIBYUV_API
856int 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.
908LIBYUV_API
909int 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.
964LIBYUV_API
965int 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.
1020LIBYUV_API
1021int 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).
1076LIBYUV_API
1077int 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).
1150LIBYUV_API
1151int 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.
1228LIBYUV_API
1229int 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