Line data Source code
1 : /*
2 : * Copyright 2011 The LibYuv Project Authors. All rights reserved.
3 : *
4 : * Use of this source code is governed by a BSD-style license
5 : * that can be found in the LICENSE file in the root of the source
6 : * tree. An additional intellectual property rights grant can be found
7 : * in the file PATENTS. All contributing project authors may
8 : * be found in the AUTHORS file in the root of the source tree.
9 : */
10 :
11 : #include "libyuv/convert.h"
12 :
13 : #include "libyuv/basic_types.h"
14 : #include "libyuv/cpu_id.h"
15 : #include "libyuv/planar_functions.h"
16 : #include "libyuv/rotate.h"
17 : #include "libyuv/scale.h" // For ScalePlane()
18 : #include "libyuv/row.h"
19 :
20 : #ifdef __cplusplus
21 : namespace libyuv {
22 : extern "C" {
23 : #endif
24 :
25 : #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
26 0 : static __inline int Abs(int v) {
27 0 : return v >= 0 ? v : -v;
28 : }
29 :
30 : // Any I4xx To I420 format with mirroring.
31 0 : 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 0 : const int dst_y_width = Abs(src_y_width);
48 0 : const int dst_y_height = Abs(src_y_height);
49 0 : const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
50 0 : const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
51 0 : if (src_uv_width == 0 || src_uv_height == 0) {
52 0 : return -1;
53 : }
54 0 : if (dst_y) {
55 : ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, dst_y,
56 0 : 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 0 : 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 0 : dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
62 0 : 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
69 0 : 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 0 : int halfwidth = (width + 1) >> 1;
84 0 : int halfheight = (height + 1) >> 1;
85 0 : if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
86 0 : return -1;
87 : }
88 : // Negative height means invert the image.
89 0 : if (height < 0) {
90 0 : height = -height;
91 0 : halfheight = (height + 1) >> 1;
92 0 : src_y = src_y + (height - 1) * src_stride_y;
93 0 : src_u = src_u + (halfheight - 1) * src_stride_u;
94 0 : src_v = src_v + (halfheight - 1) * src_stride_v;
95 0 : src_stride_y = -src_stride_y;
96 0 : src_stride_u = -src_stride_u;
97 0 : src_stride_v = -src_stride_v;
98 : }
99 :
100 0 : if (dst_y) {
101 0 : CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
102 : }
103 : // Copy UV planes.
104 0 : CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
105 0 : CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
106 0 : 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
112 0 : 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 0 : 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 0 : 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
135 0 : 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 0 : dst_v, dst_stride_v, width, height, width, height);
152 : }
153 :
154 : // I400 is greyscale typically used in MJPG
155 : LIBYUV_API
156 0 : 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 0 : int halfwidth = (width + 1) >> 1;
167 0 : int halfheight = (height + 1) >> 1;
168 0 : if (!dst_u || !dst_v || width <= 0 || height == 0) {
169 0 : return -1;
170 : }
171 : // Negative height means invert the image.
172 0 : if (height < 0) {
173 0 : height = -height;
174 0 : halfheight = (height + 1) >> 1;
175 0 : src_y = src_y + (height - 1) * src_stride_y;
176 0 : src_stride_y = -src_stride_y;
177 : }
178 0 : if (dst_y) {
179 0 : CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
180 : }
181 0 : SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128);
182 0 : SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128);
183 0 : return 0;
184 : }
185 :
186 0 : 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 0 : void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
195 : #if defined(HAS_COPYROW_SSE2)
196 0 : if (TestCpuFlag(kCpuHasSSE2)) {
197 0 : CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2;
198 : }
199 : #endif
200 : #if defined(HAS_COPYROW_AVX)
201 0 : if (TestCpuFlag(kCpuHasAVX)) {
202 0 : CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
203 : }
204 : #endif
205 : #if defined(HAS_COPYROW_ERMS)
206 0 : if (TestCpuFlag(kCpuHasERMS)) {
207 0 : 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 0 : for (y = 0; y < height - 1; y += 2) {
223 0 : CopyRow(src, dst, width);
224 0 : CopyRow(src + src_stride_0, dst + dst_stride, width);
225 0 : src += src_stride_0 + src_stride_1;
226 0 : dst += dst_stride * 2;
227 : }
228 0 : if (height & 1) {
229 0 : CopyRow(src, dst, width);
230 : }
231 0 : }
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.
242 0 : 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 0 : int halfwidth = (width + 1) >> 1;
256 0 : int halfheight = (height + 1) >> 1;
257 0 : if (!src_uv || !dst_u || !dst_v || width <= 0 || height == 0) {
258 0 : return -1;
259 : }
260 : // Negative height means invert the image.
261 0 : if (height < 0) {
262 0 : height = -height;
263 0 : halfheight = (height + 1) >> 1;
264 0 : if (dst_y) {
265 0 : dst_y = dst_y + (height - 1) * dst_stride_y;
266 : }
267 0 : dst_u = dst_u + (halfheight - 1) * dst_stride_u;
268 0 : dst_v = dst_v + (halfheight - 1) * dst_stride_v;
269 0 : dst_stride_y = -dst_stride_y;
270 0 : dst_stride_u = -dst_stride_u;
271 0 : dst_stride_v = -dst_stride_v;
272 : }
273 : // Coalesce rows.
274 0 : if (src_stride_y0 == width && src_stride_y1 == width &&
275 : dst_stride_y == width) {
276 0 : width *= height;
277 0 : height = 1;
278 0 : src_stride_y0 = src_stride_y1 = dst_stride_y = 0;
279 : }
280 : // Coalesce rows.
281 0 : if (src_stride_uv == halfwidth * 2 && dst_stride_u == halfwidth &&
282 : dst_stride_v == halfwidth) {
283 0 : halfwidth *= halfheight;
284 0 : halfheight = 1;
285 0 : src_stride_uv = dst_stride_u = dst_stride_v = 0;
286 : }
287 :
288 0 : if (dst_y) {
289 0 : if (src_stride_y0 == src_stride_y1) {
290 0 : 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 0 : 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 0 : halfwidth, halfheight);
300 :
301 0 : return 0;
302 : }
303 :
304 : // Convert NV12 to I420.
305 : LIBYUV_API
306 0 : 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 0 : dst_stride_v, width, height);
321 : }
322 :
323 : // Convert NV21 to I420. Same as NV12 but u and v pointers swapped.
324 : LIBYUV_API
325 0 : 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 0 : dst_stride_u, width, height);
340 : }
341 :
342 : // Convert M420 to I420.
343 : LIBYUV_API
344 0 : 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 0 : return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2,
355 0 : 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 0 : width, height);
358 : }
359 :
360 : // Convert YUY2 to I420.
361 : LIBYUV_API
362 0 : 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 0 : uint8* dst_v, int width) = YUY2ToUVRow_C;
375 : void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int width) =
376 0 : YUY2ToYRow_C;
377 : // Negative height means invert the image.
378 0 : if (height < 0) {
379 0 : height = -height;
380 0 : src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
381 0 : src_stride_yuy2 = -src_stride_yuy2;
382 : }
383 : #if defined(HAS_YUY2TOYROW_SSE2)
384 0 : if (TestCpuFlag(kCpuHasSSE2)) {
385 0 : YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
386 0 : YUY2ToYRow = YUY2ToYRow_Any_SSE2;
387 0 : if (IS_ALIGNED(width, 16)) {
388 0 : YUY2ToUVRow = YUY2ToUVRow_SSE2;
389 0 : YUY2ToYRow = YUY2ToYRow_SSE2;
390 : }
391 : }
392 : #endif
393 : #if defined(HAS_YUY2TOYROW_AVX2)
394 0 : if (TestCpuFlag(kCpuHasAVX2)) {
395 0 : YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
396 0 : YUY2ToYRow = YUY2ToYRow_Any_AVX2;
397 0 : if (IS_ALIGNED(width, 32)) {
398 0 : YUY2ToUVRow = YUY2ToUVRow_AVX2;
399 0 : 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 0 : for (y = 0; y < height - 1; y += 2) {
425 0 : YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
426 0 : YUY2ToYRow(src_yuy2, dst_y, width);
427 0 : YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
428 0 : src_yuy2 += src_stride_yuy2 * 2;
429 0 : dst_y += dst_stride_y * 2;
430 0 : dst_u += dst_stride_u;
431 0 : dst_v += dst_stride_v;
432 : }
433 0 : if (height & 1) {
434 0 : YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
435 0 : YUY2ToYRow(src_yuy2, dst_y, width);
436 : }
437 0 : return 0;
438 : }
439 :
440 : // Convert UYVY to I420.
441 : LIBYUV_API
442 0 : 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 0 : uint8* dst_v, int width) = UYVYToUVRow_C;
455 : void (*UYVYToYRow)(const uint8* src_uyvy, uint8* dst_y, int width) =
456 0 : UYVYToYRow_C;
457 : // Negative height means invert the image.
458 0 : if (height < 0) {
459 0 : height = -height;
460 0 : src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
461 0 : src_stride_uyvy = -src_stride_uyvy;
462 : }
463 : #if defined(HAS_UYVYTOYROW_SSE2)
464 0 : if (TestCpuFlag(kCpuHasSSE2)) {
465 0 : UYVYToUVRow = UYVYToUVRow_Any_SSE2;
466 0 : UYVYToYRow = UYVYToYRow_Any_SSE2;
467 0 : if (IS_ALIGNED(width, 16)) {
468 0 : UYVYToUVRow = UYVYToUVRow_SSE2;
469 0 : UYVYToYRow = UYVYToYRow_SSE2;
470 : }
471 : }
472 : #endif
473 : #if defined(HAS_UYVYTOYROW_AVX2)
474 0 : if (TestCpuFlag(kCpuHasAVX2)) {
475 0 : UYVYToUVRow = UYVYToUVRow_Any_AVX2;
476 0 : UYVYToYRow = UYVYToYRow_Any_AVX2;
477 0 : if (IS_ALIGNED(width, 32)) {
478 0 : UYVYToUVRow = UYVYToUVRow_AVX2;
479 0 : 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 0 : for (y = 0; y < height - 1; y += 2) {
505 0 : UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
506 0 : UYVYToYRow(src_uyvy, dst_y, width);
507 0 : UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
508 0 : src_uyvy += src_stride_uyvy * 2;
509 0 : dst_y += dst_stride_y * 2;
510 0 : dst_u += dst_stride_u;
511 0 : dst_v += dst_stride_v;
512 : }
513 0 : if (height & 1) {
514 0 : UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
515 0 : UYVYToYRow(src_uyvy, dst_y, width);
516 : }
517 0 : return 0;
518 : }
519 :
520 : // Convert ARGB to I420.
521 : LIBYUV_API
522 0 : 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 0 : uint8* dst_v, int width) = ARGBToUVRow_C;
535 : void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
536 0 : ARGBToYRow_C;
537 0 : if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
538 0 : return -1;
539 : }
540 : // Negative height means invert the image.
541 0 : if (height < 0) {
542 0 : height = -height;
543 0 : src_argb = src_argb + (height - 1) * src_stride_argb;
544 0 : src_stride_argb = -src_stride_argb;
545 : }
546 : #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
547 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
548 0 : ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
549 0 : ARGBToYRow = ARGBToYRow_Any_SSSE3;
550 0 : if (IS_ALIGNED(width, 16)) {
551 0 : ARGBToUVRow = ARGBToUVRow_SSSE3;
552 0 : ARGBToYRow = ARGBToYRow_SSSE3;
553 : }
554 : }
555 : #endif
556 : #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
557 0 : if (TestCpuFlag(kCpuHasAVX2)) {
558 0 : ARGBToUVRow = ARGBToUVRow_Any_AVX2;
559 0 : ARGBToYRow = ARGBToYRow_Any_AVX2;
560 0 : if (IS_ALIGNED(width, 32)) {
561 0 : ARGBToUVRow = ARGBToUVRow_AVX2;
562 0 : 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 0 : for (y = 0; y < height - 1; y += 2) {
616 0 : ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
617 0 : ARGBToYRow(src_argb, dst_y, width);
618 0 : ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
619 0 : src_argb += src_stride_argb * 2;
620 0 : dst_y += dst_stride_y * 2;
621 0 : dst_u += dst_stride_u;
622 0 : dst_v += dst_stride_v;
623 : }
624 0 : if (height & 1) {
625 0 : ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
626 0 : ARGBToYRow(src_argb, dst_y, width);
627 : }
628 0 : return 0;
629 : }
630 :
631 : // Convert BGRA to I420.
632 : LIBYUV_API
633 0 : 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 0 : uint8* dst_v, int width) = BGRAToUVRow_C;
646 : void (*BGRAToYRow)(const uint8* src_bgra, uint8* dst_y, int width) =
647 0 : BGRAToYRow_C;
648 0 : if (!src_bgra || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
649 0 : return -1;
650 : }
651 : // Negative height means invert the image.
652 0 : if (height < 0) {
653 0 : height = -height;
654 0 : src_bgra = src_bgra + (height - 1) * src_stride_bgra;
655 0 : src_stride_bgra = -src_stride_bgra;
656 : }
657 : #if defined(HAS_BGRATOYROW_SSSE3) && defined(HAS_BGRATOUVROW_SSSE3)
658 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
659 0 : BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
660 0 : BGRAToYRow = BGRAToYRow_Any_SSSE3;
661 0 : if (IS_ALIGNED(width, 16)) {
662 0 : BGRAToUVRow = BGRAToUVRow_SSSE3;
663 0 : 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 0 : for (y = 0; y < height - 1; y += 2) {
717 0 : BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
718 0 : BGRAToYRow(src_bgra, dst_y, width);
719 0 : BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
720 0 : src_bgra += src_stride_bgra * 2;
721 0 : dst_y += dst_stride_y * 2;
722 0 : dst_u += dst_stride_u;
723 0 : dst_v += dst_stride_v;
724 : }
725 0 : if (height & 1) {
726 0 : BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
727 0 : BGRAToYRow(src_bgra, dst_y, width);
728 : }
729 0 : return 0;
730 : }
731 :
732 : // Convert ABGR to I420.
733 : LIBYUV_API
734 0 : 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 0 : uint8* dst_v, int width) = ABGRToUVRow_C;
747 : void (*ABGRToYRow)(const uint8* src_abgr, uint8* dst_y, int width) =
748 0 : ABGRToYRow_C;
749 0 : if (!src_abgr || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
750 0 : return -1;
751 : }
752 : // Negative height means invert the image.
753 0 : if (height < 0) {
754 0 : height = -height;
755 0 : src_abgr = src_abgr + (height - 1) * src_stride_abgr;
756 0 : src_stride_abgr = -src_stride_abgr;
757 : }
758 : #if defined(HAS_ABGRTOYROW_SSSE3) && defined(HAS_ABGRTOUVROW_SSSE3)
759 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
760 0 : ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
761 0 : ABGRToYRow = ABGRToYRow_Any_SSSE3;
762 0 : if (IS_ALIGNED(width, 16)) {
763 0 : ABGRToUVRow = ABGRToUVRow_SSSE3;
764 0 : 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 0 : for (y = 0; y < height - 1; y += 2) {
818 0 : ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
819 0 : ABGRToYRow(src_abgr, dst_y, width);
820 0 : ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
821 0 : src_abgr += src_stride_abgr * 2;
822 0 : dst_y += dst_stride_y * 2;
823 0 : dst_u += dst_stride_u;
824 0 : dst_v += dst_stride_v;
825 : }
826 0 : if (height & 1) {
827 0 : ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
828 0 : ABGRToYRow(src_abgr, dst_y, width);
829 : }
830 0 : return 0;
831 : }
832 :
833 : // Convert RGBA to I420.
834 : LIBYUV_API
835 0 : 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 0 : uint8* dst_v, int width) = RGBAToUVRow_C;
848 : void (*RGBAToYRow)(const uint8* src_rgba, uint8* dst_y, int width) =
849 0 : RGBAToYRow_C;
850 0 : if (!src_rgba || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
851 0 : return -1;
852 : }
853 : // Negative height means invert the image.
854 0 : if (height < 0) {
855 0 : height = -height;
856 0 : src_rgba = src_rgba + (height - 1) * src_stride_rgba;
857 0 : src_stride_rgba = -src_stride_rgba;
858 : }
859 : #if defined(HAS_RGBATOYROW_SSSE3) && defined(HAS_RGBATOUVROW_SSSE3)
860 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
861 0 : RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
862 0 : RGBAToYRow = RGBAToYRow_Any_SSSE3;
863 0 : if (IS_ALIGNED(width, 16)) {
864 0 : RGBAToUVRow = RGBAToUVRow_SSSE3;
865 0 : 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 0 : for (y = 0; y < height - 1; y += 2) {
919 0 : RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
920 0 : RGBAToYRow(src_rgba, dst_y, width);
921 0 : RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
922 0 : src_rgba += src_stride_rgba * 2;
923 0 : dst_y += dst_stride_y * 2;
924 0 : dst_u += dst_stride_u;
925 0 : dst_v += dst_stride_v;
926 : }
927 0 : if (height & 1) {
928 0 : RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
929 0 : RGBAToYRow(src_rgba, dst_y, width);
930 : }
931 0 : return 0;
932 : }
933 :
934 : // Convert RGB24 to I420.
935 : LIBYUV_API
936 0 : 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 0 : RGB24ToARGBRow_C;
955 : void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u,
956 0 : uint8* dst_v, int width) = ARGBToUVRow_C;
957 : void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
958 0 : ARGBToYRow_C;
959 : #endif
960 0 : if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
961 0 : return -1;
962 : }
963 : // Negative height means invert the image.
964 0 : if (height < 0) {
965 0 : height = -height;
966 0 : src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
967 0 : 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 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
995 0 : RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
996 0 : if (IS_ALIGNED(width, 16)) {
997 0 : RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
998 : }
999 : }
1000 : #endif
1001 : #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1002 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
1003 0 : ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1004 0 : ARGBToYRow = ARGBToYRow_Any_SSSE3;
1005 0 : if (IS_ALIGNED(width, 16)) {
1006 0 : ARGBToUVRow = ARGBToUVRow_SSSE3;
1007 0 : ARGBToYRow = ARGBToYRow_SSSE3;
1008 : }
1009 : }
1010 : #endif
1011 : #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1012 0 : if (TestCpuFlag(kCpuHasAVX2)) {
1013 0 : ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1014 0 : ARGBToYRow = ARGBToYRow_Any_AVX2;
1015 0 : if (IS_ALIGNED(width, 32)) {
1016 0 : ARGBToUVRow = ARGBToUVRow_AVX2;
1017 0 : ARGBToYRow = ARGBToYRow_AVX2;
1018 : }
1019 : }
1020 : #endif
1021 : {
1022 : // Allocate 2 rows of ARGB.
1023 0 : const int kRowSize = (width * 4 + 31) & ~31;
1024 0 : align_buffer_64(row, kRowSize * 2);
1025 : #endif
1026 :
1027 0 : for (y = 0; y < height - 1; y += 2) {
1028 : #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA))
1029 : RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
1030 : RGB24ToYRow(src_rgb24, dst_y, width);
1031 : RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
1032 : #else
1033 0 : RGB24ToARGBRow(src_rgb24, row, width);
1034 0 : RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
1035 0 : ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1036 0 : ARGBToYRow(row, dst_y, width);
1037 0 : ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1038 : #endif
1039 0 : src_rgb24 += src_stride_rgb24 * 2;
1040 0 : dst_y += dst_stride_y * 2;
1041 0 : dst_u += dst_stride_u;
1042 0 : dst_v += dst_stride_v;
1043 : }
1044 0 : if (height & 1) {
1045 : #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA))
1046 : RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
1047 : RGB24ToYRow(src_rgb24, dst_y, width);
1048 : #else
1049 0 : RGB24ToARGBRow(src_rgb24, row, width);
1050 0 : ARGBToUVRow(row, 0, dst_u, dst_v, width);
1051 0 : ARGBToYRow(row, dst_y, width);
1052 : #endif
1053 : }
1054 : #if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA))
1055 0 : free_aligned_buffer_64(row);
1056 : }
1057 : #endif
1058 0 : return 0;
1059 : }
1060 :
1061 : // Convert RAW to I420.
1062 : LIBYUV_API
1063 0 : int RAWToI420(const uint8* src_raw,
1064 : int src_stride_raw,
1065 : uint8* dst_y,
1066 : int dst_stride_y,
1067 : uint8* dst_u,
1068 : int dst_stride_u,
1069 : uint8* dst_v,
1070 : int dst_stride_v,
1071 : int width,
1072 : int height) {
1073 : int y;
1074 : #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
1075 : void (*RAWToUVRow)(const uint8* src_raw, int src_stride_raw, uint8* dst_u,
1076 : uint8* dst_v, int width) = RAWToUVRow_C;
1077 : void (*RAWToYRow)(const uint8* src_raw, uint8* dst_y, int width) =
1078 : RAWToYRow_C;
1079 : #else
1080 : void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) =
1081 0 : RAWToARGBRow_C;
1082 : void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u,
1083 0 : uint8* dst_v, int width) = ARGBToUVRow_C;
1084 : void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
1085 0 : ARGBToYRow_C;
1086 : #endif
1087 0 : if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1088 0 : return -1;
1089 : }
1090 : // Negative height means invert the image.
1091 0 : if (height < 0) {
1092 0 : height = -height;
1093 0 : src_raw = src_raw + (height - 1) * src_stride_raw;
1094 0 : src_stride_raw = -src_stride_raw;
1095 : }
1096 :
1097 : // Neon version does direct RAW to YUV.
1098 : #if defined(HAS_RAWTOYROW_NEON)
1099 : if (TestCpuFlag(kCpuHasNEON)) {
1100 : RAWToUVRow = RAWToUVRow_Any_NEON;
1101 : RAWToYRow = RAWToYRow_Any_NEON;
1102 : if (IS_ALIGNED(width, 8)) {
1103 : RAWToYRow = RAWToYRow_NEON;
1104 : if (IS_ALIGNED(width, 16)) {
1105 : RAWToUVRow = RAWToUVRow_NEON;
1106 : }
1107 : }
1108 : }
1109 : #elif defined(HAS_RAWTOYROW_MSA)
1110 : if (TestCpuFlag(kCpuHasMSA)) {
1111 : RAWToUVRow = RAWToUVRow_Any_MSA;
1112 : RAWToYRow = RAWToYRow_Any_MSA;
1113 : if (IS_ALIGNED(width, 16)) {
1114 : RAWToYRow = RAWToYRow_MSA;
1115 : RAWToUVRow = RAWToUVRow_MSA;
1116 : }
1117 : }
1118 : // Other platforms do intermediate conversion from RAW to ARGB.
1119 : #else
1120 : #if defined(HAS_RAWTOARGBROW_SSSE3)
1121 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
1122 0 : RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
1123 0 : if (IS_ALIGNED(width, 16)) {
1124 0 : RAWToARGBRow = RAWToARGBRow_SSSE3;
1125 : }
1126 : }
1127 : #endif
1128 : #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1129 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
1130 0 : ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1131 0 : ARGBToYRow = ARGBToYRow_Any_SSSE3;
1132 0 : if (IS_ALIGNED(width, 16)) {
1133 0 : ARGBToUVRow = ARGBToUVRow_SSSE3;
1134 0 : ARGBToYRow = ARGBToYRow_SSSE3;
1135 : }
1136 : }
1137 : #endif
1138 : #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1139 0 : if (TestCpuFlag(kCpuHasAVX2)) {
1140 0 : ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1141 0 : ARGBToYRow = ARGBToYRow_Any_AVX2;
1142 0 : if (IS_ALIGNED(width, 32)) {
1143 0 : ARGBToUVRow = ARGBToUVRow_AVX2;
1144 0 : ARGBToYRow = ARGBToYRow_AVX2;
1145 : }
1146 : }
1147 : #endif
1148 : #if defined(HAS_RAWTOARGBROW_DSPR2)
1149 : if (TestCpuFlag(kCpuHasDSPR2)) {
1150 : RAWToARGBRow = RAWToARGBRow_Any_DSPR2;
1151 : if (IS_ALIGNED(width, 4)) {
1152 : RAWToARGBRow = RAWToARGBRow_DSPR2;
1153 : }
1154 : }
1155 : #endif
1156 : {
1157 : // Allocate 2 rows of ARGB.
1158 0 : const int kRowSize = (width * 4 + 31) & ~31;
1159 0 : align_buffer_64(row, kRowSize * 2);
1160 : #endif
1161 :
1162 0 : for (y = 0; y < height - 1; y += 2) {
1163 : #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
1164 : RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width);
1165 : RAWToYRow(src_raw, dst_y, width);
1166 : RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
1167 : #else
1168 0 : RAWToARGBRow(src_raw, row, width);
1169 0 : RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width);
1170 0 : ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1171 0 : ARGBToYRow(row, dst_y, width);
1172 0 : ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1173 : #endif
1174 0 : src_raw += src_stride_raw * 2;
1175 0 : dst_y += dst_stride_y * 2;
1176 0 : dst_u += dst_stride_u;
1177 0 : dst_v += dst_stride_v;
1178 : }
1179 0 : if (height & 1) {
1180 : #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
1181 : RAWToUVRow(src_raw, 0, dst_u, dst_v, width);
1182 : RAWToYRow(src_raw, dst_y, width);
1183 : #else
1184 0 : RAWToARGBRow(src_raw, row, width);
1185 0 : ARGBToUVRow(row, 0, dst_u, dst_v, width);
1186 0 : ARGBToYRow(row, dst_y, width);
1187 : #endif
1188 : }
1189 : #if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA))
1190 0 : free_aligned_buffer_64(row);
1191 : }
1192 : #endif
1193 0 : return 0;
1194 : }
1195 :
1196 : // Convert RGB565 to I420.
1197 : LIBYUV_API
1198 0 : int RGB565ToI420(const uint8* src_rgb565,
1199 : int src_stride_rgb565,
1200 : uint8* dst_y,
1201 : int dst_stride_y,
1202 : uint8* dst_u,
1203 : int dst_stride_u,
1204 : uint8* dst_v,
1205 : int dst_stride_v,
1206 : int width,
1207 : int height) {
1208 : int y;
1209 : #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
1210 : void (*RGB565ToUVRow)(const uint8* src_rgb565, int src_stride_rgb565,
1211 : uint8* dst_u, uint8* dst_v, int width) =
1212 : RGB565ToUVRow_C;
1213 : void (*RGB565ToYRow)(const uint8* src_rgb565, uint8* dst_y, int width) =
1214 : RGB565ToYRow_C;
1215 : #else
1216 : void (*RGB565ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) =
1217 0 : RGB565ToARGBRow_C;
1218 : void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u,
1219 0 : uint8* dst_v, int width) = ARGBToUVRow_C;
1220 : void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
1221 0 : ARGBToYRow_C;
1222 : #endif
1223 0 : if (!src_rgb565 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1224 0 : return -1;
1225 : }
1226 : // Negative height means invert the image.
1227 0 : if (height < 0) {
1228 0 : height = -height;
1229 0 : src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
1230 0 : src_stride_rgb565 = -src_stride_rgb565;
1231 : }
1232 :
1233 : // Neon version does direct RGB565 to YUV.
1234 : #if defined(HAS_RGB565TOYROW_NEON)
1235 : if (TestCpuFlag(kCpuHasNEON)) {
1236 : RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
1237 : RGB565ToYRow = RGB565ToYRow_Any_NEON;
1238 : if (IS_ALIGNED(width, 8)) {
1239 : RGB565ToYRow = RGB565ToYRow_NEON;
1240 : if (IS_ALIGNED(width, 16)) {
1241 : RGB565ToUVRow = RGB565ToUVRow_NEON;
1242 : }
1243 : }
1244 : }
1245 : #elif defined(HAS_RGB565TOYROW_MSA)
1246 : if (TestCpuFlag(kCpuHasMSA)) {
1247 : RGB565ToUVRow = RGB565ToUVRow_Any_MSA;
1248 : RGB565ToYRow = RGB565ToYRow_Any_MSA;
1249 : if (IS_ALIGNED(width, 16)) {
1250 : RGB565ToYRow = RGB565ToYRow_MSA;
1251 : RGB565ToUVRow = RGB565ToUVRow_MSA;
1252 : }
1253 : }
1254 : // Other platforms do intermediate conversion from RGB565 to ARGB.
1255 : #else
1256 : #if defined(HAS_RGB565TOARGBROW_SSE2)
1257 0 : if (TestCpuFlag(kCpuHasSSE2)) {
1258 0 : RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
1259 0 : if (IS_ALIGNED(width, 8)) {
1260 0 : RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
1261 : }
1262 : }
1263 : #endif
1264 : #if defined(HAS_RGB565TOARGBROW_AVX2)
1265 : if (TestCpuFlag(kCpuHasAVX2)) {
1266 : RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
1267 : if (IS_ALIGNED(width, 16)) {
1268 : RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
1269 : }
1270 : }
1271 : #endif
1272 : #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1273 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
1274 0 : ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1275 0 : ARGBToYRow = ARGBToYRow_Any_SSSE3;
1276 0 : if (IS_ALIGNED(width, 16)) {
1277 0 : ARGBToUVRow = ARGBToUVRow_SSSE3;
1278 0 : ARGBToYRow = ARGBToYRow_SSSE3;
1279 : }
1280 : }
1281 : #endif
1282 : #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1283 0 : if (TestCpuFlag(kCpuHasAVX2)) {
1284 0 : ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1285 0 : ARGBToYRow = ARGBToYRow_Any_AVX2;
1286 0 : if (IS_ALIGNED(width, 32)) {
1287 0 : ARGBToUVRow = ARGBToUVRow_AVX2;
1288 0 : ARGBToYRow = ARGBToYRow_AVX2;
1289 : }
1290 : }
1291 : #endif
1292 : #if defined(HAS_RGB565TOARGBROW_DSPR2)
1293 : if (TestCpuFlag(kCpuHasDSPR2)) {
1294 : RGB565ToARGBRow = RGB565ToARGBRow_Any_DSPR2;
1295 : if (IS_ALIGNED(width, 8)) {
1296 : RGB565ToARGBRow = RGB565ToARGBRow_DSPR2;
1297 : }
1298 : }
1299 : #endif
1300 : {
1301 : // Allocate 2 rows of ARGB.
1302 0 : const int kRowSize = (width * 4 + 31) & ~31;
1303 0 : align_buffer_64(row, kRowSize * 2);
1304 : #endif
1305 :
1306 0 : for (y = 0; y < height - 1; y += 2) {
1307 : #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
1308 : RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width);
1309 : RGB565ToYRow(src_rgb565, dst_y, width);
1310 : RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
1311 : #else
1312 0 : RGB565ToARGBRow(src_rgb565, row, width);
1313 0 : RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width);
1314 0 : ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1315 0 : ARGBToYRow(row, dst_y, width);
1316 0 : ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1317 : #endif
1318 0 : src_rgb565 += src_stride_rgb565 * 2;
1319 0 : dst_y += dst_stride_y * 2;
1320 0 : dst_u += dst_stride_u;
1321 0 : dst_v += dst_stride_v;
1322 : }
1323 0 : if (height & 1) {
1324 : #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
1325 : RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width);
1326 : RGB565ToYRow(src_rgb565, dst_y, width);
1327 : #else
1328 0 : RGB565ToARGBRow(src_rgb565, row, width);
1329 0 : ARGBToUVRow(row, 0, dst_u, dst_v, width);
1330 0 : ARGBToYRow(row, dst_y, width);
1331 : #endif
1332 : }
1333 : #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA))
1334 0 : free_aligned_buffer_64(row);
1335 : }
1336 : #endif
1337 0 : return 0;
1338 : }
1339 :
1340 : // Convert ARGB1555 to I420.
1341 : LIBYUV_API
1342 0 : int ARGB1555ToI420(const uint8* src_argb1555,
1343 : int src_stride_argb1555,
1344 : uint8* dst_y,
1345 : int dst_stride_y,
1346 : uint8* dst_u,
1347 : int dst_stride_u,
1348 : uint8* dst_v,
1349 : int dst_stride_v,
1350 : int width,
1351 : int height) {
1352 : int y;
1353 : #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
1354 : void (*ARGB1555ToUVRow)(const uint8* src_argb1555, int src_stride_argb1555,
1355 : uint8* dst_u, uint8* dst_v, int width) =
1356 : ARGB1555ToUVRow_C;
1357 : void (*ARGB1555ToYRow)(const uint8* src_argb1555, uint8* dst_y, int width) =
1358 : ARGB1555ToYRow_C;
1359 : #else
1360 : void (*ARGB1555ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) =
1361 0 : ARGB1555ToARGBRow_C;
1362 : void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u,
1363 0 : uint8* dst_v, int width) = ARGBToUVRow_C;
1364 : void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
1365 0 : ARGBToYRow_C;
1366 : #endif
1367 0 : if (!src_argb1555 || !dst_y || !dst_u || !dst_v || width <= 0 ||
1368 : height == 0) {
1369 0 : return -1;
1370 : }
1371 : // Negative height means invert the image.
1372 0 : if (height < 0) {
1373 0 : height = -height;
1374 0 : src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
1375 0 : src_stride_argb1555 = -src_stride_argb1555;
1376 : }
1377 :
1378 : // Neon version does direct ARGB1555 to YUV.
1379 : #if defined(HAS_ARGB1555TOYROW_NEON)
1380 : if (TestCpuFlag(kCpuHasNEON)) {
1381 : ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
1382 : ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
1383 : if (IS_ALIGNED(width, 8)) {
1384 : ARGB1555ToYRow = ARGB1555ToYRow_NEON;
1385 : if (IS_ALIGNED(width, 16)) {
1386 : ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
1387 : }
1388 : }
1389 : }
1390 : #elif defined(HAS_ARGB1555TOYROW_MSA)
1391 : if (TestCpuFlag(kCpuHasMSA)) {
1392 : ARGB1555ToUVRow = ARGB1555ToUVRow_Any_MSA;
1393 : ARGB1555ToYRow = ARGB1555ToYRow_Any_MSA;
1394 : if (IS_ALIGNED(width, 16)) {
1395 : ARGB1555ToYRow = ARGB1555ToYRow_MSA;
1396 : ARGB1555ToUVRow = ARGB1555ToUVRow_MSA;
1397 : }
1398 : }
1399 : // Other platforms do intermediate conversion from ARGB1555 to ARGB.
1400 : #else
1401 : #if defined(HAS_ARGB1555TOARGBROW_SSE2)
1402 0 : if (TestCpuFlag(kCpuHasSSE2)) {
1403 0 : ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
1404 0 : if (IS_ALIGNED(width, 8)) {
1405 0 : ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
1406 : }
1407 : }
1408 : #endif
1409 : #if defined(HAS_ARGB1555TOARGBROW_AVX2)
1410 : if (TestCpuFlag(kCpuHasAVX2)) {
1411 : ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
1412 : if (IS_ALIGNED(width, 16)) {
1413 : ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
1414 : }
1415 : }
1416 : #endif
1417 : #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1418 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
1419 0 : ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1420 0 : ARGBToYRow = ARGBToYRow_Any_SSSE3;
1421 0 : if (IS_ALIGNED(width, 16)) {
1422 0 : ARGBToUVRow = ARGBToUVRow_SSSE3;
1423 0 : ARGBToYRow = ARGBToYRow_SSSE3;
1424 : }
1425 : }
1426 : #endif
1427 : #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1428 0 : if (TestCpuFlag(kCpuHasAVX2)) {
1429 0 : ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1430 0 : ARGBToYRow = ARGBToYRow_Any_AVX2;
1431 0 : if (IS_ALIGNED(width, 32)) {
1432 0 : ARGBToUVRow = ARGBToUVRow_AVX2;
1433 0 : ARGBToYRow = ARGBToYRow_AVX2;
1434 : }
1435 : }
1436 : #endif
1437 : {
1438 : // Allocate 2 rows of ARGB.
1439 0 : const int kRowSize = (width * 4 + 31) & ~31;
1440 0 : align_buffer_64(row, kRowSize * 2);
1441 : #endif
1442 :
1443 0 : for (y = 0; y < height - 1; y += 2) {
1444 : #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
1445 : ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width);
1446 : ARGB1555ToYRow(src_argb1555, dst_y, width);
1447 : ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y,
1448 : width);
1449 : #else
1450 0 : ARGB1555ToARGBRow(src_argb1555, row, width);
1451 0 : ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize,
1452 0 : width);
1453 0 : ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1454 0 : ARGBToYRow(row, dst_y, width);
1455 0 : ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1456 : #endif
1457 0 : src_argb1555 += src_stride_argb1555 * 2;
1458 0 : dst_y += dst_stride_y * 2;
1459 0 : dst_u += dst_stride_u;
1460 0 : dst_v += dst_stride_v;
1461 : }
1462 0 : if (height & 1) {
1463 : #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
1464 : ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width);
1465 : ARGB1555ToYRow(src_argb1555, dst_y, width);
1466 : #else
1467 0 : ARGB1555ToARGBRow(src_argb1555, row, width);
1468 0 : ARGBToUVRow(row, 0, dst_u, dst_v, width);
1469 0 : ARGBToYRow(row, dst_y, width);
1470 : #endif
1471 : }
1472 : #if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA))
1473 0 : free_aligned_buffer_64(row);
1474 : }
1475 : #endif
1476 0 : return 0;
1477 : }
1478 :
1479 : // Convert ARGB4444 to I420.
1480 : LIBYUV_API
1481 0 : int ARGB4444ToI420(const uint8* src_argb4444,
1482 : int src_stride_argb4444,
1483 : uint8* dst_y,
1484 : int dst_stride_y,
1485 : uint8* dst_u,
1486 : int dst_stride_u,
1487 : uint8* dst_v,
1488 : int dst_stride_v,
1489 : int width,
1490 : int height) {
1491 : int y;
1492 : #if defined(HAS_ARGB4444TOYROW_NEON)
1493 : void (*ARGB4444ToUVRow)(const uint8* src_argb4444, int src_stride_argb4444,
1494 : uint8* dst_u, uint8* dst_v, int width) =
1495 : ARGB4444ToUVRow_C;
1496 : void (*ARGB4444ToYRow)(const uint8* src_argb4444, uint8* dst_y, int width) =
1497 : ARGB4444ToYRow_C;
1498 : #else
1499 : void (*ARGB4444ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int width) =
1500 0 : ARGB4444ToARGBRow_C;
1501 : void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb, uint8* dst_u,
1502 0 : uint8* dst_v, int width) = ARGBToUVRow_C;
1503 : void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
1504 0 : ARGBToYRow_C;
1505 : #endif
1506 0 : if (!src_argb4444 || !dst_y || !dst_u || !dst_v || width <= 0 ||
1507 : height == 0) {
1508 0 : return -1;
1509 : }
1510 : // Negative height means invert the image.
1511 0 : if (height < 0) {
1512 0 : height = -height;
1513 0 : src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
1514 0 : src_stride_argb4444 = -src_stride_argb4444;
1515 : }
1516 :
1517 : // Neon version does direct ARGB4444 to YUV.
1518 : #if defined(HAS_ARGB4444TOYROW_NEON)
1519 : if (TestCpuFlag(kCpuHasNEON)) {
1520 : ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
1521 : ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
1522 : if (IS_ALIGNED(width, 8)) {
1523 : ARGB4444ToYRow = ARGB4444ToYRow_NEON;
1524 : if (IS_ALIGNED(width, 16)) {
1525 : ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
1526 : }
1527 : }
1528 : }
1529 : // Other platforms do intermediate conversion from ARGB4444 to ARGB.
1530 : #else
1531 : #if defined(HAS_ARGB4444TOARGBROW_SSE2)
1532 0 : if (TestCpuFlag(kCpuHasSSE2)) {
1533 0 : ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
1534 0 : if (IS_ALIGNED(width, 8)) {
1535 0 : ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
1536 : }
1537 : }
1538 : #endif
1539 : #if defined(HAS_ARGB4444TOARGBROW_AVX2)
1540 : if (TestCpuFlag(kCpuHasAVX2)) {
1541 : ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
1542 : if (IS_ALIGNED(width, 16)) {
1543 : ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
1544 : }
1545 : }
1546 : #endif
1547 : #if defined(HAS_ARGB4444TOARGBROW_MSA)
1548 : if (TestCpuFlag(kCpuHasMSA)) {
1549 : ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA;
1550 : if (IS_ALIGNED(width, 16)) {
1551 : ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA;
1552 : }
1553 : }
1554 : #endif
1555 : #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1556 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
1557 0 : ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1558 0 : ARGBToYRow = ARGBToYRow_Any_SSSE3;
1559 0 : if (IS_ALIGNED(width, 16)) {
1560 0 : ARGBToUVRow = ARGBToUVRow_SSSE3;
1561 0 : ARGBToYRow = ARGBToYRow_SSSE3;
1562 : }
1563 : }
1564 : #endif
1565 : #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1566 0 : if (TestCpuFlag(kCpuHasAVX2)) {
1567 0 : ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1568 0 : ARGBToYRow = ARGBToYRow_Any_AVX2;
1569 0 : if (IS_ALIGNED(width, 32)) {
1570 0 : ARGBToUVRow = ARGBToUVRow_AVX2;
1571 0 : ARGBToYRow = ARGBToYRow_AVX2;
1572 : }
1573 : }
1574 : #endif
1575 : #if defined(HAS_ARGBTOYROW_MSA)
1576 : if (TestCpuFlag(kCpuHasMSA)) {
1577 : ARGBToUVRow = ARGBToUVRow_Any_MSA;
1578 : ARGBToYRow = ARGBToYRow_Any_MSA;
1579 : if (IS_ALIGNED(width, 16)) {
1580 : ARGBToYRow = ARGBToYRow_MSA;
1581 : if (IS_ALIGNED(width, 32)) {
1582 : ARGBToUVRow = ARGBToUVRow_MSA;
1583 : }
1584 : }
1585 : }
1586 : #endif
1587 : {
1588 : // Allocate 2 rows of ARGB.
1589 0 : const int kRowSize = (width * 4 + 31) & ~31;
1590 0 : align_buffer_64(row, kRowSize * 2);
1591 : #endif
1592 :
1593 0 : for (y = 0; y < height - 1; y += 2) {
1594 : #if defined(HAS_ARGB4444TOYROW_NEON)
1595 : ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width);
1596 : ARGB4444ToYRow(src_argb4444, dst_y, width);
1597 : ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y,
1598 : width);
1599 : #else
1600 0 : ARGB4444ToARGBRow(src_argb4444, row, width);
1601 0 : ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize,
1602 0 : width);
1603 0 : ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1604 0 : ARGBToYRow(row, dst_y, width);
1605 0 : ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1606 : #endif
1607 0 : src_argb4444 += src_stride_argb4444 * 2;
1608 0 : dst_y += dst_stride_y * 2;
1609 0 : dst_u += dst_stride_u;
1610 0 : dst_v += dst_stride_v;
1611 : }
1612 0 : if (height & 1) {
1613 : #if defined(HAS_ARGB4444TOYROW_NEON)
1614 : ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width);
1615 : ARGB4444ToYRow(src_argb4444, dst_y, width);
1616 : #else
1617 0 : ARGB4444ToARGBRow(src_argb4444, row, width);
1618 0 : ARGBToUVRow(row, 0, dst_u, dst_v, width);
1619 0 : ARGBToYRow(row, dst_y, width);
1620 : #endif
1621 : }
1622 : #if !defined(HAS_ARGB4444TOYROW_NEON)
1623 0 : free_aligned_buffer_64(row);
1624 : }
1625 : #endif
1626 0 : return 0;
1627 : }
1628 :
1629 0 : static void SplitPixels(const uint8* src_u,
1630 : int src_pixel_stride_uv,
1631 : uint8* dst_u,
1632 : int width) {
1633 : int i;
1634 0 : for (i = 0; i < width; ++i) {
1635 0 : *dst_u = *src_u;
1636 0 : ++dst_u;
1637 0 : src_u += src_pixel_stride_uv;
1638 : }
1639 0 : }
1640 :
1641 : // Convert Android420 to I420.
1642 : LIBYUV_API
1643 0 : int Android420ToI420(const uint8* src_y,
1644 : int src_stride_y,
1645 : const uint8* src_u,
1646 : int src_stride_u,
1647 : const uint8* src_v,
1648 : int src_stride_v,
1649 : int src_pixel_stride_uv,
1650 : uint8* dst_y,
1651 : int dst_stride_y,
1652 : uint8* dst_u,
1653 : int dst_stride_u,
1654 : uint8* dst_v,
1655 : int dst_stride_v,
1656 : int width,
1657 : int height) {
1658 : int y;
1659 0 : const ptrdiff_t vu_off = src_v - src_u;
1660 0 : int halfwidth = (width + 1) >> 1;
1661 0 : int halfheight = (height + 1) >> 1;
1662 0 : if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
1663 0 : return -1;
1664 : }
1665 : // Negative height means invert the image.
1666 0 : if (height < 0) {
1667 0 : height = -height;
1668 0 : halfheight = (height + 1) >> 1;
1669 0 : src_y = src_y + (height - 1) * src_stride_y;
1670 0 : src_u = src_u + (halfheight - 1) * src_stride_u;
1671 0 : src_v = src_v + (halfheight - 1) * src_stride_v;
1672 0 : src_stride_y = -src_stride_y;
1673 0 : src_stride_u = -src_stride_u;
1674 0 : src_stride_v = -src_stride_v;
1675 : }
1676 :
1677 0 : if (dst_y) {
1678 0 : CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1679 : }
1680 :
1681 : // Copy UV planes as is - I420
1682 0 : if (src_pixel_stride_uv == 1) {
1683 0 : CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
1684 0 : CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
1685 0 : return 0;
1686 : // Split UV planes - NV21
1687 0 : } else if (src_pixel_stride_uv == 2 && vu_off == -1 &&
1688 : src_stride_u == src_stride_v) {
1689 : SplitUVPlane(src_v, src_stride_v, dst_v, dst_stride_v, dst_u, dst_stride_u,
1690 0 : halfwidth, halfheight);
1691 0 : return 0;
1692 : // Split UV planes - NV12
1693 0 : } else if (src_pixel_stride_uv == 2 && vu_off == 1 &&
1694 : src_stride_u == src_stride_v) {
1695 : SplitUVPlane(src_u, src_stride_u, dst_u, dst_stride_u, dst_v, dst_stride_v,
1696 0 : halfwidth, halfheight);
1697 0 : return 0;
1698 : }
1699 :
1700 0 : for (y = 0; y < halfheight; ++y) {
1701 0 : SplitPixels(src_u, src_pixel_stride_uv, dst_u, halfwidth);
1702 0 : SplitPixels(src_v, src_pixel_stride_uv, dst_v, halfwidth);
1703 0 : src_u += src_stride_u;
1704 0 : src_v += src_stride_v;
1705 0 : dst_u += dst_stride_u;
1706 0 : dst_v += dst_stride_v;
1707 : }
1708 0 : return 0;
1709 : }
1710 :
1711 : #ifdef __cplusplus
1712 : } // extern "C"
1713 : } // namespace libyuv
1714 : #endif
|