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