Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /*
2 * Copyright 2011 The LibYuv Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
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"
20 #ifdef __cplusplus
21 namespace libyuv {
22 extern "C" {
23 #endif
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;
28 }
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 if (src_y_width == 0 || src_y_height == 0 ||
40 src_uv_width == 0 || src_uv_height == 0) {
41 return -1;
42 }
43 const int dst_y_width = Abs(src_y_width);
44 const int dst_y_height = Abs(src_y_height);
45 const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
46 const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
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,
49 kFilterBilinear);
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,
52 kFilterBilinear);
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,
55 kFilterBilinear);
56 return 0;
57 }
59 // Copy I420 with optional flipping
60 // TODO(fbarchard): Use Scale plane which supports mirroring, but ensure
61 // is does row coalescing.
62 LIBYUV_API
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 if (!src_y || !src_u || !src_v ||
71 !dst_y || !dst_u || !dst_v ||
72 width <= 0 || height == 0) {
73 return -1;
74 }
75 // Negative height means invert the image.
76 if (height < 0) {
77 height = -height;
78 const int halfheight = (height + 1) >> 1;
79 src_y = src_y + (height - 1) * src_stride_y;
80 src_u = src_u + (halfheight - 1) * src_stride_u;
81 src_v = src_v + (halfheight - 1) * src_stride_v;
82 src_stride_y = -src_stride_y;
83 src_stride_u = -src_stride_u;
84 src_stride_v = -src_stride_v;
85 }
87 if (dst_y) {
88 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
89 }
90 // Copy UV planes.
91 const int halfwidth = (width + 1) >> 1;
92 const int halfheight = (height + 1) >> 1;
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);
95 return 0;
96 }
98 // 422 chroma is 1/2 width, 1x height
99 // 420 chroma is 1/2 width, 1/2 height
100 LIBYUV_API
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,
110 src_u, src_stride_u,
111 src_v, src_stride_v,
112 dst_y, dst_stride_y,
113 dst_u, dst_stride_u,
114 dst_v, dst_stride_v,
115 width, height,
116 src_uv_width, height);
117 }
119 // 444 chroma is 1x width, 1x height
120 // 420 chroma is 1/2 width, 1/2 height
121 LIBYUV_API
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,
130 src_u, src_stride_u,
131 src_v, src_stride_v,
132 dst_y, dst_stride_y,
133 dst_u, dst_stride_u,
134 dst_v, dst_stride_v,
135 width, height,
136 width, height);
137 }
139 // 411 chroma is 1/4 width, 1x height
140 // 420 chroma is 1/2 width, 1/2 height
141 LIBYUV_API
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,
151 src_u, src_stride_u,
152 src_v, src_stride_v,
153 dst_y, dst_stride_y,
154 dst_u, dst_stride_u,
155 dst_v, dst_stride_v,
156 width, height,
157 src_uv_width, height);
158 }
160 // I400 is greyscale typically used in MJPG
161 LIBYUV_API
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 if (!src_y || !dst_y || !dst_u || !dst_v ||
168 width <= 0 || height == 0) {
169 return -1;
170 }
171 // Negative height means invert the image.
172 if (height < 0) {
173 height = -height;
174 src_y = src_y + (height - 1) * src_stride_y;
175 src_stride_y = -src_stride_y;
176 }
177 int halfwidth = (width + 1) >> 1;
178 int halfheight = (height + 1) >> 1;
179 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
180 SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128);
181 SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128);
182 return 0;
183 }
185 static void CopyPlane2(const uint8* src, int src_stride_0, int src_stride_1,
186 uint8* dst, int dst_stride,
187 int width, int height) {
188 void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
189 #if defined(HAS_COPYROW_X86)
190 if (TestCpuFlag(kCpuHasX86) && IS_ALIGNED(width, 4)) {
191 CopyRow = CopyRow_X86;
192 }
193 #endif
194 #if defined(HAS_COPYROW_SSE2)
195 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
196 IS_ALIGNED(src, 16) &&
197 IS_ALIGNED(src_stride_0, 16) && IS_ALIGNED(src_stride_1, 16) &&
198 IS_ALIGNED(dst, 16) && IS_ALIGNED(dst_stride, 16)) {
199 CopyRow = CopyRow_SSE2;
200 }
201 #endif
202 #if defined(HAS_COPYROW_ERMS)
203 if (TestCpuFlag(kCpuHasERMS)) {
204 CopyRow = CopyRow_ERMS;
205 }
206 #endif
207 #if defined(HAS_COPYROW_NEON)
208 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
209 CopyRow = CopyRow_NEON;
210 }
211 #endif
212 #if defined(HAS_COPYROW_MIPS)
213 if (TestCpuFlag(kCpuHasMIPS)) {
214 CopyRow = CopyRow_MIPS;
215 }
216 #endif
218 // Copy plane
219 for (int y = 0; y < height - 1; y += 2) {
220 CopyRow(src, dst, width);
221 CopyRow(src + src_stride_0, dst + dst_stride, width);
222 src += src_stride_0 + src_stride_1;
223 dst += dst_stride * 2;
224 }
225 if (height & 1) {
226 CopyRow(src, dst, width);
227 }
228 }
230 // Support converting from FOURCC_M420
231 // Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for
232 // easy conversion to I420.
233 // M420 format description:
234 // M420 is row biplanar 420: 2 rows of Y and 1 row of UV.
235 // Chroma is half width / half height. (420)
236 // src_stride_m420 is row planar. Normally this will be the width in pixels.
237 // The UV plane is half width, but 2 values, so src_stride_m420 applies to
238 // this as well as the two Y planes.
239 static int X420ToI420(const uint8* src_y,
240 int src_stride_y0, int src_stride_y1,
241 const uint8* src_uv, int src_stride_uv,
242 uint8* dst_y, int dst_stride_y,
243 uint8* dst_u, int dst_stride_u,
244 uint8* dst_v, int dst_stride_v,
245 int width, int height) {
246 if (!src_y || !src_uv ||
247 !dst_y || !dst_u || !dst_v ||
248 width <= 0 || height == 0) {
249 return -1;
250 }
251 // Negative height means invert the image.
252 if (height < 0) {
253 height = -height;
254 int halfheight = (height + 1) >> 1;
255 dst_y = dst_y + (height - 1) * dst_stride_y;
256 dst_u = dst_u + (halfheight - 1) * dst_stride_u;
257 dst_v = dst_v + (halfheight - 1) * dst_stride_v;
258 dst_stride_y = -dst_stride_y;
259 dst_stride_u = -dst_stride_u;
260 dst_stride_v = -dst_stride_v;
261 }
262 // Coalesce rows.
263 int halfwidth = (width + 1) >> 1;
264 int halfheight = (height + 1) >> 1;
265 if (src_stride_y0 == width &&
266 src_stride_y1 == width &&
267 dst_stride_y == width) {
268 width *= height;
269 height = 1;
270 src_stride_y0 = src_stride_y1 = dst_stride_y = 0;
271 }
272 // Coalesce rows.
273 if (src_stride_uv == halfwidth * 2 &&
274 dst_stride_u == halfwidth &&
275 dst_stride_v == halfwidth) {
276 halfwidth *= halfheight;
277 halfheight = 1;
278 src_stride_uv = dst_stride_u = dst_stride_v = 0;
279 }
280 void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix) =
281 SplitUVRow_C;
282 #if defined(HAS_SPLITUVROW_SSE2)
283 if (TestCpuFlag(kCpuHasSSE2) && halfwidth >= 16) {
284 SplitUVRow = SplitUVRow_Any_SSE2;
285 if (IS_ALIGNED(halfwidth, 16)) {
286 SplitUVRow = SplitUVRow_Unaligned_SSE2;
287 if (IS_ALIGNED(src_uv, 16) && IS_ALIGNED(src_stride_uv, 16) &&
288 IS_ALIGNED(dst_u, 16) && IS_ALIGNED(dst_stride_u, 16) &&
289 IS_ALIGNED(dst_v, 16) && IS_ALIGNED(dst_stride_v, 16)) {
290 SplitUVRow = SplitUVRow_SSE2;
291 }
292 }
293 }
294 #endif
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;
300 }
301 }
302 #endif
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;
308 }
309 }
310 #endif
311 #if defined(HAS_SPLITUVROW_MIPS_DSPR2)
312 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && halfwidth >= 16) {
313 SplitUVRow = SplitUVRow_Any_MIPS_DSPR2;
314 if (IS_ALIGNED(halfwidth, 16)) {
315 SplitUVRow = SplitUVRow_Unaligned_MIPS_DSPR2;
316 if (IS_ALIGNED(src_uv, 4) && IS_ALIGNED(src_stride_uv, 4) &&
317 IS_ALIGNED(dst_u, 4) && IS_ALIGNED(dst_stride_u, 4) &&
318 IS_ALIGNED(dst_v, 4) && IS_ALIGNED(dst_stride_v, 4)) {
319 SplitUVRow = SplitUVRow_MIPS_DSPR2;
320 }
321 }
322 }
323 #endif
325 if (dst_y) {
326 if (src_stride_y0 == src_stride_y1) {
327 CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height);
328 } else {
329 CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y,
330 width, height);
331 }
332 }
334 for (int y = 0; y < halfheight; ++y) {
335 // Copy a row of UV.
336 SplitUVRow(src_uv, dst_u, dst_v, halfwidth);
337 dst_u += dst_stride_u;
338 dst_v += dst_stride_v;
339 src_uv += src_stride_uv;
340 }
341 return 0;
342 }
344 // Convert NV12 to I420.
345 LIBYUV_API
346 int NV12ToI420(const uint8* src_y, int src_stride_y,
347 const uint8* src_uv, int src_stride_uv,
348 uint8* dst_y, int dst_stride_y,
349 uint8* dst_u, int dst_stride_u,
350 uint8* dst_v, int dst_stride_v,
351 int width, int height) {
352 return X420ToI420(src_y, src_stride_y, src_stride_y,
353 src_uv, src_stride_uv,
354 dst_y, dst_stride_y,
355 dst_u, dst_stride_u,
356 dst_v, dst_stride_v,
357 width, height);
358 }
360 // Convert NV21 to I420. Same as NV12 but u and v pointers swapped.
361 LIBYUV_API
362 int NV21ToI420(const uint8* src_y, int src_stride_y,
363 const uint8* src_vu, int src_stride_vu,
364 uint8* dst_y, int dst_stride_y,
365 uint8* dst_u, int dst_stride_u,
366 uint8* dst_v, int dst_stride_v,
367 int width, int height) {
368 return X420ToI420(src_y, src_stride_y, src_stride_y,
369 src_vu, src_stride_vu,
370 dst_y, dst_stride_y,
371 dst_v, dst_stride_v,
372 dst_u, dst_stride_u,
373 width, height);
374 }
376 // Convert M420 to I420.
377 LIBYUV_API
378 int M420ToI420(const uint8* src_m420, int src_stride_m420,
379 uint8* dst_y, int dst_stride_y,
380 uint8* dst_u, int dst_stride_u,
381 uint8* dst_v, int dst_stride_v,
382 int width, int height) {
383 return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2,
384 src_m420 + src_stride_m420 * 2, src_stride_m420 * 3,
385 dst_y, dst_stride_y,
386 dst_u, dst_stride_u,
387 dst_v, dst_stride_v,
388 width, height);
389 }
391 // Convert Q420 to I420.
392 // Format is rows of YY/YUYV
393 LIBYUV_API
394 int Q420ToI420(const uint8* src_y, int src_stride_y,
395 const uint8* src_yuy2, int src_stride_yuy2,
396 uint8* dst_y, int dst_stride_y,
397 uint8* dst_u, int dst_stride_u,
398 uint8* dst_v, int dst_stride_v,
399 int width, int height) {
400 if (!src_y || !src_yuy2 ||
401 !dst_y || !dst_u || !dst_v ||
402 width <= 0 || height == 0) {
403 return -1;
404 }
405 // Negative height means invert the image.
406 if (height < 0) {
407 height = -height;
408 int halfheight = (height + 1) >> 1;
409 dst_y = dst_y + (height - 1) * dst_stride_y;
410 dst_u = dst_u + (halfheight - 1) * dst_stride_u;
411 dst_v = dst_v + (halfheight - 1) * dst_stride_v;
412 dst_stride_y = -dst_stride_y;
413 dst_stride_u = -dst_stride_u;
414 dst_stride_v = -dst_stride_v;
415 }
416 // CopyRow for rows of just Y in Q420 copied to Y plane of I420.
417 void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
418 #if defined(HAS_COPYROW_NEON)
419 if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
420 CopyRow = CopyRow_NEON;
421 }
422 #endif
423 #if defined(HAS_COPYROW_X86)
424 if (IS_ALIGNED(width, 4)) {
425 CopyRow = CopyRow_X86;
426 }
427 #endif
428 #if defined(HAS_COPYROW_SSE2)
429 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32) &&
430 IS_ALIGNED(src_y, 16) && IS_ALIGNED(src_stride_y, 16) &&
431 IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
432 CopyRow = CopyRow_SSE2;
433 }
434 #endif
435 #if defined(HAS_COPYROW_ERMS)
436 if (TestCpuFlag(kCpuHasERMS)) {
437 CopyRow = CopyRow_ERMS;
438 }
439 #endif
440 #if defined(HAS_COPYROW_MIPS)
441 if (TestCpuFlag(kCpuHasMIPS)) {
442 CopyRow = CopyRow_MIPS;
443 }
444 #endif
446 void (*YUY2ToUV422Row)(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v,
447 int pix) = YUY2ToUV422Row_C;
448 void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int pix) =
449 YUY2ToYRow_C;
450 #if defined(HAS_YUY2TOYROW_SSE2)
451 if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
452 YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2;
453 YUY2ToYRow = YUY2ToYRow_Any_SSE2;
454 if (IS_ALIGNED(width, 16)) {
455 YUY2ToUV422Row = YUY2ToUV422Row_Unaligned_SSE2;
456 YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
457 if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
458 YUY2ToUV422Row = YUY2ToUV422Row_SSE2;
459 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
460 YUY2ToYRow = YUY2ToYRow_SSE2;
461 }
462 }
463 }
464 }
465 #endif
466 #if defined(HAS_YUY2TOYROW_AVX2)
467 if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
468 YUY2ToUV422Row = YUY2ToUV422Row_Any_AVX2;
469 YUY2ToYRow = YUY2ToYRow_Any_AVX2;
470 if (IS_ALIGNED(width, 32)) {
471 YUY2ToUV422Row = YUY2ToUV422Row_AVX2;
472 YUY2ToYRow = YUY2ToYRow_AVX2;
473 }
474 }
475 #endif
476 #if defined(HAS_YUY2TOYROW_NEON)
477 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
478 YUY2ToYRow = YUY2ToYRow_Any_NEON;
479 if (width >= 16) {
480 YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON;
481 }
482 if (IS_ALIGNED(width, 16)) {
483 YUY2ToYRow = YUY2ToYRow_NEON;
484 YUY2ToUV422Row = YUY2ToUV422Row_NEON;
485 }
486 }
487 #endif
489 for (int y = 0; y < height - 1; y += 2) {
490 CopyRow(src_y, dst_y, width);
491 src_y += src_stride_y;
492 dst_y += dst_stride_y;
494 YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
495 YUY2ToYRow(src_yuy2, dst_y, width);
496 src_yuy2 += src_stride_yuy2;
497 dst_y += dst_stride_y;
498 dst_u += dst_stride_u;
499 dst_v += dst_stride_v;
500 }
501 if (height & 1) {
502 CopyRow(src_y, dst_y, width);
503 YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
504 }
505 return 0;
506 }
508 // Convert YUY2 to I420.
509 LIBYUV_API
510 int YUY2ToI420(const uint8* src_yuy2, int src_stride_yuy2,
511 uint8* dst_y, int dst_stride_y,
512 uint8* dst_u, int dst_stride_u,
513 uint8* dst_v, int dst_stride_v,
514 int width, int height) {
515 // Negative height means invert the image.
516 if (height < 0) {
517 height = -height;
518 src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
519 src_stride_yuy2 = -src_stride_yuy2;
520 }
521 void (*YUY2ToUVRow)(const uint8* src_yuy2, int src_stride_yuy2,
522 uint8* dst_u, uint8* dst_v, int pix);
523 void (*YUY2ToYRow)(const uint8* src_yuy2,
524 uint8* dst_y, int pix);
525 YUY2ToYRow = YUY2ToYRow_C;
526 YUY2ToUVRow = YUY2ToUVRow_C;
527 #if defined(HAS_YUY2TOYROW_SSE2)
528 if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
529 YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
530 YUY2ToYRow = YUY2ToYRow_Any_SSE2;
531 if (IS_ALIGNED(width, 16)) {
532 YUY2ToUVRow = YUY2ToUVRow_Unaligned_SSE2;
533 YUY2ToYRow = YUY2ToYRow_Unaligned_SSE2;
534 if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16)) {
535 YUY2ToUVRow = YUY2ToUVRow_SSE2;
536 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
537 YUY2ToYRow = YUY2ToYRow_SSE2;
538 }
539 }
540 }
541 }
542 #endif
543 #if defined(HAS_YUY2TOYROW_AVX2)
544 if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
545 YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
546 YUY2ToYRow = YUY2ToYRow_Any_AVX2;
547 if (IS_ALIGNED(width, 32)) {
548 YUY2ToUVRow = YUY2ToUVRow_AVX2;
549 YUY2ToYRow = YUY2ToYRow_AVX2;
550 }
551 }
552 #endif
553 #if defined(HAS_YUY2TOYROW_NEON)
554 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
555 YUY2ToYRow = YUY2ToYRow_Any_NEON;
556 if (width >= 16) {
557 YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
558 }
559 if (IS_ALIGNED(width, 16)) {
560 YUY2ToYRow = YUY2ToYRow_NEON;
561 YUY2ToUVRow = YUY2ToUVRow_NEON;
562 }
563 }
564 #endif
566 for (int y = 0; y < height - 1; y += 2) {
567 YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
568 YUY2ToYRow(src_yuy2, dst_y, width);
569 YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
570 src_yuy2 += src_stride_yuy2 * 2;
571 dst_y += dst_stride_y * 2;
572 dst_u += dst_stride_u;
573 dst_v += dst_stride_v;
574 }
575 if (height & 1) {
576 YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
577 YUY2ToYRow(src_yuy2, dst_y, width);
578 }
579 return 0;
580 }
582 // Convert UYVY to I420.
583 LIBYUV_API
584 int UYVYToI420(const uint8* src_uyvy, int src_stride_uyvy,
585 uint8* dst_y, int dst_stride_y,
586 uint8* dst_u, int dst_stride_u,
587 uint8* dst_v, int dst_stride_v,
588 int width, int height) {
589 // Negative height means invert the image.
590 if (height < 0) {
591 height = -height;
592 src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
593 src_stride_uyvy = -src_stride_uyvy;
594 }
595 void (*UYVYToUVRow)(const uint8* src_uyvy, int src_stride_uyvy,
596 uint8* dst_u, uint8* dst_v, int pix);
597 void (*UYVYToYRow)(const uint8* src_uyvy,
598 uint8* dst_y, int pix);
599 UYVYToYRow = UYVYToYRow_C;
600 UYVYToUVRow = UYVYToUVRow_C;
601 #if defined(HAS_UYVYTOYROW_SSE2)
602 if (TestCpuFlag(kCpuHasSSE2) && width >= 16) {
603 UYVYToUVRow = UYVYToUVRow_Any_SSE2;
604 UYVYToYRow = UYVYToYRow_Any_SSE2;
605 if (IS_ALIGNED(width, 16)) {
606 UYVYToUVRow = UYVYToUVRow_Unaligned_SSE2;
607 UYVYToYRow = UYVYToYRow_Unaligned_SSE2;
608 if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16)) {
609 UYVYToUVRow = UYVYToUVRow_SSE2;
610 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
611 UYVYToYRow = UYVYToYRow_SSE2;
612 }
613 }
614 }
615 }
616 #endif
617 #if defined(HAS_UYVYTOYROW_AVX2)
618 if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
619 UYVYToUVRow = UYVYToUVRow_Any_AVX2;
620 UYVYToYRow = UYVYToYRow_Any_AVX2;
621 if (IS_ALIGNED(width, 32)) {
622 UYVYToUVRow = UYVYToUVRow_AVX2;
623 UYVYToYRow = UYVYToYRow_AVX2;
624 }
625 }
626 #endif
627 #if defined(HAS_UYVYTOYROW_NEON)
628 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
629 UYVYToYRow = UYVYToYRow_Any_NEON;
630 if (width >= 16) {
631 UYVYToUVRow = UYVYToUVRow_Any_NEON;
632 }
633 if (IS_ALIGNED(width, 16)) {
634 UYVYToYRow = UYVYToYRow_NEON;
635 UYVYToUVRow = UYVYToUVRow_NEON;
636 }
637 }
638 #endif
640 for (int y = 0; y < height - 1; y += 2) {
641 UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
642 UYVYToYRow(src_uyvy, dst_y, width);
643 UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
644 src_uyvy += src_stride_uyvy * 2;
645 dst_y += dst_stride_y * 2;
646 dst_u += dst_stride_u;
647 dst_v += dst_stride_v;
648 }
649 if (height & 1) {
650 UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
651 UYVYToYRow(src_uyvy, dst_y, width);
652 }
653 return 0;
654 }
656 // Convert ARGB to I420.
657 LIBYUV_API
658 int ARGBToI420(const uint8* src_argb, int src_stride_argb,
659 uint8* dst_y, int dst_stride_y,
660 uint8* dst_u, int dst_stride_u,
661 uint8* dst_v, int dst_stride_v,
662 int width, int height) {
663 if (!src_argb ||
664 !dst_y || !dst_u || !dst_v ||
665 width <= 0 || height == 0) {
666 return -1;
667 }
668 // Negative height means invert the image.
669 if (height < 0) {
670 height = -height;
671 src_argb = src_argb + (height - 1) * src_stride_argb;
672 src_stride_argb = -src_stride_argb;
673 }
674 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
675 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
676 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
677 ARGBToYRow_C;
678 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
679 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
680 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
681 ARGBToYRow = ARGBToYRow_Any_SSSE3;
682 if (IS_ALIGNED(width, 16)) {
683 ARGBToUVRow = ARGBToUVRow_Unaligned_SSSE3;
684 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
685 if (IS_ALIGNED(src_argb, 16) && IS_ALIGNED(src_stride_argb, 16)) {
686 ARGBToUVRow = ARGBToUVRow_SSSE3;
687 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
688 ARGBToYRow = ARGBToYRow_SSSE3;
689 }
690 }
691 }
692 }
693 #endif
694 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
695 if (TestCpuFlag(kCpuHasAVX2) && width >= 32) {
696 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
697 ARGBToYRow = ARGBToYRow_Any_AVX2;
698 if (IS_ALIGNED(width, 32)) {
699 ARGBToUVRow = ARGBToUVRow_AVX2;
700 ARGBToYRow = ARGBToYRow_AVX2;
701 }
702 }
703 #endif
704 #if defined(HAS_ARGBTOYROW_NEON)
705 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
706 ARGBToYRow = ARGBToYRow_Any_NEON;
707 if (IS_ALIGNED(width, 8)) {
708 ARGBToYRow = ARGBToYRow_NEON;
709 }
710 if (width >= 16) {
711 ARGBToUVRow = ARGBToUVRow_Any_NEON;
712 if (IS_ALIGNED(width, 16)) {
713 ARGBToUVRow = ARGBToUVRow_NEON;
714 }
715 }
716 }
717 #endif
719 for (int y = 0; y < height - 1; y += 2) {
720 ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
721 ARGBToYRow(src_argb, dst_y, width);
722 ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
723 src_argb += src_stride_argb * 2;
724 dst_y += dst_stride_y * 2;
725 dst_u += dst_stride_u;
726 dst_v += dst_stride_v;
727 }
728 if (height & 1) {
729 ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
730 ARGBToYRow(src_argb, dst_y, width);
731 }
732 return 0;
733 }
735 // Convert BGRA to I420.
736 LIBYUV_API
737 int BGRAToI420(const uint8* src_bgra, int src_stride_bgra,
738 uint8* dst_y, int dst_stride_y,
739 uint8* dst_u, int dst_stride_u,
740 uint8* dst_v, int dst_stride_v,
741 int width, int height) {
742 if (!src_bgra ||
743 !dst_y || !dst_u || !dst_v ||
744 width <= 0 || height == 0) {
745 return -1;
746 }
747 // Negative height means invert the image.
748 if (height < 0) {
749 height = -height;
750 src_bgra = src_bgra + (height - 1) * src_stride_bgra;
751 src_stride_bgra = -src_stride_bgra;
752 }
753 void (*BGRAToUVRow)(const uint8* src_bgra0, int src_stride_bgra,
754 uint8* dst_u, uint8* dst_v, int width) = BGRAToUVRow_C;
755 void (*BGRAToYRow)(const uint8* src_bgra, uint8* dst_y, int pix) =
756 BGRAToYRow_C;
757 #if defined(HAS_BGRATOYROW_SSSE3)
758 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
759 BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
760 BGRAToYRow = BGRAToYRow_Any_SSSE3;
761 if (IS_ALIGNED(width, 16)) {
762 BGRAToUVRow = BGRAToUVRow_Unaligned_SSSE3;
763 BGRAToYRow = BGRAToYRow_Unaligned_SSSE3;
764 if (IS_ALIGNED(src_bgra, 16) && IS_ALIGNED(src_stride_bgra, 16)) {
765 BGRAToUVRow = BGRAToUVRow_SSSE3;
766 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
767 BGRAToYRow = BGRAToYRow_SSSE3;
768 }
769 }
770 }
771 }
772 #elif defined(HAS_BGRATOYROW_NEON)
773 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
774 BGRAToYRow = BGRAToYRow_Any_NEON;
775 if (IS_ALIGNED(width, 8)) {
776 BGRAToYRow = BGRAToYRow_NEON;
777 }
778 if (width >= 16) {
779 BGRAToUVRow = BGRAToUVRow_Any_NEON;
780 if (IS_ALIGNED(width, 16)) {
781 BGRAToUVRow = BGRAToUVRow_NEON;
782 }
783 }
784 }
785 #endif
787 for (int y = 0; y < height - 1; y += 2) {
788 BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
789 BGRAToYRow(src_bgra, dst_y, width);
790 BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
791 src_bgra += src_stride_bgra * 2;
792 dst_y += dst_stride_y * 2;
793 dst_u += dst_stride_u;
794 dst_v += dst_stride_v;
795 }
796 if (height & 1) {
797 BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
798 BGRAToYRow(src_bgra, dst_y, width);
799 }
800 return 0;
801 }
803 // Convert ABGR to I420.
804 LIBYUV_API
805 int ABGRToI420(const uint8* src_abgr, int src_stride_abgr,
806 uint8* dst_y, int dst_stride_y,
807 uint8* dst_u, int dst_stride_u,
808 uint8* dst_v, int dst_stride_v,
809 int width, int height) {
810 if (!src_abgr ||
811 !dst_y || !dst_u || !dst_v ||
812 width <= 0 || height == 0) {
813 return -1;
814 }
815 // Negative height means invert the image.
816 if (height < 0) {
817 height = -height;
818 src_abgr = src_abgr + (height - 1) * src_stride_abgr;
819 src_stride_abgr = -src_stride_abgr;
820 }
821 void (*ABGRToUVRow)(const uint8* src_abgr0, int src_stride_abgr,
822 uint8* dst_u, uint8* dst_v, int width) = ABGRToUVRow_C;
823 void (*ABGRToYRow)(const uint8* src_abgr, uint8* dst_y, int pix) =
824 ABGRToYRow_C;
825 #if defined(HAS_ABGRTOYROW_SSSE3)
826 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
827 ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
828 ABGRToYRow = ABGRToYRow_Any_SSSE3;
829 if (IS_ALIGNED(width, 16)) {
830 ABGRToUVRow = ABGRToUVRow_Unaligned_SSSE3;
831 ABGRToYRow = ABGRToYRow_Unaligned_SSSE3;
832 if (IS_ALIGNED(src_abgr, 16) && IS_ALIGNED(src_stride_abgr, 16)) {
833 ABGRToUVRow = ABGRToUVRow_SSSE3;
834 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
835 ABGRToYRow = ABGRToYRow_SSSE3;
836 }
837 }
838 }
839 }
840 #elif defined(HAS_ABGRTOYROW_NEON)
841 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
842 ABGRToYRow = ABGRToYRow_Any_NEON;
843 if (IS_ALIGNED(width, 8)) {
844 ABGRToYRow = ABGRToYRow_NEON;
845 }
846 if (width >= 16) {
847 ABGRToUVRow = ABGRToUVRow_Any_NEON;
848 if (IS_ALIGNED(width, 16)) {
849 ABGRToUVRow = ABGRToUVRow_NEON;
850 }
851 }
852 }
853 #endif
855 for (int y = 0; y < height - 1; y += 2) {
856 ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
857 ABGRToYRow(src_abgr, dst_y, width);
858 ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
859 src_abgr += src_stride_abgr * 2;
860 dst_y += dst_stride_y * 2;
861 dst_u += dst_stride_u;
862 dst_v += dst_stride_v;
863 }
864 if (height & 1) {
865 ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
866 ABGRToYRow(src_abgr, dst_y, width);
867 }
868 return 0;
869 }
871 // Convert RGBA to I420.
872 LIBYUV_API
873 int RGBAToI420(const uint8* src_rgba, int src_stride_rgba,
874 uint8* dst_y, int dst_stride_y,
875 uint8* dst_u, int dst_stride_u,
876 uint8* dst_v, int dst_stride_v,
877 int width, int height) {
878 if (!src_rgba ||
879 !dst_y || !dst_u || !dst_v ||
880 width <= 0 || height == 0) {
881 return -1;
882 }
883 // Negative height means invert the image.
884 if (height < 0) {
885 height = -height;
886 src_rgba = src_rgba + (height - 1) * src_stride_rgba;
887 src_stride_rgba = -src_stride_rgba;
888 }
889 void (*RGBAToUVRow)(const uint8* src_rgba0, int src_stride_rgba,
890 uint8* dst_u, uint8* dst_v, int width) = RGBAToUVRow_C;
891 void (*RGBAToYRow)(const uint8* src_rgba, uint8* dst_y, int pix) =
892 RGBAToYRow_C;
893 #if defined(HAS_RGBATOYROW_SSSE3)
894 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
895 RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
896 RGBAToYRow = RGBAToYRow_Any_SSSE3;
897 if (IS_ALIGNED(width, 16)) {
898 RGBAToUVRow = RGBAToUVRow_Unaligned_SSSE3;
899 RGBAToYRow = RGBAToYRow_Unaligned_SSSE3;
900 if (IS_ALIGNED(src_rgba, 16) && IS_ALIGNED(src_stride_rgba, 16)) {
901 RGBAToUVRow = RGBAToUVRow_SSSE3;
902 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
903 RGBAToYRow = RGBAToYRow_SSSE3;
904 }
905 }
906 }
907 }
908 #elif defined(HAS_RGBATOYROW_NEON)
909 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
910 RGBAToYRow = RGBAToYRow_Any_NEON;
911 if (IS_ALIGNED(width, 8)) {
912 RGBAToYRow = RGBAToYRow_NEON;
913 }
914 if (width >= 16) {
915 RGBAToUVRow = RGBAToUVRow_Any_NEON;
916 if (IS_ALIGNED(width, 16)) {
917 RGBAToUVRow = RGBAToUVRow_NEON;
918 }
919 }
920 }
921 #endif
923 for (int y = 0; y < height - 1; y += 2) {
924 RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
925 RGBAToYRow(src_rgba, dst_y, width);
926 RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
927 src_rgba += src_stride_rgba * 2;
928 dst_y += dst_stride_y * 2;
929 dst_u += dst_stride_u;
930 dst_v += dst_stride_v;
931 }
932 if (height & 1) {
933 RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
934 RGBAToYRow(src_rgba, dst_y, width);
935 }
936 return 0;
937 }
939 // Convert RGB24 to I420.
940 LIBYUV_API
941 int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24,
942 uint8* dst_y, int dst_stride_y,
943 uint8* dst_u, int dst_stride_u,
944 uint8* dst_v, int dst_stride_v,
945 int width, int height) {
946 if (!src_rgb24 || !dst_y || !dst_u || !dst_v ||
947 width <= 0 || height == 0) {
948 return -1;
949 }
950 // Negative height means invert the image.
951 if (height < 0) {
952 height = -height;
953 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
954 src_stride_rgb24 = -src_stride_rgb24;
955 }
957 #if defined(HAS_RGB24TOYROW_NEON)
958 void (*RGB24ToUVRow)(const uint8* src_rgb24, int src_stride_rgb24,
959 uint8* dst_u, uint8* dst_v, int width) = RGB24ToUVRow_C;
960 void (*RGB24ToYRow)(const uint8* src_rgb24, uint8* dst_y, int pix) =
961 RGB24ToYRow_C;
962 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
963 RGB24ToYRow = RGB24ToYRow_Any_NEON;
964 if (IS_ALIGNED(width, 8)) {
965 RGB24ToYRow = RGB24ToYRow_NEON;
966 }
967 if (width >= 16) {
968 RGB24ToUVRow = RGB24ToUVRow_Any_NEON;
969 if (IS_ALIGNED(width, 16)) {
970 RGB24ToUVRow = RGB24ToUVRow_NEON;
971 }
972 }
973 }
974 #else // HAS_RGB24TOYROW_NEON
976 // Allocate 2 rows of ARGB.
977 const int kRowSize = (width * 4 + 15) & ~15;
978 align_buffer_64(row, kRowSize * 2);
980 void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
981 RGB24ToARGBRow_C;
982 #if defined(HAS_RGB24TOARGBROW_SSSE3)
983 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
984 RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
985 if (IS_ALIGNED(width, 16)) {
986 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
987 }
988 }
989 #endif
990 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
991 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
992 #if defined(HAS_ARGBTOUVROW_SSSE3)
993 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
994 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
995 if (IS_ALIGNED(width, 16)) {
996 ARGBToUVRow = ARGBToUVRow_SSSE3;
997 }
998 }
999 #endif
1000 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1001 ARGBToYRow_C;
1002 #if defined(HAS_ARGBTOUVROW_SSSE3)
1003 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1004 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1005 if (IS_ALIGNED(width, 16)) {
1006 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1007 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1008 ARGBToYRow = ARGBToYRow_SSSE3;
1009 }
1010 }
1011 }
1012 #endif // HAS_ARGBTOUVROW_SSSE3
1013 #endif // HAS_RGB24TOYROW_NEON
1015 for (int y = 0; y < height - 1; y += 2) {
1016 #if defined(HAS_RGB24TOYROW_NEON)
1017 RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
1018 RGB24ToYRow(src_rgb24, dst_y, width);
1019 RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
1020 #else
1021 RGB24ToARGBRow(src_rgb24, row, width);
1022 RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
1023 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1024 ARGBToYRow(row, dst_y, width);
1025 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1026 #endif
1027 src_rgb24 += src_stride_rgb24 * 2;
1028 dst_y += dst_stride_y * 2;
1029 dst_u += dst_stride_u;
1030 dst_v += dst_stride_v;
1031 }
1032 if (height & 1) {
1033 #if defined(HAS_RGB24TOYROW_NEON)
1034 RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
1035 RGB24ToYRow(src_rgb24, dst_y, width);
1036 #else
1037 RGB24ToARGBRow(src_rgb24, row, width);
1038 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1039 ARGBToYRow(row, dst_y, width);
1040 #endif
1041 }
1042 #if !defined(HAS_RGB24TOYROW_NEON)
1043 free_aligned_buffer_64(row);
1044 #endif
1045 return 0;
1046 }
1048 // Convert RAW to I420.
1049 LIBYUV_API
1050 int RAWToI420(const uint8* src_raw, int src_stride_raw,
1051 uint8* dst_y, int dst_stride_y,
1052 uint8* dst_u, int dst_stride_u,
1053 uint8* dst_v, int dst_stride_v,
1054 int width, int height) {
1055 if (!src_raw || !dst_y || !dst_u || !dst_v ||
1056 width <= 0 || height == 0) {
1057 return -1;
1058 }
1059 // Negative height means invert the image.
1060 if (height < 0) {
1061 height = -height;
1062 src_raw = src_raw + (height - 1) * src_stride_raw;
1063 src_stride_raw = -src_stride_raw;
1064 }
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) =
1070 RAWToYRow_C;
1071 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
1072 RAWToYRow = RAWToYRow_Any_NEON;
1073 if (IS_ALIGNED(width, 8)) {
1074 RAWToYRow = RAWToYRow_NEON;
1075 }
1076 if (width >= 16) {
1077 RAWToUVRow = RAWToUVRow_Any_NEON;
1078 if (IS_ALIGNED(width, 16)) {
1079 RAWToUVRow = RAWToUVRow_NEON;
1080 }
1081 }
1082 }
1083 #else // HAS_RAWTOYROW_NEON
1085 // Allocate 2 rows of ARGB.
1086 const int kRowSize = (width * 4 + 15) & ~15;
1087 align_buffer_64(row, kRowSize * 2);
1089 void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1090 RAWToARGBRow_C;
1091 #if defined(HAS_RAWTOARGBROW_SSSE3)
1092 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1093 RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
1094 if (IS_ALIGNED(width, 16)) {
1095 RAWToARGBRow = RAWToARGBRow_SSSE3;
1096 }
1097 }
1098 #endif
1099 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1100 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1101 #if defined(HAS_ARGBTOUVROW_SSSE3)
1102 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1103 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1104 if (IS_ALIGNED(width, 16)) {
1105 ARGBToUVRow = ARGBToUVRow_SSSE3;
1106 }
1107 }
1108 #endif
1109 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1110 ARGBToYRow_C;
1111 #if defined(HAS_ARGBTOUVROW_SSSE3)
1112 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1113 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1114 if (IS_ALIGNED(width, 16)) {
1115 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1116 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1117 ARGBToYRow = ARGBToYRow_SSSE3;
1118 }
1119 }
1120 }
1121 #endif // HAS_ARGBTOUVROW_SSSE3
1122 #endif // HAS_RAWTOYROW_NEON
1124 for (int y = 0; y < height - 1; y += 2) {
1125 #if defined(HAS_RAWTOYROW_NEON)
1126 RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width);
1127 RAWToYRow(src_raw, dst_y, width);
1128 RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
1129 #else
1130 RAWToARGBRow(src_raw, row, width);
1131 RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width);
1132 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1133 ARGBToYRow(row, dst_y, width);
1134 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1135 #endif
1136 src_raw += src_stride_raw * 2;
1137 dst_y += dst_stride_y * 2;
1138 dst_u += dst_stride_u;
1139 dst_v += dst_stride_v;
1140 }
1141 if (height & 1) {
1142 #if defined(HAS_RAWTOYROW_NEON)
1143 RAWToUVRow(src_raw, 0, dst_u, dst_v, width);
1144 RAWToYRow(src_raw, dst_y, width);
1145 #else
1146 RAWToARGBRow(src_raw, row, width);
1147 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1148 ARGBToYRow(row, dst_y, width);
1149 #endif
1150 }
1151 #if !defined(HAS_RAWTOYROW_NEON)
1152 free_aligned_buffer_64(row);
1153 #endif
1154 return 0;
1155 }
1157 // Convert RGB565 to I420.
1158 LIBYUV_API
1159 int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565,
1160 uint8* dst_y, int dst_stride_y,
1161 uint8* dst_u, int dst_stride_u,
1162 uint8* dst_v, int dst_stride_v,
1163 int width, int height) {
1164 if (!src_rgb565 || !dst_y || !dst_u || !dst_v ||
1165 width <= 0 || height == 0) {
1166 return -1;
1167 }
1168 // Negative height means invert the image.
1169 if (height < 0) {
1170 height = -height;
1171 src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
1172 src_stride_rgb565 = -src_stride_rgb565;
1173 }
1175 #if defined(HAS_RGB565TOYROW_NEON)
1176 void (*RGB565ToUVRow)(const uint8* src_rgb565, int src_stride_rgb565,
1177 uint8* dst_u, uint8* dst_v, int width) = RGB565ToUVRow_C;
1178 void (*RGB565ToYRow)(const uint8* src_rgb565, uint8* dst_y, int pix) =
1179 RGB565ToYRow_C;
1180 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
1181 RGB565ToYRow = RGB565ToYRow_Any_NEON;
1182 if (IS_ALIGNED(width, 8)) {
1183 RGB565ToYRow = RGB565ToYRow_NEON;
1184 }
1185 if (width >= 16) {
1186 RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
1187 if (IS_ALIGNED(width, 16)) {
1188 RGB565ToUVRow = RGB565ToUVRow_NEON;
1189 }
1190 }
1191 }
1192 #else // HAS_RGB565TOYROW_NEON
1194 // Allocate 2 rows of ARGB.
1195 const int kRowSize = (width * 4 + 15) & ~15;
1196 align_buffer_64(row, kRowSize * 2);
1198 void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1199 RGB565ToARGBRow_C;
1200 #if defined(HAS_RGB565TOARGBROW_SSE2)
1201 if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
1202 RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
1203 if (IS_ALIGNED(width, 8)) {
1204 RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
1205 }
1206 }
1207 #endif
1208 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1209 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1210 #if defined(HAS_ARGBTOUVROW_SSSE3)
1211 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1212 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1213 if (IS_ALIGNED(width, 16)) {
1214 ARGBToUVRow = ARGBToUVRow_SSSE3;
1215 }
1216 }
1217 #endif
1218 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1219 ARGBToYRow_C;
1220 #if defined(HAS_ARGBTOUVROW_SSSE3)
1221 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1222 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1223 if (IS_ALIGNED(width, 16)) {
1224 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1225 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1226 ARGBToYRow = ARGBToYRow_SSSE3;
1227 }
1228 }
1229 }
1230 #endif // HAS_ARGBTOUVROW_SSSE3
1231 #endif // HAS_RGB565TOYROW_NEON
1233 for (int y = 0; y < height - 1; y += 2) {
1234 #if defined(HAS_RGB565TOYROW_NEON)
1235 RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width);
1236 RGB565ToYRow(src_rgb565, dst_y, width);
1237 RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
1238 #else
1239 RGB565ToARGBRow(src_rgb565, row, width);
1240 RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width);
1241 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1242 ARGBToYRow(row, dst_y, width);
1243 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1244 #endif
1245 src_rgb565 += src_stride_rgb565 * 2;
1246 dst_y += dst_stride_y * 2;
1247 dst_u += dst_stride_u;
1248 dst_v += dst_stride_v;
1249 }
1250 if (height & 1) {
1251 #if defined(HAS_RGB565TOYROW_NEON)
1252 RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width);
1253 RGB565ToYRow(src_rgb565, dst_y, width);
1254 #else
1255 RGB565ToARGBRow(src_rgb565, row, width);
1256 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1257 ARGBToYRow(row, dst_y, width);
1258 #endif
1259 }
1260 #if !defined(HAS_RGB565TOYROW_NEON)
1261 free_aligned_buffer_64(row);
1262 #endif
1263 return 0;
1264 }
1266 // Convert ARGB1555 to I420.
1267 LIBYUV_API
1268 int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555,
1269 uint8* dst_y, int dst_stride_y,
1270 uint8* dst_u, int dst_stride_u,
1271 uint8* dst_v, int dst_stride_v,
1272 int width, int height) {
1273 if (!src_argb1555 || !dst_y || !dst_u || !dst_v ||
1274 width <= 0 || height == 0) {
1275 return -1;
1276 }
1277 // Negative height means invert the image.
1278 if (height < 0) {
1279 height = -height;
1280 src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
1281 src_stride_argb1555 = -src_stride_argb1555;
1282 }
1284 #if defined(HAS_ARGB1555TOYROW_NEON)
1285 void (*ARGB1555ToUVRow)(const uint8* src_argb1555, int src_stride_argb1555,
1286 uint8* dst_u, uint8* dst_v, int width) = ARGB1555ToUVRow_C;
1287 void (*ARGB1555ToYRow)(const uint8* src_argb1555, uint8* dst_y, int pix) =
1288 ARGB1555ToYRow_C;
1289 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
1290 ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
1291 if (IS_ALIGNED(width, 8)) {
1292 ARGB1555ToYRow = ARGB1555ToYRow_NEON;
1293 }
1294 if (width >= 16) {
1295 ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
1296 if (IS_ALIGNED(width, 16)) {
1297 ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
1298 }
1299 }
1300 }
1301 #else // HAS_ARGB1555TOYROW_NEON
1303 // Allocate 2 rows of ARGB.
1304 const int kRowSize = (width * 4 + 15) & ~15;
1305 align_buffer_64(row, kRowSize * 2);
1307 void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1308 ARGB1555ToARGBRow_C;
1309 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
1310 if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
1311 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
1312 if (IS_ALIGNED(width, 8)) {
1313 ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
1314 }
1315 }
1316 #endif
1317 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1318 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1319 #if defined(HAS_ARGBTOUVROW_SSSE3)
1320 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1321 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1322 if (IS_ALIGNED(width, 16)) {
1323 ARGBToUVRow = ARGBToUVRow_SSSE3;
1324 }
1325 }
1326 #endif
1327 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1328 ARGBToYRow_C;
1329 #if defined(HAS_ARGBTOUVROW_SSSE3)
1330 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1331 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1332 if (IS_ALIGNED(width, 16)) {
1333 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1334 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1335 ARGBToYRow = ARGBToYRow_SSSE3;
1336 }
1337 }
1338 }
1339 #endif // HAS_ARGBTOUVROW_SSSE3
1340 #endif // HAS_ARGB1555TOYROW_NEON
1342 for (int y = 0; y < height - 1; y += 2) {
1343 #if defined(HAS_ARGB1555TOYROW_NEON)
1344 ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width);
1345 ARGB1555ToYRow(src_argb1555, dst_y, width);
1346 ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y,
1347 width);
1348 #else
1349 ARGB1555ToARGBRow(src_argb1555, row, width);
1350 ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize,
1351 width);
1352 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1353 ARGBToYRow(row, dst_y, width);
1354 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1355 #endif
1356 src_argb1555 += src_stride_argb1555 * 2;
1357 dst_y += dst_stride_y * 2;
1358 dst_u += dst_stride_u;
1359 dst_v += dst_stride_v;
1360 }
1361 if (height & 1) {
1362 #if defined(HAS_ARGB1555TOYROW_NEON)
1363 ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width);
1364 ARGB1555ToYRow(src_argb1555, dst_y, width);
1365 #else
1366 ARGB1555ToARGBRow(src_argb1555, row, width);
1367 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1368 ARGBToYRow(row, dst_y, width);
1369 #endif
1370 }
1371 #if !defined(HAS_ARGB1555TOYROW_NEON)
1372 free_aligned_buffer_64(row);
1373 #endif
1374 return 0;
1375 }
1377 // Convert ARGB4444 to I420.
1378 LIBYUV_API
1379 int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444,
1380 uint8* dst_y, int dst_stride_y,
1381 uint8* dst_u, int dst_stride_u,
1382 uint8* dst_v, int dst_stride_v,
1383 int width, int height) {
1384 if (!src_argb4444 || !dst_y || !dst_u || !dst_v ||
1385 width <= 0 || height == 0) {
1386 return -1;
1387 }
1388 // Negative height means invert the image.
1389 if (height < 0) {
1390 height = -height;
1391 src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
1392 src_stride_argb4444 = -src_stride_argb4444;
1393 }
1395 #if defined(HAS_ARGB4444TOYROW_NEON)
1396 void (*ARGB4444ToUVRow)(const uint8* src_argb4444, int src_stride_argb4444,
1397 uint8* dst_u, uint8* dst_v, int width) = ARGB4444ToUVRow_C;
1398 void (*ARGB4444ToYRow)(const uint8* src_argb4444, uint8* dst_y, int pix) =
1399 ARGB4444ToYRow_C;
1400 if (TestCpuFlag(kCpuHasNEON) && width >= 8) {
1401 ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
1402 if (IS_ALIGNED(width, 8)) {
1403 ARGB4444ToYRow = ARGB4444ToYRow_NEON;
1404 }
1405 if (width >= 16) {
1406 ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
1407 if (IS_ALIGNED(width, 16)) {
1408 ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
1409 }
1410 }
1411 }
1412 #else // HAS_ARGB4444TOYROW_NEON
1414 // Allocate 2 rows of ARGB.
1415 const int kRowSize = (width * 4 + 15) & ~15;
1416 align_buffer_64(row, kRowSize * 2);
1418 void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1419 ARGB4444ToARGBRow_C;
1420 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
1421 if (TestCpuFlag(kCpuHasSSE2) && width >= 8) {
1422 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
1423 if (IS_ALIGNED(width, 8)) {
1424 ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
1425 }
1426 }
1427 #endif
1428 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1429 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1430 #if defined(HAS_ARGBTOUVROW_SSSE3)
1431 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1432 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1433 if (IS_ALIGNED(width, 16)) {
1434 ARGBToUVRow = ARGBToUVRow_SSSE3;
1435 }
1436 }
1437 #endif
1438 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1439 ARGBToYRow_C;
1440 #if defined(HAS_ARGBTOUVROW_SSSE3)
1441 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) {
1442 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1443 if (IS_ALIGNED(width, 16)) {
1444 ARGBToYRow = ARGBToYRow_Unaligned_SSSE3;
1445 if (IS_ALIGNED(dst_y, 16) && IS_ALIGNED(dst_stride_y, 16)) {
1446 ARGBToYRow = ARGBToYRow_SSSE3;
1447 }
1448 }
1449 }
1450 #endif // HAS_ARGBTOUVROW_SSSE3
1451 #endif // HAS_ARGB4444TOYROW_NEON
1453 for (int y = 0; y < height - 1; y += 2) {
1454 #if defined(HAS_ARGB4444TOYROW_NEON)
1455 ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width);
1456 ARGB4444ToYRow(src_argb4444, dst_y, width);
1457 ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y,
1458 width);
1459 #else
1460 ARGB4444ToARGBRow(src_argb4444, row, width);
1461 ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize,
1462 width);
1463 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1464 ARGBToYRow(row, dst_y, width);
1465 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1466 #endif
1467 src_argb4444 += src_stride_argb4444 * 2;
1468 dst_y += dst_stride_y * 2;
1469 dst_u += dst_stride_u;
1470 dst_v += dst_stride_v;
1471 }
1472 if (height & 1) {
1473 #if defined(HAS_ARGB4444TOYROW_NEON)
1474 ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width);
1475 ARGB4444ToYRow(src_argb4444, dst_y, width);
1476 #else
1477 ARGB4444ToARGBRow(src_argb4444, row, width);
1478 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1479 ARGBToYRow(row, dst_y, width);
1480 #endif
1481 }
1482 #if !defined(HAS_ARGB4444TOYROW_NEON)
1483 free_aligned_buffer_64(row);
1484 #endif
1485 return 0;
1486 }
1488 #ifdef __cplusplus
1489 } // extern "C"
1490 } // namespace libyuv
1491 #endif