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/row.h"
18 #include "libyuv/scale.h" // For ScalePlane()
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,
32 int src_stride_y,
33 const uint8* src_u,
34 int src_stride_u,
35 const uint8* src_v,
36 int src_stride_v,
37 uint8* dst_y,
38 int dst_stride_y,
39 uint8* dst_u,
40 int dst_stride_u,
41 uint8* dst_v,
42 int dst_stride_v,
43 int src_y_width,
44 int src_y_height,
45 int src_uv_width,
46 int src_uv_height) {
47 const int dst_y_width = Abs(src_y_width);
48 const int dst_y_height = Abs(src_y_height);
49 const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
50 const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
51 if (src_uv_width == 0 || src_uv_height == 0) {
52 return -1;
53 }
54 if (dst_y) {
55 ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, dst_y,
56 dst_stride_y, dst_y_width, dst_y_height, kFilterBilinear);
57 }
58 ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
59 dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
60 ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
61 dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
62 return 0;
63 }
64
65 // Copy I420 with optional flipping
66 // TODO(fbarchard): Use Scale plane which supports mirroring, but ensure
67 // is does row coalescing.
68 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)69 int I420Copy(const uint8* src_y,
70 int src_stride_y,
71 const uint8* src_u,
72 int src_stride_u,
73 const uint8* src_v,
74 int src_stride_v,
75 uint8* dst_y,
76 int dst_stride_y,
77 uint8* dst_u,
78 int dst_stride_u,
79 uint8* dst_v,
80 int dst_stride_v,
81 int width,
82 int height) {
83 int halfwidth = (width + 1) >> 1;
84 int halfheight = (height + 1) >> 1;
85 if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
86 return -1;
87 }
88 // Negative height means invert the image.
89 if (height < 0) {
90 height = -height;
91 halfheight = (height + 1) >> 1;
92 src_y = src_y + (height - 1) * src_stride_y;
93 src_u = src_u + (halfheight - 1) * src_stride_u;
94 src_v = src_v + (halfheight - 1) * src_stride_v;
95 src_stride_y = -src_stride_y;
96 src_stride_u = -src_stride_u;
97 src_stride_v = -src_stride_v;
98 }
99
100 if (dst_y) {
101 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
102 }
103 // Copy UV planes.
104 CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
105 CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
106 return 0;
107 }
108
109 // 422 chroma is 1/2 width, 1x height
110 // 420 chroma is 1/2 width, 1/2 height
111 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)112 int I422ToI420(const uint8* src_y,
113 int src_stride_y,
114 const uint8* src_u,
115 int src_stride_u,
116 const uint8* src_v,
117 int src_stride_v,
118 uint8* dst_y,
119 int dst_stride_y,
120 uint8* dst_u,
121 int dst_stride_u,
122 uint8* dst_v,
123 int dst_stride_v,
124 int width,
125 int height) {
126 const int src_uv_width = SUBSAMPLE(width, 1, 1);
127 return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
128 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
129 dst_v, dst_stride_v, width, height, src_uv_width, height);
130 }
131
132 // 444 chroma is 1x width, 1x height
133 // 420 chroma is 1/2 width, 1/2 height
134 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)135 int I444ToI420(const uint8* src_y,
136 int src_stride_y,
137 const uint8* src_u,
138 int src_stride_u,
139 const uint8* src_v,
140 int src_stride_v,
141 uint8* dst_y,
142 int dst_stride_y,
143 uint8* dst_u,
144 int dst_stride_u,
145 uint8* dst_v,
146 int dst_stride_v,
147 int width,
148 int height) {
149 return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
150 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
151 dst_v, dst_stride_v, width, height, width, height);
152 }
153
154 // I400 is greyscale typically used in MJPG
155 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)156 int I400ToI420(const uint8* src_y,
157 int src_stride_y,
158 uint8* dst_y,
159 int dst_stride_y,
160 uint8* dst_u,
161 int dst_stride_u,
162 uint8* dst_v,
163 int dst_stride_v,
164 int width,
165 int height) {
166 int halfwidth = (width + 1) >> 1;
167 int halfheight = (height + 1) >> 1;
168 if (!dst_u || !dst_v || width <= 0 || height == 0) {
169 return -1;
170 }
171 // Negative height means invert the image.
172 if (height < 0) {
173 height = -height;
174 halfheight = (height + 1) >> 1;
175 src_y = src_y + (height - 1) * src_stride_y;
176 src_stride_y = -src_stride_y;
177 }
178 if (dst_y) {
179 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
180 }
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,
187 int src_stride_0,
188 int src_stride_1,
189 uint8* dst,
190 int dst_stride,
191 int width,
192 int height) {
193 int y;
194 void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
195 #if defined(HAS_COPYROW_SSE2)
196 if (TestCpuFlag(kCpuHasSSE2)) {
197 CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2;
198 }
199 #endif
200 #if defined(HAS_COPYROW_AVX)
201 if (TestCpuFlag(kCpuHasAVX)) {
202 CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
203 }
204 #endif
205 #if defined(HAS_COPYROW_ERMS)
206 if (TestCpuFlag(kCpuHasERMS)) {
207 CopyRow = CopyRow_ERMS;
208 }
209 #endif
210 #if defined(HAS_COPYROW_NEON)
211 if (TestCpuFlag(kCpuHasNEON)) {
212 CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
213 }
214 #endif
215 #if defined(HAS_COPYROW_MIPS)
216 if (TestCpuFlag(kCpuHasMIPS)) {
217 CopyRow = CopyRow_MIPS;
218 }
219 #endif
220
221 // Copy plane
222 for (y = 0; y < height - 1; y += 2) {
223 CopyRow(src, dst, width);
224 CopyRow(src + src_stride_0, dst + dst_stride, width);
225 src += src_stride_0 + src_stride_1;
226 dst += dst_stride * 2;
227 }
228 if (height & 1) {
229 CopyRow(src, dst, width);
230 }
231 }
232
233 // Support converting from FOURCC_M420
234 // Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for
235 // easy conversion to I420.
236 // M420 format description:
237 // M420 is row biplanar 420: 2 rows of Y and 1 row of UV.
238 // Chroma is half width / half height. (420)
239 // src_stride_m420 is row planar. Normally this will be the width in pixels.
240 // The UV plane is half width, but 2 values, so src_stride_m420 applies to
241 // 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)242 static int X420ToI420(const uint8* src_y,
243 int src_stride_y0,
244 int src_stride_y1,
245 const uint8* src_uv,
246 int src_stride_uv,
247 uint8* dst_y,
248 int dst_stride_y,
249 uint8* dst_u,
250 int dst_stride_u,
251 uint8* dst_v,
252 int dst_stride_v,
253 int width,
254 int height) {
255 int halfwidth = (width + 1) >> 1;
256 int halfheight = (height + 1) >> 1;
257 if (!src_uv || !dst_u || !dst_v || width <= 0 || height == 0) {
258 return -1;
259 }
260 // Negative height means invert the image.
261 if (height < 0) {
262 height = -height;
263 halfheight = (height + 1) >> 1;
264 if (dst_y) {
265 dst_y = dst_y + (height - 1) * dst_stride_y;
266 }
267 dst_u = dst_u + (halfheight - 1) * dst_stride_u;
268 dst_v = dst_v + (halfheight - 1) * dst_stride_v;
269 dst_stride_y = -dst_stride_y;
270 dst_stride_u = -dst_stride_u;
271 dst_stride_v = -dst_stride_v;
272 }
273 // Coalesce rows.
274 if (src_stride_y0 == width && src_stride_y1 == width &&
275 dst_stride_y == width) {
276 width *= height;
277 height = 1;
278 src_stride_y0 = src_stride_y1 = dst_stride_y = 0;
279 }
280 // Coalesce rows.
281 if (src_stride_uv == halfwidth * 2 && dst_stride_u == halfwidth &&
282 dst_stride_v == halfwidth) {
283 halfwidth *= halfheight;
284 halfheight = 1;
285 src_stride_uv = dst_stride_u = dst_stride_v = 0;
286 }
287
288 if (dst_y) {
289 if (src_stride_y0 == src_stride_y1) {
290 CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height);
291 } else {
292 CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y,
293 width, height);
294 }
295 }
296
297 // Split UV plane - NV12 / NV21
298 SplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v, dst_stride_v,
299 halfwidth, halfheight);
300
301 return 0;
302 }
303
304 // Convert NV12 to I420.
305 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)306 int NV12ToI420(const uint8* src_y,
307 int src_stride_y,
308 const uint8* src_uv,
309 int src_stride_uv,
310 uint8* dst_y,
311 int dst_stride_y,
312 uint8* dst_u,
313 int dst_stride_u,
314 uint8* dst_v,
315 int dst_stride_v,
316 int width,
317 int height) {
318 return X420ToI420(src_y, src_stride_y, src_stride_y, src_uv, src_stride_uv,
319 dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v,
320 dst_stride_v, width, height);
321 }
322
323 // Convert NV21 to I420. Same as NV12 but u and v pointers swapped.
324 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)325 int NV21ToI420(const uint8* src_y,
326 int src_stride_y,
327 const uint8* src_vu,
328 int src_stride_vu,
329 uint8* dst_y,
330 int dst_stride_y,
331 uint8* dst_u,
332 int dst_stride_u,
333 uint8* dst_v,
334 int dst_stride_v,
335 int width,
336 int height) {
337 return X420ToI420(src_y, src_stride_y, src_stride_y, src_vu, src_stride_vu,
338 dst_y, dst_stride_y, dst_v, dst_stride_v, dst_u,
339 dst_stride_u, width, height);
340 }
341
342 // Convert M420 to I420.
343 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)344 int M420ToI420(const uint8* src_m420,
345 int src_stride_m420,
346 uint8* dst_y,
347 int dst_stride_y,
348 uint8* dst_u,
349 int dst_stride_u,
350 uint8* dst_v,
351 int dst_stride_v,
352 int width,
353 int height) {
354 return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2,
355 src_m420 + src_stride_m420 * 2, src_stride_m420 * 3, dst_y,
356 dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
357 width, height);
358 }
359
360 // Convert YUY2 to I420.
361 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)362 int YUY2ToI420(const uint8* src_yuy2,
363 int src_stride_yuy2,
364 uint8* dst_y,
365 int dst_stride_y,
366 uint8* dst_u,
367 int dst_stride_u,
368 uint8* dst_v,
369 int dst_stride_v,
370 int width,
371 int height) {
372 int y;
373 void (*YUY2ToUVRow)(const uint8* src_yuy2, int src_stride_yuy2, uint8* dst_u,
374 uint8* dst_v, int width) = YUY2ToUVRow_C;
375 void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int width) =
376 YUY2ToYRow_C;
377 // Negative height means invert the image.
378 if (height < 0) {
379 height = -height;
380 src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
381 src_stride_yuy2 = -src_stride_yuy2;
382 }
383 #if defined(HAS_YUY2TOYROW_SSE2)
384 if (TestCpuFlag(kCpuHasSSE2)) {
385 YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
386 YUY2ToYRow = YUY2ToYRow_Any_SSE2;
387 if (IS_ALIGNED(width, 16)) {
388 YUY2ToUVRow = YUY2ToUVRow_SSE2;
389 YUY2ToYRow = YUY2ToYRow_SSE2;
390 }
391 }
392 #endif
393 #if defined(HAS_YUY2TOYROW_AVX2)
394 if (TestCpuFlag(kCpuHasAVX2)) {
395 YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
396 YUY2ToYRow = YUY2ToYRow_Any_AVX2;
397 if (IS_ALIGNED(width, 32)) {
398 YUY2ToUVRow = YUY2ToUVRow_AVX2;
399 YUY2ToYRow = YUY2ToYRow_AVX2;
400 }
401 }
402 #endif
403 #if defined(HAS_YUY2TOYROW_NEON)
404 if (TestCpuFlag(kCpuHasNEON)) {
405 YUY2ToYRow = YUY2ToYRow_Any_NEON;
406 YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
407 if (IS_ALIGNED(width, 16)) {
408 YUY2ToYRow = YUY2ToYRow_NEON;
409 YUY2ToUVRow = YUY2ToUVRow_NEON;
410 }
411 }
412 #endif
413 #if defined(HAS_YUY2TOYROW_MSA)
414 if (TestCpuFlag(kCpuHasMSA)) {
415 YUY2ToYRow = YUY2ToYRow_Any_MSA;
416 YUY2ToUVRow = YUY2ToUVRow_Any_MSA;
417 if (IS_ALIGNED(width, 32)) {
418 YUY2ToYRow = YUY2ToYRow_MSA;
419 YUY2ToUVRow = YUY2ToUVRow_MSA;
420 }
421 }
422 #endif
423
424 for (y = 0; y < height - 1; y += 2) {
425 YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
426 YUY2ToYRow(src_yuy2, dst_y, width);
427 YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
428 src_yuy2 += src_stride_yuy2 * 2;
429 dst_y += dst_stride_y * 2;
430 dst_u += dst_stride_u;
431 dst_v += dst_stride_v;
432 }
433 if (height & 1) {
434 YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
435 YUY2ToYRow(src_yuy2, dst_y, width);
436 }
437 return 0;
438 }
439
440 // Convert UYVY to I420.
441 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)442 int UYVYToI420(const uint8* src_uyvy,
443 int src_stride_uyvy,
444 uint8* dst_y,
445 int dst_stride_y,
446 uint8* dst_u,
447 int dst_stride_u,
448 uint8* dst_v,
449 int dst_stride_v,
450 int width,
451 int height) {
452 int y;
453 void (*UYVYToUVRow)(const uint8* src_uyvy, int src_stride_uyvy, uint8* dst_u,
454 uint8* dst_v, int width) = UYVYToUVRow_C;
455 void (*UYVYToYRow)(const uint8* src_uyvy, uint8* dst_y, int width) =
456 UYVYToYRow_C;
457 // Negative height means invert the image.
458 if (height < 0) {
459 height = -height;
460 src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
461 src_stride_uyvy = -src_stride_uyvy;
462 }
463 #if defined(HAS_UYVYTOYROW_SSE2)
464 if (TestCpuFlag(kCpuHasSSE2)) {
465 UYVYToUVRow = UYVYToUVRow_Any_SSE2;
466 UYVYToYRow = UYVYToYRow_Any_SSE2;
467 if (IS_ALIGNED(width, 16)) {
468 UYVYToUVRow = UYVYToUVRow_SSE2;
469 UYVYToYRow = UYVYToYRow_SSE2;
470 }
471 }
472 #endif
473 #if defined(HAS_UYVYTOYROW_AVX2)
474 if (TestCpuFlag(kCpuHasAVX2)) {
475 UYVYToUVRow = UYVYToUVRow_Any_AVX2;
476 UYVYToYRow = UYVYToYRow_Any_AVX2;
477 if (IS_ALIGNED(width, 32)) {
478 UYVYToUVRow = UYVYToUVRow_AVX2;
479 UYVYToYRow = UYVYToYRow_AVX2;
480 }
481 }
482 #endif
483 #if defined(HAS_UYVYTOYROW_NEON)
484 if (TestCpuFlag(kCpuHasNEON)) {
485 UYVYToYRow = UYVYToYRow_Any_NEON;
486 UYVYToUVRow = UYVYToUVRow_Any_NEON;
487 if (IS_ALIGNED(width, 16)) {
488 UYVYToYRow = UYVYToYRow_NEON;
489 UYVYToUVRow = UYVYToUVRow_NEON;
490 }
491 }
492 #endif
493 #if defined(HAS_UYVYTOYROW_MSA)
494 if (TestCpuFlag(kCpuHasMSA)) {
495 UYVYToYRow = UYVYToYRow_Any_MSA;
496 UYVYToUVRow = UYVYToUVRow_Any_MSA;
497 if (IS_ALIGNED(width, 32)) {
498 UYVYToYRow = UYVYToYRow_MSA;
499 UYVYToUVRow = UYVYToUVRow_MSA;
500 }
501 }
502 #endif
503
504 for (y = 0; y < height - 1; y += 2) {
505 UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
506 UYVYToYRow(src_uyvy, dst_y, width);
507 UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
508 src_uyvy += src_stride_uyvy * 2;
509 dst_y += dst_stride_y * 2;
510 dst_u += dst_stride_u;
511 dst_v += dst_stride_v;
512 }
513 if (height & 1) {
514 UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
515 UYVYToYRow(src_uyvy, dst_y, width);
516 }
517 return 0;
518 }
519
520 // Convert ARGB to I420.
521 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)522 int ARGBToI420(const uint8* src_argb,
523 int src_stride_argb,
524 uint8* dst_y,
525 int dst_stride_y,
526 uint8* dst_u,
527 int dst_stride_u,
528 uint8* dst_v,
529 int dst_stride_v,
530 int width,
531 int height) {
532 int y;
533 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u,
534 uint8* dst_v, int width) = ARGBToUVRow_C;
535 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
536 ARGBToYRow_C;
537 if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
538 return -1;
539 }
540 // Negative height means invert the image.
541 if (height < 0) {
542 height = -height;
543 src_argb = src_argb + (height - 1) * src_stride_argb;
544 src_stride_argb = -src_stride_argb;
545 }
546 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
547 if (TestCpuFlag(kCpuHasSSSE3)) {
548 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
549 ARGBToYRow = ARGBToYRow_Any_SSSE3;
550 if (IS_ALIGNED(width, 16)) {
551 ARGBToUVRow = ARGBToUVRow_SSSE3;
552 ARGBToYRow = ARGBToYRow_SSSE3;
553 }
554 }
555 #endif
556 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
557 if (TestCpuFlag(kCpuHasAVX2)) {
558 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
559 ARGBToYRow = ARGBToYRow_Any_AVX2;
560 if (IS_ALIGNED(width, 32)) {
561 ARGBToUVRow = ARGBToUVRow_AVX2;
562 ARGBToYRow = ARGBToYRow_AVX2;
563 }
564 }
565 #endif
566 #if defined(HAS_ARGBTOYROW_NEON)
567 if (TestCpuFlag(kCpuHasNEON)) {
568 ARGBToYRow = ARGBToYRow_Any_NEON;
569 if (IS_ALIGNED(width, 8)) {
570 ARGBToYRow = ARGBToYRow_NEON;
571 }
572 }
573 #endif
574 #if defined(HAS_ARGBTOUVROW_NEON)
575 if (TestCpuFlag(kCpuHasNEON)) {
576 ARGBToUVRow = ARGBToUVRow_Any_NEON;
577 if (IS_ALIGNED(width, 16)) {
578 ARGBToUVRow = ARGBToUVRow_NEON;
579 }
580 }
581 #endif
582 #if defined(HAS_ARGBTOYROW_DSPR2)
583 if (TestCpuFlag(kCpuHasDSPR2)) {
584 ARGBToYRow = ARGBToYRow_Any_DSPR2;
585 if (IS_ALIGNED(width, 8)) {
586 ARGBToYRow = ARGBToYRow_DSPR2;
587 }
588 }
589 #endif
590 #if defined(HAS_ARGBTOYROW_MSA)
591 if (TestCpuFlag(kCpuHasMSA)) {
592 ARGBToYRow = ARGBToYRow_Any_MSA;
593 if (IS_ALIGNED(width, 16)) {
594 ARGBToYRow = ARGBToYRow_MSA;
595 }
596 }
597 #endif
598 #if defined(HAS_ARGBTOUVROW_DSPR2)
599 if (TestCpuFlag(kCpuHasDSPR2)) {
600 ARGBToUVRow = ARGBToUVRow_Any_DSPR2;
601 if (IS_ALIGNED(width, 16)) {
602 ARGBToUVRow = ARGBToUVRow_DSPR2;
603 }
604 }
605 #endif
606 #if defined(HAS_ARGBTOUVROW_MSA)
607 if (TestCpuFlag(kCpuHasMSA)) {
608 ARGBToUVRow = ARGBToUVRow_Any_MSA;
609 if (IS_ALIGNED(width, 32)) {
610 ARGBToUVRow = ARGBToUVRow_MSA;
611 }
612 }
613 #endif
614
615 for (y = 0; y < height - 1; y += 2) {
616 ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
617 ARGBToYRow(src_argb, dst_y, width);
618 ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
619 src_argb += src_stride_argb * 2;
620 dst_y += dst_stride_y * 2;
621 dst_u += dst_stride_u;
622 dst_v += dst_stride_v;
623 }
624 if (height & 1) {
625 ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
626 ARGBToYRow(src_argb, dst_y, width);
627 }
628 return 0;
629 }
630
631 // Convert BGRA to I420.
632 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)633 int BGRAToI420(const uint8* src_bgra,
634 int src_stride_bgra,
635 uint8* dst_y,
636 int dst_stride_y,
637 uint8* dst_u,
638 int dst_stride_u,
639 uint8* dst_v,
640 int dst_stride_v,
641 int width,
642 int height) {
643 int y;
644 void (*BGRAToUVRow)(const uint8* src_bgra0, int src_stride_bgra, uint8* dst_u,
645 uint8* dst_v, int width) = BGRAToUVRow_C;
646 void (*BGRAToYRow)(const uint8* src_bgra, uint8* dst_y, int width) =
647 BGRAToYRow_C;
648 if (!src_bgra || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
649 return -1;
650 }
651 // Negative height means invert the image.
652 if (height < 0) {
653 height = -height;
654 src_bgra = src_bgra + (height - 1) * src_stride_bgra;
655 src_stride_bgra = -src_stride_bgra;
656 }
657 #if defined(HAS_BGRATOYROW_SSSE3) && defined(HAS_BGRATOUVROW_SSSE3)
658 if (TestCpuFlag(kCpuHasSSSE3)) {
659 BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
660 BGRAToYRow = BGRAToYRow_Any_SSSE3;
661 if (IS_ALIGNED(width, 16)) {
662 BGRAToUVRow = BGRAToUVRow_SSSE3;
663 BGRAToYRow = BGRAToYRow_SSSE3;
664 }
665 }
666 #endif
667 #if defined(HAS_BGRATOYROW_NEON)
668 if (TestCpuFlag(kCpuHasNEON)) {
669 BGRAToYRow = BGRAToYRow_Any_NEON;
670 if (IS_ALIGNED(width, 8)) {
671 BGRAToYRow = BGRAToYRow_NEON;
672 }
673 }
674 #endif
675 #if defined(HAS_BGRATOUVROW_NEON)
676 if (TestCpuFlag(kCpuHasNEON)) {
677 BGRAToUVRow = BGRAToUVRow_Any_NEON;
678 if (IS_ALIGNED(width, 16)) {
679 BGRAToUVRow = BGRAToUVRow_NEON;
680 }
681 }
682 #endif
683 #if defined(HAS_BGRATOYROW_DSPR2)
684 if (TestCpuFlag(kCpuHasDSPR2)) {
685 BGRAToYRow = BGRAToYRow_Any_DSPR2;
686 if (IS_ALIGNED(width, 8)) {
687 BGRAToYRow = BGRAToYRow_DSPR2;
688 }
689 }
690 #endif
691 #if defined(HAS_BGRATOUVROW_DSPR2)
692 if (TestCpuFlag(kCpuHasDSPR2)) {
693 BGRAToUVRow = BGRAToUVRow_Any_DSPR2;
694 if (IS_ALIGNED(width, 16)) {
695 BGRAToUVRow = BGRAToUVRow_DSPR2;
696 }
697 }
698 #endif
699 #if defined(HAS_BGRATOYROW_MSA)
700 if (TestCpuFlag(kCpuHasMSA)) {
701 BGRAToYRow = BGRAToYRow_Any_MSA;
702 if (IS_ALIGNED(width, 16)) {
703 BGRAToYRow = BGRAToYRow_MSA;
704 }
705 }
706 #endif
707 #if defined(HAS_BGRATOUVROW_MSA)
708 if (TestCpuFlag(kCpuHasMSA)) {
709 BGRAToUVRow = BGRAToUVRow_Any_MSA;
710 if (IS_ALIGNED(width, 16)) {
711 BGRAToUVRow = BGRAToUVRow_MSA;
712 }
713 }
714 #endif
715
716 for (y = 0; y < height - 1; y += 2) {
717 BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
718 BGRAToYRow(src_bgra, dst_y, width);
719 BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
720 src_bgra += src_stride_bgra * 2;
721 dst_y += dst_stride_y * 2;
722 dst_u += dst_stride_u;
723 dst_v += dst_stride_v;
724 }
725 if (height & 1) {
726 BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
727 BGRAToYRow(src_bgra, dst_y, width);
728 }
729 return 0;
730 }
731
732 // Convert ABGR to I420.
733 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)734 int ABGRToI420(const uint8* src_abgr,
735 int src_stride_abgr,
736 uint8* dst_y,
737 int dst_stride_y,
738 uint8* dst_u,
739 int dst_stride_u,
740 uint8* dst_v,
741 int dst_stride_v,
742 int width,
743 int height) {
744 int y;
745 void (*ABGRToUVRow)(const uint8* src_abgr0, int src_stride_abgr, uint8* dst_u,
746 uint8* dst_v, int width) = ABGRToUVRow_C;
747 void (*ABGRToYRow)(const uint8* src_abgr, uint8* dst_y, int width) =
748 ABGRToYRow_C;
749 if (!src_abgr || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
750 return -1;
751 }
752 // Negative height means invert the image.
753 if (height < 0) {
754 height = -height;
755 src_abgr = src_abgr + (height - 1) * src_stride_abgr;
756 src_stride_abgr = -src_stride_abgr;
757 }
758 #if defined(HAS_ABGRTOYROW_SSSE3) && defined(HAS_ABGRTOUVROW_SSSE3)
759 if (TestCpuFlag(kCpuHasSSSE3)) {
760 ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
761 ABGRToYRow = ABGRToYRow_Any_SSSE3;
762 if (IS_ALIGNED(width, 16)) {
763 ABGRToUVRow = ABGRToUVRow_SSSE3;
764 ABGRToYRow = ABGRToYRow_SSSE3;
765 }
766 }
767 #endif
768 #if defined(HAS_ABGRTOYROW_NEON)
769 if (TestCpuFlag(kCpuHasNEON)) {
770 ABGRToYRow = ABGRToYRow_Any_NEON;
771 if (IS_ALIGNED(width, 8)) {
772 ABGRToYRow = ABGRToYRow_NEON;
773 }
774 }
775 #endif
776 #if defined(HAS_ABGRTOUVROW_NEON)
777 if (TestCpuFlag(kCpuHasNEON)) {
778 ABGRToUVRow = ABGRToUVRow_Any_NEON;
779 if (IS_ALIGNED(width, 16)) {
780 ABGRToUVRow = ABGRToUVRow_NEON;
781 }
782 }
783 #endif
784 #if defined(HAS_ABGRTOYROW_DSPR2)
785 if (TestCpuFlag(kCpuHasDSPR2)) {
786 ABGRToYRow = ABGRToYRow_Any_DSPR2;
787 if (IS_ALIGNED(width, 8)) {
788 ABGRToYRow = ABGRToYRow_DSPR2;
789 }
790 }
791 #endif
792 #if defined(HAS_ABGRTOUVROW_DSPR2)
793 if (TestCpuFlag(kCpuHasDSPR2)) {
794 ABGRToUVRow = ABGRToUVRow_Any_DSPR2;
795 if (IS_ALIGNED(width, 16)) {
796 ABGRToUVRow = ABGRToUVRow_DSPR2;
797 }
798 }
799 #endif
800 #if defined(HAS_ABGRTOYROW_MSA)
801 if (TestCpuFlag(kCpuHasMSA)) {
802 ABGRToYRow = ABGRToYRow_Any_MSA;
803 if (IS_ALIGNED(width, 16)) {
804 ABGRToYRow = ABGRToYRow_MSA;
805 }
806 }
807 #endif
808 #if defined(HAS_ABGRTOUVROW_MSA)
809 if (TestCpuFlag(kCpuHasMSA)) {
810 ABGRToUVRow = ABGRToUVRow_Any_MSA;
811 if (IS_ALIGNED(width, 16)) {
812 ABGRToUVRow = ABGRToUVRow_MSA;
813 }
814 }
815 #endif
816
817 for (y = 0; y < height - 1; y += 2) {
818 ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
819 ABGRToYRow(src_abgr, dst_y, width);
820 ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
821 src_abgr += src_stride_abgr * 2;
822 dst_y += dst_stride_y * 2;
823 dst_u += dst_stride_u;
824 dst_v += dst_stride_v;
825 }
826 if (height & 1) {
827 ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
828 ABGRToYRow(src_abgr, dst_y, width);
829 }
830 return 0;
831 }
832
833 // Convert RGBA to I420.
834 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)835 int RGBAToI420(const uint8* src_rgba,
836 int src_stride_rgba,
837 uint8* dst_y,
838 int dst_stride_y,
839 uint8* dst_u,
840 int dst_stride_u,
841 uint8* dst_v,
842 int dst_stride_v,
843 int width,
844 int height) {
845 int y;
846 void (*RGBAToUVRow)(const uint8* src_rgba0, int src_stride_rgba, uint8* dst_u,
847 uint8* dst_v, int width) = RGBAToUVRow_C;
848 void (*RGBAToYRow)(const uint8* src_rgba, uint8* dst_y, int width) =
849 RGBAToYRow_C;
850 if (!src_rgba || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
851 return -1;
852 }
853 // Negative height means invert the image.
854 if (height < 0) {
855 height = -height;
856 src_rgba = src_rgba + (height - 1) * src_stride_rgba;
857 src_stride_rgba = -src_stride_rgba;
858 }
859 #if defined(HAS_RGBATOYROW_SSSE3) && defined(HAS_RGBATOUVROW_SSSE3)
860 if (TestCpuFlag(kCpuHasSSSE3)) {
861 RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
862 RGBAToYRow = RGBAToYRow_Any_SSSE3;
863 if (IS_ALIGNED(width, 16)) {
864 RGBAToUVRow = RGBAToUVRow_SSSE3;
865 RGBAToYRow = RGBAToYRow_SSSE3;
866 }
867 }
868 #endif
869 #if defined(HAS_RGBATOYROW_NEON)
870 if (TestCpuFlag(kCpuHasNEON)) {
871 RGBAToYRow = RGBAToYRow_Any_NEON;
872 if (IS_ALIGNED(width, 8)) {
873 RGBAToYRow = RGBAToYRow_NEON;
874 }
875 }
876 #endif
877 #if defined(HAS_RGBATOUVROW_NEON)
878 if (TestCpuFlag(kCpuHasNEON)) {
879 RGBAToUVRow = RGBAToUVRow_Any_NEON;
880 if (IS_ALIGNED(width, 16)) {
881 RGBAToUVRow = RGBAToUVRow_NEON;
882 }
883 }
884 #endif
885 #if defined(HAS_RGBATOYROW_DSPR2)
886 if (TestCpuFlag(kCpuHasDSPR2)) {
887 RGBAToYRow = RGBAToYRow_Any_DSPR2;
888 if (IS_ALIGNED(width, 8)) {
889 RGBAToYRow = RGBAToYRow_DSPR2;
890 }
891 }
892 #endif
893 #if defined(HAS_RGBATOUVROW_DSPR2)
894 if (TestCpuFlag(kCpuHasDSPR2)) {
895 RGBAToUVRow = RGBAToUVRow_Any_DSPR2;
896 if (IS_ALIGNED(width, 16)) {
897 RGBAToUVRow = RGBAToUVRow_DSPR2;
898 }
899 }
900 #endif
901 #if defined(HAS_RGBATOYROW_MSA)
902 if (TestCpuFlag(kCpuHasMSA)) {
903 RGBAToYRow = RGBAToYRow_Any_MSA;
904 if (IS_ALIGNED(width, 16)) {
905 RGBAToYRow = RGBAToYRow_MSA;
906 }
907 }
908 #endif
909 #if defined(HAS_RGBATOUVROW_MSA)
910 if (TestCpuFlag(kCpuHasMSA)) {
911 RGBAToUVRow = RGBAToUVRow_Any_MSA;
912 if (IS_ALIGNED(width, 16)) {
913 RGBAToUVRow = RGBAToUVRow_MSA;
914 }
915 }
916 #endif
917
918 for (y = 0; y < height - 1; y += 2) {
919 RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
920 RGBAToYRow(src_rgba, dst_y, width);
921 RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
922 src_rgba += src_stride_rgba * 2;
923 dst_y += dst_stride_y * 2;
924 dst_u += dst_stride_u;
925 dst_v += dst_stride_v;
926 }
927 if (height & 1) {
928 RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
929 RGBAToYRow(src_rgba, dst_y, width);
930 }
931 return 0;
932 }
933
934 // Convert RGB24 to I420.
935 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)936 int RGB24ToI420(const uint8* src_rgb24,
937 int src_stride_rgb24,
938 uint8* dst_y,
939 int dst_stride_y,
940 uint8* dst_u,
941 int dst_stride_u,
942 uint8* dst_v,
943 int dst_stride_v,
944 int width,
945 int height) {
946 int y;
947 #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA))
948 void (*RGB24ToUVRow)(const uint8* src_rgb24, int src_stride_rgb24,
949 uint8* dst_u, uint8* dst_v, int width) = RGB24ToUVRow_C;
950 void (*RGB24ToYRow)(const uint8* src_rgb24, uint8* dst_y, int width) =
951 RGB24ToYRow_C;
952 #else
953 void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) =
954 RGB24ToARGBRow_C;
955 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u,
956 uint8* dst_v, int width) = ARGBToUVRow_C;
957 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
958 ARGBToYRow_C;
959 #endif
960 if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
961 return -1;
962 }
963 // Negative height means invert the image.
964 if (height < 0) {
965 height = -height;
966 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
967 src_stride_rgb24 = -src_stride_rgb24;
968 }
969
970 // Neon version does direct RGB24 to YUV.
971 #if defined(HAS_RGB24TOYROW_NEON)
972 if (TestCpuFlag(kCpuHasNEON)) {
973 RGB24ToUVRow = RGB24ToUVRow_Any_NEON;
974 RGB24ToYRow = RGB24ToYRow_Any_NEON;
975 if (IS_ALIGNED(width, 8)) {
976 RGB24ToYRow = RGB24ToYRow_NEON;
977 if (IS_ALIGNED(width, 16)) {
978 RGB24ToUVRow = RGB24ToUVRow_NEON;
979 }
980 }
981 }
982 #elif defined(HAS_RGB24TOYROW_MSA)
983 if (TestCpuFlag(kCpuHasMSA)) {
984 RGB24ToUVRow = RGB24ToUVRow_Any_MSA;
985 RGB24ToYRow = RGB24ToYRow_Any_MSA;
986 if (IS_ALIGNED(width, 16)) {
987 RGB24ToYRow = RGB24ToYRow_MSA;
988 RGB24ToUVRow = RGB24ToUVRow_MSA;
989 }
990 }
991 // Other platforms do intermediate conversion from RGB24 to ARGB.
992 #else
993 #if defined(HAS_RGB24TOARGBROW_SSSE3)
994 if (TestCpuFlag(kCpuHasSSSE3)) {
995 RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
996 if (IS_ALIGNED(width, 16)) {
997 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
998 }
999 }
1000 #endif
1001 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1002 if (TestCpuFlag(kCpuHasSSSE3)) {
1003 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1004 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1005 if (IS_ALIGNED(width, 16)) {
1006 ARGBToUVRow = ARGBToUVRow_SSSE3;
1007 ARGBToYRow = ARGBToYRow_SSSE3;
1008 }
1009 }
1010 #endif
1011 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1012 if (TestCpuFlag(kCpuHasAVX2)) {
1013 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1014 ARGBToYRow = ARGBToYRow_Any_AVX2;
1015 if (IS_ALIGNED(width, 32)) {
1016 ARGBToUVRow = ARGBToUVRow_AVX2;
1017 ARGBToYRow = ARGBToYRow_AVX2;
1018 }
1019 }
1020 #endif
1021 #endif
1022
1023 {
1024 #if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA))
1025 // Allocate 2 rows of ARGB.
1026 const int kRowSize = (width * 4 + 31) & ~31;
1027 align_buffer_64(row, kRowSize * 2);
1028 #endif
1029
1030 for (y = 0; y < height - 1; y += 2) {
1031 #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA))
1032 RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
1033 RGB24ToYRow(src_rgb24, dst_y, width);
1034 RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
1035 #else
1036 RGB24ToARGBRow(src_rgb24, row, width);
1037 RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
1038 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1039 ARGBToYRow(row, dst_y, width);
1040 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1041 #endif
1042 src_rgb24 += src_stride_rgb24 * 2;
1043 dst_y += dst_stride_y * 2;
1044 dst_u += dst_stride_u;
1045 dst_v += dst_stride_v;
1046 }
1047 if (height & 1) {
1048 #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA))
1049 RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
1050 RGB24ToYRow(src_rgb24, dst_y, width);
1051 #else
1052 RGB24ToARGBRow(src_rgb24, row, width);
1053 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1054 ARGBToYRow(row, dst_y, width);
1055 #endif
1056 }
1057 #if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA))
1058 free_aligned_buffer_64(row);
1059 #endif
1060 }
1061 return 0;
1062 }
1063
1064 // Convert RAW to I420.
1065 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)1066 int RAWToI420(const uint8* src_raw,
1067 int src_stride_raw,
1068 uint8* dst_y,
1069 int dst_stride_y,
1070 uint8* dst_u,
1071 int dst_stride_u,
1072 uint8* dst_v,
1073 int dst_stride_v,
1074 int width,
1075 int height) {
1076 int y;
1077 #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
1078 void (*RAWToUVRow)(const uint8* src_raw, int src_stride_raw, uint8* dst_u,
1079 uint8* dst_v, int width) = RAWToUVRow_C;
1080 void (*RAWToYRow)(const uint8* src_raw, uint8* dst_y, int width) =
1081 RAWToYRow_C;
1082 #else
1083 void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) =
1084 RAWToARGBRow_C;
1085 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u,
1086 uint8* dst_v, int width) = ARGBToUVRow_C;
1087 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
1088 ARGBToYRow_C;
1089 #endif
1090 if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1091 return -1;
1092 }
1093 // Negative height means invert the image.
1094 if (height < 0) {
1095 height = -height;
1096 src_raw = src_raw + (height - 1) * src_stride_raw;
1097 src_stride_raw = -src_stride_raw;
1098 }
1099
1100 // Neon version does direct RAW to YUV.
1101 #if defined(HAS_RAWTOYROW_NEON)
1102 if (TestCpuFlag(kCpuHasNEON)) {
1103 RAWToUVRow = RAWToUVRow_Any_NEON;
1104 RAWToYRow = RAWToYRow_Any_NEON;
1105 if (IS_ALIGNED(width, 8)) {
1106 RAWToYRow = RAWToYRow_NEON;
1107 if (IS_ALIGNED(width, 16)) {
1108 RAWToUVRow = RAWToUVRow_NEON;
1109 }
1110 }
1111 }
1112 #elif defined(HAS_RAWTOYROW_MSA)
1113 if (TestCpuFlag(kCpuHasMSA)) {
1114 RAWToUVRow = RAWToUVRow_Any_MSA;
1115 RAWToYRow = RAWToYRow_Any_MSA;
1116 if (IS_ALIGNED(width, 16)) {
1117 RAWToYRow = RAWToYRow_MSA;
1118 RAWToUVRow = RAWToUVRow_MSA;
1119 }
1120 }
1121 // Other platforms do intermediate conversion from RAW to ARGB.
1122 #else
1123 #if defined(HAS_RAWTOARGBROW_SSSE3)
1124 if (TestCpuFlag(kCpuHasSSSE3)) {
1125 RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
1126 if (IS_ALIGNED(width, 16)) {
1127 RAWToARGBRow = RAWToARGBRow_SSSE3;
1128 }
1129 }
1130 #endif
1131 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1132 if (TestCpuFlag(kCpuHasSSSE3)) {
1133 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1134 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1135 if (IS_ALIGNED(width, 16)) {
1136 ARGBToUVRow = ARGBToUVRow_SSSE3;
1137 ARGBToYRow = ARGBToYRow_SSSE3;
1138 }
1139 }
1140 #endif
1141 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1142 if (TestCpuFlag(kCpuHasAVX2)) {
1143 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1144 ARGBToYRow = ARGBToYRow_Any_AVX2;
1145 if (IS_ALIGNED(width, 32)) {
1146 ARGBToUVRow = ARGBToUVRow_AVX2;
1147 ARGBToYRow = ARGBToYRow_AVX2;
1148 }
1149 }
1150 #endif
1151 #endif
1152
1153 {
1154 #if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
1155 // Allocate 2 rows of ARGB.
1156 const int kRowSize = (width * 4 + 31) & ~31;
1157 align_buffer_64(row, kRowSize * 2);
1158 #endif
1159
1160 for (y = 0; y < height - 1; y += 2) {
1161 #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
1162 RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width);
1163 RAWToYRow(src_raw, dst_y, width);
1164 RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
1165 #else
1166 RAWToARGBRow(src_raw, row, width);
1167 RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width);
1168 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1169 ARGBToYRow(row, dst_y, width);
1170 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1171 #endif
1172 src_raw += src_stride_raw * 2;
1173 dst_y += dst_stride_y * 2;
1174 dst_u += dst_stride_u;
1175 dst_v += dst_stride_v;
1176 }
1177 if (height & 1) {
1178 #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
1179 RAWToUVRow(src_raw, 0, dst_u, dst_v, width);
1180 RAWToYRow(src_raw, dst_y, width);
1181 #else
1182 RAWToARGBRow(src_raw, row, width);
1183 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1184 ARGBToYRow(row, dst_y, width);
1185 #endif
1186 }
1187 #if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
1188 free_aligned_buffer_64(row);
1189 #endif
1190 }
1191 return 0;
1192 }
1193
1194 // Convert RGB565 to I420.
1195 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)1196 int RGB565ToI420(const uint8* src_rgb565,
1197 int src_stride_rgb565,
1198 uint8* dst_y,
1199 int dst_stride_y,
1200 uint8* dst_u,
1201 int dst_stride_u,
1202 uint8* dst_v,
1203 int dst_stride_v,
1204 int width,
1205 int height) {
1206 int y;
1207 #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
1208 void (*RGB565ToUVRow)(const uint8* src_rgb565, int src_stride_rgb565,
1209 uint8* dst_u, uint8* dst_v, int width) =
1210 RGB565ToUVRow_C;
1211 void (*RGB565ToYRow)(const uint8* src_rgb565, uint8* dst_y, int width) =
1212 RGB565ToYRow_C;
1213 #else
1214 void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) =
1215 RGB565ToARGBRow_C;
1216 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u,
1217 uint8* dst_v, int width) = ARGBToUVRow_C;
1218 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
1219 ARGBToYRow_C;
1220 #endif
1221 if (!src_rgb565 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1222 return -1;
1223 }
1224 // Negative height means invert the image.
1225 if (height < 0) {
1226 height = -height;
1227 src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
1228 src_stride_rgb565 = -src_stride_rgb565;
1229 }
1230
1231 // Neon version does direct RGB565 to YUV.
1232 #if defined(HAS_RGB565TOYROW_NEON)
1233 if (TestCpuFlag(kCpuHasNEON)) {
1234 RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
1235 RGB565ToYRow = RGB565ToYRow_Any_NEON;
1236 if (IS_ALIGNED(width, 8)) {
1237 RGB565ToYRow = RGB565ToYRow_NEON;
1238 if (IS_ALIGNED(width, 16)) {
1239 RGB565ToUVRow = RGB565ToUVRow_NEON;
1240 }
1241 }
1242 }
1243 #elif defined(HAS_RGB565TOYROW_MSA)
1244 if (TestCpuFlag(kCpuHasMSA)) {
1245 RGB565ToUVRow = RGB565ToUVRow_Any_MSA;
1246 RGB565ToYRow = RGB565ToYRow_Any_MSA;
1247 if (IS_ALIGNED(width, 16)) {
1248 RGB565ToYRow = RGB565ToYRow_MSA;
1249 RGB565ToUVRow = RGB565ToUVRow_MSA;
1250 }
1251 }
1252 // Other platforms do intermediate conversion from RGB565 to ARGB.
1253 #else
1254 #if defined(HAS_RGB565TOARGBROW_SSE2)
1255 if (TestCpuFlag(kCpuHasSSE2)) {
1256 RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
1257 if (IS_ALIGNED(width, 8)) {
1258 RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
1259 }
1260 }
1261 #endif
1262 #if defined(HAS_RGB565TOARGBROW_AVX2)
1263 if (TestCpuFlag(kCpuHasAVX2)) {
1264 RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
1265 if (IS_ALIGNED(width, 16)) {
1266 RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
1267 }
1268 }
1269 #endif
1270 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1271 if (TestCpuFlag(kCpuHasSSSE3)) {
1272 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1273 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1274 if (IS_ALIGNED(width, 16)) {
1275 ARGBToUVRow = ARGBToUVRow_SSSE3;
1276 ARGBToYRow = ARGBToYRow_SSSE3;
1277 }
1278 }
1279 #endif
1280 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1281 if (TestCpuFlag(kCpuHasAVX2)) {
1282 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1283 ARGBToYRow = ARGBToYRow_Any_AVX2;
1284 if (IS_ALIGNED(width, 32)) {
1285 ARGBToUVRow = ARGBToUVRow_AVX2;
1286 ARGBToYRow = ARGBToYRow_AVX2;
1287 }
1288 }
1289 #endif
1290 #if defined(HAS_RGB565TOARGBROW_DSPR2)
1291 if (TestCpuFlag(kCpuHasDSPR2)) {
1292 RGB565ToARGBRow = RGB565ToARGBRow_Any_DSPR2;
1293 if (IS_ALIGNED(width, 8)) {
1294 RGB565ToARGBRow = RGB565ToARGBRow_DSPR2;
1295 }
1296 }
1297 #endif
1298 #endif
1299 {
1300 #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
1301 // Allocate 2 rows of ARGB.
1302 const int kRowSize = (width * 4 + 31) & ~31;
1303 align_buffer_64(row, kRowSize * 2);
1304 #endif
1305 for (y = 0; y < height - 1; y += 2) {
1306 #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
1307 RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width);
1308 RGB565ToYRow(src_rgb565, dst_y, width);
1309 RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
1310 #else
1311 RGB565ToARGBRow(src_rgb565, row, width);
1312 RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width);
1313 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1314 ARGBToYRow(row, dst_y, width);
1315 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1316 #endif
1317 src_rgb565 += src_stride_rgb565 * 2;
1318 dst_y += dst_stride_y * 2;
1319 dst_u += dst_stride_u;
1320 dst_v += dst_stride_v;
1321 }
1322 if (height & 1) {
1323 #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
1324 RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width);
1325 RGB565ToYRow(src_rgb565, dst_y, width);
1326 #else
1327 RGB565ToARGBRow(src_rgb565, row, width);
1328 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1329 ARGBToYRow(row, dst_y, width);
1330 #endif
1331 }
1332 #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
1333 free_aligned_buffer_64(row);
1334 #endif
1335 }
1336 return 0;
1337 }
1338
1339 // Convert ARGB1555 to I420.
1340 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)1341 int ARGB1555ToI420(const uint8* src_argb1555,
1342 int src_stride_argb1555,
1343 uint8* dst_y,
1344 int dst_stride_y,
1345 uint8* dst_u,
1346 int dst_stride_u,
1347 uint8* dst_v,
1348 int dst_stride_v,
1349 int width,
1350 int height) {
1351 int y;
1352 #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
1353 void (*ARGB1555ToUVRow)(const uint8* src_argb1555, int src_stride_argb1555,
1354 uint8* dst_u, uint8* dst_v, int width) =
1355 ARGB1555ToUVRow_C;
1356 void (*ARGB1555ToYRow)(const uint8* src_argb1555, uint8* dst_y, int width) =
1357 ARGB1555ToYRow_C;
1358 #else
1359 void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) =
1360 ARGB1555ToARGBRow_C;
1361 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u,
1362 uint8* dst_v, int width) = ARGBToUVRow_C;
1363 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
1364 ARGBToYRow_C;
1365 #endif
1366 if (!src_argb1555 || !dst_y || !dst_u || !dst_v || width <= 0 ||
1367 height == 0) {
1368 return -1;
1369 }
1370 // Negative height means invert the image.
1371 if (height < 0) {
1372 height = -height;
1373 src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
1374 src_stride_argb1555 = -src_stride_argb1555;
1375 }
1376
1377 // Neon version does direct ARGB1555 to YUV.
1378 #if defined(HAS_ARGB1555TOYROW_NEON)
1379 if (TestCpuFlag(kCpuHasNEON)) {
1380 ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
1381 ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
1382 if (IS_ALIGNED(width, 8)) {
1383 ARGB1555ToYRow = ARGB1555ToYRow_NEON;
1384 if (IS_ALIGNED(width, 16)) {
1385 ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
1386 }
1387 }
1388 }
1389 #elif defined(HAS_ARGB1555TOYROW_MSA)
1390 if (TestCpuFlag(kCpuHasMSA)) {
1391 ARGB1555ToUVRow = ARGB1555ToUVRow_Any_MSA;
1392 ARGB1555ToYRow = ARGB1555ToYRow_Any_MSA;
1393 if (IS_ALIGNED(width, 16)) {
1394 ARGB1555ToYRow = ARGB1555ToYRow_MSA;
1395 ARGB1555ToUVRow = ARGB1555ToUVRow_MSA;
1396 }
1397 }
1398 // Other platforms do intermediate conversion from ARGB1555 to ARGB.
1399 #else
1400 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
1401 if (TestCpuFlag(kCpuHasSSE2)) {
1402 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
1403 if (IS_ALIGNED(width, 8)) {
1404 ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
1405 }
1406 }
1407 #endif
1408 #if defined(HAS_ARGB1555TOARGBROW_AVX2)
1409 if (TestCpuFlag(kCpuHasAVX2)) {
1410 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
1411 if (IS_ALIGNED(width, 16)) {
1412 ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
1413 }
1414 }
1415 #endif
1416 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1417 if (TestCpuFlag(kCpuHasSSSE3)) {
1418 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1419 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1420 if (IS_ALIGNED(width, 16)) {
1421 ARGBToUVRow = ARGBToUVRow_SSSE3;
1422 ARGBToYRow = ARGBToYRow_SSSE3;
1423 }
1424 }
1425 #endif
1426 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1427 if (TestCpuFlag(kCpuHasAVX2)) {
1428 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1429 ARGBToYRow = ARGBToYRow_Any_AVX2;
1430 if (IS_ALIGNED(width, 32)) {
1431 ARGBToUVRow = ARGBToUVRow_AVX2;
1432 ARGBToYRow = ARGBToYRow_AVX2;
1433 }
1434 }
1435 #endif
1436 #endif
1437 {
1438 #if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
1439 // Allocate 2 rows of ARGB.
1440 const int kRowSize = (width * 4 + 31) & ~31;
1441 align_buffer_64(row, kRowSize * 2);
1442 #endif
1443
1444 for (y = 0; y < height - 1; y += 2) {
1445 #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
1446 ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width);
1447 ARGB1555ToYRow(src_argb1555, dst_y, width);
1448 ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y,
1449 width);
1450 #else
1451 ARGB1555ToARGBRow(src_argb1555, row, width);
1452 ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize,
1453 width);
1454 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1455 ARGBToYRow(row, dst_y, width);
1456 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1457 #endif
1458 src_argb1555 += src_stride_argb1555 * 2;
1459 dst_y += dst_stride_y * 2;
1460 dst_u += dst_stride_u;
1461 dst_v += dst_stride_v;
1462 }
1463 if (height & 1) {
1464 #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
1465 ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width);
1466 ARGB1555ToYRow(src_argb1555, dst_y, width);
1467 #else
1468 ARGB1555ToARGBRow(src_argb1555, row, width);
1469 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1470 ARGBToYRow(row, dst_y, width);
1471 #endif
1472 }
1473 #if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
1474 free_aligned_buffer_64(row);
1475 #endif
1476 }
1477 return 0;
1478 }
1479
1480 // Convert ARGB4444 to I420.
1481 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)1482 int ARGB4444ToI420(const uint8* src_argb4444,
1483 int src_stride_argb4444,
1484 uint8* dst_y,
1485 int dst_stride_y,
1486 uint8* dst_u,
1487 int dst_stride_u,
1488 uint8* dst_v,
1489 int dst_stride_v,
1490 int width,
1491 int height) {
1492 int y;
1493 #if defined(HAS_ARGB4444TOYROW_NEON)
1494 void (*ARGB4444ToUVRow)(const uint8* src_argb4444, int src_stride_argb4444,
1495 uint8* dst_u, uint8* dst_v, int width) =
1496 ARGB4444ToUVRow_C;
1497 void (*ARGB4444ToYRow)(const uint8* src_argb4444, uint8* dst_y, int width) =
1498 ARGB4444ToYRow_C;
1499 #else
1500 void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) =
1501 ARGB4444ToARGBRow_C;
1502 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u,
1503 uint8* dst_v, int width) = ARGBToUVRow_C;
1504 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
1505 ARGBToYRow_C;
1506 #endif
1507 if (!src_argb4444 || !dst_y || !dst_u || !dst_v || width <= 0 ||
1508 height == 0) {
1509 return -1;
1510 }
1511 // Negative height means invert the image.
1512 if (height < 0) {
1513 height = -height;
1514 src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
1515 src_stride_argb4444 = -src_stride_argb4444;
1516 }
1517
1518 // Neon version does direct ARGB4444 to YUV.
1519 #if defined(HAS_ARGB4444TOYROW_NEON)
1520 if (TestCpuFlag(kCpuHasNEON)) {
1521 ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
1522 ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
1523 if (IS_ALIGNED(width, 8)) {
1524 ARGB4444ToYRow = ARGB4444ToYRow_NEON;
1525 if (IS_ALIGNED(width, 16)) {
1526 ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
1527 }
1528 }
1529 }
1530 // Other platforms do intermediate conversion from ARGB4444 to ARGB.
1531 #else
1532 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
1533 if (TestCpuFlag(kCpuHasSSE2)) {
1534 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
1535 if (IS_ALIGNED(width, 8)) {
1536 ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
1537 }
1538 }
1539 #endif
1540 #if defined(HAS_ARGB4444TOARGBROW_AVX2)
1541 if (TestCpuFlag(kCpuHasAVX2)) {
1542 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
1543 if (IS_ALIGNED(width, 16)) {
1544 ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
1545 }
1546 }
1547 #endif
1548 #if defined(HAS_ARGB4444TOARGBROW_MSA)
1549 if (TestCpuFlag(kCpuHasMSA)) {
1550 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA;
1551 if (IS_ALIGNED(width, 16)) {
1552 ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA;
1553 }
1554 }
1555 #endif
1556 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1557 if (TestCpuFlag(kCpuHasSSSE3)) {
1558 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1559 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1560 if (IS_ALIGNED(width, 16)) {
1561 ARGBToUVRow = ARGBToUVRow_SSSE3;
1562 ARGBToYRow = ARGBToYRow_SSSE3;
1563 }
1564 }
1565 #endif
1566 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1567 if (TestCpuFlag(kCpuHasAVX2)) {
1568 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1569 ARGBToYRow = ARGBToYRow_Any_AVX2;
1570 if (IS_ALIGNED(width, 32)) {
1571 ARGBToUVRow = ARGBToUVRow_AVX2;
1572 ARGBToYRow = ARGBToYRow_AVX2;
1573 }
1574 }
1575 #endif
1576 #if defined(HAS_ARGBTOYROW_MSA)
1577 if (TestCpuFlag(kCpuHasMSA)) {
1578 ARGBToUVRow = ARGBToUVRow_Any_MSA;
1579 ARGBToYRow = ARGBToYRow_Any_MSA;
1580 if (IS_ALIGNED(width, 16)) {
1581 ARGBToYRow = ARGBToYRow_MSA;
1582 if (IS_ALIGNED(width, 32)) {
1583 ARGBToUVRow = ARGBToUVRow_MSA;
1584 }
1585 }
1586 }
1587 #endif
1588 #endif
1589
1590 {
1591 #if !defined(HAS_ARGB4444TOYROW_NEON)
1592 // Allocate 2 rows of ARGB.
1593 const int kRowSize = (width * 4 + 31) & ~31;
1594 align_buffer_64(row, kRowSize * 2);
1595 #endif
1596
1597 for (y = 0; y < height - 1; y += 2) {
1598 #if defined(HAS_ARGB4444TOYROW_NEON)
1599 ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width);
1600 ARGB4444ToYRow(src_argb4444, dst_y, width);
1601 ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y,
1602 width);
1603 #else
1604 ARGB4444ToARGBRow(src_argb4444, row, width);
1605 ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize,
1606 width);
1607 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1608 ARGBToYRow(row, dst_y, width);
1609 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1610 #endif
1611 src_argb4444 += src_stride_argb4444 * 2;
1612 dst_y += dst_stride_y * 2;
1613 dst_u += dst_stride_u;
1614 dst_v += dst_stride_v;
1615 }
1616 if (height & 1) {
1617 #if defined(HAS_ARGB4444TOYROW_NEON)
1618 ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width);
1619 ARGB4444ToYRow(src_argb4444, dst_y, width);
1620 #else
1621 ARGB4444ToARGBRow(src_argb4444, row, width);
1622 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1623 ARGBToYRow(row, dst_y, width);
1624 #endif
1625 }
1626 #if !defined(HAS_ARGB4444TOYROW_NEON)
1627 free_aligned_buffer_64(row);
1628 #endif
1629 }
1630 return 0;
1631 }
1632
SplitPixels(const uint8 * src_u,int src_pixel_stride_uv,uint8 * dst_u,int width)1633 static void SplitPixels(const uint8* src_u,
1634 int src_pixel_stride_uv,
1635 uint8* dst_u,
1636 int width) {
1637 int i;
1638 for (i = 0; i < width; ++i) {
1639 *dst_u = *src_u;
1640 ++dst_u;
1641 src_u += src_pixel_stride_uv;
1642 }
1643 }
1644
1645 // Convert Android420 to I420.
1646 LIBYUV_API
Android420ToI420(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,int src_pixel_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)1647 int Android420ToI420(const uint8* src_y,
1648 int src_stride_y,
1649 const uint8* src_u,
1650 int src_stride_u,
1651 const uint8* src_v,
1652 int src_stride_v,
1653 int src_pixel_stride_uv,
1654 uint8* dst_y,
1655 int dst_stride_y,
1656 uint8* dst_u,
1657 int dst_stride_u,
1658 uint8* dst_v,
1659 int dst_stride_v,
1660 int width,
1661 int height) {
1662 int y;
1663 const ptrdiff_t vu_off = src_v - src_u;
1664 int halfwidth = (width + 1) >> 1;
1665 int halfheight = (height + 1) >> 1;
1666 if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
1667 return -1;
1668 }
1669 // Negative height means invert the image.
1670 if (height < 0) {
1671 height = -height;
1672 halfheight = (height + 1) >> 1;
1673 src_y = src_y + (height - 1) * src_stride_y;
1674 src_u = src_u + (halfheight - 1) * src_stride_u;
1675 src_v = src_v + (halfheight - 1) * src_stride_v;
1676 src_stride_y = -src_stride_y;
1677 src_stride_u = -src_stride_u;
1678 src_stride_v = -src_stride_v;
1679 }
1680
1681 if (dst_y) {
1682 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1683 }
1684
1685 // Copy UV planes as is - I420
1686 if (src_pixel_stride_uv == 1) {
1687 CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
1688 CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
1689 return 0;
1690 // Split UV planes - NV21
1691 } else if (src_pixel_stride_uv == 2 && vu_off == -1 &&
1692 src_stride_u == src_stride_v) {
1693 SplitUVPlane(src_v, src_stride_v, dst_v, dst_stride_v, dst_u, dst_stride_u,
1694 halfwidth, halfheight);
1695 return 0;
1696 // Split UV planes - NV12
1697 } else if (src_pixel_stride_uv == 2 && vu_off == 1 &&
1698 src_stride_u == src_stride_v) {
1699 SplitUVPlane(src_u, src_stride_u, dst_u, dst_stride_u, dst_v, dst_stride_v,
1700 halfwidth, halfheight);
1701 return 0;
1702 }
1703
1704 for (y = 0; y < halfheight; ++y) {
1705 SplitPixels(src_u, src_pixel_stride_uv, dst_u, halfwidth);
1706 SplitPixels(src_v, src_pixel_stride_uv, dst_v, halfwidth);
1707 src_u += src_stride_u;
1708 src_v += src_stride_v;
1709 dst_u += dst_stride_u;
1710 dst_v += dst_stride_v;
1711 }
1712 return 0;
1713 }
1714
1715 #ifdef __cplusplus
1716 } // extern "C"
1717 } // namespace libyuv
1718 #endif
1719