2 * Copyright 2011 The LibYuv Project Authors. All rights reserved.
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.
11 #include "libyuv/convert.h"
13 #include "libyuv/basic_types.h"
14 #include "libyuv/cpu_id.h"
15 #include "libyuv/planar_functions.h"
16 #include "libyuv/rotate.h"
17 #include "libyuv/scale.h" // For ScalePlane()
18 #include "libyuv/row.h"
25 #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
26 static __inline int Abs(int v) {
27 return v >= 0 ? v : -v;
30 // Any I4xx To I420 format with mirroring.
31 static int I4xxToI420(const uint8* src_y, int src_stride_y,
32 const uint8* src_u, int src_stride_u,
33 const uint8* src_v, int src_stride_v,
34 uint8* dst_y, int dst_stride_y,
35 uint8* dst_u, int dst_stride_u,
36 uint8* dst_v, int dst_stride_v,
37 int src_y_width, int src_y_height,
38 int src_uv_width, int src_uv_height) {
39 const int dst_y_width = Abs(src_y_width);
40 const int dst_y_height = Abs(src_y_height);
41 const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
42 const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
43 if (src_y_width == 0 || src_y_height == 0 ||
44 src_uv_width == 0 || src_uv_height == 0) {
47 ScalePlane(src_y, src_stride_y, src_y_width, src_y_height,
48 dst_y, dst_stride_y, dst_y_width, dst_y_height,
50 ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height,
51 dst_u, dst_stride_u, dst_uv_width, dst_uv_height,
53 ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height,
54 dst_v, dst_stride_v, dst_uv_width, dst_uv_height,
59 // Copy I420 with optional flipping
60 // TODO(fbarchard): Use Scale plane which supports mirroring, but ensure
61 // is does row coalescing.
63 int I420Copy(const uint8* src_y, int src_stride_y,
64 const uint8* src_u, int src_stride_u,
65 const uint8* src_v, int src_stride_v,
66 uint8* dst_y, int dst_stride_y,
67 uint8* dst_u, int dst_stride_u,
68 uint8* dst_v, int dst_stride_v,
69 int width, int height) {
70 int halfwidth = (width + 1) >> 1;
71 int halfheight = (height + 1) >> 1;
72 if (!src_y || !src_u || !src_v ||
73 !dst_y || !dst_u || !dst_v ||
74 width <= 0 || height == 0) {
77 // Negative height means invert the image.
80 halfheight = (height + 1) >> 1;
81 src_y = src_y + (height - 1) * src_stride_y;
82 src_u = src_u + (halfheight - 1) * src_stride_u;
83 src_v = src_v + (halfheight - 1) * src_stride_v;
84 src_stride_y = -src_stride_y;
85 src_stride_u = -src_stride_u;
86 src_stride_v = -src_stride_v;
90 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
93 CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
94 CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
98 // 422 chroma is 1/2 width, 1x height
99 // 420 chroma is 1/2 width, 1/2 height
101 int I422ToI420(const uint8* src_y, int src_stride_y,
102 const uint8* src_u, int src_stride_u,
103 const uint8* src_v, int src_stride_v,
104 uint8* dst_y, int dst_stride_y,
105 uint8* dst_u, int dst_stride_u,
106 uint8* dst_v, int dst_stride_v,
107 int width, int height) {
108 const int src_uv_width = SUBSAMPLE(width, 1, 1);
109 return I4xxToI420(src_y, src_stride_y,
116 src_uv_width, height);
119 // 444 chroma is 1x width, 1x height
120 // 420 chroma is 1/2 width, 1/2 height
122 int I444ToI420(const uint8* src_y, int src_stride_y,
123 const uint8* src_u, int src_stride_u,
124 const uint8* src_v, int src_stride_v,
125 uint8* dst_y, int dst_stride_y,
126 uint8* dst_u, int dst_stride_u,
127 uint8* dst_v, int dst_stride_v,
128 int width, int height) {
129 return I4xxToI420(src_y, src_stride_y,
139 // 411 chroma is 1/4 width, 1x height
140 // 420 chroma is 1/2 width, 1/2 height
142 int I411ToI420(const uint8* src_y, int src_stride_y,
143 const uint8* src_u, int src_stride_u,
144 const uint8* src_v, int src_stride_v,
145 uint8* dst_y, int dst_stride_y,
146 uint8* dst_u, int dst_stride_u,
147 uint8* dst_v, int dst_stride_v,
148 int width, int height) {
149 const int src_uv_width = SUBSAMPLE(width, 3, 2);
150 return I4xxToI420(src_y, src_stride_y,
157 src_uv_width, height);
160 // I400 is greyscale typically used in MJPG
162 int I400ToI420(const uint8* src_y, int src_stride_y,
163 uint8* dst_y, int dst_stride_y,
164 uint8* dst_u, int dst_stride_u,
165 uint8* dst_v, int dst_stride_v,
166 int width, int height) {
167 int halfwidth = (width + 1) >> 1;
168 int halfheight = (height + 1) >> 1;
169 if (!src_y || !dst_y || !dst_u || !dst_v ||
170 width <= 0 || height == 0) {
173 // Negative height means invert the image.
176 halfheight = (height + 1) >> 1;
177 src_y = src_y + (height - 1) * src_stride_y;
178 src_stride_y = -src_stride_y;
180 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
181 SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128);
182 SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128);
186 static void CopyPlane2(const uint8* src, int src_stride_0, int src_stride_1,
187 uint8* dst, int dst_stride,
188 int width, int height) {
190 void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
191 #if defined(HAS_COPYROW_X86)
192 if (TestCpuFlag(kCpuHasX86) && IS_ALIGNED(width, 4)) {
193 CopyRow = CopyRow_X86;
196 #if defined(HAS_COPYROW_SSE2)
197 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
198 IS_ALIGNED(src, 16) &&
199 IS_ALIGNED(src_stride_0, 16) && IS_ALIGNED(src_stride_1, 16) &&
200 IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) {
201 CopyRow = CopyRow_SSE2;
204 #if defined(HAS_COPYROW_ERMS)
205 if (TestCpuFlag(kCpuHasERMS)) {
206 CopyRow = CopyRow_ERMS;
209 #if defined(HAS_COPYROW_NEON)
210 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
211 CopyRow = CopyRow_NEON;
214 #if defined(HAS_COPYROW_MIPS)
215 if (TestCpuFlag(kCpuHasMIPS)) {
216 CopyRow = CopyRow_MIPS;
221 for (y = 0; y < height - 1; y += 2) {
222 CopyRow(src, dst, width);
223 CopyRow(src + src_stride_0, dst + dst_stride, width);
224 src += src_stride_0 + src_stride_1;
225 dst += dst_stride * 2;
228 CopyRow(src, dst, width);
232 // Support converting from FOURCC_M420
233 // Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for
234 // easy conversion to I420.
235 // M420 format description:
236 // M420 is row biplanar 420: 2 rows of Y and 1 row of UV.
237 // Chroma is half width / half height. (420)
238 // src_stride_m420 is row planar. Normally this will be the width in pixels.
239 // The UV plane is half width, but 2 values, so src_stride_m420 applies to
240 // this as well as the two Y planes.
241 static int X420ToI420(const uint8* src_y,
242 int src_stride_y0, int src_stride_y1,
243 const uint8* src_uv, int src_stride_uv,
244 uint8* dst_y, int dst_stride_y,
245 uint8* dst_u, int dst_stride_u,
246 uint8* dst_v, int dst_stride_v,
247 int width, int height) {
249 int halfwidth = (width + 1) >> 1;
250 int halfheight = (height + 1) >> 1;
251 void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix) =
253 if (!src_y || !src_uv ||
254 !dst_y || !dst_u || !dst_v ||
255 width <= 0 || height == 0) {
258 // Negative height means invert the image.
261 halfheight = (height + 1) >> 1;
262 dst_y = dst_y + (height - 1) * dst_stride_y;
263 dst_u = dst_u + (halfheight - 1) * dst_stride_u;
264 dst_v = dst_v + (halfheight - 1) * dst_stride_v;
265 dst_stride_y = -dst_stride_y;
266 dst_stride_u = -dst_stride_u;
267 dst_stride_v = -dst_stride_v;
270 if (src_stride_y0 == width &&
271 src_stride_y1 == width &&
272 dst_stride_y == width) {
275 src_stride_y0 = src_stride_y1 = dst_stride_y = 0;
278 if (src_stride_uv == halfwidth * 2 &&
279 dst_stride_u == halfwidth &&
280 dst_stride_v == halfwidth) {
281 halfwidth *= halfheight;
283 src_stride_uv = dst_stride_u = dst_stride_v = 0;
285 #if defined(HAS_SPLITUVROW_SSE2)
286 if (TestCpuFlag(kCpuHasSSE2) && halfwidth >= 16) {
287 SplitUVRow = SplitUVRow_Any_SSE2;
288 if (IS_ALIGNED(halfwidth, 16)) {
289 SplitUVRow = SplitUVRow_Unaligned_SSE2;
290 if (IS_ALIGNED(src_uv, 16) && IS_ALIGNED(src_stride_uv, 16) &&
291 IS_ALIGNED(dst_u, 16) && IS_ALIGNED(dst_stride_u, 16) &&
292 IS_ALIGNED(dst_v, 16) && IS_ALIGNED(dst_stride_v, 16)) {
293 SplitUVRow = SplitUVRow_SSE2;
298 #if defined(HAS_SPLITUVROW_AVX2)
299 if (TestCpuFlag(kCpuHasAVX2) && halfwidth >= 32) {
300 SplitUVRow = SplitUVRow_Any_AVX2;
301 if (IS_ALIGNED(halfwidth, 32)) {
302 SplitUVRow = SplitUVRow_AVX2;
306 #if defined(HAS_SPLITUVROW_NEON)
307 if (TestCpuFlag(kCpuHasNEON) && halfwidth >= 16) {
308 SplitUVRow = SplitUVRow_Any_NEON;
309 if (IS_ALIGNED(halfwidth, 16)) {
310 SplitUVRow = SplitUVRow_NEON;
314 #if defined(HAS_SPLITUVROW_MIPS_DSPR2)
315 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && halfwidth >= 16) {
316 SplitUVRow = SplitUVRow_Any_MIPS_DSPR2;
317 if (IS_ALIGNED(halfwidth, 16)) {
318 SplitUVRow = SplitUVRow_Unaligned_MIPS_DSPR2;
319 if (IS_ALIGNED(src_uv, 4) && IS_ALIGNED(src_stride_uv, 4) &&
320 IS_ALIGNED(dst_u, 4) && IS_ALIGNED(dst_stride_u, 4) &&
321 IS_ALIGNED(dst_v, 4) && IS_ALIGNED(dst_stride_v, 4)) {
322 SplitUVRow = SplitUVRow_MIPS_DSPR2;
329 if (src_stride_y0 == src_stride_y1) {
330 CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height);
332 CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y,
337 for (y = 0; y < halfheight; ++y) {
339 SplitUVRow(src_uv, dst_u, dst_v, halfwidth);
340 dst_u += dst_stride_u;
341 dst_v += dst_stride_v;
342 src_uv += src_stride_uv;
347 // Convert NV12 to I420.
349 int NV12ToI420(const uint8* src_y, int src_stride_y,
350 const uint8* src_uv, int src_stride_uv,
351 uint8* dst_y, int dst_stride_y,
352 uint8* dst_u, int dst_stride_u,
353 uint8* dst_v, int dst_stride_v,
354 int width, int height) {
355 return X420ToI420(src_y, src_stride_y, src_stride_y,
356 src_uv, src_stride_uv,
363 // Convert NV21 to I420. Same as NV12 but u and v pointers swapped.
365 int NV21ToI420(const uint8* src_y, int src_stride_y,
366 const uint8* src_vu, int src_stride_vu,
367 uint8* dst_y, int dst_stride_y,
368 uint8* dst_u, int dst_stride_u,
369 uint8* dst_v, int dst_stride_v,
370 int width, int height) {
371 return X420ToI420(src_y, src_stride_y, src_stride_y,
372 src_vu, src_stride_vu,
379 // Convert M420 to I420.
381 int M420ToI420(const uint8* src_m420, int src_stride_m420,
382 uint8* dst_y, int dst_stride_y,
383 uint8* dst_u, int dst_stride_u,
384 uint8* dst_v, int dst_stride_v,
385 int width, int height) {
386 return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2,
387 src_m420 + src_stride_m420 * 2, src_stride_m420 * 3,
394 // Convert Q420 to I420.
395 // Format is rows of YY/YUYV
397 int Q420ToI420(const uint8* src_y, int src_stride_y,
398 const uint8* src_yuy2, int src_stride_yuy2,
399 uint8* dst_y, int dst_stride_y,
400 uint8* dst_u, int dst_stride_u,
401 uint8* dst_v, int dst_stride_v,
402 int width, int height) {
404 int halfheight = (height + 1) >> 1;
405 void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
406 void (*YUY2ToUV422Row)(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v,
407 int pix) = YUY2ToUV422Row_C;
408 void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int pix) =
410 if (!src_y || !src_yuy2 ||
411 !dst_y || !dst_u || !dst_v ||
412 width <= 0 || height == 0) {
415 // Negative height means invert the image.
418 halfheight = (height + 1) >> 1;
419 dst_y = dst_y + (height - 1) * dst_stride_y;
420 dst_u = dst_u + (halfheight - 1) * dst_stride_u;
421 dst_v = dst_v + (halfheight - 1) * dst_stride_v;
422 dst_stride_y = -dst_stride_y;
423 dst_stride_u = -dst_stride_u;
424 dst_stride_v = -dst_stride_v;
426 // CopyRow for rows of just Y in Q420 copied to Y plane of I420.
427 #if defined(HAS_COPYROW_NEON)
428 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
429 CopyRow = CopyRow_NEON;
432 #if defined(HAS_COPYROW_X86)
433 if (IS_ALIGNED(width, 4)) {
434 CopyRow = CopyRow_X86;
437 #if defined(HAS_COPYROW_SSE2)
438 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
439 IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
440 IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
441 CopyRow = CopyRow_SSE2;
444 #if defined(HAS_COPYROW_ERMS)
445 if (TestCpuFlag(kCpuHasERMS)) {
446 CopyRow = CopyRow_ERMS;
449 #if defined(HAS_COPYROW_MIPS)
450 if (TestCpuFlag(kCpuHasMIPS)) {
451 CopyRow = CopyRow_MIPS;
455 #if defined(HAS_YUY2TOYROW_SSE2)
456 if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
457 YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2;
458 YUY2ToYRow = YUY2ToYRow_Any_SSE2;
459 if (IS_ALIGNED(width, 16)) {
460 YUY2ToUV422Row = YUY2ToUV422Row_Unaligned_SSE2;
461 YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
462 if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
463 YUY2ToUV422Row = YUY2ToUV422Row_SSE2;
464 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
465 YUY2ToYRow = YUY2ToYRow_SSE2;
471 #if defined(HAS_YUY2TOYROW_AVX2)
472 if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
473 YUY2ToUV422Row = YUY2ToUV422Row_Any_AVX2;
474 YUY2ToYRow = YUY2ToYRow_Any_AVX2;
475 if (IS_ALIGNED(width, 32)) {
476 YUY2ToUV422Row = YUY2ToUV422Row_AVX2;
477 YUY2ToYRow = YUY2ToYRow_AVX2;
481 #if defined(HAS_YUY2TOYROW_NEON)
482 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
483 YUY2ToYRow = YUY2ToYRow_Any_NEON;
485 YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON;
487 if (IS_ALIGNED(width, 16)) {
488 YUY2ToYRow = YUY2ToYRow_NEON;
489 YUY2ToUV422Row = YUY2ToUV422Row_NEON;
494 for (y = 0; y < height - 1; y += 2) {
495 CopyRow(src_y, dst_y, width);
496 src_y += src_stride_y;
497 dst_y += dst_stride_y;
499 YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
500 YUY2ToYRow(src_yuy2, dst_y, width);
501 src_yuy2 += src_stride_yuy2;
502 dst_y += dst_stride_y;
503 dst_u += dst_stride_u;
504 dst_v += dst_stride_v;
507 CopyRow(src_y, dst_y, width);
508 YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
513 // Convert YUY2 to I420.
515 int YUY2ToI420(const uint8* src_yuy2, int src_stride_yuy2,
516 uint8* dst_y, int dst_stride_y,
517 uint8* dst_u, int dst_stride_u,
518 uint8* dst_v, int dst_stride_v,
519 int width, int height) {
521 void (*YUY2ToUVRow)(const uint8* src_yuy2, int src_stride_yuy2,
522 uint8* dst_u, uint8* dst_v, int pix) = YUY2ToUVRow_C;
523 void (*YUY2ToYRow)(const uint8* src_yuy2,
524 uint8* dst_y, int pix) = YUY2ToYRow_C;
525 // Negative height means invert the image.
528 src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
529 src_stride_yuy2 = -src_stride_yuy2;
531 #if defined(HAS_YUY2TOYROW_SSE2)
532 if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
533 YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
534 YUY2ToYRow = YUY2ToYRow_Any_SSE2;
535 if (IS_ALIGNED(width, 16)) {
536 YUY2ToUVRow = YUY2ToUVRow_Unaligned_SSE2;
537 YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
538 if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
539 YUY2ToUVRow = YUY2ToUVRow_SSE2;
540 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
541 YUY2ToYRow = YUY2ToYRow_SSE2;
547 #if defined(HAS_YUY2TOYROW_AVX2)
548 if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
549 YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
550 YUY2ToYRow = YUY2ToYRow_Any_AVX2;
551 if (IS_ALIGNED(width, 32)) {
552 YUY2ToUVRow = YUY2ToUVRow_AVX2;
553 YUY2ToYRow = YUY2ToYRow_AVX2;
557 #if defined(HAS_YUY2TOYROW_NEON)
558 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
559 YUY2ToYRow = YUY2ToYRow_Any_NEON;
561 YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
563 if (IS_ALIGNED(width, 16)) {
564 YUY2ToYRow = YUY2ToYRow_NEON;
565 YUY2ToUVRow = YUY2ToUVRow_NEON;
570 for (y = 0; y < height - 1; y += 2) {
571 YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
572 YUY2ToYRow(src_yuy2, dst_y, width);
573 YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
574 src_yuy2 += src_stride_yuy2 * 2;
575 dst_y += dst_stride_y * 2;
576 dst_u += dst_stride_u;
577 dst_v += dst_stride_v;
580 YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
581 YUY2ToYRow(src_yuy2, dst_y, width);
586 // Convert UYVY to I420.
588 int UYVYToI420(const uint8* src_uyvy, int src_stride_uyvy,
589 uint8* dst_y, int dst_stride_y,
590 uint8* dst_u, int dst_stride_u,
591 uint8* dst_v, int dst_stride_v,
592 int width, int height) {
594 void (*UYVYToUVRow)(const uint8* src_uyvy, int src_stride_uyvy,
595 uint8* dst_u, uint8* dst_v, int pix) = UYVYToUVRow_C;
596 void (*UYVYToYRow)(const uint8* src_uyvy,
597 uint8* dst_y, int pix) = UYVYToYRow_C;
598 // Negative height means invert the image.
601 src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
602 src_stride_uyvy = -src_stride_uyvy;
604 #if defined(HAS_UYVYTOYROW_SSE2)
605 if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
606 UYVYToUVRow = UYVYToUVRow_Any_SSE2;
607 UYVYToYRow = UYVYToYRow_Any_SSE2;
608 if (IS_ALIGNED(width, 16)) {
609 UYVYToUVRow = UYVYToUVRow_Unaligned_SSE2;
610 UYVYToYRow = UYVYToYRow_Unaligned_SSE2;
611 if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16)) {
612 UYVYToUVRow = UYVYToUVRow_SSE2;
613 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
614 UYVYToYRow = UYVYToYRow_SSE2;
620 #if defined(HAS_UYVYTOYROW_AVX2)
621 if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
622 UYVYToUVRow = UYVYToUVRow_Any_AVX2;
623 UYVYToYRow = UYVYToYRow_Any_AVX2;
624 if (IS_ALIGNED(width, 32)) {
625 UYVYToUVRow = UYVYToUVRow_AVX2;
626 UYVYToYRow = UYVYToYRow_AVX2;
630 #if defined(HAS_UYVYTOYROW_NEON)
631 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
632 UYVYToYRow = UYVYToYRow_Any_NEON;
634 UYVYToUVRow = UYVYToUVRow_Any_NEON;
636 if (IS_ALIGNED(width, 16)) {
637 UYVYToYRow = UYVYToYRow_NEON;
638 UYVYToUVRow = UYVYToUVRow_NEON;
643 for (y = 0; y < height - 1; y += 2) {
644 UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
645 UYVYToYRow(src_uyvy, dst_y, width);
646 UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
647 src_uyvy += src_stride_uyvy * 2;
648 dst_y += dst_stride_y * 2;
649 dst_u += dst_stride_u;
650 dst_v += dst_stride_v;
653 UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
654 UYVYToYRow(src_uyvy, dst_y, width);
659 // Convert ARGB to I420.
661 int ARGBToI420(const uint8* src_argb, int src_stride_argb,
662 uint8* dst_y, int dst_stride_y,
663 uint8* dst_u, int dst_stride_u,
664 uint8* dst_v, int dst_stride_v,
665 int width, int height) {
667 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
668 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
669 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
672 !dst_y || !dst_u || !dst_v ||
673 width <= 0 || height == 0) {
676 // Negative height means invert the image.
679 src_argb = src_argb + (height - 1) * src_stride_argb;
680 src_stride_argb = -src_stride_argb;
682 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
683 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
684 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
685 ARGBToYRow = ARGBToYRow_Any_SSSE3;
686 if (IS_ALIGNED(width, 16)) {
687 ARGBToUVRow = ARGBToUVRow_Unaligned_SSSE3;
688 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
689 if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
690 ARGBToUVRow = ARGBToUVRow_SSSE3;
691 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
692 ARGBToYRow = ARGBToYRow_SSSE3;
698 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
699 if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
700 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
701 ARGBToYRow = ARGBToYRow_Any_AVX2;
702 if (IS_ALIGNED(width, 32)) {
703 ARGBToUVRow = ARGBToUVRow_AVX2;
704 ARGBToYRow = ARGBToYRow_AVX2;
708 #if defined(HAS_ARGBTOYROW_NEON)
709 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
710 ARGBToYRow = ARGBToYRow_Any_NEON;
711 if (IS_ALIGNED(width, 8)) {
712 ARGBToYRow = ARGBToYRow_NEON;
715 ARGBToUVRow = ARGBToUVRow_Any_NEON;
716 if (IS_ALIGNED(width, 16)) {
717 ARGBToUVRow = ARGBToUVRow_NEON;
723 for (y = 0; y < height - 1; y += 2) {
724 ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
725 ARGBToYRow(src_argb, dst_y, width);
726 ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
727 src_argb += src_stride_argb * 2;
728 dst_y += dst_stride_y * 2;
729 dst_u += dst_stride_u;
730 dst_v += dst_stride_v;
733 ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
734 ARGBToYRow(src_argb, dst_y, width);
739 // Convert BGRA to I420.
741 int BGRAToI420(const uint8* src_bgra, int src_stride_bgra,
742 uint8* dst_y, int dst_stride_y,
743 uint8* dst_u, int dst_stride_u,
744 uint8* dst_v, int dst_stride_v,
745 int width, int height) {
747 void (*BGRAToUVRow)(const uint8* src_bgra0, int src_stride_bgra,
748 uint8* dst_u, uint8* dst_v, int width) = BGRAToUVRow_C;
749 void (*BGRAToYRow)(const uint8* src_bgra, uint8* dst_y, int pix) =
752 !dst_y || !dst_u || !dst_v ||
753 width <= 0 || height == 0) {
756 // Negative height means invert the image.
759 src_bgra = src_bgra + (height - 1) * src_stride_bgra;
760 src_stride_bgra = -src_stride_bgra;
762 #if defined(HAS_BGRATOYROW_SSSE3)
763 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
764 BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
765 BGRAToYRow = BGRAToYRow_Any_SSSE3;
766 if (IS_ALIGNED(width, 16)) {
767 BGRAToUVRow = BGRAToUVRow_Unaligned_SSSE3;
768 BGRAToYRow = BGRAToYRow_Unaligned_SSSE3;
769 if (IS_ALIGNED(src_bgra, 16) && IS_ALIGNED(src_stride_bgra, 16)) {
770 BGRAToUVRow = BGRAToUVRow_SSSE3;
771 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
772 BGRAToYRow = BGRAToYRow_SSSE3;
777 #elif defined(HAS_BGRATOYROW_NEON)
778 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
779 BGRAToYRow = BGRAToYRow_Any_NEON;
780 if (IS_ALIGNED(width, 8)) {
781 BGRAToYRow = BGRAToYRow_NEON;
784 BGRAToUVRow = BGRAToUVRow_Any_NEON;
785 if (IS_ALIGNED(width, 16)) {
786 BGRAToUVRow = BGRAToUVRow_NEON;
792 for (y = 0; y < height - 1; y += 2) {
793 BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
794 BGRAToYRow(src_bgra, dst_y, width);
795 BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
796 src_bgra += src_stride_bgra * 2;
797 dst_y += dst_stride_y * 2;
798 dst_u += dst_stride_u;
799 dst_v += dst_stride_v;
802 BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
803 BGRAToYRow(src_bgra, dst_y, width);
808 // Convert ABGR to I420.
810 int ABGRToI420(const uint8* src_abgr, int src_stride_abgr,
811 uint8* dst_y, int dst_stride_y,
812 uint8* dst_u, int dst_stride_u,
813 uint8* dst_v, int dst_stride_v,
814 int width, int height) {
816 void (*ABGRToUVRow)(const uint8* src_abgr0, int src_stride_abgr,
817 uint8* dst_u, uint8* dst_v, int width) = ABGRToUVRow_C;
818 void (*ABGRToYRow)(const uint8* src_abgr, uint8* dst_y, int pix) =
821 !dst_y || !dst_u || !dst_v ||
822 width <= 0 || height == 0) {
825 // Negative height means invert the image.
828 src_abgr = src_abgr + (height - 1) * src_stride_abgr;
829 src_stride_abgr = -src_stride_abgr;
831 #if defined(HAS_ABGRTOYROW_SSSE3)
832 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
833 ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
834 ABGRToYRow = ABGRToYRow_Any_SSSE3;
835 if (IS_ALIGNED(width, 16)) {
836 ABGRToUVRow = ABGRToUVRow_Unaligned_SSSE3;
837 ABGRToYRow = ABGRToYRow_Unaligned_SSSE3;
838 if (IS_ALIGNED(src_abgr, 16) && IS_ALIGNED(src_stride_abgr, 16)) {
839 ABGRToUVRow = ABGRToUVRow_SSSE3;
840 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
841 ABGRToYRow = ABGRToYRow_SSSE3;
846 #elif defined(HAS_ABGRTOYROW_NEON)
847 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
848 ABGRToYRow = ABGRToYRow_Any_NEON;
849 if (IS_ALIGNED(width, 8)) {
850 ABGRToYRow = ABGRToYRow_NEON;
853 ABGRToUVRow = ABGRToUVRow_Any_NEON;
854 if (IS_ALIGNED(width, 16)) {
855 ABGRToUVRow = ABGRToUVRow_NEON;
861 for (y = 0; y < height - 1; y += 2) {
862 ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
863 ABGRToYRow(src_abgr, dst_y, width);
864 ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
865 src_abgr += src_stride_abgr * 2;
866 dst_y += dst_stride_y * 2;
867 dst_u += dst_stride_u;
868 dst_v += dst_stride_v;
871 ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
872 ABGRToYRow(src_abgr, dst_y, width);
877 // Convert RGBA to I420.
879 int RGBAToI420(const uint8* src_rgba, int src_stride_rgba,
880 uint8* dst_y, int dst_stride_y,
881 uint8* dst_u, int dst_stride_u,
882 uint8* dst_v, int dst_stride_v,
883 int width, int height) {
885 void (*RGBAToUVRow)(const uint8* src_rgba0, int src_stride_rgba,
886 uint8* dst_u, uint8* dst_v, int width) = RGBAToUVRow_C;
887 void (*RGBAToYRow)(const uint8* src_rgba, uint8* dst_y, int pix) =
890 !dst_y || !dst_u || !dst_v ||
891 width <= 0 || height == 0) {
894 // Negative height means invert the image.
897 src_rgba = src_rgba + (height - 1) * src_stride_rgba;
898 src_stride_rgba = -src_stride_rgba;
900 #if defined(HAS_RGBATOYROW_SSSE3)
901 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
902 RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
903 RGBAToYRow = RGBAToYRow_Any_SSSE3;
904 if (IS_ALIGNED(width, 16)) {
905 RGBAToUVRow = RGBAToUVRow_Unaligned_SSSE3;
906 RGBAToYRow = RGBAToYRow_Unaligned_SSSE3;
907 if (IS_ALIGNED(src_rgba, 16) && IS_ALIGNED(src_stride_rgba, 16)) {
908 RGBAToUVRow = RGBAToUVRow_SSSE3;
909 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
910 RGBAToYRow = RGBAToYRow_SSSE3;
915 #elif defined(HAS_RGBATOYROW_NEON)
916 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
917 RGBAToYRow = RGBAToYRow_Any_NEON;
918 if (IS_ALIGNED(width, 8)) {
919 RGBAToYRow = RGBAToYRow_NEON;
922 RGBAToUVRow = RGBAToUVRow_Any_NEON;
923 if (IS_ALIGNED(width, 16)) {
924 RGBAToUVRow = RGBAToUVRow_NEON;
930 for (y = 0; y < height - 1; y += 2) {
931 RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
932 RGBAToYRow(src_rgba, dst_y, width);
933 RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
934 src_rgba += src_stride_rgba * 2;
935 dst_y += dst_stride_y * 2;
936 dst_u += dst_stride_u;
937 dst_v += dst_stride_v;
940 RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
941 RGBAToYRow(src_rgba, dst_y, width);
946 // Convert RGB24 to I420.
948 int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24,
949 uint8* dst_y, int dst_stride_y,
950 uint8* dst_u, int dst_stride_u,
951 uint8* dst_v, int dst_stride_v,
952 int width, int height) {
954 #if defined(HAS_RGB24TOYROW_NEON)
955 void (*RGB24ToUVRow)(const uint8* src_rgb24, int src_stride_rgb24,
956 uint8* dst_u, uint8* dst_v, int width) = RGB24ToUVRow_C;
957 void (*RGB24ToYRow)(const uint8* src_rgb24, uint8* dst_y, int pix) =
960 void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
962 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
963 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
964 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
966 // Allocate 2 rows of ARGB.
967 const int kRowSize = (width * 4 + 15) & ~15;
968 align_buffer_64(row, kRowSize * 2);
970 if (!src_rgb24 || !dst_y || !dst_u || !dst_v ||
971 width <= 0 || height == 0) {
974 // Negative height means invert the image.
977 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
978 src_stride_rgb24 = -src_stride_rgb24;
981 #if defined(HAS_RGB24TOYROW_NEON)
982 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
983 RGB24ToYRow = RGB24ToYRow_Any_NEON;
984 if (IS_ALIGNED(width, 8)) {
985 RGB24ToYRow = RGB24ToYRow_NEON;
988 RGB24ToUVRow = RGB24ToUVRow_Any_NEON;
989 if (IS_ALIGNED(width, 16)) {
990 RGB24ToUVRow = RGB24ToUVRow_NEON;
994 #else // HAS_RGB24TOYROW_NEON
996 #if defined(HAS_RGB24TOARGBROW_SSSE3)
997 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
998 RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
999 if (IS_ALIGNED(width, 16)) {
1000 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
1004 #if defined(HAS_ARGBTOUVROW_SSSE3)
1005 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1006 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1007 if (IS_ALIGNED(width, 16)) {
1008 ARGBToUVRow = ARGBToUVRow_SSSE3;
1012 #if defined(HAS_ARGBTOUVROW_SSSE3)
1013 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1014 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1015 if (IS_ALIGNED(width, 16)) {
1016 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1017 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1018 ARGBToYRow = ARGBToYRow_SSSE3;
1022 #endif // HAS_ARGBTOUVROW_SSSE3
1023 #endif // HAS_RGB24TOYROW_NEON
1025 for (y = 0; y < height - 1; y += 2) {
1026 #if defined(HAS_RGB24TOYROW_NEON)
1027 RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
1028 RGB24ToYRow(src_rgb24, dst_y, width);
1029 RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
1031 RGB24ToARGBRow(src_rgb24, row, width);
1032 RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
1033 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1034 ARGBToYRow(row, dst_y, width);
1035 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1037 src_rgb24 += src_stride_rgb24 * 2;
1038 dst_y += dst_stride_y * 2;
1039 dst_u += dst_stride_u;
1040 dst_v += dst_stride_v;
1043 #if defined(HAS_RGB24TOYROW_NEON)
1044 RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
1045 RGB24ToYRow(src_rgb24, dst_y, width);
1047 RGB24ToARGBRow(src_rgb24, row, width);
1048 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1049 ARGBToYRow(row, dst_y, width);
1052 #if !defined(HAS_RGB24TOYROW_NEON)
1053 free_aligned_buffer_64(row);
1058 // Convert RAW to I420.
1060 int RAWToI420(const uint8* src_raw, int src_stride_raw,
1061 uint8* dst_y, int dst_stride_y,
1062 uint8* dst_u, int dst_stride_u,
1063 uint8* dst_v, int dst_stride_v,
1064 int width, int height) {
1066 #if defined(HAS_RAWTOYROW_NEON)
1067 void (*RAWToUVRow)(const uint8* src_raw, int src_stride_raw,
1068 uint8* dst_u, uint8* dst_v, int width) = RAWToUVRow_C;
1069 void (*RAWToYRow)(const uint8* src_raw, uint8* dst_y, int pix) =
1072 void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1074 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1075 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1076 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1078 // Allocate 2 rows of ARGB.
1079 const int kRowSize = (width * 4 + 15) & ~15;
1080 align_buffer_64(row, kRowSize * 2);
1082 if (!src_raw || !dst_y || !dst_u || !dst_v ||
1083 width <= 0 || height == 0) {
1086 // Negative height means invert the image.
1089 src_raw = src_raw + (height - 1) * src_stride_raw;
1090 src_stride_raw = -src_stride_raw;
1093 #if defined(HAS_RAWTOYROW_NEON)
1094 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
1095 RAWToYRow = RAWToYRow_Any_NEON;
1096 if (IS_ALIGNED(width, 8)) {
1097 RAWToYRow = RAWToYRow_NEON;
1100 RAWToUVRow = RAWToUVRow_Any_NEON;
1101 if (IS_ALIGNED(width, 16)) {
1102 RAWToUVRow = RAWToUVRow_NEON;
1106 #else // HAS_RAWTOYROW_NEON
1108 #if defined(HAS_RAWTOARGBROW_SSSE3)
1109 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1110 RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
1111 if (IS_ALIGNED(width, 16)) {
1112 RAWToARGBRow = RAWToARGBRow_SSSE3;
1116 #if defined(HAS_ARGBTOUVROW_SSSE3)
1117 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1118 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1119 if (IS_ALIGNED(width, 16)) {
1120 ARGBToUVRow = ARGBToUVRow_SSSE3;
1124 #if defined(HAS_ARGBTOUVROW_SSSE3)
1125 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1126 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1127 if (IS_ALIGNED(width, 16)) {
1128 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1129 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1130 ARGBToYRow = ARGBToYRow_SSSE3;
1134 #endif // HAS_ARGBTOUVROW_SSSE3
1135 #endif // HAS_RAWTOYROW_NEON
1137 for (y = 0; y < height - 1; y += 2) {
1138 #if defined(HAS_RAWTOYROW_NEON)
1139 RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width);
1140 RAWToYRow(src_raw, dst_y, width);
1141 RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
1143 RAWToARGBRow(src_raw, row, width);
1144 RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width);
1145 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1146 ARGBToYRow(row, dst_y, width);
1147 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1149 src_raw += src_stride_raw * 2;
1150 dst_y += dst_stride_y * 2;
1151 dst_u += dst_stride_u;
1152 dst_v += dst_stride_v;
1155 #if defined(HAS_RAWTOYROW_NEON)
1156 RAWToUVRow(src_raw, 0, dst_u, dst_v, width);
1157 RAWToYRow(src_raw, dst_y, width);
1159 RAWToARGBRow(src_raw, row, width);
1160 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1161 ARGBToYRow(row, dst_y, width);
1164 #if !defined(HAS_RAWTOYROW_NEON)
1165 free_aligned_buffer_64(row);
1170 // Convert RGB565 to I420.
1172 int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565,
1173 uint8* dst_y, int dst_stride_y,
1174 uint8* dst_u, int dst_stride_u,
1175 uint8* dst_v, int dst_stride_v,
1176 int width, int height) {
1178 #if defined(HAS_RGB565TOYROW_NEON)
1179 void (*RGB565ToUVRow)(const uint8* src_rgb565, int src_stride_rgb565,
1180 uint8* dst_u, uint8* dst_v, int width) = RGB565ToUVRow_C;
1181 void (*RGB565ToYRow)(const uint8* src_rgb565, uint8* dst_y, int pix) =
1184 void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1186 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1187 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1188 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1190 // Allocate 2 rows of ARGB.
1191 const int kRowSize = (width * 4 + 15) & ~15;
1192 align_buffer_64(row, kRowSize * 2);
1194 if (!src_rgb565 || !dst_y || !dst_u || !dst_v ||
1195 width <= 0 || height == 0) {
1198 // Negative height means invert the image.
1201 src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
1202 src_stride_rgb565 = -src_stride_rgb565;
1205 #if defined(HAS_RGB565TOYROW_NEON)
1206 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
1207 RGB565ToYRow = RGB565ToYRow_Any_NEON;
1208 if (IS_ALIGNED(width, 8)) {
1209 RGB565ToYRow = RGB565ToYRow_NEON;
1212 RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
1213 if (IS_ALIGNED(width, 16)) {
1214 RGB565ToUVRow = RGB565ToUVRow_NEON;
1218 #else // HAS_RGB565TOYROW_NEON
1220 #if defined(HAS_RGB565TOARGBROW_SSE2)
1221 if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
1222 RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
1223 if (IS_ALIGNED(width, 8)) {
1224 RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
1228 #if defined(HAS_ARGBTOUVROW_SSSE3)
1229 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1230 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1231 if (IS_ALIGNED(width, 16)) {
1232 ARGBToUVRow = ARGBToUVRow_SSSE3;
1236 #if defined(HAS_ARGBTOUVROW_SSSE3)
1237 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1238 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1239 if (IS_ALIGNED(width, 16)) {
1240 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1241 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1242 ARGBToYRow = ARGBToYRow_SSSE3;
1246 #endif // HAS_ARGBTOUVROW_SSSE3
1247 #endif // HAS_RGB565TOYROW_NEON
1249 for (y = 0; y < height - 1; y += 2) {
1250 #if defined(HAS_RGB565TOYROW_NEON)
1251 RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width);
1252 RGB565ToYRow(src_rgb565, dst_y, width);
1253 RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
1255 RGB565ToARGBRow(src_rgb565, row, width);
1256 RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width);
1257 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1258 ARGBToYRow(row, dst_y, width);
1259 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1261 src_rgb565 += src_stride_rgb565 * 2;
1262 dst_y += dst_stride_y * 2;
1263 dst_u += dst_stride_u;
1264 dst_v += dst_stride_v;
1267 #if defined(HAS_RGB565TOYROW_NEON)
1268 RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width);
1269 RGB565ToYRow(src_rgb565, dst_y, width);
1271 RGB565ToARGBRow(src_rgb565, row, width);
1272 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1273 ARGBToYRow(row, dst_y, width);
1276 #if !defined(HAS_RGB565TOYROW_NEON)
1277 free_aligned_buffer_64(row);
1282 // Convert ARGB1555 to I420.
1284 int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555,
1285 uint8* dst_y, int dst_stride_y,
1286 uint8* dst_u, int dst_stride_u,
1287 uint8* dst_v, int dst_stride_v,
1288 int width, int height) {
1290 #if defined(HAS_ARGB1555TOYROW_NEON)
1291 void (*ARGB1555ToUVRow)(const uint8* src_argb1555, int src_stride_argb1555,
1292 uint8* dst_u, uint8* dst_v, int width) = ARGB1555ToUVRow_C;
1293 void (*ARGB1555ToYRow)(const uint8* src_argb1555, uint8* dst_y, int pix) =
1296 void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1297 ARGB1555ToARGBRow_C;
1298 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1299 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1300 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1302 // Allocate 2 rows of ARGB.
1303 const int kRowSize = (width * 4 + 15) & ~15;
1304 align_buffer_64(row, kRowSize * 2);
1306 if (!src_argb1555 || !dst_y || !dst_u || !dst_v ||
1307 width <= 0 || height == 0) {
1310 // Negative height means invert the image.
1313 src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
1314 src_stride_argb1555 = -src_stride_argb1555;
1317 #if defined(HAS_ARGB1555TOYROW_NEON)
1318 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
1319 ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
1320 if (IS_ALIGNED(width, 8)) {
1321 ARGB1555ToYRow = ARGB1555ToYRow_NEON;
1324 ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
1325 if (IS_ALIGNED(width, 16)) {
1326 ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
1330 #else // HAS_ARGB1555TOYROW_NEON
1332 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
1333 if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
1334 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
1335 if (IS_ALIGNED(width, 8)) {
1336 ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
1340 #if defined(HAS_ARGBTOUVROW_SSSE3)
1341 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1342 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1343 if (IS_ALIGNED(width, 16)) {
1344 ARGBToUVRow = ARGBToUVRow_SSSE3;
1348 #if defined(HAS_ARGBTOUVROW_SSSE3)
1349 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1350 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1351 if (IS_ALIGNED(width, 16)) {
1352 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1353 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1354 ARGBToYRow = ARGBToYRow_SSSE3;
1358 #endif // HAS_ARGBTOUVROW_SSSE3
1359 #endif // HAS_ARGB1555TOYROW_NEON
1361 for (y = 0; y < height - 1; y += 2) {
1362 #if defined(HAS_ARGB1555TOYROW_NEON)
1363 ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width);
1364 ARGB1555ToYRow(src_argb1555, dst_y, width);
1365 ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y,
1368 ARGB1555ToARGBRow(src_argb1555, row, width);
1369 ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize,
1371 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1372 ARGBToYRow(row, dst_y, width);
1373 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1375 src_argb1555 += src_stride_argb1555 * 2;
1376 dst_y += dst_stride_y * 2;
1377 dst_u += dst_stride_u;
1378 dst_v += dst_stride_v;
1381 #if defined(HAS_ARGB1555TOYROW_NEON)
1382 ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width);
1383 ARGB1555ToYRow(src_argb1555, dst_y, width);
1385 ARGB1555ToARGBRow(src_argb1555, row, width);
1386 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1387 ARGBToYRow(row, dst_y, width);
1390 #if !defined(HAS_ARGB1555TOYROW_NEON)
1391 free_aligned_buffer_64(row);
1396 // Convert ARGB4444 to I420.
1398 int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444,
1399 uint8* dst_y, int dst_stride_y,
1400 uint8* dst_u, int dst_stride_u,
1401 uint8* dst_v, int dst_stride_v,
1402 int width, int height) {
1404 #if defined(HAS_ARGB4444TOYROW_NEON)
1405 void (*ARGB4444ToUVRow)(const uint8* src_argb4444, int src_stride_argb4444,
1406 uint8* dst_u, uint8* dst_v, int width) = ARGB4444ToUVRow_C;
1407 void (*ARGB4444ToYRow)(const uint8* src_argb4444, uint8* dst_y, int pix) =
1410 void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1411 ARGB4444ToARGBRow_C;
1412 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1413 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1414 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1416 // Allocate 2 rows of ARGB.
1417 const int kRowSize = (width * 4 + 15) & ~15;
1418 align_buffer_64(row, kRowSize * 2);
1420 if (!src_argb4444 || !dst_y || !dst_u || !dst_v ||
1421 width <= 0 || height == 0) {
1424 // Negative height means invert the image.
1427 src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
1428 src_stride_argb4444 = -src_stride_argb4444;
1431 #if defined(HAS_ARGB4444TOYROW_NEON)
1432 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
1433 ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
1434 if (IS_ALIGNED(width, 8)) {
1435 ARGB4444ToYRow = ARGB4444ToYRow_NEON;
1438 ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
1439 if (IS_ALIGNED(width, 16)) {
1440 ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
1444 #else // HAS_ARGB4444TOYROW_NEON
1446 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
1447 if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
1448 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
1449 if (IS_ALIGNED(width, 8)) {
1450 ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
1454 #if defined(HAS_ARGBTOUVROW_SSSE3)
1455 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1456 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1457 if (IS_ALIGNED(width, 16)) {
1458 ARGBToUVRow = ARGBToUVRow_SSSE3;
1462 #if defined(HAS_ARGBTOUVROW_SSSE3)
1463 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1464 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1465 if (IS_ALIGNED(width, 16)) {
1466 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1467 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1468 ARGBToYRow = ARGBToYRow_SSSE3;
1472 #endif // HAS_ARGBTOUVROW_SSSE3
1473 #endif // HAS_ARGB4444TOYROW_NEON
1475 for (y = 0; y < height - 1; y += 2) {
1476 #if defined(HAS_ARGB4444TOYROW_NEON)
1477 ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width);
1478 ARGB4444ToYRow(src_argb4444, dst_y, width);
1479 ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y,
1482 ARGB4444ToARGBRow(src_argb4444, row, width);
1483 ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize,
1485 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1486 ARGBToYRow(row, dst_y, width);
1487 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1489 src_argb4444 += src_stride_argb4444 * 2;
1490 dst_y += dst_stride_y * 2;
1491 dst_u += dst_stride_u;
1492 dst_v += dst_stride_v;
1495 #if defined(HAS_ARGB4444TOYROW_NEON)
1496 ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width);
1497 ARGB4444ToYRow(src_argb4444, dst_y, width);
1499 ARGB4444ToARGBRow(src_argb4444, row, width);
1500 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1501 ARGBToYRow(row, dst_y, width);
1504 #if !defined(HAS_ARGB4444TOYROW_NEON)
1505 free_aligned_buffer_64(row);
1512 } // namespace libyuv