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.h"
12
13#include "libyuv/basic_types.h"
14#include "libyuv/convert.h"  // For I420Copy
15#include "libyuv/cpu_id.h"
16#include "libyuv/format_conversion.h"
17#include "libyuv/planar_functions.h"
18#include "libyuv/rotate.h"
19#include "libyuv/video_common.h"
20#include "libyuv/row.h"
21
22#ifdef __cplusplus
23namespace libyuv {
24extern "C" {
25#endif
26
27LIBYUV_API
28int I420ToI422(const uint8* src_y, int src_stride_y,
29               const uint8* src_u, int src_stride_u,
30               const uint8* src_v, int src_stride_v,
31               uint8* dst_y, int dst_stride_y,
32               uint8* dst_u, int dst_stride_u,
33               uint8* dst_v, int dst_stride_v,
34               int width, int height) {
35  if (!src_y || !src_u || !src_v ||
36      !dst_y || !dst_u || !dst_v ||
37      width <= 0 || height == 0) {
38    return -1;
39  }
40  // Negative height means invert the image.
41  if (height < 0) {
42    height = -height;
43    dst_y = dst_y + (height - 1) * dst_stride_y;
44    dst_u = dst_u + (height - 1) * dst_stride_u;
45    dst_v = dst_v + (height - 1) * dst_stride_v;
46    dst_stride_y = -dst_stride_y;
47    dst_stride_u = -dst_stride_u;
48    dst_stride_v = -dst_stride_v;
49  }
50  int halfwidth = (width + 1) >> 1;
51  void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
52#if defined(HAS_COPYROW_NEON)
53  if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(halfwidth, 64)) {
54    CopyRow = CopyRow_NEON;
55  }
56#elif defined(HAS_COPYROW_X86)
57  if (IS_ALIGNED(halfwidth, 4)) {
58    CopyRow = CopyRow_X86;
59#if defined(HAS_COPYROW_SSE2)
60    if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(halfwidth, 32) &&
61        IS_ALIGNED(src_u, 16) && IS_ALIGNED(src_stride_u, 16) &&
62        IS_ALIGNED(src_v, 16) && IS_ALIGNED(src_stride_v, 16) &&
63        IS_ALIGNED(dst_u, 16) && IS_ALIGNED(dst_stride_u, 16) &&
64        IS_ALIGNED(dst_v, 16) && IS_ALIGNED(dst_stride_v, 16)) {
65      CopyRow = CopyRow_SSE2;
66    }
67#endif
68  }
69#endif
70
71  // Copy Y plane
72  if (dst_y) {
73    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
74  }
75
76  // UpSample U plane.
77  int y;
78  for (y = 0; y < height - 1; y += 2) {
79    CopyRow(src_u, dst_u, halfwidth);
80    CopyRow(src_u, dst_u + dst_stride_u, halfwidth);
81    src_u += src_stride_u;
82    dst_u += dst_stride_u * 2;
83  }
84  if (height & 1) {
85    CopyRow(src_u, dst_u, halfwidth);
86  }
87
88  // UpSample V plane.
89  for (y = 0; y < height - 1; y += 2) {
90    CopyRow(src_v, dst_v, halfwidth);
91    CopyRow(src_v, dst_v + dst_stride_v, halfwidth);
92    src_v += src_stride_v;
93    dst_v += dst_stride_v * 2;
94  }
95  if (height & 1) {
96    CopyRow(src_v, dst_v, halfwidth);
97  }
98  return 0;
99}
100
101// use Bilinear for upsampling chroma
102void ScalePlaneBilinear(int src_width, int src_height,
103                        int dst_width, int dst_height,
104                        int src_stride, int dst_stride,
105                        const uint8* src_ptr, uint8* dst_ptr);
106
107LIBYUV_API
108int I420ToI444(const uint8* src_y, int src_stride_y,
109               const uint8* src_u, int src_stride_u,
110               const uint8* src_v, int src_stride_v,
111               uint8* dst_y, int dst_stride_y,
112               uint8* dst_u, int dst_stride_u,
113               uint8* dst_v, int dst_stride_v,
114               int width, int height) {
115  if (!src_y || !src_u|| !src_v ||
116      !dst_y || !dst_u || !dst_v ||
117      width <= 0 || height == 0) {
118    return -1;
119  }
120  // Negative height means invert the image.
121  if (height < 0) {
122    height = -height;
123    dst_y = dst_y + (height - 1) * dst_stride_y;
124    dst_u = dst_u + (height - 1) * dst_stride_u;
125    dst_v = dst_v + (height - 1) * dst_stride_v;
126    dst_stride_y = -dst_stride_y;
127    dst_stride_u = -dst_stride_u;
128    dst_stride_v = -dst_stride_v;
129  }
130
131  // Copy Y plane
132  if (dst_y) {
133    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
134  }
135
136  int halfwidth = (width + 1) >> 1;
137  int halfheight = (height + 1) >> 1;
138
139  // Upsample U plane.
140  ScalePlaneBilinear(halfwidth, halfheight,
141                     width, height,
142                     src_stride_u,
143                     dst_stride_u,
144                     src_u, dst_u);
145
146  // Upsample V plane.
147  ScalePlaneBilinear(halfwidth, halfheight,
148                     width, height,
149                     src_stride_v,
150                     dst_stride_v,
151                     src_v, dst_v);
152  return 0;
153}
154
155// 420 chroma is 1/2 width, 1/2 height
156// 411 chroma is 1/4 width, 1x height
157LIBYUV_API
158int I420ToI411(const uint8* src_y, int src_stride_y,
159               const uint8* src_u, int src_stride_u,
160               const uint8* src_v, int src_stride_v,
161               uint8* dst_y, int dst_stride_y,
162               uint8* dst_u, int dst_stride_u,
163               uint8* dst_v, int dst_stride_v,
164               int width, int height) {
165  if (!src_y || !src_u || !src_v ||
166      !dst_y || !dst_u || !dst_v ||
167      width <= 0 || height == 0) {
168    return -1;
169  }
170  // Negative height means invert the image.
171  if (height < 0) {
172    height = -height;
173    dst_y = dst_y + (height - 1) * dst_stride_y;
174    dst_u = dst_u + (height - 1) * dst_stride_u;
175    dst_v = dst_v + (height - 1) * dst_stride_v;
176    dst_stride_y = -dst_stride_y;
177    dst_stride_u = -dst_stride_u;
178    dst_stride_v = -dst_stride_v;
179  }
180
181  // Copy Y plane
182  if (dst_y) {
183    CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
184  }
185
186  int halfwidth = (width + 1) >> 1;
187  int halfheight = (height + 1) >> 1;
188  int quarterwidth = (width + 3) >> 2;
189
190  // Resample U plane.
191  ScalePlaneBilinear(halfwidth, halfheight,  // from 1/2 width, 1/2 height
192                     quarterwidth, height,  // to 1/4 width, 1x height
193                     src_stride_u,
194                     dst_stride_u,
195                     src_u, dst_u);
196
197  // Resample V plane.
198  ScalePlaneBilinear(halfwidth, halfheight,  // from 1/2 width, 1/2 height
199                     quarterwidth, height,  // to 1/4 width, 1x height
200                     src_stride_v,
201                     dst_stride_v,
202                     src_v, dst_v);
203  return 0;
204}
205
206// Copy to I400. Source can be I420,422,444,400,NV12,NV21
207LIBYUV_API
208int I400Copy(const uint8* src_y, int src_stride_y,
209             uint8* dst_y, int dst_stride_y,
210             int width, int height) {
211  if (!src_y || !dst_y ||
212      width <= 0 || height == 0) {
213    return -1;
214  }
215  // Negative height means invert the image.
216  if (height < 0) {
217    height = -height;
218    src_y = src_y + (height - 1) * src_stride_y;
219    src_stride_y = -src_stride_y;
220  }
221  CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
222  return 0;
223}
224
225// YUY2 - Macro-pixel = 2 image pixels
226// Y0U0Y1V0....Y2U2Y3V2...Y4U4Y5V4....
227
228// UYVY - Macro-pixel = 2 image pixels
229// U0Y0V0Y1
230
231#if !defined(YUV_DISABLE_ASM) && defined(_M_IX86)
232#define HAS_I42XTOYUY2ROW_SSE2
233__declspec(naked) __declspec(align(16))
234static void I42xToYUY2Row_SSE2(const uint8* src_y,
235                               const uint8* src_u,
236                               const uint8* src_v,
237                               uint8* dst_frame, int width) {
238  __asm {
239    push       esi
240    push       edi
241    mov        eax, [esp + 8 + 4]    // src_y
242    mov        esi, [esp + 8 + 8]    // src_u
243    mov        edx, [esp + 8 + 12]   // src_v
244    mov        edi, [esp + 8 + 16]   // dst_frame
245    mov        ecx, [esp + 8 + 20]   // width
246    sub        edx, esi
247
248    align      16
249  convertloop:
250    movq       xmm2, qword ptr [esi] // U
251    movq       xmm3, qword ptr [esi + edx] // V
252    lea        esi, [esi + 8]
253    punpcklbw  xmm2, xmm3 // UV
254    movdqa     xmm0, [eax] // Y
255    lea        eax, [eax + 16]
256    movdqa     xmm1, xmm0
257    punpcklbw  xmm0, xmm2 // YUYV
258    punpckhbw  xmm1, xmm2
259    movdqa     [edi], xmm0
260    movdqa     [edi + 16], xmm1
261    lea        edi, [edi + 32]
262    sub        ecx, 16
263    jg         convertloop
264
265    pop        edi
266    pop        esi
267    ret
268  }
269}
270
271#define HAS_I42XTOUYVYROW_SSE2
272__declspec(naked) __declspec(align(16))
273static void I42xToUYVYRow_SSE2(const uint8* src_y,
274                               const uint8* src_u,
275                               const uint8* src_v,
276                               uint8* dst_frame, int width) {
277  __asm {
278    push       esi
279    push       edi
280    mov        eax, [esp + 8 + 4]    // src_y
281    mov        esi, [esp + 8 + 8]    // src_u
282    mov        edx, [esp + 8 + 12]   // src_v
283    mov        edi, [esp + 8 + 16]   // dst_frame
284    mov        ecx, [esp + 8 + 20]   // width
285    sub        edx, esi
286
287    align      16
288  convertloop:
289    movq       xmm2, qword ptr [esi] // U
290    movq       xmm3, qword ptr [esi + edx] // V
291    lea        esi, [esi + 8]
292    punpcklbw  xmm2, xmm3 // UV
293    movdqa     xmm0, [eax] // Y
294    movdqa     xmm1, xmm2
295    lea        eax, [eax + 16]
296    punpcklbw  xmm1, xmm0 // UYVY
297    punpckhbw  xmm2, xmm0
298    movdqa     [edi], xmm1
299    movdqa     [edi + 16], xmm2
300    lea        edi, [edi + 32]
301    sub        ecx, 16
302    jg         convertloop
303
304    pop        edi
305    pop        esi
306    ret
307  }
308}
309#elif !defined(YUV_DISABLE_ASM) && (defined(__x86_64__) || defined(__i386__))
310#define HAS_I42XTOYUY2ROW_SSE2
311static void I42xToYUY2Row_SSE2(const uint8* src_y,
312                               const uint8* src_u,
313                               const uint8* src_v,
314                               uint8* dst_frame, int width) {
315 asm volatile (
316    "sub        %1,%2                            \n"
317    ".p2align  4                                 \n"
318  "1:                                            \n"
319    "movq      (%1),%%xmm2                       \n"
320    "movq      (%1,%2,1),%%xmm3                  \n"
321    "lea       0x8(%1),%1                        \n"
322    "punpcklbw %%xmm3,%%xmm2                     \n"
323    "movdqa    (%0),%%xmm0                       \n"
324    "lea       0x10(%0),%0                       \n"
325    "movdqa    %%xmm0,%%xmm1                     \n"
326    "punpcklbw %%xmm2,%%xmm0                     \n"
327    "punpckhbw %%xmm2,%%xmm1                     \n"
328    "movdqa    %%xmm0,(%3)                       \n"
329    "movdqa    %%xmm1,0x10(%3)                   \n"
330    "lea       0x20(%3),%3                       \n"
331    "sub       $0x10,%4                          \n"
332    "jg         1b                               \n"
333    : "+r"(src_y),  // %0
334      "+r"(src_u),  // %1
335      "+r"(src_v),  // %2
336      "+r"(dst_frame),  // %3
337      "+rm"(width)  // %4
338    :
339    : "memory", "cc"
340#if defined(__SSE2__)
341    , "xmm0", "xmm1", "xmm2", "xmm3"
342#endif
343  );
344}
345
346#define HAS_I42XTOUYVYROW_SSE2
347static void I42xToUYVYRow_SSE2(const uint8* src_y,
348                               const uint8* src_u,
349                               const uint8* src_v,
350                               uint8* dst_frame, int width) {
351 asm volatile (
352    "sub        %1,%2                            \n"
353    ".p2align  4                                 \n"
354  "1:                                            \n"
355    "movq      (%1),%%xmm2                       \n"
356    "movq      (%1,%2,1),%%xmm3                  \n"
357    "lea       0x8(%1),%1                        \n"
358    "punpcklbw %%xmm3,%%xmm2                     \n"
359    "movdqa    (%0),%%xmm0                       \n"
360    "movdqa    %%xmm2,%%xmm1                     \n"
361    "lea       0x10(%0),%0                       \n"
362    "punpcklbw %%xmm0,%%xmm1                     \n"
363    "punpckhbw %%xmm0,%%xmm2                     \n"
364    "movdqa    %%xmm1,(%3)                       \n"
365    "movdqa    %%xmm2,0x10(%3)                   \n"
366    "lea       0x20(%3),%3                       \n"
367    "sub       $0x10,%4                          \n"
368    "jg         1b                               \n"
369    : "+r"(src_y),  // %0
370      "+r"(src_u),  // %1
371      "+r"(src_v),  // %2
372      "+r"(dst_frame),  // %3
373      "+rm"(width)  // %4
374    :
375    : "memory", "cc"
376#if defined(__SSE2__)
377    , "xmm0", "xmm1", "xmm2", "xmm3"
378#endif
379  );
380}
381#endif
382
383static void I42xToYUY2Row_C(const uint8* src_y,
384                            const uint8* src_u,
385                            const uint8* src_v,
386                            uint8* dst_frame, int width) {
387    for (int x = 0; x < width - 1; x += 2) {
388      dst_frame[0] = src_y[0];
389      dst_frame[1] = src_u[0];
390      dst_frame[2] = src_y[1];
391      dst_frame[3] = src_v[0];
392      dst_frame += 4;
393      src_y += 2;
394      src_u += 1;
395      src_v += 1;
396    }
397    if (width & 1) {
398      dst_frame[0] = src_y[0];
399      dst_frame[1] = src_u[0];
400      dst_frame[2] = src_y[0];  // duplicate last y
401      dst_frame[3] = src_v[0];
402    }
403}
404
405static void I42xToUYVYRow_C(const uint8* src_y,
406                            const uint8* src_u,
407                            const uint8* src_v,
408                            uint8* dst_frame, int width) {
409    for (int x = 0; x < width - 1; x += 2) {
410      dst_frame[0] = src_u[0];
411      dst_frame[1] = src_y[0];
412      dst_frame[2] = src_v[0];
413      dst_frame[3] = src_y[1];
414      dst_frame += 4;
415      src_y += 2;
416      src_u += 1;
417      src_v += 1;
418    }
419    if (width & 1) {
420      dst_frame[0] = src_u[0];
421      dst_frame[1] = src_y[0];
422      dst_frame[2] = src_v[0];
423      dst_frame[3] = src_y[0];  // duplicate last y
424    }
425}
426
427// Visual C x86 or GCC little endian.
428#if defined(__x86_64__) || defined(_M_X64) || \
429  defined(__i386__) || defined(_M_IX86) || \
430  defined(__arm__) || defined(_M_ARM) || \
431  (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)
432#define LIBYUV_LITTLE_ENDIAN
433#endif
434
435#ifdef LIBYUV_LITTLE_ENDIAN
436#define WRITEWORD(p, v) *reinterpret_cast<uint32*>(p) = v
437#else
438static inline void WRITEWORD(uint8* p, uint32 v) {
439  p[0] = (uint8)(v & 255);
440  p[1] = (uint8)((v >> 8) & 255);
441  p[2] = (uint8)((v >> 16) & 255);
442  p[3] = (uint8)((v >> 24) & 255);
443}
444#endif
445
446#define EIGHTTOTEN(x) (x << 2 | x >> 6)
447static void UYVYToV210Row_C(const uint8* src_uyvy, uint8* dst_v210, int width) {
448  for (int x = 0; x < width; x += 6) {
449    WRITEWORD(dst_v210 + 0, (EIGHTTOTEN(src_uyvy[0])) |
450                            (EIGHTTOTEN(src_uyvy[1]) << 10) |
451                            (EIGHTTOTEN(src_uyvy[2]) << 20));
452    WRITEWORD(dst_v210 + 4, (EIGHTTOTEN(src_uyvy[3])) |
453                            (EIGHTTOTEN(src_uyvy[4]) << 10) |
454                            (EIGHTTOTEN(src_uyvy[5]) << 20));
455    WRITEWORD(dst_v210 + 8, (EIGHTTOTEN(src_uyvy[6])) |
456                            (EIGHTTOTEN(src_uyvy[7]) << 10) |
457                            (EIGHTTOTEN(src_uyvy[8]) << 20));
458    WRITEWORD(dst_v210 + 12, (EIGHTTOTEN(src_uyvy[9])) |
459                             (EIGHTTOTEN(src_uyvy[10]) << 10) |
460                             (EIGHTTOTEN(src_uyvy[11]) << 20));
461    src_uyvy += 12;
462    dst_v210 += 16;
463  }
464}
465
466// TODO(fbarchard): Deprecate, move or expand 422 support?
467LIBYUV_API
468int I422ToYUY2(const uint8* src_y, int src_stride_y,
469               const uint8* src_u, int src_stride_u,
470               const uint8* src_v, int src_stride_v,
471               uint8* dst_frame, int dst_stride_frame,
472               int width, int height) {
473  if (!src_y || !src_u || !src_v || !dst_frame ||
474      width <= 0 || height == 0) {
475    return -1;
476  }
477  // Negative height means invert the image.
478  if (height < 0) {
479    height = -height;
480    dst_frame = dst_frame + (height - 1) * dst_stride_frame;
481    dst_stride_frame = -dst_stride_frame;
482  }
483  void (*I42xToYUY2Row)(const uint8* src_y, const uint8* src_u,
484                        const uint8* src_v, uint8* dst_frame, int width) =
485      I42xToYUY2Row_C;
486#if defined(HAS_I42XTOYUY2ROW_SSE2)
487  if (TestCpuFlag(kCpuHasSSE2) &&
488      IS_ALIGNED(width, 16) &&
489      IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
490      IS_ALIGNED(dst_frame, 16) && IS_ALIGNED(dst_stride_frame, 16)) {
491    I42xToYUY2Row = I42xToYUY2Row_SSE2;
492  }
493#endif
494
495  for (int y = 0; y < height; ++y) {
496    I42xToYUY2Row(src_y, src_u, src_y, dst_frame, width);
497    src_y += src_stride_y;
498    src_u += src_stride_u;
499    src_v += src_stride_v;
500    dst_frame += dst_stride_frame;
501  }
502  return 0;
503}
504
505LIBYUV_API
506int I420ToYUY2(const uint8* src_y, int src_stride_y,
507               const uint8* src_u, int src_stride_u,
508               const uint8* src_v, int src_stride_v,
509               uint8* dst_frame, int dst_stride_frame,
510               int width, int height) {
511  if (!src_y || !src_u || !src_v || !dst_frame ||
512      width <= 0 || height == 0) {
513    return -1;
514  }
515  // Negative height means invert the image.
516  if (height < 0) {
517    height = -height;
518    dst_frame = dst_frame + (height - 1) * dst_stride_frame;
519    dst_stride_frame = -dst_stride_frame;
520  }
521  void (*I42xToYUY2Row)(const uint8* src_y, const uint8* src_u,
522                        const uint8* src_v, uint8* dst_frame, int width) =
523      I42xToYUY2Row_C;
524#if defined(HAS_I42XTOYUY2ROW_SSE2)
525  if (TestCpuFlag(kCpuHasSSE2) &&
526      IS_ALIGNED(width, 16) &&
527      IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
528      IS_ALIGNED(dst_frame, 16) && IS_ALIGNED(dst_stride_frame, 16)) {
529    I42xToYUY2Row = I42xToYUY2Row_SSE2;
530  }
531#endif
532
533  for (int y = 0; y < height - 1; y += 2) {
534    I42xToYUY2Row(src_y, src_u, src_v, dst_frame, width);
535    I42xToYUY2Row(src_y + src_stride_y, src_u, src_v,
536                  dst_frame + dst_stride_frame, width);
537    src_y += src_stride_y * 2;
538    src_u += src_stride_u;
539    src_v += src_stride_v;
540    dst_frame += dst_stride_frame * 2;
541  }
542  if (height & 1) {
543    I42xToYUY2Row(src_y, src_u, src_v, dst_frame, width);
544  }
545  return 0;
546}
547
548// TODO(fbarchard): Deprecate, move or expand 422 support?
549LIBYUV_API
550int I422ToUYVY(const uint8* src_y, int src_stride_y,
551               const uint8* src_u, int src_stride_u,
552               const uint8* src_v, int src_stride_v,
553               uint8* dst_frame, int dst_stride_frame,
554               int width, int height) {
555  if (!src_y || !src_u || !src_v || !dst_frame ||
556      width <= 0 || height == 0) {
557    return -1;
558  }
559  // Negative height means invert the image.
560  if (height < 0) {
561    height = -height;
562    dst_frame = dst_frame + (height - 1) * dst_stride_frame;
563    dst_stride_frame = -dst_stride_frame;
564  }
565  void (*I42xToUYVYRow)(const uint8* src_y, const uint8* src_u,
566                        const uint8* src_v, uint8* dst_frame, int width) =
567      I42xToUYVYRow_C;
568#if defined(HAS_I42XTOUYVYROW_SSE2)
569  if (TestCpuFlag(kCpuHasSSE2) &&
570      IS_ALIGNED(width, 16) &&
571      IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
572      IS_ALIGNED(dst_frame, 16) && IS_ALIGNED(dst_stride_frame, 16)) {
573    I42xToUYVYRow = I42xToUYVYRow_SSE2;
574  }
575#endif
576
577  for (int y = 0; y < height; ++y) {
578    I42xToUYVYRow(src_y, src_u, src_y, dst_frame, width);
579    src_y += src_stride_y;
580    src_u += src_stride_u;
581    src_v += src_stride_v;
582    dst_frame += dst_stride_frame;
583  }
584  return 0;
585}
586
587LIBYUV_API
588int I420ToUYVY(const uint8* src_y, int src_stride_y,
589               const uint8* src_u, int src_stride_u,
590               const uint8* src_v, int src_stride_v,
591               uint8* dst_frame, int dst_stride_frame,
592               int width, int height) {
593  if (!src_y || !src_u || !src_v || !dst_frame ||
594      width <= 0 || height == 0) {
595    return -1;
596  }
597  // Negative height means invert the image.
598  if (height < 0) {
599    height = -height;
600    dst_frame = dst_frame + (height - 1) * dst_stride_frame;
601    dst_stride_frame = -dst_stride_frame;
602  }
603  void (*I42xToUYVYRow)(const uint8* src_y, const uint8* src_u,
604                        const uint8* src_v, uint8* dst_frame, int width) =
605      I42xToUYVYRow_C;
606#if defined(HAS_I42XTOUYVYROW_SSE2)
607  if (TestCpuFlag(kCpuHasSSE2) &&
608      IS_ALIGNED(width, 16) &&
609      IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
610      IS_ALIGNED(dst_frame, 16) && IS_ALIGNED(dst_stride_frame, 16)) {
611    I42xToUYVYRow = I42xToUYVYRow_SSE2;
612  }
613#endif
614
615  for (int y = 0; y < height - 1; y += 2) {
616    I42xToUYVYRow(src_y, src_u, src_v, dst_frame, width);
617    I42xToUYVYRow(src_y + src_stride_y, src_u, src_v,
618                  dst_frame + dst_stride_frame, width);
619    src_y += src_stride_y * 2;
620    src_u += src_stride_u;
621    src_v += src_stride_v;
622    dst_frame += dst_stride_frame * 2;
623  }
624  if (height & 1) {
625    I42xToUYVYRow(src_y, src_u, src_v, dst_frame, width);
626  }
627  return 0;
628}
629
630LIBYUV_API
631int I420ToV210(const uint8* src_y, int src_stride_y,
632               const uint8* src_u, int src_stride_u,
633               const uint8* src_v, int src_stride_v,
634               uint8* dst_frame, int dst_stride_frame,
635               int width, int height) {
636  if (width * 16 / 6 > kMaxStride) {  // Row buffer of V210 is required.
637    return -1;
638  } else if (!src_y || !src_u || !src_v || !dst_frame ||
639      width <= 0 || height == 0) {
640    return -1;
641  }
642  // Negative height means invert the image.
643  if (height < 0) {
644    height = -height;
645    dst_frame = dst_frame + (height - 1) * dst_stride_frame;
646    dst_stride_frame = -dst_stride_frame;
647  }
648
649  SIMD_ALIGNED(uint8 row[kMaxStride]);
650  void (*UYVYToV210Row)(const uint8* src_uyvy, uint8* dst_v210, int pix);
651  UYVYToV210Row = UYVYToV210Row_C;
652
653  void (*I42xToUYVYRow)(const uint8* src_y, const uint8* src_u,
654                        const uint8* src_v, uint8* dst_frame, int width) =
655      I42xToUYVYRow_C;
656#if defined(HAS_I42XTOUYVYROW_SSE2)
657  if (TestCpuFlag(kCpuHasSSE2) &&
658      IS_ALIGNED(width, 16) &&
659      IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16)) {
660    I42xToUYVYRow = I42xToUYVYRow_SSE2;
661  }
662#endif
663
664  for (int y = 0; y < height - 1; y += 2) {
665    I42xToUYVYRow(src_y, src_u, src_v, row, width);
666    UYVYToV210Row(row, dst_frame, width);
667    I42xToUYVYRow(src_y + src_stride_y, src_u, src_v, row, width);
668    UYVYToV210Row(row, dst_frame + dst_stride_frame, width);
669
670    src_y += src_stride_y * 2;
671    src_u += src_stride_u;
672    src_v += src_stride_v;
673    dst_frame += dst_stride_frame * 2;
674  }
675  if (height & 1) {
676    I42xToUYVYRow(src_y, src_u, src_v, row, width);
677    UYVYToV210Row(row, dst_frame, width);
678  }
679  return 0;
680}
681
682// Convert I420 to ARGB.
683LIBYUV_API
684int I420ToARGB(const uint8* src_y, int src_stride_y,
685               const uint8* src_u, int src_stride_u,
686               const uint8* src_v, int src_stride_v,
687               uint8* dst_argb, int dst_stride_argb,
688               int width, int height) {
689  if (!src_y || !src_u || !src_v || !dst_argb ||
690      width <= 0 || height == 0) {
691    return -1;
692  }
693  // Negative height means invert the image.
694  if (height < 0) {
695    height = -height;
696    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
697    dst_stride_argb = -dst_stride_argb;
698  }
699  void (*I422ToARGBRow)(const uint8* y_buf,
700                        const uint8* u_buf,
701                        const uint8* v_buf,
702                        uint8* rgb_buf,
703                        int width) = I422ToARGBRow_C;
704#if defined(HAS_I422TOARGBROW_NEON)
705  if (TestCpuFlag(kCpuHasNEON)) {
706    I422ToARGBRow = I422ToARGBRow_Any_NEON;
707    if (IS_ALIGNED(width, 16)) {
708      I422ToARGBRow = I422ToARGBRow_NEON;
709    }
710  }
711#elif defined(HAS_I422TOARGBROW_SSSE3)
712  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
713    I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
714    if (IS_ALIGNED(width, 8)) {
715      I422ToARGBRow = I422ToARGBRow_Unaligned_SSSE3;
716      if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
717        I422ToARGBRow = I422ToARGBRow_SSSE3;
718      }
719    }
720  }
721#endif
722
723  for (int y = 0; y < height; ++y) {
724    I422ToARGBRow(src_y, src_u, src_v, dst_argb, width);
725    dst_argb += dst_stride_argb;
726    src_y += src_stride_y;
727    if (y & 1) {
728      src_u += src_stride_u;
729      src_v += src_stride_v;
730    }
731  }
732  return 0;
733}
734
735// Convert I420 to BGRA.
736LIBYUV_API
737int I420ToBGRA(const uint8* src_y, int src_stride_y,
738               const uint8* src_u, int src_stride_u,
739               const uint8* src_v, int src_stride_v,
740               uint8* dst_bgra, int dst_stride_bgra,
741               int width, int height) {
742  if (!src_y || !src_u || !src_v ||
743      !dst_bgra ||
744      width <= 0 || height == 0) {
745    return -1;
746  }
747  // Negative height means invert the image.
748  if (height < 0) {
749    height = -height;
750    dst_bgra = dst_bgra + (height - 1) * dst_stride_bgra;
751    dst_stride_bgra = -dst_stride_bgra;
752  }
753  void (*I422ToBGRARow)(const uint8* y_buf,
754                        const uint8* u_buf,
755                        const uint8* v_buf,
756                        uint8* rgb_buf,
757                        int width) = I422ToBGRARow_C;
758#if defined(HAS_I422TOBGRAROW_NEON)
759  if (TestCpuFlag(kCpuHasNEON)) {
760    I422ToBGRARow = I422ToBGRARow_Any_NEON;
761    if (IS_ALIGNED(width, 16)) {
762      I422ToBGRARow = I422ToBGRARow_NEON;
763    }
764  }
765#elif defined(HAS_I422TOBGRAROW_SSSE3)
766  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
767    I422ToBGRARow = I422ToBGRARow_Any_SSSE3;
768    if (IS_ALIGNED(width, 8)) {
769      I422ToBGRARow = I422ToBGRARow_Unaligned_SSSE3;
770      if (IS_ALIGNED(dst_bgra, 16) && IS_ALIGNED(dst_stride_bgra, 16)) {
771        I422ToBGRARow = I422ToBGRARow_SSSE3;
772      }
773    }
774  }
775#endif
776
777  for (int y = 0; y < height; ++y) {
778    I422ToBGRARow(src_y, src_u, src_v, dst_bgra, width);
779    dst_bgra += dst_stride_bgra;
780    src_y += src_stride_y;
781    if (y & 1) {
782      src_u += src_stride_u;
783      src_v += src_stride_v;
784    }
785  }
786  return 0;
787}
788
789// Convert I420 to ABGR.
790LIBYUV_API
791int I420ToABGR(const uint8* src_y, int src_stride_y,
792               const uint8* src_u, int src_stride_u,
793               const uint8* src_v, int src_stride_v,
794               uint8* dst_abgr, int dst_stride_abgr,
795               int width, int height) {
796  if (!src_y || !src_u || !src_v ||
797      !dst_abgr ||
798      width <= 0 || height == 0) {
799    return -1;
800  }
801  // Negative height means invert the image.
802  if (height < 0) {
803    height = -height;
804    dst_abgr = dst_abgr + (height - 1) * dst_stride_abgr;
805    dst_stride_abgr = -dst_stride_abgr;
806  }
807  void (*I422ToABGRRow)(const uint8* y_buf,
808                        const uint8* u_buf,
809                        const uint8* v_buf,
810                        uint8* rgb_buf,
811                        int width) = I422ToABGRRow_C;
812#if defined(HAS_I422TOABGRROW_NEON)
813  if (TestCpuFlag(kCpuHasNEON)) {
814    I422ToABGRRow = I422ToABGRRow_Any_NEON;
815    if (IS_ALIGNED(width, 16)) {
816      I422ToABGRRow = I422ToABGRRow_NEON;
817    }
818  }
819#elif defined(HAS_I422TOABGRROW_SSSE3)
820  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
821    I422ToABGRRow = I422ToABGRRow_Any_SSSE3;
822    if (IS_ALIGNED(width, 8)) {
823      I422ToABGRRow = I422ToABGRRow_Unaligned_SSSE3;
824      if (IS_ALIGNED(dst_abgr, 16) && IS_ALIGNED(dst_stride_abgr, 16)) {
825        I422ToABGRRow = I422ToABGRRow_SSSE3;
826      }
827    }
828  }
829#endif
830
831  for (int y = 0; y < height; ++y) {
832    I422ToABGRRow(src_y, src_u, src_v, dst_abgr, width);
833    dst_abgr += dst_stride_abgr;
834    src_y += src_stride_y;
835    if (y & 1) {
836      src_u += src_stride_u;
837      src_v += src_stride_v;
838    }
839  }
840  return 0;
841}
842
843// Convert I420 to RGBA.
844LIBYUV_API
845int I420ToRGBA(const uint8* src_y, int src_stride_y,
846               const uint8* src_u, int src_stride_u,
847               const uint8* src_v, int src_stride_v,
848               uint8* dst_rgba, int dst_stride_rgba,
849               int width, int height) {
850  if (!src_y || !src_u || !src_v ||
851      !dst_rgba ||
852      width <= 0 || height == 0) {
853    return -1;
854  }
855  // Negative height means invert the image.
856  if (height < 0) {
857    height = -height;
858    dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
859    dst_stride_rgba = -dst_stride_rgba;
860  }
861  void (*I422ToRGBARow)(const uint8* y_buf,
862                        const uint8* u_buf,
863                        const uint8* v_buf,
864                        uint8* rgb_buf,
865                        int width) = I422ToRGBARow_C;
866#if defined(HAS_I422TORGBAROW_NEON)
867  if (TestCpuFlag(kCpuHasNEON)) {
868    I422ToRGBARow = I422ToRGBARow_Any_NEON;
869    if (IS_ALIGNED(width, 16)) {
870      I422ToRGBARow = I422ToRGBARow_NEON;
871    }
872  }
873#elif defined(HAS_I422TORGBAROW_SSSE3)
874  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
875    I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
876    if (IS_ALIGNED(width, 8)) {
877      I422ToRGBARow = I422ToRGBARow_Unaligned_SSSE3;
878      if (IS_ALIGNED(dst_rgba, 16) && IS_ALIGNED(dst_stride_rgba, 16)) {
879        I422ToRGBARow = I422ToRGBARow_SSSE3;
880      }
881    }
882  }
883#endif
884
885  for (int y = 0; y < height; ++y) {
886    I422ToRGBARow(src_y, src_u, src_v, dst_rgba, width);
887    dst_rgba += dst_stride_rgba;
888    src_y += src_stride_y;
889    if (y & 1) {
890      src_u += src_stride_u;
891      src_v += src_stride_v;
892    }
893  }
894  return 0;
895}
896
897// Convert I420 to RGB24.
898LIBYUV_API
899int I420ToRGB24(const uint8* src_y, int src_stride_y,
900                const uint8* src_u, int src_stride_u,
901                const uint8* src_v, int src_stride_v,
902                uint8* dst_rgb24, int dst_stride_rgb24,
903                int width, int height) {
904  if (!src_y || !src_u || !src_v ||
905      !dst_rgb24 ||
906      width <= 0 || height == 0) {
907    return -1;
908  }
909  // Negative height means invert the image.
910  if (height < 0) {
911    height = -height;
912    dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
913    dst_stride_rgb24 = -dst_stride_rgb24;
914  }
915  void (*I422ToRGB24Row)(const uint8* y_buf,
916                         const uint8* u_buf,
917                         const uint8* v_buf,
918                         uint8* rgb_buf,
919                         int width) = I422ToRGB24Row_C;
920#if defined(HAS_I422TORGB24ROW_NEON)
921  if (TestCpuFlag(kCpuHasNEON)) {
922    I422ToRGB24Row = I422ToRGB24Row_Any_NEON;
923    if (IS_ALIGNED(width, 16)) {
924      I422ToRGB24Row = I422ToRGB24Row_NEON;
925    }
926  }
927#elif defined(HAS_I422TORGB24ROW_SSSE3)
928  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
929    I422ToRGB24Row = I422ToRGB24Row_Any_SSSE3;
930    if (IS_ALIGNED(width, 8)) {
931      I422ToRGB24Row = I422ToRGB24Row_Unaligned_SSSE3;
932      if (IS_ALIGNED(dst_rgb24, 16) && IS_ALIGNED(dst_stride_rgb24, 16)) {
933        I422ToRGB24Row = I422ToRGB24Row_SSSE3;
934      }
935    }
936  }
937#endif
938
939  for (int y = 0; y < height; ++y) {
940    I422ToRGB24Row(src_y, src_u, src_v, dst_rgb24, width);
941    dst_rgb24 += dst_stride_rgb24;
942    src_y += src_stride_y;
943    if (y & 1) {
944      src_u += src_stride_u;
945      src_v += src_stride_v;
946    }
947  }
948  return 0;
949}
950
951// Convert I420 to RAW.
952LIBYUV_API
953int I420ToRAW(const uint8* src_y, int src_stride_y,
954              const uint8* src_u, int src_stride_u,
955              const uint8* src_v, int src_stride_v,
956              uint8* dst_raw, int dst_stride_raw,
957              int width, int height) {
958  if (!src_y || !src_u || !src_v ||
959      !dst_raw ||
960      width <= 0 || height == 0) {
961    return -1;
962  }
963  // Negative height means invert the image.
964  if (height < 0) {
965    height = -height;
966    dst_raw = dst_raw + (height - 1) * dst_stride_raw;
967    dst_stride_raw = -dst_stride_raw;
968  }
969  void (*I422ToRAWRow)(const uint8* y_buf,
970                       const uint8* u_buf,
971                       const uint8* v_buf,
972                       uint8* rgb_buf,
973                       int width) = I422ToRAWRow_C;
974#if defined(HAS_I422TORAWROW_NEON)
975  if (TestCpuFlag(kCpuHasNEON)) {
976    I422ToRAWRow = I422ToRAWRow_Any_NEON;
977    if (IS_ALIGNED(width, 16)) {
978      I422ToRAWRow = I422ToRAWRow_NEON;
979    }
980  }
981#elif defined(HAS_I422TORAWROW_SSSE3)
982  if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
983    I422ToRAWRow = I422ToRAWRow_Any_SSSE3;
984    if (IS_ALIGNED(width, 8)) {
985      I422ToRAWRow = I422ToRAWRow_Unaligned_SSSE3;
986      if (IS_ALIGNED(dst_raw, 16) && IS_ALIGNED(dst_stride_raw, 16)) {
987        I422ToRAWRow = I422ToRAWRow_SSSE3;
988      }
989    }
990  }
991#endif
992
993  for (int y = 0; y < height; ++y) {
994    I422ToRAWRow(src_y, src_u, src_v, dst_raw, width);
995    dst_raw += dst_stride_raw;
996    src_y += src_stride_y;
997    if (y & 1) {
998      src_u += src_stride_u;
999      src_v += src_stride_v;
1000    }
1001  }
1002  return 0;
1003}
1004
1005// Convert I420 to RGB565.
1006LIBYUV_API
1007int I420ToRGB565(const uint8* src_y, int src_stride_y,
1008                 const uint8* src_u, int src_stride_u,
1009                 const uint8* src_v, int src_stride_v,
1010                 uint8* dst_rgb, int dst_stride_rgb,
1011                 int width, int height) {
1012  if (!src_y || !src_u || !src_v ||
1013      !dst_rgb ||
1014      width <= 0 || height == 0) {
1015    return -1;
1016  }
1017  // Negative height means invert the image.
1018  if (height < 0) {
1019    height = -height;
1020    dst_rgb = dst_rgb + (height - 1) * dst_stride_rgb;
1021    dst_stride_rgb = -dst_stride_rgb;
1022  }
1023  void (*I422ToARGBRow)(const uint8* y_buf,
1024                        const uint8* u_buf,
1025                        const uint8* v_buf,
1026                        uint8* rgb_buf,
1027                        int width) = I422ToARGBRow_C;
1028#if defined(HAS_I422TOARGBROW_NEON)
1029  if (TestCpuFlag(kCpuHasNEON)) {
1030    I422ToARGBRow = I422ToARGBRow_NEON;
1031  }
1032#elif defined(HAS_I422TOARGBROW_SSSE3)
1033  if (TestCpuFlag(kCpuHasSSSE3)) {
1034    I422ToARGBRow = I422ToARGBRow_SSSE3;
1035  }
1036#endif
1037
1038  SIMD_ALIGNED(uint8 row[kMaxStride]);
1039  void (*ARGBToRGB565Row)(const uint8* src_rgb, uint8* dst_rgb, int pix) =
1040      ARGBToRGB565Row_C;
1041#if defined(HAS_ARGBTORGB565ROW_SSE2)
1042  if (TestCpuFlag(kCpuHasSSE2)) {
1043    if (width * 2 <= kMaxStride) {
1044      ARGBToRGB565Row = ARGBToRGB565Row_Any_SSE2;
1045    }
1046    if (IS_ALIGNED(width, 4)) {
1047      ARGBToRGB565Row = ARGBToRGB565Row_SSE2;
1048    }
1049  }
1050#endif
1051
1052  for (int y = 0; y < height; ++y) {
1053    I422ToARGBRow(src_y, src_u, src_v, row, width);
1054    ARGBToRGB565Row(row, dst_rgb, width);
1055    dst_rgb += dst_stride_rgb;
1056    src_y += src_stride_y;
1057    if (y & 1) {
1058      src_u += src_stride_u;
1059      src_v += src_stride_v;
1060    }
1061  }
1062  return 0;
1063}
1064
1065// Convert I420 to ARGB1555.
1066LIBYUV_API
1067int I420ToARGB1555(const uint8* src_y, int src_stride_y,
1068                   const uint8* src_u, int src_stride_u,
1069                   const uint8* src_v, int src_stride_v,
1070                   uint8* dst_argb, int dst_stride_argb,
1071                   int width, int height) {
1072  if (!src_y || !src_u || !src_v ||
1073      !dst_argb ||
1074      width <= 0 || height == 0) {
1075    return -1;
1076  }
1077  // Negative height means invert the image.
1078  if (height < 0) {
1079    height = -height;
1080    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1081    dst_stride_argb = -dst_stride_argb;
1082  }
1083  void (*I422ToARGBRow)(const uint8* y_buf,
1084                        const uint8* u_buf,
1085                        const uint8* v_buf,
1086                        uint8* rgb_buf,
1087                        int width) = I422ToARGBRow_C;
1088#if defined(HAS_I422TOARGBROW_NEON)
1089  if (TestCpuFlag(kCpuHasNEON)) {
1090    I422ToARGBRow = I422ToARGBRow_NEON;
1091  }
1092#elif defined(HAS_I422TOARGBROW_SSSE3)
1093  if (TestCpuFlag(kCpuHasSSSE3)) {
1094    I422ToARGBRow = I422ToARGBRow_SSSE3;
1095  }
1096#endif
1097
1098  SIMD_ALIGNED(uint8 row[kMaxStride]);
1099  void (*ARGBToARGB1555Row)(const uint8* src_argb, uint8* dst_rgb, int pix) =
1100      ARGBToARGB1555Row_C;
1101#if defined(HAS_ARGBTOARGB1555ROW_SSE2)
1102  if (TestCpuFlag(kCpuHasSSE2)) {
1103    if (width * 2 <= kMaxStride) {
1104      ARGBToARGB1555Row = ARGBToARGB1555Row_Any_SSE2;
1105    }
1106    if (IS_ALIGNED(width, 4)) {
1107      ARGBToARGB1555Row = ARGBToARGB1555Row_SSE2;
1108    }
1109  }
1110#endif
1111
1112  for (int y = 0; y < height; ++y) {
1113    I422ToARGBRow(src_y, src_u, src_v, row, width);
1114    ARGBToARGB1555Row(row, dst_argb, width);
1115    dst_argb += dst_stride_argb;
1116    src_y += src_stride_y;
1117    if (y & 1) {
1118      src_u += src_stride_u;
1119      src_v += src_stride_v;
1120    }
1121  }
1122  return 0;
1123}
1124
1125// Convert I420 to ARGB4444.
1126LIBYUV_API
1127int I420ToARGB4444(const uint8* src_y, int src_stride_y,
1128                   const uint8* src_u, int src_stride_u,
1129                   const uint8* src_v, int src_stride_v,
1130                   uint8* dst_argb, int dst_stride_argb,
1131                   int width, int height) {
1132  if (!src_y || !src_u || !src_v ||
1133      !dst_argb ||
1134      width <= 0 || height == 0) {
1135    return -1;
1136  }
1137  // Negative height means invert the image.
1138  if (height < 0) {
1139    height = -height;
1140    dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1141    dst_stride_argb = -dst_stride_argb;
1142  }
1143  void (*I422ToARGBRow)(const uint8* y_buf,
1144                        const uint8* u_buf,
1145                        const uint8* v_buf,
1146                        uint8* rgb_buf,
1147                        int width) = I422ToARGBRow_C;
1148#if defined(HAS_I422TOARGBROW_NEON)
1149  if (TestCpuFlag(kCpuHasNEON)) {
1150    I422ToARGBRow = I422ToARGBRow_NEON;
1151  }
1152#elif defined(HAS_I422TOARGBROW_SSSE3)
1153  if (TestCpuFlag(kCpuHasSSSE3)) {
1154    I422ToARGBRow = I422ToARGBRow_SSSE3;
1155  }
1156#endif
1157
1158  SIMD_ALIGNED(uint8 row[kMaxStride]);
1159  void (*ARGBToARGB4444Row)(const uint8* src_argb, uint8* dst_rgb, int pix) =
1160     ARGBToARGB4444Row_C;
1161#if defined(HAS_ARGBTOARGB4444ROW_SSE2)
1162  if (TestCpuFlag(kCpuHasSSE2)) {
1163    if (width * 2 <= kMaxStride) {
1164      ARGBToARGB4444Row = ARGBToARGB4444Row_Any_SSE2;
1165    }
1166    if (IS_ALIGNED(width, 4)) {
1167      ARGBToARGB4444Row = ARGBToARGB4444Row_SSE2;
1168    }
1169  }
1170#endif
1171
1172  for (int y = 0; y < height; ++y) {
1173    I422ToARGBRow(src_y, src_u, src_v, row, width);
1174    ARGBToARGB4444Row(row, dst_argb, width);
1175    dst_argb += dst_stride_argb;
1176    src_y += src_stride_y;
1177    if (y & 1) {
1178      src_u += src_stride_u;
1179      src_v += src_stride_v;
1180    }
1181  }
1182  return 0;
1183}
1184
1185// Convert I420 to specified format
1186LIBYUV_API
1187int ConvertFromI420(const uint8* y, int y_stride,
1188                    const uint8* u, int u_stride,
1189                    const uint8* v, int v_stride,
1190                    uint8* dst_sample, int dst_sample_stride,
1191                    int width, int height,
1192                    uint32 format) {
1193  if (!y || !u|| !v || !dst_sample ||
1194      width <= 0 || height == 0) {
1195    return -1;
1196  }
1197  int r = 0;
1198  switch (format) {
1199    // Single plane formats
1200    case FOURCC_YUY2:
1201      r = I420ToYUY2(y, y_stride,
1202                     u, u_stride,
1203                     v, v_stride,
1204                     dst_sample,
1205                     dst_sample_stride ? dst_sample_stride : width * 2,
1206                     width, height);
1207      break;
1208    case FOURCC_UYVY:
1209      r = I420ToUYVY(y, y_stride,
1210                     u, u_stride,
1211                     v, v_stride,
1212                     dst_sample,
1213                     dst_sample_stride ? dst_sample_stride : width * 2,
1214                     width, height);
1215      break;
1216    case FOURCC_V210:
1217      r = I420ToV210(y, y_stride,
1218                     u, u_stride,
1219                     v, v_stride,
1220                     dst_sample,
1221                     dst_sample_stride ? dst_sample_stride :
1222                         (width + 47) / 48 * 128,
1223                     width, height);
1224      break;
1225    case FOURCC_RGBP:
1226      r = I420ToRGB565(y, y_stride,
1227                       u, u_stride,
1228                       v, v_stride,
1229                       dst_sample,
1230                       dst_sample_stride ? dst_sample_stride : width * 2,
1231                       width, height);
1232      break;
1233    case FOURCC_RGBO:
1234      r = I420ToARGB1555(y, y_stride,
1235                         u, u_stride,
1236                         v, v_stride,
1237                         dst_sample,
1238                         dst_sample_stride ? dst_sample_stride : width * 2,
1239                         width, height);
1240      break;
1241    case FOURCC_R444:
1242      r = I420ToARGB4444(y, y_stride,
1243                         u, u_stride,
1244                         v, v_stride,
1245                         dst_sample,
1246                         dst_sample_stride ? dst_sample_stride : width * 2,
1247                         width, height);
1248      break;
1249    case FOURCC_24BG:
1250      r = I420ToRGB24(y, y_stride,
1251                      u, u_stride,
1252                      v, v_stride,
1253                      dst_sample,
1254                      dst_sample_stride ? dst_sample_stride : width * 3,
1255                      width, height);
1256      break;
1257    case FOURCC_RAW:
1258      r = I420ToRAW(y, y_stride,
1259                    u, u_stride,
1260                    v, v_stride,
1261                    dst_sample,
1262                    dst_sample_stride ? dst_sample_stride : width * 3,
1263                    width, height);
1264      break;
1265    case FOURCC_ARGB:
1266      r = I420ToARGB(y, y_stride,
1267                     u, u_stride,
1268                     v, v_stride,
1269                     dst_sample,
1270                     dst_sample_stride ? dst_sample_stride : width * 4,
1271                     width, height);
1272      break;
1273    case FOURCC_BGRA:
1274      r = I420ToBGRA(y, y_stride,
1275                     u, u_stride,
1276                     v, v_stride,
1277                     dst_sample,
1278                     dst_sample_stride ? dst_sample_stride : width * 4,
1279                     width, height);
1280      break;
1281    case FOURCC_ABGR:
1282      r = I420ToABGR(y, y_stride,
1283                     u, u_stride,
1284                     v, v_stride,
1285                     dst_sample,
1286                     dst_sample_stride ? dst_sample_stride : width * 4,
1287                     width, height);
1288      break;
1289    case FOURCC_RGBA:
1290      r = I420ToRGBA(y, y_stride,
1291                     u, u_stride,
1292                     v, v_stride,
1293                     dst_sample,
1294                     dst_sample_stride ? dst_sample_stride : width * 4,
1295                     width, height);
1296      break;
1297    case FOURCC_BGGR:
1298      r = I420ToBayerBGGR(y, y_stride,
1299                          u, u_stride,
1300                          v, v_stride,
1301                          dst_sample,
1302                          dst_sample_stride ? dst_sample_stride : width,
1303                          width, height);
1304      break;
1305    case FOURCC_GBRG:
1306      r = I420ToBayerGBRG(y, y_stride,
1307                          u, u_stride,
1308                          v, v_stride,
1309                          dst_sample,
1310                          dst_sample_stride ? dst_sample_stride : width,
1311                          width, height);
1312      break;
1313    case FOURCC_GRBG:
1314      r = I420ToBayerGRBG(y, y_stride,
1315                          u, u_stride,
1316                          v, v_stride,
1317                          dst_sample,
1318                          dst_sample_stride ? dst_sample_stride : width,
1319                          width, height);
1320      break;
1321    case FOURCC_RGGB:
1322      r = I420ToBayerRGGB(y, y_stride,
1323                          u, u_stride,
1324                          v, v_stride,
1325                          dst_sample,
1326                          dst_sample_stride ? dst_sample_stride : width,
1327                          width, height);
1328      break;
1329    case FOURCC_I400:
1330      r = I400Copy(y, y_stride,
1331                   dst_sample,
1332                   dst_sample_stride ? dst_sample_stride : width,
1333                   width, height);
1334      break;
1335    // Triplanar formats
1336    // TODO(fbarchard): halfstride instead of halfwidth
1337    case FOURCC_I420:
1338    case FOURCC_YU12:
1339    case FOURCC_YV12: {
1340      int halfwidth = (width + 1) / 2;
1341      int halfheight = (height + 1) / 2;
1342      uint8* dst_u;
1343      uint8* dst_v;
1344      if (format == FOURCC_YV12) {
1345        dst_v = dst_sample + width * height;
1346        dst_u = dst_v + halfwidth * halfheight;
1347      } else {
1348        dst_u = dst_sample + width * height;
1349        dst_v = dst_u + halfwidth * halfheight;
1350      }
1351      r = I420Copy(y, y_stride,
1352                   u, u_stride,
1353                   v, v_stride,
1354                   dst_sample, width,
1355                   dst_u, halfwidth,
1356                   dst_v, halfwidth,
1357                   width, height);
1358      break;
1359    }
1360    case FOURCC_I422:
1361    case FOURCC_YV16: {
1362      int halfwidth = (width + 1) / 2;
1363      uint8* dst_u;
1364      uint8* dst_v;
1365      if (format == FOURCC_YV16) {
1366        dst_v = dst_sample + width * height;
1367        dst_u = dst_v + halfwidth * height;
1368      } else {
1369        dst_u = dst_sample + width * height;
1370        dst_v = dst_u + halfwidth * height;
1371      }
1372      r = I420ToI422(y, y_stride,
1373                     u, u_stride,
1374                     v, v_stride,
1375                     dst_sample, width,
1376                     dst_u, halfwidth,
1377                     dst_v, halfwidth,
1378                     width, height);
1379      break;
1380    }
1381    case FOURCC_I444:
1382    case FOURCC_YV24: {
1383      uint8* dst_u;
1384      uint8* dst_v;
1385      if (format == FOURCC_YV24) {
1386        dst_v = dst_sample + width * height;
1387        dst_u = dst_v + width * height;
1388      } else {
1389        dst_u = dst_sample + width * height;
1390        dst_v = dst_u + width * height;
1391      }
1392      r = I420ToI444(y, y_stride,
1393                     u, u_stride,
1394                     v, v_stride,
1395                     dst_sample, width,
1396                     dst_u, width,
1397                     dst_v, width,
1398                     width, height);
1399      break;
1400    }
1401    case FOURCC_I411: {
1402      int quarterwidth = (width + 3) / 4;
1403      uint8* dst_u = dst_sample + width * height;
1404      uint8* dst_v = dst_u + quarterwidth * height;
1405      r = I420ToI411(y, y_stride,
1406                     u, u_stride,
1407                     v, v_stride,
1408                     dst_sample, width,
1409                     dst_u, quarterwidth,
1410                     dst_v, quarterwidth,
1411                     width, height);
1412      break;
1413    }
1414
1415    // Formats not supported - MJPG, biplanar, some rgb formats.
1416    default:
1417      return -1;  // unknown fourcc - return failure code.
1418  }
1419  return r;
1420}
1421
1422#ifdef __cplusplus
1423}  // extern "C"
1424}  // namespace libyuv
1425#endif
1426