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