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 CopyRow = CopyRow_SSE2;
201 #if defined(HAS_COPYROW_AVX)
202 if (TestCpuFlag(kCpuHasAVX) && IS_ALIGNED(width, 64)) {
203 CopyRow = CopyRow_AVX;
206 #if defined(HAS_COPYROW_ERMS)
207 if (TestCpuFlag(kCpuHasERMS)) {
208 CopyRow = CopyRow_ERMS;
211 #if defined(HAS_COPYROW_NEON)
212 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
213 CopyRow = CopyRow_NEON;
216 #if defined(HAS_COPYROW_MIPS)
217 if (TestCpuFlag(kCpuHasMIPS)) {
218 CopyRow = CopyRow_MIPS;
223 for (y = 0; y < height - 1; y += 2) {
224 CopyRow(src, dst, width);
225 CopyRow(src + src_stride_0, dst + dst_stride, width);
226 src += src_stride_0 + src_stride_1;
227 dst += dst_stride * 2;
230 CopyRow(src, dst, width);
234 // Support converting from FOURCC_M420
235 // Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for
236 // easy conversion to I420.
237 // M420 format description:
238 // M420 is row biplanar 420: 2 rows of Y and 1 row of UV.
239 // Chroma is half width / half height. (420)
240 // src_stride_m420 is row planar. Normally this will be the width in pixels.
241 // The UV plane is half width, but 2 values, so src_stride_m420 applies to
242 // this as well as the two Y planes.
243 static int X420ToI420(const uint8* src_y,
244 int src_stride_y0, int src_stride_y1,
245 const uint8* src_uv, int src_stride_uv,
246 uint8* dst_y, int dst_stride_y,
247 uint8* dst_u, int dst_stride_u,
248 uint8* dst_v, int dst_stride_v,
249 int width, int height) {
251 int halfwidth = (width + 1) >> 1;
252 int halfheight = (height + 1) >> 1;
253 void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix) =
255 if (!src_y || !src_uv ||
256 !dst_y || !dst_u || !dst_v ||
257 width <= 0 || height == 0) {
260 // Negative height means invert the image.
263 halfheight = (height + 1) >> 1;
264 dst_y = dst_y + (height - 1) * dst_stride_y;
265 dst_u = dst_u + (halfheight - 1) * dst_stride_u;
266 dst_v = dst_v + (halfheight - 1) * dst_stride_v;
267 dst_stride_y = -dst_stride_y;
268 dst_stride_u = -dst_stride_u;
269 dst_stride_v = -dst_stride_v;
272 if (src_stride_y0 == width &&
273 src_stride_y1 == width &&
274 dst_stride_y == width) {
277 src_stride_y0 = src_stride_y1 = dst_stride_y = 0;
280 if (src_stride_uv == halfwidth * 2 &&
281 dst_stride_u == halfwidth &&
282 dst_stride_v == halfwidth) {
283 halfwidth *= halfheight;
285 src_stride_uv = dst_stride_u = dst_stride_v = 0;
287 #if defined(HAS_SPLITUVROW_SSE2)
288 if (TestCpuFlag(kCpuHasSSE2) && halfwidth >= 16) {
289 SplitUVRow = SplitUVRow_Any_SSE2;
290 if (IS_ALIGNED(halfwidth, 16)) {
291 SplitUVRow = SplitUVRow_SSE2;
295 #if defined(HAS_SPLITUVROW_AVX2)
296 if (TestCpuFlag(kCpuHasAVX2) && halfwidth >= 32) {
297 SplitUVRow = SplitUVRow_Any_AVX2;
298 if (IS_ALIGNED(halfwidth, 32)) {
299 SplitUVRow = SplitUVRow_AVX2;
303 #if defined(HAS_SPLITUVROW_NEON)
304 if (TestCpuFlag(kCpuHasNEON) && halfwidth >= 16) {
305 SplitUVRow = SplitUVRow_Any_NEON;
306 if (IS_ALIGNED(halfwidth, 16)) {
307 SplitUVRow = SplitUVRow_NEON;
311 #if defined(HAS_SPLITUVROW_MIPS_DSPR2)
312 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && halfwidth >= 16 &&
313 IS_ALIGNED(src_uv, 4) && IS_ALIGNED(src_stride_uv, 4) &&
314 IS_ALIGNED(dst_u, 4) && IS_ALIGNED(dst_stride_u, 4) &&
315 IS_ALIGNED(dst_v, 4) && IS_ALIGNED(dst_stride_v, 4)) {
316 SplitUVRow = SplitUVRow_Any_MIPS_DSPR2;
317 if (IS_ALIGNED(halfwidth, 16)) {
318 SplitUVRow = SplitUVRow_MIPS_DSPR2;
324 if (src_stride_y0 == src_stride_y1) {
325 CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height);
327 CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y,
332 for (y = 0; y < halfheight; ++y) {
334 SplitUVRow(src_uv, dst_u, dst_v, halfwidth);
335 dst_u += dst_stride_u;
336 dst_v += dst_stride_v;
337 src_uv += src_stride_uv;
342 // Convert NV12 to I420.
344 int NV12ToI420(const uint8* src_y, int src_stride_y,
345 const uint8* src_uv, int src_stride_uv,
346 uint8* dst_y, int dst_stride_y,
347 uint8* dst_u, int dst_stride_u,
348 uint8* dst_v, int dst_stride_v,
349 int width, int height) {
350 return X420ToI420(src_y, src_stride_y, src_stride_y,
351 src_uv, src_stride_uv,
358 // Convert NV21 to I420. Same as NV12 but u and v pointers swapped.
360 int NV21ToI420(const uint8* src_y, int src_stride_y,
361 const uint8* src_vu, int src_stride_vu,
362 uint8* dst_y, int dst_stride_y,
363 uint8* dst_u, int dst_stride_u,
364 uint8* dst_v, int dst_stride_v,
365 int width, int height) {
366 return X420ToI420(src_y, src_stride_y, src_stride_y,
367 src_vu, src_stride_vu,
374 // Convert M420 to I420.
376 int M420ToI420(const uint8* src_m420, int src_stride_m420,
377 uint8* dst_y, int dst_stride_y,
378 uint8* dst_u, int dst_stride_u,
379 uint8* dst_v, int dst_stride_v,
380 int width, int height) {
381 return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2,
382 src_m420 + src_stride_m420 * 2, src_stride_m420 * 3,
389 // Convert Q420 to I420.
390 // Format is rows of YY/YUYV
392 int Q420ToI420(const uint8* src_y, int src_stride_y,
393 const uint8* src_yuy2, int src_stride_yuy2,
394 uint8* dst_y, int dst_stride_y,
395 uint8* dst_u, int dst_stride_u,
396 uint8* dst_v, int dst_stride_v,
397 int width, int height) {
400 void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
401 void (*YUY2ToUV422Row)(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v,
402 int pix) = YUY2ToUV422Row_C;
403 void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int pix) =
405 if (!src_y || !src_yuy2 ||
406 !dst_y || !dst_u || !dst_v ||
407 width <= 0 || height == 0) {
410 // Negative height means invert the image.
413 halfheight = (height + 1) >> 1;
414 dst_y = dst_y + (height - 1) * dst_stride_y;
415 dst_u = dst_u + (halfheight - 1) * dst_stride_u;
416 dst_v = dst_v + (halfheight - 1) * dst_stride_v;
417 dst_stride_y = -dst_stride_y;
418 dst_stride_u = -dst_stride_u;
419 dst_stride_v = -dst_stride_v;
421 // CopyRow for rows of just Y in Q420 copied to Y plane of I420.
422 #if defined(HAS_COPYROW_NEON)
423 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
424 CopyRow = CopyRow_NEON;
427 #if defined(HAS_COPYROW_X86)
428 if (IS_ALIGNED(width, 4)) {
429 CopyRow = CopyRow_X86;
432 #if defined(HAS_COPYROW_SSE2)
433 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32)) {
434 CopyRow = CopyRow_SSE2;
437 #if defined(HAS_COPYROW_AVX)
438 if (TestCpuFlag(kCpuHasAVX) && IS_ALIGNED(width, 64)) {
439 CopyRow = CopyRow_AVX;
442 #if defined(HAS_COPYROW_ERMS)
443 if (TestCpuFlag(kCpuHasERMS)) {
444 CopyRow = CopyRow_ERMS;
447 #if defined(HAS_COPYROW_MIPS)
448 if (TestCpuFlag(kCpuHasMIPS)) {
449 CopyRow = CopyRow_MIPS;
453 #if defined(HAS_YUY2TOYROW_SSE2)
454 if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
455 YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2;
456 YUY2ToYRow = YUY2ToYRow_Any_SSE2;
457 if (IS_ALIGNED(width, 16)) {
458 YUY2ToUV422Row = YUY2ToUV422Row_SSE2;
459 YUY2ToYRow = YUY2ToYRow_SSE2;
463 #if defined(HAS_YUY2TOYROW_AVX2)
464 if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
465 YUY2ToUV422Row = YUY2ToUV422Row_Any_AVX2;
466 YUY2ToYRow = YUY2ToYRow_Any_AVX2;
467 if (IS_ALIGNED(width, 32)) {
468 YUY2ToUV422Row = YUY2ToUV422Row_AVX2;
469 YUY2ToYRow = YUY2ToYRow_AVX2;
473 #if defined(HAS_YUY2TOYROW_NEON)
474 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
475 YUY2ToYRow = YUY2ToYRow_Any_NEON;
477 YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON;
479 if (IS_ALIGNED(width, 16)) {
480 YUY2ToYRow = YUY2ToYRow_NEON;
481 YUY2ToUV422Row = YUY2ToUV422Row_NEON;
486 for (y = 0; y < height - 1; y += 2) {
487 CopyRow(src_y, dst_y, width);
488 src_y += src_stride_y;
489 dst_y += dst_stride_y;
491 YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
492 YUY2ToYRow(src_yuy2, dst_y, width);
493 src_yuy2 += src_stride_yuy2;
494 dst_y += dst_stride_y;
495 dst_u += dst_stride_u;
496 dst_v += dst_stride_v;
499 CopyRow(src_y, dst_y, width);
500 YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
505 // Convert YUY2 to I420.
507 int YUY2ToI420(const uint8* src_yuy2, int src_stride_yuy2,
508 uint8* dst_y, int dst_stride_y,
509 uint8* dst_u, int dst_stride_u,
510 uint8* dst_v, int dst_stride_v,
511 int width, int height) {
513 void (*YUY2ToUVRow)(const uint8* src_yuy2, int src_stride_yuy2,
514 uint8* dst_u, uint8* dst_v, int pix) = YUY2ToUVRow_C;
515 void (*YUY2ToYRow)(const uint8* src_yuy2,
516 uint8* dst_y, int pix) = YUY2ToYRow_C;
517 // Negative height means invert the image.
520 src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
521 src_stride_yuy2 = -src_stride_yuy2;
523 #if defined(HAS_YUY2TOYROW_SSE2)
524 if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
525 YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
526 YUY2ToYRow = YUY2ToYRow_Any_SSE2;
527 if (IS_ALIGNED(width, 16)) {
528 YUY2ToUVRow = YUY2ToUVRow_SSE2;
529 YUY2ToYRow = YUY2ToYRow_SSE2;
533 #if defined(HAS_YUY2TOYROW_AVX2)
534 if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
535 YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
536 YUY2ToYRow = YUY2ToYRow_Any_AVX2;
537 if (IS_ALIGNED(width, 32)) {
538 YUY2ToUVRow = YUY2ToUVRow_AVX2;
539 YUY2ToYRow = YUY2ToYRow_AVX2;
543 #if defined(HAS_YUY2TOYROW_NEON)
544 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
545 YUY2ToYRow = YUY2ToYRow_Any_NEON;
547 YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
549 if (IS_ALIGNED(width, 16)) {
550 YUY2ToYRow = YUY2ToYRow_NEON;
551 YUY2ToUVRow = YUY2ToUVRow_NEON;
556 for (y = 0; y < height - 1; y += 2) {
557 YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
558 YUY2ToYRow(src_yuy2, dst_y, width);
559 YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
560 src_yuy2 += src_stride_yuy2 * 2;
561 dst_y += dst_stride_y * 2;
562 dst_u += dst_stride_u;
563 dst_v += dst_stride_v;
566 YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
567 YUY2ToYRow(src_yuy2, dst_y, width);
572 // Convert UYVY to I420.
574 int UYVYToI420(const uint8* src_uyvy, int src_stride_uyvy,
575 uint8* dst_y, int dst_stride_y,
576 uint8* dst_u, int dst_stride_u,
577 uint8* dst_v, int dst_stride_v,
578 int width, int height) {
580 void (*UYVYToUVRow)(const uint8* src_uyvy, int src_stride_uyvy,
581 uint8* dst_u, uint8* dst_v, int pix) = UYVYToUVRow_C;
582 void (*UYVYToYRow)(const uint8* src_uyvy,
583 uint8* dst_y, int pix) = UYVYToYRow_C;
584 // Negative height means invert the image.
587 src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
588 src_stride_uyvy = -src_stride_uyvy;
590 #if defined(HAS_UYVYTOYROW_SSE2)
591 if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
592 UYVYToUVRow = UYVYToUVRow_Any_SSE2;
593 UYVYToYRow = UYVYToYRow_Any_SSE2;
594 if (IS_ALIGNED(width, 16)) {
595 UYVYToUVRow = UYVYToUVRow_SSE2;
596 UYVYToYRow = UYVYToYRow_SSE2;
600 #if defined(HAS_UYVYTOYROW_AVX2)
601 if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
602 UYVYToUVRow = UYVYToUVRow_Any_AVX2;
603 UYVYToYRow = UYVYToYRow_Any_AVX2;
604 if (IS_ALIGNED(width, 32)) {
605 UYVYToUVRow = UYVYToUVRow_AVX2;
606 UYVYToYRow = UYVYToYRow_AVX2;
610 #if defined(HAS_UYVYTOYROW_NEON)
611 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
612 UYVYToYRow = UYVYToYRow_Any_NEON;
614 UYVYToUVRow = UYVYToUVRow_Any_NEON;
616 if (IS_ALIGNED(width, 16)) {
617 UYVYToYRow = UYVYToYRow_NEON;
618 UYVYToUVRow = UYVYToUVRow_NEON;
623 for (y = 0; y < height - 1; y += 2) {
624 UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
625 UYVYToYRow(src_uyvy, dst_y, width);
626 UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
627 src_uyvy += src_stride_uyvy * 2;
628 dst_y += dst_stride_y * 2;
629 dst_u += dst_stride_u;
630 dst_v += dst_stride_v;
633 UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
634 UYVYToYRow(src_uyvy, dst_y, width);
639 // Convert ARGB to I420.
641 int ARGBToI420(const uint8* src_argb, int src_stride_argb,
642 uint8* dst_y, int dst_stride_y,
643 uint8* dst_u, int dst_stride_u,
644 uint8* dst_v, int dst_stride_v,
645 int width, int height) {
647 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
648 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
649 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
652 !dst_y || !dst_u || !dst_v ||
653 width <= 0 || height == 0) {
656 // Negative height means invert the image.
659 src_argb = src_argb + (height - 1) * src_stride_argb;
660 src_stride_argb = -src_stride_argb;
662 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
663 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
664 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
665 ARGBToYRow = ARGBToYRow_Any_SSSE3;
666 if (IS_ALIGNED(width, 16)) {
667 ARGBToUVRow = ARGBToUVRow_SSSE3;
668 ARGBToYRow = ARGBToYRow_SSSE3;
672 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
673 if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
674 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
675 ARGBToYRow = ARGBToYRow_Any_AVX2;
676 if (IS_ALIGNED(width, 32)) {
677 ARGBToUVRow = ARGBToUVRow_AVX2;
678 ARGBToYRow = ARGBToYRow_AVX2;
682 #if defined(HAS_ARGBTOYROW_NEON)
683 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
684 ARGBToYRow = ARGBToYRow_Any_NEON;
685 if (IS_ALIGNED(width, 8)) {
686 ARGBToYRow = ARGBToYRow_NEON;
690 #if defined(HAS_ARGBTOUVROW_NEON)
691 if (TestCpuFlag(kCpuHasNEON) && width >= 16) {
692 ARGBToUVRow = ARGBToUVRow_Any_NEON;
693 if (IS_ALIGNED(width, 16)) {
694 ARGBToUVRow = ARGBToUVRow_NEON;
699 for (y = 0; y < height - 1; y += 2) {
700 ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
701 ARGBToYRow(src_argb, dst_y, width);
702 ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
703 src_argb += src_stride_argb * 2;
704 dst_y += dst_stride_y * 2;
705 dst_u += dst_stride_u;
706 dst_v += dst_stride_v;
709 ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
710 ARGBToYRow(src_argb, dst_y, width);
715 // Convert BGRA to I420.
717 int BGRAToI420(const uint8* src_bgra, int src_stride_bgra,
718 uint8* dst_y, int dst_stride_y,
719 uint8* dst_u, int dst_stride_u,
720 uint8* dst_v, int dst_stride_v,
721 int width, int height) {
723 void (*BGRAToUVRow)(const uint8* src_bgra0, int src_stride_bgra,
724 uint8* dst_u, uint8* dst_v, int width) = BGRAToUVRow_C;
725 void (*BGRAToYRow)(const uint8* src_bgra, uint8* dst_y, int pix) =
728 !dst_y || !dst_u || !dst_v ||
729 width <= 0 || height == 0) {
732 // Negative height means invert the image.
735 src_bgra = src_bgra + (height - 1) * src_stride_bgra;
736 src_stride_bgra = -src_stride_bgra;
738 #if defined(HAS_BGRATOYROW_SSSE3) && defined(HAS_BGRATOUVROW_SSSE3)
739 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
740 BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
741 BGRAToYRow = BGRAToYRow_Any_SSSE3;
742 if (IS_ALIGNED(width, 16)) {
743 BGRAToUVRow = BGRAToUVRow_SSSE3;
744 BGRAToYRow = BGRAToYRow_SSSE3;
748 #if defined(HAS_BGRATOYROW_NEON)
749 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
750 BGRAToYRow = BGRAToYRow_Any_NEON;
751 if (IS_ALIGNED(width, 8)) {
752 BGRAToYRow = BGRAToYRow_NEON;
756 #if defined(HAS_BGRATOUVROW_NEON)
757 if (TestCpuFlag(kCpuHasNEON) && width >= 16) {
758 BGRAToUVRow = BGRAToUVRow_Any_NEON;
759 if (IS_ALIGNED(width, 16)) {
760 BGRAToUVRow = BGRAToUVRow_NEON;
765 for (y = 0; y < height - 1; y += 2) {
766 BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
767 BGRAToYRow(src_bgra, dst_y, width);
768 BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
769 src_bgra += src_stride_bgra * 2;
770 dst_y += dst_stride_y * 2;
771 dst_u += dst_stride_u;
772 dst_v += dst_stride_v;
775 BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
776 BGRAToYRow(src_bgra, dst_y, width);
781 // Convert ABGR to I420.
783 int ABGRToI420(const uint8* src_abgr, int src_stride_abgr,
784 uint8* dst_y, int dst_stride_y,
785 uint8* dst_u, int dst_stride_u,
786 uint8* dst_v, int dst_stride_v,
787 int width, int height) {
789 void (*ABGRToUVRow)(const uint8* src_abgr0, int src_stride_abgr,
790 uint8* dst_u, uint8* dst_v, int width) = ABGRToUVRow_C;
791 void (*ABGRToYRow)(const uint8* src_abgr, uint8* dst_y, int pix) =
794 !dst_y || !dst_u || !dst_v ||
795 width <= 0 || height == 0) {
798 // Negative height means invert the image.
801 src_abgr = src_abgr + (height - 1) * src_stride_abgr;
802 src_stride_abgr = -src_stride_abgr;
804 #if defined(HAS_ABGRTOYROW_SSSE3) && defined(HAS_ABGRTOUVROW_SSSE3)
805 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
806 ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
807 ABGRToYRow = ABGRToYRow_Any_SSSE3;
808 if (IS_ALIGNED(width, 16)) {
809 ABGRToUVRow = ABGRToUVRow_SSSE3;
810 ABGRToYRow = ABGRToYRow_SSSE3;
814 #if defined(HAS_ABGRTOYROW_NEON)
815 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
816 ABGRToYRow = ABGRToYRow_Any_NEON;
817 if (IS_ALIGNED(width, 8)) {
818 ABGRToYRow = ABGRToYRow_NEON;
822 #if defined(HAS_ABGRTOUVROW_NEON)
823 if (TestCpuFlag(kCpuHasNEON) && width >= 16) {
824 ABGRToUVRow = ABGRToUVRow_Any_NEON;
825 if (IS_ALIGNED(width, 16)) {
826 ABGRToUVRow = ABGRToUVRow_NEON;
831 for (y = 0; y < height - 1; y += 2) {
832 ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
833 ABGRToYRow(src_abgr, dst_y, width);
834 ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
835 src_abgr += src_stride_abgr * 2;
836 dst_y += dst_stride_y * 2;
837 dst_u += dst_stride_u;
838 dst_v += dst_stride_v;
841 ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
842 ABGRToYRow(src_abgr, dst_y, width);
847 // Convert RGBA to I420.
849 int RGBAToI420(const uint8* src_rgba, int src_stride_rgba,
850 uint8* dst_y, int dst_stride_y,
851 uint8* dst_u, int dst_stride_u,
852 uint8* dst_v, int dst_stride_v,
853 int width, int height) {
855 void (*RGBAToUVRow)(const uint8* src_rgba0, int src_stride_rgba,
856 uint8* dst_u, uint8* dst_v, int width) = RGBAToUVRow_C;
857 void (*RGBAToYRow)(const uint8* src_rgba, uint8* dst_y, int pix) =
860 !dst_y || !dst_u || !dst_v ||
861 width <= 0 || height == 0) {
864 // Negative height means invert the image.
867 src_rgba = src_rgba + (height - 1) * src_stride_rgba;
868 src_stride_rgba = -src_stride_rgba;
870 #if defined(HAS_RGBATOYROW_SSSE3) && defined(HAS_RGBATOUVROW_SSSE3)
871 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
872 RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
873 RGBAToYRow = RGBAToYRow_Any_SSSE3;
874 if (IS_ALIGNED(width, 16)) {
875 RGBAToUVRow = RGBAToUVRow_SSSE3;
876 RGBAToYRow = RGBAToYRow_SSSE3;
880 #if defined(HAS_RGBATOYROW_NEON)
881 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
882 RGBAToYRow = RGBAToYRow_Any_NEON;
883 if (IS_ALIGNED(width, 8)) {
884 RGBAToYRow = RGBAToYRow_NEON;
888 #if defined(HAS_RGBATOUVROW_NEON)
889 if (TestCpuFlag(kCpuHasNEON) && width >= 16) {
890 RGBAToUVRow = RGBAToUVRow_Any_NEON;
891 if (IS_ALIGNED(width, 16)) {
892 RGBAToUVRow = RGBAToUVRow_NEON;
897 for (y = 0; y < height - 1; y += 2) {
898 RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
899 RGBAToYRow(src_rgba, dst_y, width);
900 RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
901 src_rgba += src_stride_rgba * 2;
902 dst_y += dst_stride_y * 2;
903 dst_u += dst_stride_u;
904 dst_v += dst_stride_v;
907 RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
908 RGBAToYRow(src_rgba, dst_y, width);
913 // Convert RGB24 to I420.
915 int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24,
916 uint8* dst_y, int dst_stride_y,
917 uint8* dst_u, int dst_stride_u,
918 uint8* dst_v, int dst_stride_v,
919 int width, int height) {
921 #if defined(HAS_RGB24TOYROW_NEON)
922 void (*RGB24ToUVRow)(const uint8* src_rgb24, int src_stride_rgb24,
923 uint8* dst_u, uint8* dst_v, int width) = RGB24ToUVRow_C;
924 void (*RGB24ToYRow)(const uint8* src_rgb24, uint8* dst_y, int pix) =
927 void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
929 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
930 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
931 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
934 if (!src_rgb24 || !dst_y || !dst_u || !dst_v ||
935 width <= 0 || height == 0) {
938 // Negative height means invert the image.
941 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
942 src_stride_rgb24 = -src_stride_rgb24;
945 #if defined(HAS_RGB24TOYROW_NEON)
946 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
947 RGB24ToYRow = RGB24ToYRow_Any_NEON;
948 if (IS_ALIGNED(width, 8)) {
949 RGB24ToYRow = RGB24ToYRow_NEON;
953 #if defined(HAS_RGB24TOUVROW_NEON)
954 if (TestCpuFlag(kCpuHasNEON) && width >= 16) {
955 RGB24ToUVRow = RGB24ToUVRow_Any_NEON;
956 if (IS_ALIGNED(width, 16)) {
957 RGB24ToUVRow = RGB24ToUVRow_NEON;
961 #if defined(HAS_RGB24TOARGBROW_SSSE3)
962 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
963 RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
964 if (IS_ALIGNED(width, 16)) {
965 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
969 #if defined(HAS_ARGBTOUVROW_SSSE3)
970 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
971 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
972 if (IS_ALIGNED(width, 16)) {
973 ARGBToUVRow = ARGBToUVRow_SSSE3;
977 #if defined(HAS_ARGBTOUVROW_SSSE3)
978 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
979 ARGBToYRow = ARGBToYRow_Any_SSSE3;
980 if (IS_ALIGNED(width, 16)) {
981 ARGBToYRow = ARGBToYRow_SSSE3;
984 #endif // HAS_ARGBTOUVROW_SSSE3
987 #if !defined(HAS_RGB24TOYROW_NEON)
988 // Allocate 2 rows of ARGB.
989 const int kRowSize = (width * 4 + 15) & ~15;
990 align_buffer_64(row, kRowSize * 2);
993 for (y = 0; y < height - 1; y += 2) {
994 #if defined(HAS_RGB24TOYROW_NEON)
995 RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
996 RGB24ToYRow(src_rgb24, dst_y, width);
997 RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
999 RGB24ToARGBRow(src_rgb24, row, width);
1000 RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
1001 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1002 ARGBToYRow(row, dst_y, width);
1003 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1005 src_rgb24 += src_stride_rgb24 * 2;
1006 dst_y += dst_stride_y * 2;
1007 dst_u += dst_stride_u;
1008 dst_v += dst_stride_v;
1011 #if defined(HAS_RGB24TOYROW_NEON)
1012 RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
1013 RGB24ToYRow(src_rgb24, dst_y, width);
1015 RGB24ToARGBRow(src_rgb24, row, width);
1016 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1017 ARGBToYRow(row, dst_y, width);
1020 #if !defined(HAS_RGB24TOYROW_NEON)
1021 free_aligned_buffer_64(row);
1027 // Convert RAW to I420.
1029 int RAWToI420(const uint8* src_raw, int src_stride_raw,
1030 uint8* dst_y, int dst_stride_y,
1031 uint8* dst_u, int dst_stride_u,
1032 uint8* dst_v, int dst_stride_v,
1033 int width, int height) {
1035 #if defined(HAS_RAWTOYROW_NEON)
1036 void (*RAWToUVRow)(const uint8* src_raw, int src_stride_raw,
1037 uint8* dst_u, uint8* dst_v, int width) = RAWToUVRow_C;
1038 void (*RAWToYRow)(const uint8* src_raw, uint8* dst_y, int pix) =
1041 void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1043 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1044 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1045 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1048 if (!src_raw || !dst_y || !dst_u || !dst_v ||
1049 width <= 0 || height == 0) {
1052 // Negative height means invert the image.
1055 src_raw = src_raw + (height - 1) * src_stride_raw;
1056 src_stride_raw = -src_stride_raw;
1059 #if defined(HAS_RAWTOYROW_NEON)
1060 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
1061 RAWToYRow = RAWToYRow_Any_NEON;
1062 if (IS_ALIGNED(width, 8)) {
1063 RAWToYRow = RAWToYRow_NEON;
1067 #if defined(HAS_RAWTOUVROW_NEON)
1068 if (TestCpuFlag(kCpuHasNEON) && width >= 16) {
1069 RAWToUVRow = RAWToUVRow_Any_NEON;
1070 if (IS_ALIGNED(width, 16)) {
1071 RAWToUVRow = RAWToUVRow_NEON;
1075 #if defined(HAS_RAWTOARGBROW_SSSE3)
1076 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1077 RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
1078 if (IS_ALIGNED(width, 16)) {
1079 RAWToARGBRow = RAWToARGBRow_SSSE3;
1083 #if defined(HAS_ARGBTOUVROW_SSSE3)
1084 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1085 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1086 if (IS_ALIGNED(width, 16)) {
1087 ARGBToUVRow = ARGBToUVRow_SSSE3;
1091 #if defined(HAS_ARGBTOUVROW_SSSE3)
1092 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1093 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1094 if (IS_ALIGNED(width, 16)) {
1095 ARGBToYRow = ARGBToYRow_SSSE3;
1098 #endif // HAS_ARGBTOUVROW_SSSE3
1101 // Allocate 2 rows of ARGB.
1102 const int kRowSize = (width * 4 + 15) & ~15;
1103 align_buffer_64(row, kRowSize * 2);
1105 for (y = 0; y < height - 1; y += 2) {
1106 #if defined(HAS_RAWTOYROW_NEON)
1107 RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width);
1108 RAWToYRow(src_raw, dst_y, width);
1109 RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
1111 RAWToARGBRow(src_raw, row, width);
1112 RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width);
1113 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1114 ARGBToYRow(row, dst_y, width);
1115 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1117 src_raw += src_stride_raw * 2;
1118 dst_y += dst_stride_y * 2;
1119 dst_u += dst_stride_u;
1120 dst_v += dst_stride_v;
1123 #if defined(HAS_RAWTOYROW_NEON)
1124 RAWToUVRow(src_raw, 0, dst_u, dst_v, width);
1125 RAWToYRow(src_raw, dst_y, width);
1127 RAWToARGBRow(src_raw, row, width);
1128 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1129 ARGBToYRow(row, dst_y, width);
1132 #if !defined(HAS_RAWTOYROW_NEON)
1133 free_aligned_buffer_64(row);
1139 // Convert RGB565 to I420.
1141 int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565,
1142 uint8* dst_y, int dst_stride_y,
1143 uint8* dst_u, int dst_stride_u,
1144 uint8* dst_v, int dst_stride_v,
1145 int width, int height) {
1147 #if defined(HAS_RGB565TOYROW_NEON)
1148 void (*RGB565ToUVRow)(const uint8* src_rgb565, int src_stride_rgb565,
1149 uint8* dst_u, uint8* dst_v, int width) = RGB565ToUVRow_C;
1150 void (*RGB565ToYRow)(const uint8* src_rgb565, uint8* dst_y, int pix) =
1153 void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1155 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1156 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1157 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1160 if (!src_rgb565 || !dst_y || !dst_u || !dst_v ||
1161 width <= 0 || height == 0) {
1164 // Negative height means invert the image.
1167 src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
1168 src_stride_rgb565 = -src_stride_rgb565;
1171 #if defined(HAS_RGB565TOYROW_NEON)
1172 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
1173 RGB565ToYRow = RGB565ToYRow_Any_NEON;
1174 if (IS_ALIGNED(width, 8)) {
1175 RGB565ToYRow = RGB565ToYRow_NEON;
1178 RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
1179 if (IS_ALIGNED(width, 16)) {
1180 RGB565ToUVRow = RGB565ToUVRow_NEON;
1184 #else // HAS_RGB565TOYROW_NEON
1186 #if defined(HAS_RGB565TOARGBROW_SSE2)
1187 if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
1188 RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
1189 if (IS_ALIGNED(width, 8)) {
1190 RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
1194 #if defined(HAS_ARGBTOUVROW_SSSE3)
1195 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1196 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1197 if (IS_ALIGNED(width, 16)) {
1198 ARGBToUVRow = ARGBToUVRow_SSSE3;
1202 #if defined(HAS_ARGBTOUVROW_SSSE3)
1203 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1204 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1205 if (IS_ALIGNED(width, 16)) {
1206 ARGBToYRow = ARGBToYRow_SSSE3;
1209 #endif // HAS_ARGBTOUVROW_SSSE3
1210 #endif // HAS_RGB565TOYROW_NEON
1213 #if !defined(HAS_RGB565TOYROW_NEON)
1214 // Allocate 2 rows of ARGB.
1215 const int kRowSize = (width * 4 + 15) & ~15;
1216 align_buffer_64(row, kRowSize * 2);
1219 for (y = 0; y < height - 1; y += 2) {
1220 #if defined(HAS_RGB565TOYROW_NEON)
1221 RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width);
1222 RGB565ToYRow(src_rgb565, dst_y, width);
1223 RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
1225 RGB565ToARGBRow(src_rgb565, row, width);
1226 RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width);
1227 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1228 ARGBToYRow(row, dst_y, width);
1229 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1231 src_rgb565 += src_stride_rgb565 * 2;
1232 dst_y += dst_stride_y * 2;
1233 dst_u += dst_stride_u;
1234 dst_v += dst_stride_v;
1237 #if defined(HAS_RGB565TOYROW_NEON)
1238 RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width);
1239 RGB565ToYRow(src_rgb565, dst_y, width);
1241 RGB565ToARGBRow(src_rgb565, row, width);
1242 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1243 ARGBToYRow(row, dst_y, width);
1246 #if !defined(HAS_RGB565TOYROW_NEON)
1247 free_aligned_buffer_64(row);
1253 // Convert ARGB1555 to I420.
1255 int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555,
1256 uint8* dst_y, int dst_stride_y,
1257 uint8* dst_u, int dst_stride_u,
1258 uint8* dst_v, int dst_stride_v,
1259 int width, int height) {
1261 #if defined(HAS_ARGB1555TOYROW_NEON)
1262 void (*ARGB1555ToUVRow)(const uint8* src_argb1555, int src_stride_argb1555,
1263 uint8* dst_u, uint8* dst_v, int width) = ARGB1555ToUVRow_C;
1264 void (*ARGB1555ToYRow)(const uint8* src_argb1555, uint8* dst_y, int pix) =
1267 void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1268 ARGB1555ToARGBRow_C;
1269 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1270 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1271 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1274 if (!src_argb1555 || !dst_y || !dst_u || !dst_v ||
1275 width <= 0 || height == 0) {
1278 // Negative height means invert the image.
1281 src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
1282 src_stride_argb1555 = -src_stride_argb1555;
1285 #if defined(HAS_ARGB1555TOYROW_NEON)
1286 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
1287 ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
1288 if (IS_ALIGNED(width, 8)) {
1289 ARGB1555ToYRow = ARGB1555ToYRow_NEON;
1292 ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
1293 if (IS_ALIGNED(width, 16)) {
1294 ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
1298 #else // HAS_ARGB1555TOYROW_NEON
1300 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
1301 if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
1302 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
1303 if (IS_ALIGNED(width, 8)) {
1304 ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
1308 #if defined(HAS_ARGBTOUVROW_SSSE3)
1309 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1310 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1311 if (IS_ALIGNED(width, 16)) {
1312 ARGBToUVRow = ARGBToUVRow_SSSE3;
1316 #if defined(HAS_ARGBTOUVROW_SSSE3)
1317 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1318 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1319 if (IS_ALIGNED(width, 16)) {
1320 ARGBToYRow = ARGBToYRow_SSSE3;
1323 #endif // HAS_ARGBTOUVROW_SSSE3
1324 #endif // HAS_ARGB1555TOYROW_NEON
1327 #if !defined(HAS_ARGB1555TOYROW_NEON)
1328 // Allocate 2 rows of ARGB.
1329 const int kRowSize = (width * 4 + 15) & ~15;
1330 align_buffer_64(row, kRowSize * 2);
1332 for (y = 0; y < height - 1; y += 2) {
1333 #if defined(HAS_ARGB1555TOYROW_NEON)
1334 ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width);
1335 ARGB1555ToYRow(src_argb1555, dst_y, width);
1336 ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y,
1339 ARGB1555ToARGBRow(src_argb1555, row, width);
1340 ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize,
1342 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1343 ARGBToYRow(row, dst_y, width);
1344 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1346 src_argb1555 += src_stride_argb1555 * 2;
1347 dst_y += dst_stride_y * 2;
1348 dst_u += dst_stride_u;
1349 dst_v += dst_stride_v;
1352 #if defined(HAS_ARGB1555TOYROW_NEON)
1353 ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width);
1354 ARGB1555ToYRow(src_argb1555, dst_y, width);
1356 ARGB1555ToARGBRow(src_argb1555, row, width);
1357 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1358 ARGBToYRow(row, dst_y, width);
1361 #if !defined(HAS_ARGB1555TOYROW_NEON)
1362 free_aligned_buffer_64(row);
1368 // Convert ARGB4444 to I420.
1370 int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444,
1371 uint8* dst_y, int dst_stride_y,
1372 uint8* dst_u, int dst_stride_u,
1373 uint8* dst_v, int dst_stride_v,
1374 int width, int height) {
1376 #if defined(HAS_ARGB4444TOYROW_NEON)
1377 void (*ARGB4444ToUVRow)(const uint8* src_argb4444, int src_stride_argb4444,
1378 uint8* dst_u, uint8* dst_v, int width) = ARGB4444ToUVRow_C;
1379 void (*ARGB4444ToYRow)(const uint8* src_argb4444, uint8* dst_y, int pix) =
1382 void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1383 ARGB4444ToARGBRow_C;
1384 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1385 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1386 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1389 if (!src_argb4444 || !dst_y || !dst_u || !dst_v ||
1390 width <= 0 || height == 0) {
1393 // Negative height means invert the image.
1396 src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
1397 src_stride_argb4444 = -src_stride_argb4444;
1400 #if defined(HAS_ARGB4444TOYROW_NEON)
1401 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
1402 ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
1403 if (IS_ALIGNED(width, 8)) {
1404 ARGB4444ToYRow = ARGB4444ToYRow_NEON;
1407 ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
1408 if (IS_ALIGNED(width, 16)) {
1409 ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
1413 #else // HAS_ARGB4444TOYROW_NEON
1415 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
1416 if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
1417 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
1418 if (IS_ALIGNED(width, 8)) {
1419 ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
1423 #if defined(HAS_ARGBTOUVROW_SSSE3)
1424 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1425 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1426 if (IS_ALIGNED(width, 16)) {
1427 ARGBToUVRow = ARGBToUVRow_SSSE3;
1431 #if defined(HAS_ARGBTOUVROW_SSSE3)
1432 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1433 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1434 if (IS_ALIGNED(width, 16)) {
1435 ARGBToYRow = ARGBToYRow_SSSE3;
1438 #endif // HAS_ARGBTOUVROW_SSSE3
1439 #endif // HAS_ARGB4444TOYROW_NEON
1442 #if !defined(HAS_ARGB4444TOYROW_NEON)
1443 // Allocate 2 rows of ARGB.
1444 const int kRowSize = (width * 4 + 15) & ~15;
1445 align_buffer_64(row, kRowSize * 2);
1448 for (y = 0; y < height - 1; y += 2) {
1449 #if defined(HAS_ARGB4444TOYROW_NEON)
1450 ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width);
1451 ARGB4444ToYRow(src_argb4444, dst_y, width);
1452 ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y,
1455 ARGB4444ToARGBRow(src_argb4444, row, width);
1456 ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize,
1458 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1459 ARGBToYRow(row, dst_y, width);
1460 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1462 src_argb4444 += src_stride_argb4444 * 2;
1463 dst_y += dst_stride_y * 2;
1464 dst_u += dst_stride_u;
1465 dst_v += dst_stride_v;
1468 #if defined(HAS_ARGB4444TOYROW_NEON)
1469 ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width);
1470 ARGB4444ToYRow(src_argb4444, dst_y, width);
1472 ARGB4444ToARGBRow(src_argb4444, row, width);
1473 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1474 ARGBToYRow(row, dst_y, width);
1477 #if !defined(HAS_ARGB4444TOYROW_NEON)
1478 free_aligned_buffer_64(row);
1486 } // namespace libyuv