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