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
23 namespace libyuv {
24 extern "C" {
25 #endif
26 
27 LIBYUV_API
I420ToI422(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)28 int 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
102 void 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 
107 LIBYUV_API
I420ToI444(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)108 int 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
157 LIBYUV_API
I420ToI411(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)158 int 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
207 LIBYUV_API
I400Copy(const uint8 * src_y,int src_stride_y,uint8 * dst_y,int dst_stride_y,int width,int height)208 int 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))
I42xToYUY2Row_SSE2(const uint8 * src_y,const uint8 * src_u,const uint8 * src_v,uint8 * dst_frame,int width)234 static 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))
I42xToUYVYRow_SSE2(const uint8 * src_y,const uint8 * src_u,const uint8 * src_v,uint8 * dst_frame,int width)273 static 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
I42xToYUY2Row_SSE2(const uint8 * src_y,const uint8 * src_u,const uint8 * src_v,uint8 * dst_frame,int width)311 static 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
I42xToUYVYRow_SSE2(const uint8 * src_y,const uint8 * src_u,const uint8 * src_v,uint8 * dst_frame,int width)347 static 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 
I42xToYUY2Row_C(const uint8 * src_y,const uint8 * src_u,const uint8 * src_v,uint8 * dst_frame,int width)383 static 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 
I42xToUYVYRow_C(const uint8 * src_y,const uint8 * src_u,const uint8 * src_v,uint8 * dst_frame,int width)405 static 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
WRITEWORD(uint8 * p,uint32 v)438 static 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)
UYVYToV210Row_C(const uint8 * src_uyvy,uint8 * dst_v210,int width)447 static 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?
467 LIBYUV_API
I422ToYUY2(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_frame,int dst_stride_frame,int width,int height)468 int 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 
505 LIBYUV_API
I420ToYUY2(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_frame,int dst_stride_frame,int width,int height)506 int 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?
549 LIBYUV_API
I422ToUYVY(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_frame,int dst_stride_frame,int width,int height)550 int 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 
587 LIBYUV_API
I420ToUYVY(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_frame,int dst_stride_frame,int width,int height)588 int 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 
630 LIBYUV_API
I420ToV210(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_frame,int dst_stride_frame,int width,int height)631 int 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.
683 LIBYUV_API
I420ToARGB(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_argb,int dst_stride_argb,int width,int height)684 int 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.
736 LIBYUV_API
I420ToBGRA(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_bgra,int dst_stride_bgra,int width,int height)737 int 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.
790 LIBYUV_API
I420ToABGR(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_abgr,int dst_stride_abgr,int width,int height)791 int 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.
844 LIBYUV_API
I420ToRGBA(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_rgba,int dst_stride_rgba,int width,int height)845 int 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.
898 LIBYUV_API
I420ToRGB24(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_rgb24,int dst_stride_rgb24,int width,int height)899 int 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.
952 LIBYUV_API
I420ToRAW(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_raw,int dst_stride_raw,int width,int height)953 int 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.
1006 LIBYUV_API
I420ToRGB565(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_rgb,int dst_stride_rgb,int width,int height)1007 int 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.
1066 LIBYUV_API
I420ToARGB1555(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_argb,int dst_stride_argb,int width,int height)1067 int 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.
1126 LIBYUV_API
I420ToARGB4444(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_argb,int dst_stride_argb,int width,int height)1127 int 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
1186 LIBYUV_API
ConvertFromI420(const uint8 * y,int y_stride,const uint8 * u,int u_stride,const uint8 * v,int v_stride,uint8 * dst_sample,int dst_sample_stride,int width,int height,uint32 format)1187 int 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