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 */
10
11 #include "libyuv/convert.h"
12
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"
19
20 #ifdef __cplusplus
21 namespace libyuv {
22 extern "C" {
23 #endif
24
25 #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
Abs(int v)26 static __inline int Abs(int v) {
27 return v >= 0 ? v : -v;
28 }
29
30 // Any I4xx To I420 format with mirroring.
I4xxToI420(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int src_y_width,int src_y_height,int src_uv_width,int src_uv_height)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) {
45 return -1;
46 }
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 }
58
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
I420Copy(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)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) {
75 return -1;
76 }
77 // Negative height means invert the image.
78 if (height < 0) {
79 height = -height;
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;
87 }
88
89 if (dst_y) {
90 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
91 }
92 // Copy UV planes.
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 }
97
98 // 422 chroma is 1/2 width, 1x height
99 // 420 chroma is 1/2 width, 1/2 height
100 LIBYUV_API
I422ToI420(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)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 }
118
119 // 444 chroma is 1x width, 1x height
120 // 420 chroma is 1/2 width, 1/2 height
121 LIBYUV_API
I444ToI420(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)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 }
138
139 // 411 chroma is 1/4 width, 1x height
140 // 420 chroma is 1/2 width, 1/2 height
141 LIBYUV_API
I411ToI420(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)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 }
159
160 // I400 is greyscale typically used in MJPG
161 LIBYUV_API
I400ToI420(const uint8 * src_y,int src_stride_y,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)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) {
171 return -1;
172 }
173 // Negative height means invert the image.
174 if (height < 0) {
175 height = -height;
176 halfheight = (height + 1) >> 1;
177 src_y = src_y + (height - 1) * src_stride_y;
178 src_stride_y = -src_stride_y;
179 }
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);
183 return 0;
184 }
185
CopyPlane2(const uint8 * src,int src_stride_0,int src_stride_1,uint8 * dst,int dst_stride,int width,int height)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) {
189 int y;
190 void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
191 #if defined(HAS_COPYROW_SSE2)
192 if (TestCpuFlag(kCpuHasSSE2)) {
193 CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2;
194 }
195 #endif
196 #if defined(HAS_COPYROW_AVX)
197 if (TestCpuFlag(kCpuHasAVX)) {
198 CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
199 }
200 #endif
201 #if defined(HAS_COPYROW_ERMS)
202 if (TestCpuFlag(kCpuHasERMS)) {
203 CopyRow = CopyRow_ERMS;
204 }
205 #endif
206 #if defined(HAS_COPYROW_NEON)
207 if (TestCpuFlag(kCpuHasNEON)) {
208 CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
209 }
210 #endif
211 #if defined(HAS_COPYROW_MIPS)
212 if (TestCpuFlag(kCpuHasMIPS)) {
213 CopyRow = CopyRow_MIPS;
214 }
215 #endif
216
217 // Copy plane
218 for (y = 0; y < height - 1; y += 2) {
219 CopyRow(src, dst, width);
220 CopyRow(src + src_stride_0, dst + dst_stride, width);
221 src += src_stride_0 + src_stride_1;
222 dst += dst_stride * 2;
223 }
224 if (height & 1) {
225 CopyRow(src, dst, width);
226 }
227 }
228
229 // Support converting from FOURCC_M420
230 // Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for
231 // easy conversion to I420.
232 // M420 format description:
233 // M420 is row biplanar 420: 2 rows of Y and 1 row of UV.
234 // Chroma is half width / half height. (420)
235 // src_stride_m420 is row planar. Normally this will be the width in pixels.
236 // The UV plane is half width, but 2 values, so src_stride_m420 applies to
237 // this as well as the two Y planes.
X420ToI420(const uint8 * src_y,int src_stride_y0,int src_stride_y1,const uint8 * src_uv,int src_stride_uv,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)238 static int X420ToI420(const uint8* src_y,
239 int src_stride_y0, int src_stride_y1,
240 const uint8* src_uv, int src_stride_uv,
241 uint8* dst_y, int dst_stride_y,
242 uint8* dst_u, int dst_stride_u,
243 uint8* dst_v, int dst_stride_v,
244 int width, int height) {
245 int y;
246 int halfwidth = (width + 1) >> 1;
247 int halfheight = (height + 1) >> 1;
248 void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v, int pix) =
249 SplitUVRow_C;
250 if (!src_y || !src_uv ||
251 !dst_y || !dst_u || !dst_v ||
252 width <= 0 || height == 0) {
253 return -1;
254 }
255 // Negative height means invert the image.
256 if (height < 0) {
257 height = -height;
258 halfheight = (height + 1) >> 1;
259 dst_y = dst_y + (height - 1) * dst_stride_y;
260 dst_u = dst_u + (halfheight - 1) * dst_stride_u;
261 dst_v = dst_v + (halfheight - 1) * dst_stride_v;
262 dst_stride_y = -dst_stride_y;
263 dst_stride_u = -dst_stride_u;
264 dst_stride_v = -dst_stride_v;
265 }
266 // Coalesce rows.
267 if (src_stride_y0 == width &&
268 src_stride_y1 == width &&
269 dst_stride_y == width) {
270 width *= height;
271 height = 1;
272 src_stride_y0 = src_stride_y1 = dst_stride_y = 0;
273 }
274 // Coalesce rows.
275 if (src_stride_uv == halfwidth * 2 &&
276 dst_stride_u == halfwidth &&
277 dst_stride_v == halfwidth) {
278 halfwidth *= halfheight;
279 halfheight = 1;
280 src_stride_uv = dst_stride_u = dst_stride_v = 0;
281 }
282 #if defined(HAS_SPLITUVROW_SSE2)
283 if (TestCpuFlag(kCpuHasSSE2)) {
284 SplitUVRow = SplitUVRow_Any_SSE2;
285 if (IS_ALIGNED(halfwidth, 16)) {
286 SplitUVRow = SplitUVRow_SSE2;
287 }
288 }
289 #endif
290 #if defined(HAS_SPLITUVROW_AVX2)
291 if (TestCpuFlag(kCpuHasAVX2)) {
292 SplitUVRow = SplitUVRow_Any_AVX2;
293 if (IS_ALIGNED(halfwidth, 32)) {
294 SplitUVRow = SplitUVRow_AVX2;
295 }
296 }
297 #endif
298 #if defined(HAS_SPLITUVROW_NEON)
299 if (TestCpuFlag(kCpuHasNEON)) {
300 SplitUVRow = SplitUVRow_Any_NEON;
301 if (IS_ALIGNED(halfwidth, 16)) {
302 SplitUVRow = SplitUVRow_NEON;
303 }
304 }
305 #endif
306 #if defined(HAS_SPLITUVROW_MIPS_DSPR2)
307 if (TestCpuFlag(kCpuHasMIPS_DSPR2) &&
308 IS_ALIGNED(src_uv, 4) && IS_ALIGNED(src_stride_uv, 4) &&
309 IS_ALIGNED(dst_u, 4) && IS_ALIGNED(dst_stride_u, 4) &&
310 IS_ALIGNED(dst_v, 4) && IS_ALIGNED(dst_stride_v, 4)) {
311 SplitUVRow = SplitUVRow_Any_MIPS_DSPR2;
312 if (IS_ALIGNED(halfwidth, 16)) {
313 SplitUVRow = SplitUVRow_MIPS_DSPR2;
314 }
315 }
316 #endif
317
318 if (dst_y) {
319 if (src_stride_y0 == src_stride_y1) {
320 CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height);
321 } else {
322 CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y,
323 width, height);
324 }
325 }
326
327 for (y = 0; y < halfheight; ++y) {
328 // Copy a row of UV.
329 SplitUVRow(src_uv, dst_u, dst_v, halfwidth);
330 dst_u += dst_stride_u;
331 dst_v += dst_stride_v;
332 src_uv += src_stride_uv;
333 }
334 return 0;
335 }
336
337 // Convert NV12 to I420.
338 LIBYUV_API
NV12ToI420(const uint8 * src_y,int src_stride_y,const uint8 * src_uv,int src_stride_uv,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)339 int NV12ToI420(const uint8* src_y, int src_stride_y,
340 const uint8* src_uv, int src_stride_uv,
341 uint8* dst_y, int dst_stride_y,
342 uint8* dst_u, int dst_stride_u,
343 uint8* dst_v, int dst_stride_v,
344 int width, int height) {
345 return X420ToI420(src_y, src_stride_y, src_stride_y,
346 src_uv, src_stride_uv,
347 dst_y, dst_stride_y,
348 dst_u, dst_stride_u,
349 dst_v, dst_stride_v,
350 width, height);
351 }
352
353 // Convert NV21 to I420. Same as NV12 but u and v pointers swapped.
354 LIBYUV_API
NV21ToI420(const uint8 * src_y,int src_stride_y,const uint8 * src_vu,int src_stride_vu,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)355 int NV21ToI420(const uint8* src_y, int src_stride_y,
356 const uint8* src_vu, int src_stride_vu,
357 uint8* dst_y, int dst_stride_y,
358 uint8* dst_u, int dst_stride_u,
359 uint8* dst_v, int dst_stride_v,
360 int width, int height) {
361 return X420ToI420(src_y, src_stride_y, src_stride_y,
362 src_vu, src_stride_vu,
363 dst_y, dst_stride_y,
364 dst_v, dst_stride_v,
365 dst_u, dst_stride_u,
366 width, height);
367 }
368
369 // Convert M420 to I420.
370 LIBYUV_API
M420ToI420(const uint8 * src_m420,int src_stride_m420,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)371 int M420ToI420(const uint8* src_m420, int src_stride_m420,
372 uint8* dst_y, int dst_stride_y,
373 uint8* dst_u, int dst_stride_u,
374 uint8* dst_v, int dst_stride_v,
375 int width, int height) {
376 return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2,
377 src_m420 + src_stride_m420 * 2, src_stride_m420 * 3,
378 dst_y, dst_stride_y,
379 dst_u, dst_stride_u,
380 dst_v, dst_stride_v,
381 width, height);
382 }
383
384 // Convert YUY2 to I420.
385 LIBYUV_API
YUY2ToI420(const uint8 * src_yuy2,int src_stride_yuy2,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)386 int YUY2ToI420(const uint8* src_yuy2, int src_stride_yuy2,
387 uint8* dst_y, int dst_stride_y,
388 uint8* dst_u, int dst_stride_u,
389 uint8* dst_v, int dst_stride_v,
390 int width, int height) {
391 int y;
392 void (*YUY2ToUVRow)(const uint8* src_yuy2, int src_stride_yuy2,
393 uint8* dst_u, uint8* dst_v, int pix) = YUY2ToUVRow_C;
394 void (*YUY2ToYRow)(const uint8* src_yuy2,
395 uint8* dst_y, int pix) = YUY2ToYRow_C;
396 // Negative height means invert the image.
397 if (height < 0) {
398 height = -height;
399 src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
400 src_stride_yuy2 = -src_stride_yuy2;
401 }
402 #if defined(HAS_YUY2TOYROW_SSE2)
403 if (TestCpuFlag(kCpuHasSSE2)) {
404 YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
405 YUY2ToYRow = YUY2ToYRow_Any_SSE2;
406 if (IS_ALIGNED(width, 16)) {
407 YUY2ToUVRow = YUY2ToUVRow_SSE2;
408 YUY2ToYRow = YUY2ToYRow_SSE2;
409 }
410 }
411 #endif
412 #if defined(HAS_YUY2TOYROW_AVX2)
413 if (TestCpuFlag(kCpuHasAVX2)) {
414 YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
415 YUY2ToYRow = YUY2ToYRow_Any_AVX2;
416 if (IS_ALIGNED(width, 32)) {
417 YUY2ToUVRow = YUY2ToUVRow_AVX2;
418 YUY2ToYRow = YUY2ToYRow_AVX2;
419 }
420 }
421 #endif
422 #if defined(HAS_YUY2TOYROW_NEON)
423 if (TestCpuFlag(kCpuHasNEON)) {
424 YUY2ToYRow = YUY2ToYRow_Any_NEON;
425 YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
426 if (IS_ALIGNED(width, 16)) {
427 YUY2ToYRow = YUY2ToYRow_NEON;
428 YUY2ToUVRow = YUY2ToUVRow_NEON;
429 }
430 }
431 #endif
432
433 for (y = 0; y < height - 1; y += 2) {
434 YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
435 YUY2ToYRow(src_yuy2, dst_y, width);
436 YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
437 src_yuy2 += src_stride_yuy2 * 2;
438 dst_y += dst_stride_y * 2;
439 dst_u += dst_stride_u;
440 dst_v += dst_stride_v;
441 }
442 if (height & 1) {
443 YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
444 YUY2ToYRow(src_yuy2, dst_y, width);
445 }
446 return 0;
447 }
448
449 // Convert UYVY to I420.
450 LIBYUV_API
UYVYToI420(const uint8 * src_uyvy,int src_stride_uyvy,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)451 int UYVYToI420(const uint8* src_uyvy, int src_stride_uyvy,
452 uint8* dst_y, int dst_stride_y,
453 uint8* dst_u, int dst_stride_u,
454 uint8* dst_v, int dst_stride_v,
455 int width, int height) {
456 int y;
457 void (*UYVYToUVRow)(const uint8* src_uyvy, int src_stride_uyvy,
458 uint8* dst_u, uint8* dst_v, int pix) = UYVYToUVRow_C;
459 void (*UYVYToYRow)(const uint8* src_uyvy,
460 uint8* dst_y, int pix) = UYVYToYRow_C;
461 // Negative height means invert the image.
462 if (height < 0) {
463 height = -height;
464 src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
465 src_stride_uyvy = -src_stride_uyvy;
466 }
467 #if defined(HAS_UYVYTOYROW_SSE2)
468 if (TestCpuFlag(kCpuHasSSE2)) {
469 UYVYToUVRow = UYVYToUVRow_Any_SSE2;
470 UYVYToYRow = UYVYToYRow_Any_SSE2;
471 if (IS_ALIGNED(width, 16)) {
472 UYVYToUVRow = UYVYToUVRow_SSE2;
473 UYVYToYRow = UYVYToYRow_SSE2;
474 }
475 }
476 #endif
477 #if defined(HAS_UYVYTOYROW_AVX2)
478 if (TestCpuFlag(kCpuHasAVX2)) {
479 UYVYToUVRow = UYVYToUVRow_Any_AVX2;
480 UYVYToYRow = UYVYToYRow_Any_AVX2;
481 if (IS_ALIGNED(width, 32)) {
482 UYVYToUVRow = UYVYToUVRow_AVX2;
483 UYVYToYRow = UYVYToYRow_AVX2;
484 }
485 }
486 #endif
487 #if defined(HAS_UYVYTOYROW_NEON)
488 if (TestCpuFlag(kCpuHasNEON)) {
489 UYVYToYRow = UYVYToYRow_Any_NEON;
490 UYVYToUVRow = UYVYToUVRow_Any_NEON;
491 if (IS_ALIGNED(width, 16)) {
492 UYVYToYRow = UYVYToYRow_NEON;
493 UYVYToUVRow = UYVYToUVRow_NEON;
494 }
495 }
496 #endif
497
498 for (y = 0; y < height - 1; y += 2) {
499 UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
500 UYVYToYRow(src_uyvy, dst_y, width);
501 UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
502 src_uyvy += src_stride_uyvy * 2;
503 dst_y += dst_stride_y * 2;
504 dst_u += dst_stride_u;
505 dst_v += dst_stride_v;
506 }
507 if (height & 1) {
508 UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
509 UYVYToYRow(src_uyvy, dst_y, width);
510 }
511 return 0;
512 }
513
514 // Convert ARGB to I420.
515 LIBYUV_API
ARGBToI420(const uint8 * src_argb,int src_stride_argb,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)516 int ARGBToI420(const uint8* src_argb, int src_stride_argb,
517 uint8* dst_y, int dst_stride_y,
518 uint8* dst_u, int dst_stride_u,
519 uint8* dst_v, int dst_stride_v,
520 int width, int height) {
521 int y;
522 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
523 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
524 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
525 ARGBToYRow_C;
526 if (!src_argb ||
527 !dst_y || !dst_u || !dst_v ||
528 width <= 0 || height == 0) {
529 return -1;
530 }
531 // Negative height means invert the image.
532 if (height < 0) {
533 height = -height;
534 src_argb = src_argb + (height - 1) * src_stride_argb;
535 src_stride_argb = -src_stride_argb;
536 }
537 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
538 if (TestCpuFlag(kCpuHasSSSE3)) {
539 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
540 ARGBToYRow = ARGBToYRow_Any_SSSE3;
541 if (IS_ALIGNED(width, 16)) {
542 ARGBToUVRow = ARGBToUVRow_SSSE3;
543 ARGBToYRow = ARGBToYRow_SSSE3;
544 }
545 }
546 #endif
547 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
548 if (TestCpuFlag(kCpuHasAVX2)) {
549 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
550 ARGBToYRow = ARGBToYRow_Any_AVX2;
551 if (IS_ALIGNED(width, 32)) {
552 ARGBToUVRow = ARGBToUVRow_AVX2;
553 ARGBToYRow = ARGBToYRow_AVX2;
554 }
555 }
556 #endif
557 #if defined(HAS_ARGBTOYROW_NEON)
558 if (TestCpuFlag(kCpuHasNEON)) {
559 ARGBToYRow = ARGBToYRow_Any_NEON;
560 if (IS_ALIGNED(width, 8)) {
561 ARGBToYRow = ARGBToYRow_NEON;
562 }
563 }
564 #endif
565 #if defined(HAS_ARGBTOUVROW_NEON)
566 if (TestCpuFlag(kCpuHasNEON)) {
567 ARGBToUVRow = ARGBToUVRow_Any_NEON;
568 if (IS_ALIGNED(width, 16)) {
569 ARGBToUVRow = ARGBToUVRow_NEON;
570 }
571 }
572 #endif
573
574 for (y = 0; y < height - 1; y += 2) {
575 ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
576 ARGBToYRow(src_argb, dst_y, width);
577 ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
578 src_argb += src_stride_argb * 2;
579 dst_y += dst_stride_y * 2;
580 dst_u += dst_stride_u;
581 dst_v += dst_stride_v;
582 }
583 if (height & 1) {
584 ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
585 ARGBToYRow(src_argb, dst_y, width);
586 }
587 return 0;
588 }
589
590 // Convert BGRA to I420.
591 LIBYUV_API
BGRAToI420(const uint8 * src_bgra,int src_stride_bgra,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)592 int BGRAToI420(const uint8* src_bgra, int src_stride_bgra,
593 uint8* dst_y, int dst_stride_y,
594 uint8* dst_u, int dst_stride_u,
595 uint8* dst_v, int dst_stride_v,
596 int width, int height) {
597 int y;
598 void (*BGRAToUVRow)(const uint8* src_bgra0, int src_stride_bgra,
599 uint8* dst_u, uint8* dst_v, int width) = BGRAToUVRow_C;
600 void (*BGRAToYRow)(const uint8* src_bgra, uint8* dst_y, int pix) =
601 BGRAToYRow_C;
602 if (!src_bgra ||
603 !dst_y || !dst_u || !dst_v ||
604 width <= 0 || height == 0) {
605 return -1;
606 }
607 // Negative height means invert the image.
608 if (height < 0) {
609 height = -height;
610 src_bgra = src_bgra + (height - 1) * src_stride_bgra;
611 src_stride_bgra = -src_stride_bgra;
612 }
613 #if defined(HAS_BGRATOYROW_SSSE3) && defined(HAS_BGRATOUVROW_SSSE3)
614 if (TestCpuFlag(kCpuHasSSSE3)) {
615 BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
616 BGRAToYRow = BGRAToYRow_Any_SSSE3;
617 if (IS_ALIGNED(width, 16)) {
618 BGRAToUVRow = BGRAToUVRow_SSSE3;
619 BGRAToYRow = BGRAToYRow_SSSE3;
620 }
621 }
622 #endif
623 #if defined(HAS_BGRATOYROW_NEON)
624 if (TestCpuFlag(kCpuHasNEON)) {
625 BGRAToYRow = BGRAToYRow_Any_NEON;
626 if (IS_ALIGNED(width, 8)) {
627 BGRAToYRow = BGRAToYRow_NEON;
628 }
629 }
630 #endif
631 #if defined(HAS_BGRATOUVROW_NEON)
632 if (TestCpuFlag(kCpuHasNEON)) {
633 BGRAToUVRow = BGRAToUVRow_Any_NEON;
634 if (IS_ALIGNED(width, 16)) {
635 BGRAToUVRow = BGRAToUVRow_NEON;
636 }
637 }
638 #endif
639
640 for (y = 0; y < height - 1; y += 2) {
641 BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
642 BGRAToYRow(src_bgra, dst_y, width);
643 BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
644 src_bgra += src_stride_bgra * 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 BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
651 BGRAToYRow(src_bgra, dst_y, width);
652 }
653 return 0;
654 }
655
656 // Convert ABGR to I420.
657 LIBYUV_API
ABGRToI420(const uint8 * src_abgr,int src_stride_abgr,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)658 int ABGRToI420(const uint8* src_abgr, int src_stride_abgr,
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 int y;
664 void (*ABGRToUVRow)(const uint8* src_abgr0, int src_stride_abgr,
665 uint8* dst_u, uint8* dst_v, int width) = ABGRToUVRow_C;
666 void (*ABGRToYRow)(const uint8* src_abgr, uint8* dst_y, int pix) =
667 ABGRToYRow_C;
668 if (!src_abgr ||
669 !dst_y || !dst_u || !dst_v ||
670 width <= 0 || height == 0) {
671 return -1;
672 }
673 // Negative height means invert the image.
674 if (height < 0) {
675 height = -height;
676 src_abgr = src_abgr + (height - 1) * src_stride_abgr;
677 src_stride_abgr = -src_stride_abgr;
678 }
679 #if defined(HAS_ABGRTOYROW_SSSE3) && defined(HAS_ABGRTOUVROW_SSSE3)
680 if (TestCpuFlag(kCpuHasSSSE3)) {
681 ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
682 ABGRToYRow = ABGRToYRow_Any_SSSE3;
683 if (IS_ALIGNED(width, 16)) {
684 ABGRToUVRow = ABGRToUVRow_SSSE3;
685 ABGRToYRow = ABGRToYRow_SSSE3;
686 }
687 }
688 #endif
689 #if defined(HAS_ABGRTOYROW_NEON)
690 if (TestCpuFlag(kCpuHasNEON)) {
691 ABGRToYRow = ABGRToYRow_Any_NEON;
692 if (IS_ALIGNED(width, 8)) {
693 ABGRToYRow = ABGRToYRow_NEON;
694 }
695 }
696 #endif
697 #if defined(HAS_ABGRTOUVROW_NEON)
698 if (TestCpuFlag(kCpuHasNEON)) {
699 ABGRToUVRow = ABGRToUVRow_Any_NEON;
700 if (IS_ALIGNED(width, 16)) {
701 ABGRToUVRow = ABGRToUVRow_NEON;
702 }
703 }
704 #endif
705
706 for (y = 0; y < height - 1; y += 2) {
707 ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
708 ABGRToYRow(src_abgr, dst_y, width);
709 ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
710 src_abgr += src_stride_abgr * 2;
711 dst_y += dst_stride_y * 2;
712 dst_u += dst_stride_u;
713 dst_v += dst_stride_v;
714 }
715 if (height & 1) {
716 ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
717 ABGRToYRow(src_abgr, dst_y, width);
718 }
719 return 0;
720 }
721
722 // Convert RGBA to I420.
723 LIBYUV_API
RGBAToI420(const uint8 * src_rgba,int src_stride_rgba,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)724 int RGBAToI420(const uint8* src_rgba, int src_stride_rgba,
725 uint8* dst_y, int dst_stride_y,
726 uint8* dst_u, int dst_stride_u,
727 uint8* dst_v, int dst_stride_v,
728 int width, int height) {
729 int y;
730 void (*RGBAToUVRow)(const uint8* src_rgba0, int src_stride_rgba,
731 uint8* dst_u, uint8* dst_v, int width) = RGBAToUVRow_C;
732 void (*RGBAToYRow)(const uint8* src_rgba, uint8* dst_y, int pix) =
733 RGBAToYRow_C;
734 if (!src_rgba ||
735 !dst_y || !dst_u || !dst_v ||
736 width <= 0 || height == 0) {
737 return -1;
738 }
739 // Negative height means invert the image.
740 if (height < 0) {
741 height = -height;
742 src_rgba = src_rgba + (height - 1) * src_stride_rgba;
743 src_stride_rgba = -src_stride_rgba;
744 }
745 #if defined(HAS_RGBATOYROW_SSSE3) && defined(HAS_RGBATOUVROW_SSSE3)
746 if (TestCpuFlag(kCpuHasSSSE3)) {
747 RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
748 RGBAToYRow = RGBAToYRow_Any_SSSE3;
749 if (IS_ALIGNED(width, 16)) {
750 RGBAToUVRow = RGBAToUVRow_SSSE3;
751 RGBAToYRow = RGBAToYRow_SSSE3;
752 }
753 }
754 #endif
755 #if defined(HAS_RGBATOYROW_NEON)
756 if (TestCpuFlag(kCpuHasNEON)) {
757 RGBAToYRow = RGBAToYRow_Any_NEON;
758 if (IS_ALIGNED(width, 8)) {
759 RGBAToYRow = RGBAToYRow_NEON;
760 }
761 }
762 #endif
763 #if defined(HAS_RGBATOUVROW_NEON)
764 if (TestCpuFlag(kCpuHasNEON)) {
765 RGBAToUVRow = RGBAToUVRow_Any_NEON;
766 if (IS_ALIGNED(width, 16)) {
767 RGBAToUVRow = RGBAToUVRow_NEON;
768 }
769 }
770 #endif
771
772 for (y = 0; y < height - 1; y += 2) {
773 RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
774 RGBAToYRow(src_rgba, dst_y, width);
775 RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
776 src_rgba += src_stride_rgba * 2;
777 dst_y += dst_stride_y * 2;
778 dst_u += dst_stride_u;
779 dst_v += dst_stride_v;
780 }
781 if (height & 1) {
782 RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
783 RGBAToYRow(src_rgba, dst_y, width);
784 }
785 return 0;
786 }
787
788 // Convert RGB24 to I420.
789 LIBYUV_API
RGB24ToI420(const uint8 * src_rgb24,int src_stride_rgb24,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)790 int RGB24ToI420(const uint8* src_rgb24, int src_stride_rgb24,
791 uint8* dst_y, int dst_stride_y,
792 uint8* dst_u, int dst_stride_u,
793 uint8* dst_v, int dst_stride_v,
794 int width, int height) {
795 int y;
796 #if defined(HAS_RGB24TOYROW_NEON)
797 void (*RGB24ToUVRow)(const uint8* src_rgb24, int src_stride_rgb24,
798 uint8* dst_u, uint8* dst_v, int width) = RGB24ToUVRow_C;
799 void (*RGB24ToYRow)(const uint8* src_rgb24, uint8* dst_y, int pix) =
800 RGB24ToYRow_C;
801 #else
802 void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
803 RGB24ToARGBRow_C;
804 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
805 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
806 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
807 ARGBToYRow_C;
808 #endif
809 if (!src_rgb24 || !dst_y || !dst_u || !dst_v ||
810 width <= 0 || height == 0) {
811 return -1;
812 }
813 // Negative height means invert the image.
814 if (height < 0) {
815 height = -height;
816 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
817 src_stride_rgb24 = -src_stride_rgb24;
818 }
819
820 // Neon version does direct RGB24 to YUV.
821 #if defined(HAS_RGB24TOYROW_NEON)
822 if (TestCpuFlag(kCpuHasNEON)) {
823 RGB24ToUVRow = RGB24ToUVRow_Any_NEON;
824 RGB24ToYRow = RGB24ToYRow_Any_NEON;
825 if (IS_ALIGNED(width, 8)) {
826 RGB24ToYRow = RGB24ToYRow_NEON;
827 if (IS_ALIGNED(width, 16)) {
828 RGB24ToUVRow = RGB24ToUVRow_NEON;
829 }
830 }
831 }
832 // Other platforms do intermediate conversion from RGB24 to ARGB.
833 #else
834 #if defined(HAS_RGB24TOARGBROW_SSSE3)
835 if (TestCpuFlag(kCpuHasSSSE3)) {
836 RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
837 if (IS_ALIGNED(width, 16)) {
838 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
839 }
840 }
841 #endif
842 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
843 if (TestCpuFlag(kCpuHasSSSE3)) {
844 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
845 ARGBToYRow = ARGBToYRow_Any_SSSE3;
846 if (IS_ALIGNED(width, 16)) {
847 ARGBToUVRow = ARGBToUVRow_SSSE3;
848 ARGBToYRow = ARGBToYRow_SSSE3;
849 }
850 }
851 #endif
852 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
853 if (TestCpuFlag(kCpuHasAVX2)) {
854 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
855 ARGBToYRow = ARGBToYRow_Any_AVX2;
856 if (IS_ALIGNED(width, 32)) {
857 ARGBToUVRow = ARGBToUVRow_AVX2;
858 ARGBToYRow = ARGBToYRow_AVX2;
859 }
860 }
861 #endif
862 {
863 // Allocate 2 rows of ARGB.
864 const int kRowSize = (width * 4 + 31) & ~31;
865 align_buffer_64(row, kRowSize * 2);
866 #endif
867
868 for (y = 0; y < height - 1; y += 2) {
869 #if defined(HAS_RGB24TOYROW_NEON)
870 RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
871 RGB24ToYRow(src_rgb24, dst_y, width);
872 RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
873 #else
874 RGB24ToARGBRow(src_rgb24, row, width);
875 RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
876 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
877 ARGBToYRow(row, dst_y, width);
878 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
879 #endif
880 src_rgb24 += src_stride_rgb24 * 2;
881 dst_y += dst_stride_y * 2;
882 dst_u += dst_stride_u;
883 dst_v += dst_stride_v;
884 }
885 if (height & 1) {
886 #if defined(HAS_RGB24TOYROW_NEON)
887 RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
888 RGB24ToYRow(src_rgb24, dst_y, width);
889 #else
890 RGB24ToARGBRow(src_rgb24, row, width);
891 ARGBToUVRow(row, 0, dst_u, dst_v, width);
892 ARGBToYRow(row, dst_y, width);
893 #endif
894 }
895 #if !defined(HAS_RGB24TOYROW_NEON)
896 free_aligned_buffer_64(row);
897 }
898 #endif
899 return 0;
900 }
901
902 // Convert RAW to I420.
903 LIBYUV_API
RAWToI420(const uint8 * src_raw,int src_stride_raw,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)904 int RAWToI420(const uint8* src_raw, int src_stride_raw,
905 uint8* dst_y, int dst_stride_y,
906 uint8* dst_u, int dst_stride_u,
907 uint8* dst_v, int dst_stride_v,
908 int width, int height) {
909 int y;
910 #if defined(HAS_RAWTOYROW_NEON)
911 void (*RAWToUVRow)(const uint8* src_raw, int src_stride_raw,
912 uint8* dst_u, uint8* dst_v, int width) = RAWToUVRow_C;
913 void (*RAWToYRow)(const uint8* src_raw, uint8* dst_y, int pix) =
914 RAWToYRow_C;
915 #else
916 void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
917 RAWToARGBRow_C;
918 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
919 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
920 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
921 ARGBToYRow_C;
922 #endif
923 if (!src_raw || !dst_y || !dst_u || !dst_v ||
924 width <= 0 || height == 0) {
925 return -1;
926 }
927 // Negative height means invert the image.
928 if (height < 0) {
929 height = -height;
930 src_raw = src_raw + (height - 1) * src_stride_raw;
931 src_stride_raw = -src_stride_raw;
932 }
933
934 // Neon version does direct RAW to YUV.
935 #if defined(HAS_RAWTOYROW_NEON)
936 if (TestCpuFlag(kCpuHasNEON)) {
937 RAWToUVRow = RAWToUVRow_Any_NEON;
938 RAWToYRow = RAWToYRow_Any_NEON;
939 if (IS_ALIGNED(width, 8)) {
940 RAWToYRow = RAWToYRow_NEON;
941 if (IS_ALIGNED(width, 16)) {
942 RAWToUVRow = RAWToUVRow_NEON;
943 }
944 }
945 }
946 // Other platforms do intermediate conversion from RAW to ARGB.
947 #else
948 #if defined(HAS_RAWTOARGBROW_SSSE3)
949 if (TestCpuFlag(kCpuHasSSSE3)) {
950 RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
951 if (IS_ALIGNED(width, 16)) {
952 RAWToARGBRow = RAWToARGBRow_SSSE3;
953 }
954 }
955 #endif
956 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
957 if (TestCpuFlag(kCpuHasSSSE3)) {
958 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
959 ARGBToYRow = ARGBToYRow_Any_SSSE3;
960 if (IS_ALIGNED(width, 16)) {
961 ARGBToUVRow = ARGBToUVRow_SSSE3;
962 ARGBToYRow = ARGBToYRow_SSSE3;
963 }
964 }
965 #endif
966 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
967 if (TestCpuFlag(kCpuHasAVX2)) {
968 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
969 ARGBToYRow = ARGBToYRow_Any_AVX2;
970 if (IS_ALIGNED(width, 32)) {
971 ARGBToUVRow = ARGBToUVRow_AVX2;
972 ARGBToYRow = ARGBToYRow_AVX2;
973 }
974 }
975 #endif
976 {
977 // Allocate 2 rows of ARGB.
978 const int kRowSize = (width * 4 + 31) & ~31;
979 align_buffer_64(row, kRowSize * 2);
980 #endif
981
982 for (y = 0; y < height - 1; y += 2) {
983 #if defined(HAS_RAWTOYROW_NEON)
984 RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width);
985 RAWToYRow(src_raw, dst_y, width);
986 RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
987 #else
988 RAWToARGBRow(src_raw, row, width);
989 RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width);
990 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
991 ARGBToYRow(row, dst_y, width);
992 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
993 #endif
994 src_raw += src_stride_raw * 2;
995 dst_y += dst_stride_y * 2;
996 dst_u += dst_stride_u;
997 dst_v += dst_stride_v;
998 }
999 if (height & 1) {
1000 #if defined(HAS_RAWTOYROW_NEON)
1001 RAWToUVRow(src_raw, 0, dst_u, dst_v, width);
1002 RAWToYRow(src_raw, dst_y, width);
1003 #else
1004 RAWToARGBRow(src_raw, row, width);
1005 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1006 ARGBToYRow(row, dst_y, width);
1007 #endif
1008 }
1009 #if !defined(HAS_RAWTOYROW_NEON)
1010 free_aligned_buffer_64(row);
1011 }
1012 #endif
1013 return 0;
1014 }
1015
1016 // Convert RGB565 to I420.
1017 LIBYUV_API
RGB565ToI420(const uint8 * src_rgb565,int src_stride_rgb565,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)1018 int RGB565ToI420(const uint8* src_rgb565, int src_stride_rgb565,
1019 uint8* dst_y, int dst_stride_y,
1020 uint8* dst_u, int dst_stride_u,
1021 uint8* dst_v, int dst_stride_v,
1022 int width, int height) {
1023 int y;
1024 #if defined(HAS_RGB565TOYROW_NEON)
1025 void (*RGB565ToUVRow)(const uint8* src_rgb565, int src_stride_rgb565,
1026 uint8* dst_u, uint8* dst_v, int width) = RGB565ToUVRow_C;
1027 void (*RGB565ToYRow)(const uint8* src_rgb565, uint8* dst_y, int pix) =
1028 RGB565ToYRow_C;
1029 #else
1030 void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1031 RGB565ToARGBRow_C;
1032 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1033 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1034 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1035 ARGBToYRow_C;
1036 #endif
1037 if (!src_rgb565 || !dst_y || !dst_u || !dst_v ||
1038 width <= 0 || height == 0) {
1039 return -1;
1040 }
1041 // Negative height means invert the image.
1042 if (height < 0) {
1043 height = -height;
1044 src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
1045 src_stride_rgb565 = -src_stride_rgb565;
1046 }
1047
1048 // Neon version does direct RGB565 to YUV.
1049 #if defined(HAS_RGB565TOYROW_NEON)
1050 if (TestCpuFlag(kCpuHasNEON)) {
1051 RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
1052 RGB565ToYRow = RGB565ToYRow_Any_NEON;
1053 if (IS_ALIGNED(width, 8)) {
1054 RGB565ToYRow = RGB565ToYRow_NEON;
1055 if (IS_ALIGNED(width, 16)) {
1056 RGB565ToUVRow = RGB565ToUVRow_NEON;
1057 }
1058 }
1059 }
1060 // Other platforms do intermediate conversion from RGB565 to ARGB.
1061 #else
1062 #if defined(HAS_RGB565TOARGBROW_SSE2)
1063 if (TestCpuFlag(kCpuHasSSE2)) {
1064 RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
1065 if (IS_ALIGNED(width, 8)) {
1066 RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
1067 }
1068 }
1069 #endif
1070 #if defined(HAS_RGB565TOARGBROW_AVX2)
1071 if (TestCpuFlag(kCpuHasAVX2)) {
1072 RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
1073 if (IS_ALIGNED(width, 16)) {
1074 RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
1075 }
1076 }
1077 #endif
1078 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1079 if (TestCpuFlag(kCpuHasSSSE3)) {
1080 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1081 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1082 if (IS_ALIGNED(width, 16)) {
1083 ARGBToUVRow = ARGBToUVRow_SSSE3;
1084 ARGBToYRow = ARGBToYRow_SSSE3;
1085 }
1086 }
1087 #endif
1088 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1089 if (TestCpuFlag(kCpuHasAVX2)) {
1090 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1091 ARGBToYRow = ARGBToYRow_Any_AVX2;
1092 if (IS_ALIGNED(width, 32)) {
1093 ARGBToUVRow = ARGBToUVRow_AVX2;
1094 ARGBToYRow = ARGBToYRow_AVX2;
1095 }
1096 }
1097 #endif
1098 {
1099 // Allocate 2 rows of ARGB.
1100 const int kRowSize = (width * 4 + 31) & ~31;
1101 align_buffer_64(row, kRowSize * 2);
1102 #endif
1103
1104 for (y = 0; y < height - 1; y += 2) {
1105 #if defined(HAS_RGB565TOYROW_NEON)
1106 RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width);
1107 RGB565ToYRow(src_rgb565, dst_y, width);
1108 RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
1109 #else
1110 RGB565ToARGBRow(src_rgb565, row, width);
1111 RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width);
1112 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1113 ARGBToYRow(row, dst_y, width);
1114 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1115 #endif
1116 src_rgb565 += src_stride_rgb565 * 2;
1117 dst_y += dst_stride_y * 2;
1118 dst_u += dst_stride_u;
1119 dst_v += dst_stride_v;
1120 }
1121 if (height & 1) {
1122 #if defined(HAS_RGB565TOYROW_NEON)
1123 RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width);
1124 RGB565ToYRow(src_rgb565, dst_y, width);
1125 #else
1126 RGB565ToARGBRow(src_rgb565, row, width);
1127 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1128 ARGBToYRow(row, dst_y, width);
1129 #endif
1130 }
1131 #if !defined(HAS_RGB565TOYROW_NEON)
1132 free_aligned_buffer_64(row);
1133 }
1134 #endif
1135 return 0;
1136 }
1137
1138 // Convert ARGB1555 to I420.
1139 LIBYUV_API
ARGB1555ToI420(const uint8 * src_argb1555,int src_stride_argb1555,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)1140 int ARGB1555ToI420(const uint8* src_argb1555, int src_stride_argb1555,
1141 uint8* dst_y, int dst_stride_y,
1142 uint8* dst_u, int dst_stride_u,
1143 uint8* dst_v, int dst_stride_v,
1144 int width, int height) {
1145 int y;
1146 #if defined(HAS_ARGB1555TOYROW_NEON)
1147 void (*ARGB1555ToUVRow)(const uint8* src_argb1555, int src_stride_argb1555,
1148 uint8* dst_u, uint8* dst_v, int width) = ARGB1555ToUVRow_C;
1149 void (*ARGB1555ToYRow)(const uint8* src_argb1555, uint8* dst_y, int pix) =
1150 ARGB1555ToYRow_C;
1151 #else
1152 void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1153 ARGB1555ToARGBRow_C;
1154 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1155 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1156 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1157 ARGBToYRow_C;
1158 #endif
1159 if (!src_argb1555 || !dst_y || !dst_u || !dst_v ||
1160 width <= 0 || height == 0) {
1161 return -1;
1162 }
1163 // Negative height means invert the image.
1164 if (height < 0) {
1165 height = -height;
1166 src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
1167 src_stride_argb1555 = -src_stride_argb1555;
1168 }
1169
1170 // Neon version does direct ARGB1555 to YUV.
1171 #if defined(HAS_ARGB1555TOYROW_NEON)
1172 if (TestCpuFlag(kCpuHasNEON)) {
1173 ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
1174 ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
1175 if (IS_ALIGNED(width, 8)) {
1176 ARGB1555ToYRow = ARGB1555ToYRow_NEON;
1177 if (IS_ALIGNED(width, 16)) {
1178 ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
1179 }
1180 }
1181 }
1182 // Other platforms do intermediate conversion from ARGB1555 to ARGB.
1183 #else
1184 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
1185 if (TestCpuFlag(kCpuHasSSE2)) {
1186 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
1187 if (IS_ALIGNED(width, 8)) {
1188 ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
1189 }
1190 }
1191 #endif
1192 #if defined(HAS_ARGB1555TOARGBROW_AVX2)
1193 if (TestCpuFlag(kCpuHasAVX2)) {
1194 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
1195 if (IS_ALIGNED(width, 16)) {
1196 ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
1197 }
1198 }
1199 #endif
1200 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1201 if (TestCpuFlag(kCpuHasSSSE3)) {
1202 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1203 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1204 if (IS_ALIGNED(width, 16)) {
1205 ARGBToUVRow = ARGBToUVRow_SSSE3;
1206 ARGBToYRow = ARGBToYRow_SSSE3;
1207 }
1208 }
1209 #endif
1210 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1211 if (TestCpuFlag(kCpuHasAVX2)) {
1212 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1213 ARGBToYRow = ARGBToYRow_Any_AVX2;
1214 if (IS_ALIGNED(width, 32)) {
1215 ARGBToUVRow = ARGBToUVRow_AVX2;
1216 ARGBToYRow = ARGBToYRow_AVX2;
1217 }
1218 }
1219 #endif
1220 {
1221 // Allocate 2 rows of ARGB.
1222 const int kRowSize = (width * 4 + 31) & ~31;
1223 align_buffer_64(row, kRowSize * 2);
1224 #endif
1225
1226 for (y = 0; y < height - 1; y += 2) {
1227 #if defined(HAS_ARGB1555TOYROW_NEON)
1228 ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width);
1229 ARGB1555ToYRow(src_argb1555, dst_y, width);
1230 ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y,
1231 width);
1232 #else
1233 ARGB1555ToARGBRow(src_argb1555, row, width);
1234 ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize,
1235 width);
1236 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1237 ARGBToYRow(row, dst_y, width);
1238 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1239 #endif
1240 src_argb1555 += src_stride_argb1555 * 2;
1241 dst_y += dst_stride_y * 2;
1242 dst_u += dst_stride_u;
1243 dst_v += dst_stride_v;
1244 }
1245 if (height & 1) {
1246 #if defined(HAS_ARGB1555TOYROW_NEON)
1247 ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width);
1248 ARGB1555ToYRow(src_argb1555, dst_y, width);
1249 #else
1250 ARGB1555ToARGBRow(src_argb1555, row, width);
1251 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1252 ARGBToYRow(row, dst_y, width);
1253 #endif
1254 }
1255 #if !defined(HAS_ARGB1555TOYROW_NEON)
1256 free_aligned_buffer_64(row);
1257 }
1258 #endif
1259 return 0;
1260 }
1261
1262 // Convert ARGB4444 to I420.
1263 LIBYUV_API
ARGB4444ToI420(const uint8 * src_argb4444,int src_stride_argb4444,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)1264 int ARGB4444ToI420(const uint8* src_argb4444, int src_stride_argb4444,
1265 uint8* dst_y, int dst_stride_y,
1266 uint8* dst_u, int dst_stride_u,
1267 uint8* dst_v, int dst_stride_v,
1268 int width, int height) {
1269 int y;
1270 #if defined(HAS_ARGB4444TOYROW_NEON)
1271 void (*ARGB4444ToUVRow)(const uint8* src_argb4444, int src_stride_argb4444,
1272 uint8* dst_u, uint8* dst_v, int width) = ARGB4444ToUVRow_C;
1273 void (*ARGB4444ToYRow)(const uint8* src_argb4444, uint8* dst_y, int pix) =
1274 ARGB4444ToYRow_C;
1275 #else
1276 void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) =
1277 ARGB4444ToARGBRow_C;
1278 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
1279 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
1280 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int pix) =
1281 ARGBToYRow_C;
1282 #endif
1283 if (!src_argb4444 || !dst_y || !dst_u || !dst_v ||
1284 width <= 0 || height == 0) {
1285 return -1;
1286 }
1287 // Negative height means invert the image.
1288 if (height < 0) {
1289 height = -height;
1290 src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
1291 src_stride_argb4444 = -src_stride_argb4444;
1292 }
1293
1294 // Neon version does direct ARGB4444 to YUV.
1295 #if defined(HAS_ARGB4444TOYROW_NEON)
1296 if (TestCpuFlag(kCpuHasNEON)) {
1297 ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
1298 ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
1299 if (IS_ALIGNED(width, 8)) {
1300 ARGB4444ToYRow = ARGB4444ToYRow_NEON;
1301 if (IS_ALIGNED(width, 16)) {
1302 ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
1303 }
1304 }
1305 }
1306 // Other platforms do intermediate conversion from ARGB4444 to ARGB.
1307 #else
1308 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
1309 if (TestCpuFlag(kCpuHasSSE2)) {
1310 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
1311 if (IS_ALIGNED(width, 8)) {
1312 ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
1313 }
1314 }
1315 #endif
1316 #if defined(HAS_ARGB4444TOARGBROW_AVX2)
1317 if (TestCpuFlag(kCpuHasAVX2)) {
1318 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
1319 if (IS_ALIGNED(width, 16)) {
1320 ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
1321 }
1322 }
1323 #endif
1324 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1325 if (TestCpuFlag(kCpuHasSSSE3)) {
1326 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1327 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1328 if (IS_ALIGNED(width, 16)) {
1329 ARGBToUVRow = ARGBToUVRow_SSSE3;
1330 ARGBToYRow = ARGBToYRow_SSSE3;
1331 }
1332 }
1333 #endif
1334 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1335 if (TestCpuFlag(kCpuHasAVX2)) {
1336 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1337 ARGBToYRow = ARGBToYRow_Any_AVX2;
1338 if (IS_ALIGNED(width, 32)) {
1339 ARGBToUVRow = ARGBToUVRow_AVX2;
1340 ARGBToYRow = ARGBToYRow_AVX2;
1341 }
1342 }
1343 #endif
1344 {
1345 // Allocate 2 rows of ARGB.
1346 const int kRowSize = (width * 4 + 31) & ~31;
1347 align_buffer_64(row, kRowSize * 2);
1348 #endif
1349
1350 for (y = 0; y < height - 1; y += 2) {
1351 #if defined(HAS_ARGB4444TOYROW_NEON)
1352 ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width);
1353 ARGB4444ToYRow(src_argb4444, dst_y, width);
1354 ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y,
1355 width);
1356 #else
1357 ARGB4444ToARGBRow(src_argb4444, row, width);
1358 ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize,
1359 width);
1360 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1361 ARGBToYRow(row, dst_y, width);
1362 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1363 #endif
1364 src_argb4444 += src_stride_argb4444 * 2;
1365 dst_y += dst_stride_y * 2;
1366 dst_u += dst_stride_u;
1367 dst_v += dst_stride_v;
1368 }
1369 if (height & 1) {
1370 #if defined(HAS_ARGB4444TOYROW_NEON)
1371 ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width);
1372 ARGB4444ToYRow(src_argb4444, dst_y, width);
1373 #else
1374 ARGB4444ToARGBRow(src_argb4444, row, width);
1375 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1376 ARGBToYRow(row, dst_y, width);
1377 #endif
1378 }
1379 #if !defined(HAS_ARGB4444TOYROW_NEON)
1380 free_aligned_buffer_64(row);
1381 }
1382 #endif
1383 return 0;
1384 }
1385
1386 #ifdef __cplusplus
1387 } // extern "C"
1388 } // namespace libyuv
1389 #endif
1390