2 * Copyright 2012 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_from.h"
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/scale.h" // For ScalePlane()
20 #include "libyuv/video_common.h"
21 #include "libyuv/row.h"
28 #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
29 static __inline int Abs(int v) {
30 return v >= 0 ? v : -v;
33 // I420 To any I4xx YUV format with mirroring.
34 static int I420ToI4xx(const uint8* src_y, int src_stride_y,
35 const uint8* src_u, int src_stride_u,
36 const uint8* src_v, int src_stride_v,
37 uint8* dst_y, int dst_stride_y,
38 uint8* dst_u, int dst_stride_u,
39 uint8* dst_v, int dst_stride_v,
40 int src_y_width, int src_y_height,
41 int dst_uv_width, int dst_uv_height) {
42 const int dst_y_width = Abs(src_y_width);
43 const int dst_y_height = Abs(src_y_height);
44 const int src_uv_width = SUBSAMPLE(src_y_width, 1, 1);
45 const int src_uv_height = SUBSAMPLE(src_y_height, 1, 1);
46 if (src_y_width == 0 || src_y_height == 0 ||
47 dst_uv_width <= 0 || dst_uv_height <= 0) {
50 ScalePlane(src_y, src_stride_y, src_y_width, src_y_height,
51 dst_y, dst_stride_y, dst_y_width, dst_y_height,
53 ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height,
54 dst_u, dst_stride_u, dst_uv_width, dst_uv_height,
56 ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height,
57 dst_v, dst_stride_v, dst_uv_width, dst_uv_height,
62 // 420 chroma is 1/2 width, 1/2 height
63 // 422 chroma is 1/2 width, 1x height
65 int I420ToI422(const uint8* src_y, int src_stride_y,
66 const uint8* src_u, int src_stride_u,
67 const uint8* src_v, int src_stride_v,
68 uint8* dst_y, int dst_stride_y,
69 uint8* dst_u, int dst_stride_u,
70 uint8* dst_v, int dst_stride_v,
71 int width, int height) {
72 const int dst_uv_width = (Abs(width) + 1) >> 1;
73 const int dst_uv_height = Abs(height);
74 return I420ToI4xx(src_y, src_stride_y,
81 dst_uv_width, dst_uv_height);
84 // 420 chroma is 1/2 width, 1/2 height
85 // 444 chroma is 1x width, 1x height
87 int I420ToI444(const uint8* src_y, int src_stride_y,
88 const uint8* src_u, int src_stride_u,
89 const uint8* src_v, int src_stride_v,
90 uint8* dst_y, int dst_stride_y,
91 uint8* dst_u, int dst_stride_u,
92 uint8* dst_v, int dst_stride_v,
93 int width, int height) {
94 const int dst_uv_width = Abs(width);
95 const int dst_uv_height = Abs(height);
96 return I420ToI4xx(src_y, src_stride_y,
103 dst_uv_width, dst_uv_height);
106 // 420 chroma is 1/2 width, 1/2 height
107 // 411 chroma is 1/4 width, 1x height
109 int I420ToI411(const uint8* src_y, int src_stride_y,
110 const uint8* src_u, int src_stride_u,
111 const uint8* src_v, int src_stride_v,
112 uint8* dst_y, int dst_stride_y,
113 uint8* dst_u, int dst_stride_u,
114 uint8* dst_v, int dst_stride_v,
115 int width, int height) {
116 const int dst_uv_width = (Abs(width) + 3) >> 2;
117 const int dst_uv_height = Abs(height);
118 return I420ToI4xx(src_y, src_stride_y,
125 dst_uv_width, dst_uv_height);
128 // Copy to I400. Source can be I420,422,444,400,NV12,NV21
130 int I400Copy(const uint8* src_y, int src_stride_y,
131 uint8* dst_y, int dst_stride_y,
132 int width, int height) {
133 if (!src_y || !dst_y ||
134 width <= 0 || height == 0) {
137 // Negative height means invert the image.
140 src_y = src_y + (height - 1) * src_stride_y;
141 src_stride_y = -src_stride_y;
143 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
148 int I422ToYUY2(const uint8* src_y, int src_stride_y,
149 const uint8* src_u, int src_stride_u,
150 const uint8* src_v, int src_stride_v,
151 uint8* dst_yuy2, int dst_stride_yuy2,
152 int width, int height) {
154 void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u,
155 const uint8* src_v, uint8* dst_yuy2, int width) =
157 if (!src_y || !src_u || !src_v || !dst_yuy2 ||
158 width <= 0 || height == 0) {
161 // Negative height means invert the image.
164 dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
165 dst_stride_yuy2 = -dst_stride_yuy2;
168 if (src_stride_y == width &&
169 src_stride_u * 2 == width &&
170 src_stride_v * 2 == width &&
171 dst_stride_yuy2 == width * 2) {
174 src_stride_y = src_stride_u = src_stride_v = dst_stride_yuy2 = 0;
176 #if defined(HAS_I422TOYUY2ROW_SSE2)
177 if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
178 I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
179 if (IS_ALIGNED(width, 16)) {
180 I422ToYUY2Row = I422ToYUY2Row_SSE2;
183 #elif defined(HAS_I422TOYUY2ROW_NEON)
184 if (TestCpuFlag(kCpuHasNEON) && width >= 16) {
185 I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
186 if (IS_ALIGNED(width, 16)) {
187 I422ToYUY2Row = I422ToYUY2Row_NEON;
192 for (y = 0; y < height; ++y) {
193 I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
194 src_y += src_stride_y;
195 src_u += src_stride_u;
196 src_v += src_stride_v;
197 dst_yuy2 += dst_stride_yuy2;
203 int I420ToYUY2(const uint8* src_y, int src_stride_y,
204 const uint8* src_u, int src_stride_u,
205 const uint8* src_v, int src_stride_v,
206 uint8* dst_yuy2, int dst_stride_yuy2,
207 int width, int height) {
209 void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u,
210 const uint8* src_v, uint8* dst_yuy2, int width) =
212 if (!src_y || !src_u || !src_v || !dst_yuy2 ||
213 width <= 0 || height == 0) {
216 // Negative height means invert the image.
219 dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
220 dst_stride_yuy2 = -dst_stride_yuy2;
222 #if defined(HAS_I422TOYUY2ROW_SSE2)
223 if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
224 I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
225 if (IS_ALIGNED(width, 16)) {
226 I422ToYUY2Row = I422ToYUY2Row_SSE2;
229 #elif defined(HAS_I422TOYUY2ROW_NEON)
230 if (TestCpuFlag(kCpuHasNEON) && width >= 16) {
231 I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
232 if (IS_ALIGNED(width, 16)) {
233 I422ToYUY2Row = I422ToYUY2Row_NEON;
238 for (y = 0; y < height - 1; y += 2) {
239 I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
240 I422ToYUY2Row(src_y + src_stride_y, src_u, src_v,
241 dst_yuy2 + dst_stride_yuy2, width);
242 src_y += src_stride_y * 2;
243 src_u += src_stride_u;
244 src_v += src_stride_v;
245 dst_yuy2 += dst_stride_yuy2 * 2;
248 I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
254 int I422ToUYVY(const uint8* src_y, int src_stride_y,
255 const uint8* src_u, int src_stride_u,
256 const uint8* src_v, int src_stride_v,
257 uint8* dst_uyvy, int dst_stride_uyvy,
258 int width, int height) {
260 void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u,
261 const uint8* src_v, uint8* dst_uyvy, int width) =
263 if (!src_y || !src_u || !src_v || !dst_uyvy ||
264 width <= 0 || height == 0) {
267 // Negative height means invert the image.
270 dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
271 dst_stride_uyvy = -dst_stride_uyvy;
274 if (src_stride_y == width &&
275 src_stride_u * 2 == width &&
276 src_stride_v * 2 == width &&
277 dst_stride_uyvy == width * 2) {
280 src_stride_y = src_stride_u = src_stride_v = dst_stride_uyvy = 0;
282 #if defined(HAS_I422TOUYVYROW_SSE2)
283 if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
284 I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
285 if (IS_ALIGNED(width, 16)) {
286 I422ToUYVYRow = I422ToUYVYRow_SSE2;
289 #elif defined(HAS_I422TOUYVYROW_NEON)
290 if (TestCpuFlag(kCpuHasNEON) && width >= 16) {
291 I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
292 if (IS_ALIGNED(width, 16)) {
293 I422ToUYVYRow = I422ToUYVYRow_NEON;
298 for (y = 0; y < height; ++y) {
299 I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
300 src_y += src_stride_y;
301 src_u += src_stride_u;
302 src_v += src_stride_v;
303 dst_uyvy += dst_stride_uyvy;
309 int I420ToUYVY(const uint8* src_y, int src_stride_y,
310 const uint8* src_u, int src_stride_u,
311 const uint8* src_v, int src_stride_v,
312 uint8* dst_uyvy, int dst_stride_uyvy,
313 int width, int height) {
315 void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u,
316 const uint8* src_v, uint8* dst_uyvy, int width) =
318 if (!src_y || !src_u || !src_v || !dst_uyvy ||
319 width <= 0 || height == 0) {
322 // Negative height means invert the image.
325 dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
326 dst_stride_uyvy = -dst_stride_uyvy;
328 #if defined(HAS_I422TOUYVYROW_SSE2)
329 if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
330 I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
331 if (IS_ALIGNED(width, 16)) {
332 I422ToUYVYRow = I422ToUYVYRow_SSE2;
335 #elif defined(HAS_I422TOUYVYROW_NEON)
336 if (TestCpuFlag(kCpuHasNEON) && width >= 16) {
337 I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
338 if (IS_ALIGNED(width, 16)) {
339 I422ToUYVYRow = I422ToUYVYRow_NEON;
344 for (y = 0; y < height - 1; y += 2) {
345 I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
346 I422ToUYVYRow(src_y + src_stride_y, src_u, src_v,
347 dst_uyvy + dst_stride_uyvy, width);
348 src_y += src_stride_y * 2;
349 src_u += src_stride_u;
350 src_v += src_stride_v;
351 dst_uyvy += dst_stride_uyvy * 2;
354 I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
360 int I420ToNV12(const uint8* src_y, int src_stride_y,
361 const uint8* src_u, int src_stride_u,
362 const uint8* src_v, int src_stride_v,
363 uint8* dst_y, int dst_stride_y,
364 uint8* dst_uv, int dst_stride_uv,
365 int width, int height) {
367 void (*MergeUVRow_)(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
368 int width) = MergeUVRow_C;
370 int halfwidth = (width + 1) >> 1;
371 int halfheight = (height + 1) >> 1;
372 if (!src_y || !src_u || !src_v || !dst_y || !dst_uv ||
373 width <= 0 || height == 0) {
376 // Negative height means invert the image.
379 halfheight = (height + 1) >> 1;
380 dst_y = dst_y + (height - 1) * dst_stride_y;
381 dst_uv = dst_uv + (halfheight - 1) * dst_stride_uv;
382 dst_stride_y = -dst_stride_y;
383 dst_stride_uv = -dst_stride_uv;
385 if (src_stride_y == width &&
386 dst_stride_y == width) {
389 src_stride_y = dst_stride_y = 0;
392 if (src_stride_u == halfwidth &&
393 src_stride_v == halfwidth &&
394 dst_stride_uv == halfwidth * 2) {
395 halfwidth *= halfheight;
397 src_stride_u = src_stride_v = dst_stride_uv = 0;
399 #if defined(HAS_MERGEUVROW_SSE2)
400 if (TestCpuFlag(kCpuHasSSE2) && halfwidth >= 16) {
401 MergeUVRow_ = MergeUVRow_Any_SSE2;
402 if (IS_ALIGNED(halfwidth, 16)) {
403 MergeUVRow_ = MergeUVRow_Unaligned_SSE2;
404 if (IS_ALIGNED(src_u, 16) && IS_ALIGNED(src_stride_u, 16) &&
405 IS_ALIGNED(src_v, 16) && IS_ALIGNED(src_stride_v, 16) &&
406 IS_ALIGNED(dst_uv, 16) && IS_ALIGNED(dst_stride_uv, 16)) {
407 MergeUVRow_ = MergeUVRow_SSE2;
412 #if defined(HAS_MERGEUVROW_AVX2)
413 if (TestCpuFlag(kCpuHasAVX2) && halfwidth >= 32) {
414 MergeUVRow_ = MergeUVRow_Any_AVX2;
415 if (IS_ALIGNED(halfwidth, 32)) {
416 MergeUVRow_ = MergeUVRow_AVX2;
420 #if defined(HAS_MERGEUVROW_NEON)
421 if (TestCpuFlag(kCpuHasNEON) && halfwidth >= 16) {
422 MergeUVRow_ = MergeUVRow_Any_NEON;
423 if (IS_ALIGNED(halfwidth, 16)) {
424 MergeUVRow_ = MergeUVRow_NEON;
429 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
430 for (y = 0; y < halfheight; ++y) {
431 // Merge a row of U and V into a row of UV.
432 MergeUVRow_(src_u, src_v, dst_uv, halfwidth);
433 src_u += src_stride_u;
434 src_v += src_stride_v;
435 dst_uv += dst_stride_uv;
441 int I420ToNV21(const uint8* src_y, int src_stride_y,
442 const uint8* src_u, int src_stride_u,
443 const uint8* src_v, int src_stride_v,
444 uint8* dst_y, int dst_stride_y,
445 uint8* dst_vu, int dst_stride_vu,
446 int width, int height) {
447 return I420ToNV12(src_y, src_stride_y,
451 dst_vu, dst_stride_vu,
455 // Convert I420 to ARGB.
457 int I420ToARGB(const uint8* src_y, int src_stride_y,
458 const uint8* src_u, int src_stride_u,
459 const uint8* src_v, int src_stride_v,
460 uint8* dst_argb, int dst_stride_argb,
461 int width, int height) {
463 void (*I422ToARGBRow)(const uint8* y_buf,
467 int width) = I422ToARGBRow_C;
468 if (!src_y || !src_u || !src_v || !dst_argb ||
469 width <= 0 || height == 0) {
472 // Negative height means invert the image.
475 dst_argb = dst_argb + (height - 1) * dst_stride_argb;
476 dst_stride_argb = -dst_stride_argb;
478 #if defined(HAS_I422TOARGBROW_SSSE3)
479 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
480 I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
481 if (IS_ALIGNED(width, 8)) {
482 I422ToARGBRow = I422ToARGBRow_Unaligned_SSSE3;
483 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) {
484 I422ToARGBRow = I422ToARGBRow_SSSE3;
489 #if defined(HAS_I422TOARGBROW_AVX2)
490 if (TestCpuFlag(kCpuHasAVX2) && width >= 16) {
491 I422ToARGBRow = I422ToARGBRow_Any_AVX2;
492 if (IS_ALIGNED(width, 16)) {
493 I422ToARGBRow = I422ToARGBRow_AVX2;
497 #if defined(HAS_I422TOARGBROW_NEON)
498 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
499 I422ToARGBRow = I422ToARGBRow_Any_NEON;
500 if (IS_ALIGNED(width, 8)) {
501 I422ToARGBRow = I422ToARGBRow_NEON;
505 #if defined(HAS_I422TOARGBROW_MIPS_DSPR2)
506 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) &&
507 IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
508 IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
509 IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
510 IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) {
511 I422ToARGBRow = I422ToARGBRow_MIPS_DSPR2;
515 for (y = 0; y < height; ++y) {
516 I422ToARGBRow(src_y, src_u, src_v, dst_argb, width);
517 dst_argb += dst_stride_argb;
518 src_y += src_stride_y;
520 src_u += src_stride_u;
521 src_v += src_stride_v;
527 // Convert I420 to BGRA.
529 int I420ToBGRA(const uint8* src_y, int src_stride_y,
530 const uint8* src_u, int src_stride_u,
531 const uint8* src_v, int src_stride_v,
532 uint8* dst_bgra, int dst_stride_bgra,
533 int width, int height) {
535 void (*I422ToBGRARow)(const uint8* y_buf,
539 int width) = I422ToBGRARow_C;
540 if (!src_y || !src_u || !src_v || !dst_bgra ||
541 width <= 0 || height == 0) {
544 // Negative height means invert the image.
547 dst_bgra = dst_bgra + (height - 1) * dst_stride_bgra;
548 dst_stride_bgra = -dst_stride_bgra;
550 #if defined(HAS_I422TOBGRAROW_SSSE3)
551 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
552 I422ToBGRARow = I422ToBGRARow_Any_SSSE3;
553 if (IS_ALIGNED(width, 8)) {
554 I422ToBGRARow = I422ToBGRARow_Unaligned_SSSE3;
555 if (IS_ALIGNED(dst_bgra, 16) && IS_ALIGNED(dst_stride_bgra, 16)) {
556 I422ToBGRARow = I422ToBGRARow_SSSE3;
560 #elif defined(HAS_I422TOBGRAROW_NEON)
561 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
562 I422ToBGRARow = I422ToBGRARow_Any_NEON;
563 if (IS_ALIGNED(width, 8)) {
564 I422ToBGRARow = I422ToBGRARow_NEON;
567 #elif defined(HAS_I422TOBGRAROW_MIPS_DSPR2)
568 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) &&
569 IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
570 IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
571 IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
572 IS_ALIGNED(dst_bgra, 4) && IS_ALIGNED(dst_stride_bgra, 4)) {
573 I422ToBGRARow = I422ToBGRARow_MIPS_DSPR2;
577 for (y = 0; y < height; ++y) {
578 I422ToBGRARow(src_y, src_u, src_v, dst_bgra, width);
579 dst_bgra += dst_stride_bgra;
580 src_y += src_stride_y;
582 src_u += src_stride_u;
583 src_v += src_stride_v;
589 // Convert I420 to ABGR.
591 int I420ToABGR(const uint8* src_y, int src_stride_y,
592 const uint8* src_u, int src_stride_u,
593 const uint8* src_v, int src_stride_v,
594 uint8* dst_abgr, int dst_stride_abgr,
595 int width, int height) {
597 void (*I422ToABGRRow)(const uint8* y_buf,
601 int width) = I422ToABGRRow_C;
602 if (!src_y || !src_u || !src_v || !dst_abgr ||
603 width <= 0 || height == 0) {
606 // Negative height means invert the image.
609 dst_abgr = dst_abgr + (height - 1) * dst_stride_abgr;
610 dst_stride_abgr = -dst_stride_abgr;
612 #if defined(HAS_I422TOABGRROW_SSSE3)
613 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
614 I422ToABGRRow = I422ToABGRRow_Any_SSSE3;
615 if (IS_ALIGNED(width, 8)) {
616 I422ToABGRRow = I422ToABGRRow_Unaligned_SSSE3;
617 if (IS_ALIGNED(dst_abgr, 16) && IS_ALIGNED(dst_stride_abgr, 16)) {
618 I422ToABGRRow = I422ToABGRRow_SSSE3;
622 #elif defined(HAS_I422TOABGRROW_NEON)
623 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
624 I422ToABGRRow = I422ToABGRRow_Any_NEON;
625 if (IS_ALIGNED(width, 8)) {
626 I422ToABGRRow = I422ToABGRRow_NEON;
631 for (y = 0; y < height; ++y) {
632 I422ToABGRRow(src_y, src_u, src_v, dst_abgr, width);
633 dst_abgr += dst_stride_abgr;
634 src_y += src_stride_y;
636 src_u += src_stride_u;
637 src_v += src_stride_v;
643 // Convert I420 to RGBA.
645 int I420ToRGBA(const uint8* src_y, int src_stride_y,
646 const uint8* src_u, int src_stride_u,
647 const uint8* src_v, int src_stride_v,
648 uint8* dst_rgba, int dst_stride_rgba,
649 int width, int height) {
651 void (*I422ToRGBARow)(const uint8* y_buf,
655 int width) = I422ToRGBARow_C;
656 if (!src_y || !src_u || !src_v || !dst_rgba ||
657 width <= 0 || height == 0) {
660 // Negative height means invert the image.
663 dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
664 dst_stride_rgba = -dst_stride_rgba;
666 #if defined(HAS_I422TORGBAROW_SSSE3)
667 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
668 I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
669 if (IS_ALIGNED(width, 8)) {
670 I422ToRGBARow = I422ToRGBARow_Unaligned_SSSE3;
671 if (IS_ALIGNED(dst_rgba, 16) && IS_ALIGNED(dst_stride_rgba, 16)) {
672 I422ToRGBARow = I422ToRGBARow_SSSE3;
676 #elif defined(HAS_I422TORGBAROW_NEON)
677 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
678 I422ToRGBARow = I422ToRGBARow_Any_NEON;
679 if (IS_ALIGNED(width, 8)) {
680 I422ToRGBARow = I422ToRGBARow_NEON;
685 for (y = 0; y < height; ++y) {
686 I422ToRGBARow(src_y, src_u, src_v, dst_rgba, width);
687 dst_rgba += dst_stride_rgba;
688 src_y += src_stride_y;
690 src_u += src_stride_u;
691 src_v += src_stride_v;
697 // Convert I420 to RGB24.
699 int I420ToRGB24(const uint8* src_y, int src_stride_y,
700 const uint8* src_u, int src_stride_u,
701 const uint8* src_v, int src_stride_v,
702 uint8* dst_rgb24, int dst_stride_rgb24,
703 int width, int height) {
705 void (*I422ToRGB24Row)(const uint8* y_buf,
709 int width) = I422ToRGB24Row_C;
710 if (!src_y || !src_u || !src_v || !dst_rgb24 ||
711 width <= 0 || height == 0) {
714 // Negative height means invert the image.
717 dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
718 dst_stride_rgb24 = -dst_stride_rgb24;
720 #if defined(HAS_I422TORGB24ROW_SSSE3)
721 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
722 I422ToRGB24Row = I422ToRGB24Row_Any_SSSE3;
723 if (IS_ALIGNED(width, 8)) {
724 I422ToRGB24Row = I422ToRGB24Row_SSSE3;
727 #elif defined(HAS_I422TORGB24ROW_NEON)
728 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
729 I422ToRGB24Row = I422ToRGB24Row_Any_NEON;
730 if (IS_ALIGNED(width, 8)) {
731 I422ToRGB24Row = I422ToRGB24Row_NEON;
736 for (y = 0; y < height; ++y) {
737 I422ToRGB24Row(src_y, src_u, src_v, dst_rgb24, width);
738 dst_rgb24 += dst_stride_rgb24;
739 src_y += src_stride_y;
741 src_u += src_stride_u;
742 src_v += src_stride_v;
748 // Convert I420 to RAW.
750 int I420ToRAW(const uint8* src_y, int src_stride_y,
751 const uint8* src_u, int src_stride_u,
752 const uint8* src_v, int src_stride_v,
753 uint8* dst_raw, int dst_stride_raw,
754 int width, int height) {
756 void (*I422ToRAWRow)(const uint8* y_buf,
760 int width) = I422ToRAWRow_C;
761 if (!src_y || !src_u || !src_v || !dst_raw ||
762 width <= 0 || height == 0) {
765 // Negative height means invert the image.
768 dst_raw = dst_raw + (height - 1) * dst_stride_raw;
769 dst_stride_raw = -dst_stride_raw;
771 #if defined(HAS_I422TORAWROW_SSSE3)
772 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
773 I422ToRAWRow = I422ToRAWRow_Any_SSSE3;
774 if (IS_ALIGNED(width, 8)) {
775 I422ToRAWRow = I422ToRAWRow_SSSE3;
778 #elif defined(HAS_I422TORAWROW_NEON)
779 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
780 I422ToRAWRow = I422ToRAWRow_Any_NEON;
781 if (IS_ALIGNED(width, 8)) {
782 I422ToRAWRow = I422ToRAWRow_NEON;
787 for (y = 0; y < height; ++y) {
788 I422ToRAWRow(src_y, src_u, src_v, dst_raw, width);
789 dst_raw += dst_stride_raw;
790 src_y += src_stride_y;
792 src_u += src_stride_u;
793 src_v += src_stride_v;
799 // Convert I420 to ARGB1555.
801 int I420ToARGB1555(const uint8* src_y, int src_stride_y,
802 const uint8* src_u, int src_stride_u,
803 const uint8* src_v, int src_stride_v,
804 uint8* dst_argb1555, int dst_stride_argb1555,
805 int width, int height) {
807 void (*I422ToARGB1555Row)(const uint8* y_buf,
811 int width) = I422ToARGB1555Row_C;
812 if (!src_y || !src_u || !src_v || !dst_argb1555 ||
813 width <= 0 || height == 0) {
816 // Negative height means invert the image.
819 dst_argb1555 = dst_argb1555 + (height - 1) * dst_stride_argb1555;
820 dst_stride_argb1555 = -dst_stride_argb1555;
822 #if defined(HAS_I422TOARGB1555ROW_SSSE3)
823 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
824 I422ToARGB1555Row = I422ToARGB1555Row_Any_SSSE3;
825 if (IS_ALIGNED(width, 8)) {
826 I422ToARGB1555Row = I422ToARGB1555Row_SSSE3;
829 #elif defined(HAS_I422TOARGB1555ROW_NEON)
830 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
831 I422ToARGB1555Row = I422ToARGB1555Row_Any_NEON;
832 if (IS_ALIGNED(width, 8)) {
833 I422ToARGB1555Row = I422ToARGB1555Row_NEON;
838 for (y = 0; y < height; ++y) {
839 I422ToARGB1555Row(src_y, src_u, src_v, dst_argb1555, width);
840 dst_argb1555 += dst_stride_argb1555;
841 src_y += src_stride_y;
843 src_u += src_stride_u;
844 src_v += src_stride_v;
851 // Convert I420 to ARGB4444.
853 int I420ToARGB4444(const uint8* src_y, int src_stride_y,
854 const uint8* src_u, int src_stride_u,
855 const uint8* src_v, int src_stride_v,
856 uint8* dst_argb4444, int dst_stride_argb4444,
857 int width, int height) {
859 void (*I422ToARGB4444Row)(const uint8* y_buf,
863 int width) = I422ToARGB4444Row_C;
864 if (!src_y || !src_u || !src_v || !dst_argb4444 ||
865 width <= 0 || height == 0) {
868 // Negative height means invert the image.
871 dst_argb4444 = dst_argb4444 + (height - 1) * dst_stride_argb4444;
872 dst_stride_argb4444 = -dst_stride_argb4444;
874 #if defined(HAS_I422TOARGB4444ROW_SSSE3)
875 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
876 I422ToARGB4444Row = I422ToARGB4444Row_Any_SSSE3;
877 if (IS_ALIGNED(width, 8)) {
878 I422ToARGB4444Row = I422ToARGB4444Row_SSSE3;
881 #elif defined(HAS_I422TOARGB4444ROW_NEON)
882 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
883 I422ToARGB4444Row = I422ToARGB4444Row_Any_NEON;
884 if (IS_ALIGNED(width, 8)) {
885 I422ToARGB4444Row = I422ToARGB4444Row_NEON;
890 for (y = 0; y < height; ++y) {
891 I422ToARGB4444Row(src_y, src_u, src_v, dst_argb4444, width);
892 dst_argb4444 += dst_stride_argb4444;
893 src_y += src_stride_y;
895 src_u += src_stride_u;
896 src_v += src_stride_v;
902 // Convert I420 to RGB565.
904 int I420ToRGB565(const uint8* src_y, int src_stride_y,
905 const uint8* src_u, int src_stride_u,
906 const uint8* src_v, int src_stride_v,
907 uint8* dst_rgb565, int dst_stride_rgb565,
908 int width, int height) {
910 void (*I422ToRGB565Row)(const uint8* y_buf,
914 int width) = I422ToRGB565Row_C;
915 if (!src_y || !src_u || !src_v || !dst_rgb565 ||
916 width <= 0 || height == 0) {
919 // Negative height means invert the image.
922 dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
923 dst_stride_rgb565 = -dst_stride_rgb565;
925 #if defined(HAS_I422TORGB565ROW_SSSE3)
926 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) {
927 I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
928 if (IS_ALIGNED(width, 8)) {
929 I422ToRGB565Row = I422ToRGB565Row_SSSE3;
932 #elif defined(HAS_I422TORGB565ROW_NEON)
933 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
934 I422ToRGB565Row = I422ToRGB565Row_Any_NEON;
935 if (IS_ALIGNED(width, 8)) {
936 I422ToRGB565Row = I422ToRGB565Row_NEON;
941 for (y = 0; y < height; ++y) {
942 I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, width);
943 dst_rgb565 += dst_stride_rgb565;
944 src_y += src_stride_y;
946 src_u += src_stride_u;
947 src_v += src_stride_v;
953 // Convert I420 to specified format
955 int ConvertFromI420(const uint8* y, int y_stride,
956 const uint8* u, int u_stride,
957 const uint8* v, int v_stride,
958 uint8* dst_sample, int dst_sample_stride,
959 int width, int height,
961 uint32 format = CanonicalFourCC(fourcc);
963 if (!y || !u|| !v || !dst_sample ||
964 width <= 0 || height == 0) {
968 // Single plane formats
970 r = I420ToYUY2(y, y_stride,
974 dst_sample_stride ? dst_sample_stride : width * 2,
978 r = I420ToUYVY(y, y_stride,
982 dst_sample_stride ? dst_sample_stride : width * 2,
986 r = I420ToRGB565(y, y_stride,
990 dst_sample_stride ? dst_sample_stride : width * 2,
994 r = I420ToARGB1555(y, y_stride,
998 dst_sample_stride ? dst_sample_stride : width * 2,
1002 r = I420ToARGB4444(y, y_stride,
1006 dst_sample_stride ? dst_sample_stride : width * 2,
1010 r = I420ToRGB24(y, y_stride,
1014 dst_sample_stride ? dst_sample_stride : width * 3,
1018 r = I420ToRAW(y, y_stride,
1022 dst_sample_stride ? dst_sample_stride : width * 3,
1026 r = I420ToARGB(y, y_stride,
1030 dst_sample_stride ? dst_sample_stride : width * 4,
1034 r = I420ToBGRA(y, y_stride,
1038 dst_sample_stride ? dst_sample_stride : width * 4,
1042 r = I420ToABGR(y, y_stride,
1046 dst_sample_stride ? dst_sample_stride : width * 4,
1050 r = I420ToRGBA(y, y_stride,
1054 dst_sample_stride ? dst_sample_stride : width * 4,
1058 r = I420ToBayerBGGR(y, y_stride,
1062 dst_sample_stride ? dst_sample_stride : width,
1066 r = I420ToBayerGBRG(y, y_stride,
1070 dst_sample_stride ? dst_sample_stride : width,
1074 r = I420ToBayerGRBG(y, y_stride,
1078 dst_sample_stride ? dst_sample_stride : width,
1082 r = I420ToBayerRGGB(y, y_stride,
1086 dst_sample_stride ? dst_sample_stride : width,
1090 r = I400Copy(y, y_stride,
1092 dst_sample_stride ? dst_sample_stride : width,
1096 uint8* dst_uv = dst_sample + width * height;
1097 r = I420ToNV12(y, y_stride,
1101 dst_sample_stride ? dst_sample_stride : width,
1103 dst_sample_stride ? dst_sample_stride : width,
1108 uint8* dst_vu = dst_sample + width * height;
1109 r = I420ToNV21(y, y_stride,
1113 dst_sample_stride ? dst_sample_stride : width,
1115 dst_sample_stride ? dst_sample_stride : width,
1119 // TODO(fbarchard): Add M420 and Q420.
1120 // Triplanar formats
1121 // TODO(fbarchard): halfstride instead of halfwidth
1125 int halfwidth = (width + 1) / 2;
1126 int halfheight = (height + 1) / 2;
1129 if (format == FOURCC_YV12) {
1130 dst_v = dst_sample + width * height;
1131 dst_u = dst_v + halfwidth * halfheight;
1133 dst_u = dst_sample + width * height;
1134 dst_v = dst_u + halfwidth * halfheight;
1136 r = I420Copy(y, y_stride,
1147 int halfwidth = (width + 1) / 2;
1150 if (format == FOURCC_YV16) {
1151 dst_v = dst_sample + width * height;
1152 dst_u = dst_v + halfwidth * height;
1154 dst_u = dst_sample + width * height;
1155 dst_v = dst_u + halfwidth * height;
1157 r = I420ToI422(y, y_stride,
1170 if (format == FOURCC_YV24) {
1171 dst_v = dst_sample + width * height;
1172 dst_u = dst_v + width * height;
1174 dst_u = dst_sample + width * height;
1175 dst_v = dst_u + width * height;
1177 r = I420ToI444(y, y_stride,
1187 int quarterwidth = (width + 3) / 4;
1188 uint8* dst_u = dst_sample + width * height;
1189 uint8* dst_v = dst_u + quarterwidth * height;
1190 r = I420ToI411(y, y_stride,
1194 dst_u, quarterwidth,
1195 dst_v, quarterwidth,
1200 // Formats not supported - MJPG, biplanar, some rgb formats.
1202 return -1; // unknown fourcc - return failure code.
1209 } // namespace libyuv