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 // TODO(fbarchard): Implement row conversion.
219 LIBYUV_API
I422ToNV21(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_vu,int dst_stride_vu,int width,int height)220 int I422ToNV21(const uint8_t* src_y,
221 int src_stride_y,
222 const uint8_t* src_u,
223 int src_stride_u,
224 const uint8_t* src_v,
225 int src_stride_v,
226 uint8_t* dst_y,
227 int dst_stride_y,
228 uint8_t* dst_vu,
229 int dst_stride_vu,
230 int width,
231 int height) {
232 int halfwidth = (width + 1) >> 1;
233 int halfheight = (height + 1) >> 1;
234 // Negative height means invert the image.
235 if (height < 0) {
236 height = -height;
237 halfheight = (height + 1) >> 1;
238 src_y = src_y + (height - 1) * src_stride_y;
239 src_u = src_u + (height - 1) * src_stride_u;
240 src_v = src_v + (height - 1) * src_stride_v;
241 src_stride_y = -src_stride_y;
242 src_stride_u = -src_stride_u;
243 src_stride_v = -src_stride_v;
244 }
245
246 // Allocate u and v buffers
247 align_buffer_64(plane_u, halfwidth * halfheight * 2);
248 uint8_t* plane_v = plane_u + halfwidth * halfheight;
249
250 I422ToI420(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
251 dst_y, dst_stride_y, plane_u, halfwidth, plane_v, halfwidth, width,
252 height);
253 MergeUVPlane(plane_v, halfwidth, plane_u, halfwidth, dst_vu, dst_stride_vu,
254 halfwidth, halfheight);
255 free_aligned_buffer_64(plane_u);
256 return 0;
257 }
258
259 #ifdef I422TONV21_ROW_VERSION
260 // Unittest fails for this version.
261 // 422 chroma is 1/2 width, 1x height
262 // 420 chroma is 1/2 width, 1/2 height
263 // Swap src_u and src_v to implement I422ToNV12
264 LIBYUV_API
I422ToNV21(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_vu,int dst_stride_vu,int width,int height)265 int I422ToNV21(const uint8_t* src_y,
266 int src_stride_y,
267 const uint8_t* src_u,
268 int src_stride_u,
269 const uint8_t* src_v,
270 int src_stride_v,
271 uint8_t* dst_y,
272 int dst_stride_y,
273 uint8_t* dst_vu,
274 int dst_stride_vu,
275 int width,
276 int height) {
277 int y;
278 void (*MergeUVRow)(const uint8_t* src_u, const uint8_t* src_v,
279 uint8_t* dst_uv, int width) = MergeUVRow_C;
280 void (*InterpolateRow)(uint8_t * dst_ptr, const uint8_t* src_ptr,
281 ptrdiff_t src_stride, int dst_width,
282 int source_y_fraction) = InterpolateRow_C;
283 int halfwidth = (width + 1) >> 1;
284 int halfheight = (height + 1) >> 1;
285 if (!src_u || !src_v || !dst_vu || width <= 0 || height == 0) {
286 return -1;
287 }
288 // Negative height means invert the image.
289 if (height < 0) {
290 height = -height;
291 halfheight = (height + 1) >> 1;
292 src_y = src_y + (height - 1) * src_stride_y;
293 src_u = src_u + (halfheight - 1) * src_stride_u;
294 src_v = src_v + (halfheight - 1) * src_stride_v;
295 src_stride_y = -src_stride_y;
296 src_stride_u = -src_stride_u;
297 src_stride_v = -src_stride_v;
298 }
299 #if defined(HAS_MERGEUVROW_SSE2)
300 if (TestCpuFlag(kCpuHasSSE2)) {
301 MergeUVRow = MergeUVRow_Any_SSE2;
302 if (IS_ALIGNED(halfwidth, 16)) {
303 MergeUVRow = MergeUVRow_SSE2;
304 }
305 }
306 #endif
307 #if defined(HAS_MERGEUVROW_AVX2)
308 if (TestCpuFlag(kCpuHasAVX2)) {
309 MergeUVRow = MergeUVRow_Any_AVX2;
310 if (IS_ALIGNED(halfwidth, 32)) {
311 MergeUVRow = MergeUVRow_AVX2;
312 }
313 }
314 #endif
315 #if defined(HAS_MERGEUVROW_NEON)
316 if (TestCpuFlag(kCpuHasNEON)) {
317 MergeUVRow = MergeUVRow_Any_NEON;
318 if (IS_ALIGNED(halfwidth, 16)) {
319 MergeUVRow = MergeUVRow_NEON;
320 }
321 }
322 #endif
323 #if defined(HAS_MERGEUVROW_MSA)
324 if (TestCpuFlag(kCpuHasMSA)) {
325 MergeUVRow = MergeUVRow_Any_MSA;
326 if (IS_ALIGNED(halfwidth, 16)) {
327 MergeUVRow = MergeUVRow_MSA;
328 }
329 }
330 #endif
331 #if defined(HAS_MERGEUVROW_MMI)
332 if (TestCpuFlag(kCpuHasMMI)) {
333 MergeUVRow = MergeUVRow_Any_MMI;
334 if (IS_ALIGNED(halfwidth, 8)) {
335 MergeUVRow = MergeUVRow_MMI;
336 }
337 }
338 #endif
339 #if defined(HAS_INTERPOLATEROW_SSSE3)
340 if (TestCpuFlag(kCpuHasSSSE3)) {
341 InterpolateRow = InterpolateRow_Any_SSSE3;
342 if (IS_ALIGNED(width, 16)) {
343 InterpolateRow = InterpolateRow_SSSE3;
344 }
345 }
346 #endif
347 #if defined(HAS_INTERPOLATEROW_AVX2)
348 if (TestCpuFlag(kCpuHasAVX2)) {
349 InterpolateRow = InterpolateRow_Any_AVX2;
350 if (IS_ALIGNED(width, 32)) {
351 InterpolateRow = InterpolateRow_AVX2;
352 }
353 }
354 #endif
355 #if defined(HAS_INTERPOLATEROW_NEON)
356 if (TestCpuFlag(kCpuHasNEON)) {
357 InterpolateRow = InterpolateRow_Any_NEON;
358 if (IS_ALIGNED(width, 16)) {
359 InterpolateRow = InterpolateRow_NEON;
360 }
361 }
362 #endif
363 #if defined(HAS_INTERPOLATEROW_MSA)
364 if (TestCpuFlag(kCpuHasMSA)) {
365 InterpolateRow = InterpolateRow_Any_MSA;
366 if (IS_ALIGNED(width, 32)) {
367 InterpolateRow = InterpolateRow_MSA;
368 }
369 }
370 #endif
371 #if defined(HAS_INTERPOLATEROW_MMI)
372 if (TestCpuFlag(kCpuHasMMI)) {
373 InterpolateRow = InterpolateRow_Any_MMI;
374 if (IS_ALIGNED(width, 8)) {
375 InterpolateRow = InterpolateRow_MMI;
376 }
377 }
378 #endif
379
380 if (dst_y) {
381 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, halfwidth, height);
382 }
383 {
384 // Allocate 2 rows of vu.
385 int awidth = halfwidth * 2;
386 align_buffer_64(row_vu_0, awidth * 2);
387 uint8_t* row_vu_1 = row_vu_0 + awidth;
388
389 for (y = 0; y < height - 1; y += 2) {
390 MergeUVRow(src_v, src_u, row_vu_0, halfwidth);
391 MergeUVRow(src_v + src_stride_v, src_u + src_stride_u, row_vu_1,
392 halfwidth);
393 InterpolateRow(dst_vu, row_vu_0, awidth, awidth, 128);
394 src_u += src_stride_u * 2;
395 src_v += src_stride_v * 2;
396 dst_vu += dst_stride_vu;
397 }
398 if (height & 1) {
399 MergeUVRow(src_v, src_u, dst_vu, halfwidth);
400 }
401 free_aligned_buffer_64(row_vu_0);
402 }
403 return 0;
404 }
405 #endif // I422TONV21_ROW_VERSION
406
407 // 444 chroma is 1x width, 1x height
408 // 420 chroma is 1/2 width, 1/2 height
409 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)410 int I444ToI420(const uint8_t* src_y,
411 int src_stride_y,
412 const uint8_t* src_u,
413 int src_stride_u,
414 const uint8_t* src_v,
415 int src_stride_v,
416 uint8_t* dst_y,
417 int dst_stride_y,
418 uint8_t* dst_u,
419 int dst_stride_u,
420 uint8_t* dst_v,
421 int dst_stride_v,
422 int width,
423 int height) {
424 return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
425 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
426 dst_v, dst_stride_v, width, height, width, height);
427 }
428
429 // TODO(fbarchard): Implement row conversion.
430 LIBYUV_API
I444ToNV21(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_vu,int dst_stride_vu,int width,int height)431 int I444ToNV21(const uint8_t* src_y,
432 int src_stride_y,
433 const uint8_t* src_u,
434 int src_stride_u,
435 const uint8_t* src_v,
436 int src_stride_v,
437 uint8_t* dst_y,
438 int dst_stride_y,
439 uint8_t* dst_vu,
440 int dst_stride_vu,
441 int width,
442 int height) {
443 int halfwidth = (width + 1) >> 1;
444 int halfheight = (height + 1) >> 1;
445 // Negative height means invert the image.
446 if (height < 0) {
447 height = -height;
448 halfheight = (height + 1) >> 1;
449 src_y = src_y + (height - 1) * src_stride_y;
450 src_u = src_u + (height - 1) * src_stride_u;
451 src_v = src_v + (height - 1) * src_stride_v;
452 src_stride_y = -src_stride_y;
453 src_stride_u = -src_stride_u;
454 src_stride_v = -src_stride_v;
455 }
456 // Allocate u and v buffers
457 align_buffer_64(plane_u, halfwidth * halfheight * 2);
458 uint8_t* plane_v = plane_u + halfwidth * halfheight;
459
460 I444ToI420(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
461 dst_y, dst_stride_y, plane_u, halfwidth, plane_v, halfwidth, width,
462 height);
463 MergeUVPlane(plane_v, halfwidth, plane_u, halfwidth, dst_vu, dst_stride_vu,
464 halfwidth, halfheight);
465 free_aligned_buffer_64(plane_u);
466 return 0;
467 }
468
469 // I400 is greyscale typically used in MJPG
470 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)471 int I400ToI420(const uint8_t* src_y,
472 int src_stride_y,
473 uint8_t* dst_y,
474 int dst_stride_y,
475 uint8_t* dst_u,
476 int dst_stride_u,
477 uint8_t* dst_v,
478 int dst_stride_v,
479 int width,
480 int height) {
481 int halfwidth = (width + 1) >> 1;
482 int halfheight = (height + 1) >> 1;
483 if (!dst_u || !dst_v || width <= 0 || height == 0) {
484 return -1;
485 }
486 // Negative height means invert the image.
487 if (height < 0) {
488 height = -height;
489 halfheight = (height + 1) >> 1;
490 src_y = src_y + (height - 1) * src_stride_y;
491 src_stride_y = -src_stride_y;
492 }
493 if (dst_y) {
494 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
495 }
496 SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128);
497 SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128);
498 return 0;
499 }
500
501 // I400 is greyscale typically used in MJPG
502 LIBYUV_API
I400ToNV21(const uint8_t * src_y,int src_stride_y,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_vu,int dst_stride_vu,int width,int height)503 int I400ToNV21(const uint8_t* src_y,
504 int src_stride_y,
505 uint8_t* dst_y,
506 int dst_stride_y,
507 uint8_t* dst_vu,
508 int dst_stride_vu,
509 int width,
510 int height) {
511 int halfwidth = (width + 1) >> 1;
512 int halfheight = (height + 1) >> 1;
513 if (!dst_vu || width <= 0 || height == 0) {
514 return -1;
515 }
516 // Negative height means invert the image.
517 if (height < 0) {
518 height = -height;
519 halfheight = (height + 1) >> 1;
520 src_y = src_y + (height - 1) * src_stride_y;
521 src_stride_y = -src_stride_y;
522 }
523 if (dst_y) {
524 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
525 }
526 SetPlane(dst_vu, dst_stride_vu, halfwidth * 2, halfheight, 128);
527 return 0;
528 }
529
CopyPlane2(const uint8_t * src,int src_stride_0,int src_stride_1,uint8_t * dst,int dst_stride,int width,int height)530 static void CopyPlane2(const uint8_t* src,
531 int src_stride_0,
532 int src_stride_1,
533 uint8_t* dst,
534 int dst_stride,
535 int width,
536 int height) {
537 int y;
538 void (*CopyRow)(const uint8_t* src, uint8_t* dst, int width) = CopyRow_C;
539 #if defined(HAS_COPYROW_SSE2)
540 if (TestCpuFlag(kCpuHasSSE2)) {
541 CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2;
542 }
543 #endif
544 #if defined(HAS_COPYROW_AVX)
545 if (TestCpuFlag(kCpuHasAVX)) {
546 CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
547 }
548 #endif
549 #if defined(HAS_COPYROW_ERMS)
550 if (TestCpuFlag(kCpuHasERMS)) {
551 CopyRow = CopyRow_ERMS;
552 }
553 #endif
554 #if defined(HAS_COPYROW_NEON)
555 if (TestCpuFlag(kCpuHasNEON)) {
556 CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
557 }
558 #endif
559
560 // Copy plane
561 for (y = 0; y < height - 1; y += 2) {
562 CopyRow(src, dst, width);
563 CopyRow(src + src_stride_0, dst + dst_stride, width);
564 src += src_stride_0 + src_stride_1;
565 dst += dst_stride * 2;
566 }
567 if (height & 1) {
568 CopyRow(src, dst, width);
569 }
570 }
571
572 // Support converting from FOURCC_M420
573 // Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for
574 // easy conversion to I420.
575 // M420 format description:
576 // M420 is row biplanar 420: 2 rows of Y and 1 row of UV.
577 // Chroma is half width / half height. (420)
578 // src_stride_m420 is row planar. Normally this will be the width in pixels.
579 // The UV plane is half width, but 2 values, so src_stride_m420 applies to
580 // 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)581 static int X420ToI420(const uint8_t* src_y,
582 int src_stride_y0,
583 int src_stride_y1,
584 const uint8_t* src_uv,
585 int src_stride_uv,
586 uint8_t* dst_y,
587 int dst_stride_y,
588 uint8_t* dst_u,
589 int dst_stride_u,
590 uint8_t* dst_v,
591 int dst_stride_v,
592 int width,
593 int height) {
594 int halfwidth = (width + 1) >> 1;
595 int halfheight = (height + 1) >> 1;
596 if (!src_uv || !dst_u || !dst_v || width <= 0 || height == 0) {
597 return -1;
598 }
599 // Negative height means invert the image.
600 if (height < 0) {
601 height = -height;
602 halfheight = (height + 1) >> 1;
603 if (dst_y) {
604 dst_y = dst_y + (height - 1) * dst_stride_y;
605 }
606 dst_u = dst_u + (halfheight - 1) * dst_stride_u;
607 dst_v = dst_v + (halfheight - 1) * dst_stride_v;
608 dst_stride_y = -dst_stride_y;
609 dst_stride_u = -dst_stride_u;
610 dst_stride_v = -dst_stride_v;
611 }
612 // Coalesce rows.
613 if (src_stride_y0 == width && src_stride_y1 == width &&
614 dst_stride_y == width) {
615 width *= height;
616 height = 1;
617 src_stride_y0 = src_stride_y1 = dst_stride_y = 0;
618 }
619 // Coalesce rows.
620 if (src_stride_uv == halfwidth * 2 && dst_stride_u == halfwidth &&
621 dst_stride_v == halfwidth) {
622 halfwidth *= halfheight;
623 halfheight = 1;
624 src_stride_uv = dst_stride_u = dst_stride_v = 0;
625 }
626
627 if (dst_y) {
628 if (src_stride_y0 == src_stride_y1) {
629 CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height);
630 } else {
631 CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y,
632 width, height);
633 }
634 }
635
636 // Split UV plane - NV12 / NV21
637 SplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v, dst_stride_v,
638 halfwidth, halfheight);
639
640 return 0;
641 }
642
643 // Convert NV12 to I420.
644 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)645 int NV12ToI420(const uint8_t* src_y,
646 int src_stride_y,
647 const uint8_t* src_uv,
648 int src_stride_uv,
649 uint8_t* dst_y,
650 int dst_stride_y,
651 uint8_t* dst_u,
652 int dst_stride_u,
653 uint8_t* dst_v,
654 int dst_stride_v,
655 int width,
656 int height) {
657 return X420ToI420(src_y, src_stride_y, src_stride_y, src_uv, src_stride_uv,
658 dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v,
659 dst_stride_v, width, height);
660 }
661
662 // Convert NV21 to I420. Same as NV12 but u and v pointers swapped.
663 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)664 int NV21ToI420(const uint8_t* src_y,
665 int src_stride_y,
666 const uint8_t* src_vu,
667 int src_stride_vu,
668 uint8_t* dst_y,
669 int dst_stride_y,
670 uint8_t* dst_u,
671 int dst_stride_u,
672 uint8_t* dst_v,
673 int dst_stride_v,
674 int width,
675 int height) {
676 return X420ToI420(src_y, src_stride_y, src_stride_y, src_vu, src_stride_vu,
677 dst_y, dst_stride_y, dst_v, dst_stride_v, dst_u,
678 dst_stride_u, width, height);
679 }
680
681 // Convert M420 to I420.
682 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)683 int M420ToI420(const uint8_t* src_m420,
684 int src_stride_m420,
685 uint8_t* dst_y,
686 int dst_stride_y,
687 uint8_t* dst_u,
688 int dst_stride_u,
689 uint8_t* dst_v,
690 int dst_stride_v,
691 int width,
692 int height) {
693 return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2,
694 src_m420 + src_stride_m420 * 2, src_stride_m420 * 3, dst_y,
695 dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
696 width, height);
697 }
698
699 // Convert YUY2 to I420.
700 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)701 int YUY2ToI420(const uint8_t* src_yuy2,
702 int src_stride_yuy2,
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 (*YUY2ToUVRow)(const uint8_t* src_yuy2, int src_stride_yuy2,
713 uint8_t* dst_u, uint8_t* dst_v, int width) =
714 YUY2ToUVRow_C;
715 void (*YUY2ToYRow)(const uint8_t* src_yuy2, uint8_t* dst_y, int width) =
716 YUY2ToYRow_C;
717 // Negative height means invert the image.
718 if (height < 0) {
719 height = -height;
720 src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
721 src_stride_yuy2 = -src_stride_yuy2;
722 }
723 #if defined(HAS_YUY2TOYROW_SSE2)
724 if (TestCpuFlag(kCpuHasSSE2)) {
725 YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
726 YUY2ToYRow = YUY2ToYRow_Any_SSE2;
727 if (IS_ALIGNED(width, 16)) {
728 YUY2ToUVRow = YUY2ToUVRow_SSE2;
729 YUY2ToYRow = YUY2ToYRow_SSE2;
730 }
731 }
732 #endif
733 #if defined(HAS_YUY2TOYROW_AVX2)
734 if (TestCpuFlag(kCpuHasAVX2)) {
735 YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
736 YUY2ToYRow = YUY2ToYRow_Any_AVX2;
737 if (IS_ALIGNED(width, 32)) {
738 YUY2ToUVRow = YUY2ToUVRow_AVX2;
739 YUY2ToYRow = YUY2ToYRow_AVX2;
740 }
741 }
742 #endif
743 #if defined(HAS_YUY2TOYROW_NEON)
744 if (TestCpuFlag(kCpuHasNEON)) {
745 YUY2ToYRow = YUY2ToYRow_Any_NEON;
746 YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
747 if (IS_ALIGNED(width, 16)) {
748 YUY2ToYRow = YUY2ToYRow_NEON;
749 YUY2ToUVRow = YUY2ToUVRow_NEON;
750 }
751 }
752 #endif
753 #if defined(HAS_YUY2TOYROW_MSA)
754 if (TestCpuFlag(kCpuHasMSA)) {
755 YUY2ToYRow = YUY2ToYRow_Any_MSA;
756 YUY2ToUVRow = YUY2ToUVRow_Any_MSA;
757 if (IS_ALIGNED(width, 32)) {
758 YUY2ToYRow = YUY2ToYRow_MSA;
759 YUY2ToUVRow = YUY2ToUVRow_MSA;
760 }
761 }
762 #endif
763 #if defined(HAS_YUY2TOYROW_MMI)
764 if (TestCpuFlag(kCpuHasMMI)) {
765 YUY2ToYRow = YUY2ToYRow_Any_MMI;
766 YUY2ToUVRow = YUY2ToUVRow_Any_MMI;
767 if (IS_ALIGNED(width, 8)) {
768 YUY2ToYRow = YUY2ToYRow_MMI;
769 if (IS_ALIGNED(width, 16)) {
770 YUY2ToUVRow = YUY2ToUVRow_MMI;
771 }
772 }
773 }
774 #endif
775
776 for (y = 0; y < height - 1; y += 2) {
777 YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
778 YUY2ToYRow(src_yuy2, dst_y, width);
779 YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
780 src_yuy2 += src_stride_yuy2 * 2;
781 dst_y += dst_stride_y * 2;
782 dst_u += dst_stride_u;
783 dst_v += dst_stride_v;
784 }
785 if (height & 1) {
786 YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
787 YUY2ToYRow(src_yuy2, dst_y, width);
788 }
789 return 0;
790 }
791
792 // Convert UYVY to I420.
793 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)794 int UYVYToI420(const uint8_t* src_uyvy,
795 int src_stride_uyvy,
796 uint8_t* dst_y,
797 int dst_stride_y,
798 uint8_t* dst_u,
799 int dst_stride_u,
800 uint8_t* dst_v,
801 int dst_stride_v,
802 int width,
803 int height) {
804 int y;
805 void (*UYVYToUVRow)(const uint8_t* src_uyvy, int src_stride_uyvy,
806 uint8_t* dst_u, uint8_t* dst_v, int width) =
807 UYVYToUVRow_C;
808 void (*UYVYToYRow)(const uint8_t* src_uyvy, uint8_t* dst_y, int width) =
809 UYVYToYRow_C;
810 // Negative height means invert the image.
811 if (height < 0) {
812 height = -height;
813 src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
814 src_stride_uyvy = -src_stride_uyvy;
815 }
816 #if defined(HAS_UYVYTOYROW_SSE2)
817 if (TestCpuFlag(kCpuHasSSE2)) {
818 UYVYToUVRow = UYVYToUVRow_Any_SSE2;
819 UYVYToYRow = UYVYToYRow_Any_SSE2;
820 if (IS_ALIGNED(width, 16)) {
821 UYVYToUVRow = UYVYToUVRow_SSE2;
822 UYVYToYRow = UYVYToYRow_SSE2;
823 }
824 }
825 #endif
826 #if defined(HAS_UYVYTOYROW_AVX2)
827 if (TestCpuFlag(kCpuHasAVX2)) {
828 UYVYToUVRow = UYVYToUVRow_Any_AVX2;
829 UYVYToYRow = UYVYToYRow_Any_AVX2;
830 if (IS_ALIGNED(width, 32)) {
831 UYVYToUVRow = UYVYToUVRow_AVX2;
832 UYVYToYRow = UYVYToYRow_AVX2;
833 }
834 }
835 #endif
836 #if defined(HAS_UYVYTOYROW_NEON)
837 if (TestCpuFlag(kCpuHasNEON)) {
838 UYVYToYRow = UYVYToYRow_Any_NEON;
839 UYVYToUVRow = UYVYToUVRow_Any_NEON;
840 if (IS_ALIGNED(width, 16)) {
841 UYVYToYRow = UYVYToYRow_NEON;
842 UYVYToUVRow = UYVYToUVRow_NEON;
843 }
844 }
845 #endif
846 #if defined(HAS_UYVYTOYROW_MSA)
847 if (TestCpuFlag(kCpuHasMSA)) {
848 UYVYToYRow = UYVYToYRow_Any_MSA;
849 UYVYToUVRow = UYVYToUVRow_Any_MSA;
850 if (IS_ALIGNED(width, 32)) {
851 UYVYToYRow = UYVYToYRow_MSA;
852 UYVYToUVRow = UYVYToUVRow_MSA;
853 }
854 }
855 #endif
856 #if defined(HAS_UYVYTOYROW_MMI)
857 if (TestCpuFlag(kCpuHasMMI)) {
858 UYVYToYRow = UYVYToYRow_Any_MMI;
859 UYVYToUVRow = UYVYToUVRow_Any_MMI;
860 if (IS_ALIGNED(width, 16)) {
861 UYVYToYRow = UYVYToYRow_MMI;
862 UYVYToUVRow = UYVYToUVRow_MMI;
863 }
864 }
865 #endif
866
867 for (y = 0; y < height - 1; y += 2) {
868 UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
869 UYVYToYRow(src_uyvy, dst_y, width);
870 UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
871 src_uyvy += src_stride_uyvy * 2;
872 dst_y += dst_stride_y * 2;
873 dst_u += dst_stride_u;
874 dst_v += dst_stride_v;
875 }
876 if (height & 1) {
877 UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
878 UYVYToYRow(src_uyvy, dst_y, width);
879 }
880 return 0;
881 }
882
883 // Convert AYUV to NV12.
884 LIBYUV_API
AYUVToNV12(const uint8_t * src_ayuv,int src_stride_ayuv,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_uv,int dst_stride_uv,int width,int height)885 int AYUVToNV12(const uint8_t* src_ayuv,
886 int src_stride_ayuv,
887 uint8_t* dst_y,
888 int dst_stride_y,
889 uint8_t* dst_uv,
890 int dst_stride_uv,
891 int width,
892 int height) {
893 int y;
894 void (*AYUVToUVRow)(const uint8_t* src_ayuv, int src_stride_ayuv,
895 uint8_t* dst_uv, int width) = AYUVToUVRow_C;
896 void (*AYUVToYRow)(const uint8_t* src_ayuv, uint8_t* dst_y, int width) =
897 AYUVToYRow_C;
898 // Negative height means invert the image.
899 if (height < 0) {
900 height = -height;
901 src_ayuv = src_ayuv + (height - 1) * src_stride_ayuv;
902 src_stride_ayuv = -src_stride_ayuv;
903 }
904 // place holders for future intel code
905 #if defined(HAS_AYUVTOYROW_SSE2)
906 if (TestCpuFlag(kCpuHasSSE2)) {
907 AYUVToUVRow = AYUVToUVRow_Any_SSE2;
908 AYUVToYRow = AYUVToYRow_Any_SSE2;
909 if (IS_ALIGNED(width, 16)) {
910 AYUVToUVRow = AYUVToUVRow_SSE2;
911 AYUVToYRow = AYUVToYRow_SSE2;
912 }
913 }
914 #endif
915 #if defined(HAS_AYUVTOYROW_AVX2)
916 if (TestCpuFlag(kCpuHasAVX2)) {
917 AYUVToUVRow = AYUVToUVRow_Any_AVX2;
918 AYUVToYRow = AYUVToYRow_Any_AVX2;
919 if (IS_ALIGNED(width, 32)) {
920 AYUVToUVRow = AYUVToUVRow_AVX2;
921 AYUVToYRow = AYUVToYRow_AVX2;
922 }
923 }
924 #endif
925
926 #if defined(HAS_AYUVTOYROW_NEON)
927 if (TestCpuFlag(kCpuHasNEON)) {
928 AYUVToYRow = AYUVToYRow_Any_NEON;
929 AYUVToUVRow = AYUVToUVRow_Any_NEON;
930 if (IS_ALIGNED(width, 16)) {
931 AYUVToYRow = AYUVToYRow_NEON;
932 AYUVToUVRow = AYUVToUVRow_NEON;
933 }
934 }
935 #endif
936
937 for (y = 0; y < height - 1; y += 2) {
938 AYUVToUVRow(src_ayuv, src_stride_ayuv, dst_uv, width);
939 AYUVToYRow(src_ayuv, dst_y, width);
940 AYUVToYRow(src_ayuv + src_stride_ayuv, dst_y + dst_stride_y, width);
941 src_ayuv += src_stride_ayuv * 2;
942 dst_y += dst_stride_y * 2;
943 dst_uv += dst_stride_uv;
944 }
945 if (height & 1) {
946 AYUVToUVRow(src_ayuv, 0, dst_uv, width);
947 AYUVToYRow(src_ayuv, dst_y, width);
948 }
949 return 0;
950 }
951
952 // Convert AYUV to NV21.
953 LIBYUV_API
AYUVToNV21(const uint8_t * src_ayuv,int src_stride_ayuv,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_vu,int dst_stride_vu,int width,int height)954 int AYUVToNV21(const uint8_t* src_ayuv,
955 int src_stride_ayuv,
956 uint8_t* dst_y,
957 int dst_stride_y,
958 uint8_t* dst_vu,
959 int dst_stride_vu,
960 int width,
961 int height) {
962 int y;
963 void (*AYUVToVURow)(const uint8_t* src_ayuv, int src_stride_ayuv,
964 uint8_t* dst_vu, int width) = AYUVToVURow_C;
965 void (*AYUVToYRow)(const uint8_t* src_ayuv, uint8_t* dst_y, int width) =
966 AYUVToYRow_C;
967 // Negative height means invert the image.
968 if (height < 0) {
969 height = -height;
970 src_ayuv = src_ayuv + (height - 1) * src_stride_ayuv;
971 src_stride_ayuv = -src_stride_ayuv;
972 }
973 // place holders for future intel code
974 #if defined(HAS_AYUVTOYROW_SSE2)
975 if (TestCpuFlag(kCpuHasSSE2)) {
976 AYUVToVURow = AYUVToVURow_Any_SSE2;
977 AYUVToYRow = AYUVToYRow_Any_SSE2;
978 if (IS_ALIGNED(width, 16)) {
979 AYUVToVURow = AYUVToVURow_SSE2;
980 AYUVToYRow = AYUVToYRow_SSE2;
981 }
982 }
983 #endif
984 #if defined(HAS_AYUVTOYROW_AVX2)
985 if (TestCpuFlag(kCpuHasAVX2)) {
986 AYUVToVURow = AYUVToVURow_Any_AVX2;
987 AYUVToYRow = AYUVToYRow_Any_AVX2;
988 if (IS_ALIGNED(width, 32)) {
989 AYUVToVURow = AYUVToVURow_AVX2;
990 AYUVToYRow = AYUVToYRow_AVX2;
991 }
992 }
993 #endif
994
995 #if defined(HAS_AYUVTOYROW_NEON)
996 if (TestCpuFlag(kCpuHasNEON)) {
997 AYUVToYRow = AYUVToYRow_Any_NEON;
998 AYUVToVURow = AYUVToVURow_Any_NEON;
999 if (IS_ALIGNED(width, 16)) {
1000 AYUVToYRow = AYUVToYRow_NEON;
1001 AYUVToVURow = AYUVToVURow_NEON;
1002 }
1003 }
1004 #endif
1005
1006 for (y = 0; y < height - 1; y += 2) {
1007 AYUVToVURow(src_ayuv, src_stride_ayuv, dst_vu, width);
1008 AYUVToYRow(src_ayuv, dst_y, width);
1009 AYUVToYRow(src_ayuv + src_stride_ayuv, dst_y + dst_stride_y, width);
1010 src_ayuv += src_stride_ayuv * 2;
1011 dst_y += dst_stride_y * 2;
1012 dst_vu += dst_stride_vu;
1013 }
1014 if (height & 1) {
1015 AYUVToVURow(src_ayuv, 0, dst_vu, width);
1016 AYUVToYRow(src_ayuv, dst_y, width);
1017 }
1018 return 0;
1019 }
1020
1021 // Convert ARGB to I420.
1022 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)1023 int ARGBToI420(const uint8_t* src_argb,
1024 int src_stride_argb,
1025 uint8_t* dst_y,
1026 int dst_stride_y,
1027 uint8_t* dst_u,
1028 int dst_stride_u,
1029 uint8_t* dst_v,
1030 int dst_stride_v,
1031 int width,
1032 int height) {
1033 int y;
1034 void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
1035 uint8_t* dst_u, uint8_t* dst_v, int width) =
1036 ARGBToUVRow_C;
1037 void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
1038 ARGBToYRow_C;
1039 if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1040 return -1;
1041 }
1042 // Negative height means invert the image.
1043 if (height < 0) {
1044 height = -height;
1045 src_argb = src_argb + (height - 1) * src_stride_argb;
1046 src_stride_argb = -src_stride_argb;
1047 }
1048 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1049 if (TestCpuFlag(kCpuHasSSSE3)) {
1050 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1051 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1052 if (IS_ALIGNED(width, 16)) {
1053 ARGBToUVRow = ARGBToUVRow_SSSE3;
1054 ARGBToYRow = ARGBToYRow_SSSE3;
1055 }
1056 }
1057 #endif
1058 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1059 if (TestCpuFlag(kCpuHasAVX2)) {
1060 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1061 ARGBToYRow = ARGBToYRow_Any_AVX2;
1062 if (IS_ALIGNED(width, 32)) {
1063 ARGBToUVRow = ARGBToUVRow_AVX2;
1064 ARGBToYRow = ARGBToYRow_AVX2;
1065 }
1066 }
1067 #endif
1068 #if defined(HAS_ARGBTOYROW_NEON)
1069 if (TestCpuFlag(kCpuHasNEON)) {
1070 ARGBToYRow = ARGBToYRow_Any_NEON;
1071 if (IS_ALIGNED(width, 8)) {
1072 ARGBToYRow = ARGBToYRow_NEON;
1073 }
1074 }
1075 #endif
1076 #if defined(HAS_ARGBTOUVROW_NEON)
1077 if (TestCpuFlag(kCpuHasNEON)) {
1078 ARGBToUVRow = ARGBToUVRow_Any_NEON;
1079 if (IS_ALIGNED(width, 16)) {
1080 ARGBToUVRow = ARGBToUVRow_NEON;
1081 }
1082 }
1083 #endif
1084 #if defined(HAS_ARGBTOYROW_MSA)
1085 if (TestCpuFlag(kCpuHasMSA)) {
1086 ARGBToYRow = ARGBToYRow_Any_MSA;
1087 if (IS_ALIGNED(width, 16)) {
1088 ARGBToYRow = ARGBToYRow_MSA;
1089 }
1090 }
1091 #endif
1092 #if defined(HAS_ARGBTOUVROW_MSA)
1093 if (TestCpuFlag(kCpuHasMSA)) {
1094 ARGBToUVRow = ARGBToUVRow_Any_MSA;
1095 if (IS_ALIGNED(width, 32)) {
1096 ARGBToUVRow = ARGBToUVRow_MSA;
1097 }
1098 }
1099 #endif
1100 #if defined(HAS_ARGBTOYROW_MMI)
1101 if (TestCpuFlag(kCpuHasMMI)) {
1102 ARGBToYRow = ARGBToYRow_Any_MMI;
1103 if (IS_ALIGNED(width, 8)) {
1104 ARGBToYRow = ARGBToYRow_MMI;
1105 }
1106 }
1107 #endif
1108 #if defined(HAS_ARGBTOUVROW_MMI)
1109 if (TestCpuFlag(kCpuHasMMI)) {
1110 ARGBToUVRow = ARGBToUVRow_Any_MMI;
1111 if (IS_ALIGNED(width, 16)) {
1112 ARGBToUVRow = ARGBToUVRow_MMI;
1113 }
1114 }
1115 #endif
1116
1117 for (y = 0; y < height - 1; y += 2) {
1118 ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
1119 ARGBToYRow(src_argb, dst_y, width);
1120 ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
1121 src_argb += src_stride_argb * 2;
1122 dst_y += dst_stride_y * 2;
1123 dst_u += dst_stride_u;
1124 dst_v += dst_stride_v;
1125 }
1126 if (height & 1) {
1127 ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
1128 ARGBToYRow(src_argb, dst_y, width);
1129 }
1130 return 0;
1131 }
1132
1133 // Convert BGRA to I420.
1134 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)1135 int BGRAToI420(const uint8_t* src_bgra,
1136 int src_stride_bgra,
1137 uint8_t* dst_y,
1138 int dst_stride_y,
1139 uint8_t* dst_u,
1140 int dst_stride_u,
1141 uint8_t* dst_v,
1142 int dst_stride_v,
1143 int width,
1144 int height) {
1145 int y;
1146 void (*BGRAToUVRow)(const uint8_t* src_bgra0, int src_stride_bgra,
1147 uint8_t* dst_u, uint8_t* dst_v, int width) =
1148 BGRAToUVRow_C;
1149 void (*BGRAToYRow)(const uint8_t* src_bgra, uint8_t* dst_y, int width) =
1150 BGRAToYRow_C;
1151 if (!src_bgra || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1152 return -1;
1153 }
1154 // Negative height means invert the image.
1155 if (height < 0) {
1156 height = -height;
1157 src_bgra = src_bgra + (height - 1) * src_stride_bgra;
1158 src_stride_bgra = -src_stride_bgra;
1159 }
1160 #if defined(HAS_BGRATOYROW_SSSE3) && defined(HAS_BGRATOUVROW_SSSE3)
1161 if (TestCpuFlag(kCpuHasSSSE3)) {
1162 BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
1163 BGRAToYRow = BGRAToYRow_Any_SSSE3;
1164 if (IS_ALIGNED(width, 16)) {
1165 BGRAToUVRow = BGRAToUVRow_SSSE3;
1166 BGRAToYRow = BGRAToYRow_SSSE3;
1167 }
1168 }
1169 #endif
1170 #if defined(HAS_BGRATOYROW_NEON)
1171 if (TestCpuFlag(kCpuHasNEON)) {
1172 BGRAToYRow = BGRAToYRow_Any_NEON;
1173 if (IS_ALIGNED(width, 8)) {
1174 BGRAToYRow = BGRAToYRow_NEON;
1175 }
1176 }
1177 #endif
1178 #if defined(HAS_BGRATOUVROW_NEON)
1179 if (TestCpuFlag(kCpuHasNEON)) {
1180 BGRAToUVRow = BGRAToUVRow_Any_NEON;
1181 if (IS_ALIGNED(width, 16)) {
1182 BGRAToUVRow = BGRAToUVRow_NEON;
1183 }
1184 }
1185 #endif
1186 #if defined(HAS_BGRATOYROW_MSA)
1187 if (TestCpuFlag(kCpuHasMSA)) {
1188 BGRAToYRow = BGRAToYRow_Any_MSA;
1189 if (IS_ALIGNED(width, 16)) {
1190 BGRAToYRow = BGRAToYRow_MSA;
1191 }
1192 }
1193 #endif
1194 #if defined(HAS_BGRATOUVROW_MSA)
1195 if (TestCpuFlag(kCpuHasMSA)) {
1196 BGRAToUVRow = BGRAToUVRow_Any_MSA;
1197 if (IS_ALIGNED(width, 16)) {
1198 BGRAToUVRow = BGRAToUVRow_MSA;
1199 }
1200 }
1201 #endif
1202 #if defined(HAS_BGRATOYROW_MMI)
1203 if (TestCpuFlag(kCpuHasMMI)) {
1204 BGRAToYRow = BGRAToYRow_Any_MMI;
1205 if (IS_ALIGNED(width, 8)) {
1206 BGRAToYRow = BGRAToYRow_MMI;
1207 }
1208 }
1209 #endif
1210 #if defined(HAS_BGRATOUVROW_MMI)
1211 if (TestCpuFlag(kCpuHasMMI)) {
1212 BGRAToUVRow = BGRAToUVRow_Any_MMI;
1213 if (IS_ALIGNED(width, 16)) {
1214 BGRAToUVRow = BGRAToUVRow_MMI;
1215 }
1216 }
1217 #endif
1218
1219 for (y = 0; y < height - 1; y += 2) {
1220 BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
1221 BGRAToYRow(src_bgra, dst_y, width);
1222 BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
1223 src_bgra += src_stride_bgra * 2;
1224 dst_y += dst_stride_y * 2;
1225 dst_u += dst_stride_u;
1226 dst_v += dst_stride_v;
1227 }
1228 if (height & 1) {
1229 BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
1230 BGRAToYRow(src_bgra, dst_y, width);
1231 }
1232 return 0;
1233 }
1234
1235 // Convert ABGR to I420.
1236 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)1237 int ABGRToI420(const uint8_t* src_abgr,
1238 int src_stride_abgr,
1239 uint8_t* dst_y,
1240 int dst_stride_y,
1241 uint8_t* dst_u,
1242 int dst_stride_u,
1243 uint8_t* dst_v,
1244 int dst_stride_v,
1245 int width,
1246 int height) {
1247 int y;
1248 void (*ABGRToUVRow)(const uint8_t* src_abgr0, int src_stride_abgr,
1249 uint8_t* dst_u, uint8_t* dst_v, int width) =
1250 ABGRToUVRow_C;
1251 void (*ABGRToYRow)(const uint8_t* src_abgr, uint8_t* dst_y, int width) =
1252 ABGRToYRow_C;
1253 if (!src_abgr || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1254 return -1;
1255 }
1256 // Negative height means invert the image.
1257 if (height < 0) {
1258 height = -height;
1259 src_abgr = src_abgr + (height - 1) * src_stride_abgr;
1260 src_stride_abgr = -src_stride_abgr;
1261 }
1262 #if defined(HAS_ABGRTOYROW_SSSE3) && defined(HAS_ABGRTOUVROW_SSSE3)
1263 if (TestCpuFlag(kCpuHasSSSE3)) {
1264 ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
1265 ABGRToYRow = ABGRToYRow_Any_SSSE3;
1266 if (IS_ALIGNED(width, 16)) {
1267 ABGRToUVRow = ABGRToUVRow_SSSE3;
1268 ABGRToYRow = ABGRToYRow_SSSE3;
1269 }
1270 }
1271 #endif
1272 #if defined(HAS_ABGRTOYROW_NEON)
1273 if (TestCpuFlag(kCpuHasNEON)) {
1274 ABGRToYRow = ABGRToYRow_Any_NEON;
1275 if (IS_ALIGNED(width, 8)) {
1276 ABGRToYRow = ABGRToYRow_NEON;
1277 }
1278 }
1279 #endif
1280 #if defined(HAS_ABGRTOUVROW_NEON)
1281 if (TestCpuFlag(kCpuHasNEON)) {
1282 ABGRToUVRow = ABGRToUVRow_Any_NEON;
1283 if (IS_ALIGNED(width, 16)) {
1284 ABGRToUVRow = ABGRToUVRow_NEON;
1285 }
1286 }
1287 #endif
1288 #if defined(HAS_ABGRTOYROW_MSA)
1289 if (TestCpuFlag(kCpuHasMSA)) {
1290 ABGRToYRow = ABGRToYRow_Any_MSA;
1291 if (IS_ALIGNED(width, 16)) {
1292 ABGRToYRow = ABGRToYRow_MSA;
1293 }
1294 }
1295 #endif
1296 #if defined(HAS_ABGRTOUVROW_MSA)
1297 if (TestCpuFlag(kCpuHasMSA)) {
1298 ABGRToUVRow = ABGRToUVRow_Any_MSA;
1299 if (IS_ALIGNED(width, 16)) {
1300 ABGRToUVRow = ABGRToUVRow_MSA;
1301 }
1302 }
1303 #endif
1304 #if defined(HAS_ABGRTOYROW_MMI)
1305 if (TestCpuFlag(kCpuHasMMI)) {
1306 ABGRToYRow = ABGRToYRow_Any_MMI;
1307 if (IS_ALIGNED(width, 8)) {
1308 ABGRToYRow = ABGRToYRow_MMI;
1309 }
1310 }
1311 #endif
1312 #if defined(HAS_ABGRTOUVROW_MMI)
1313 if (TestCpuFlag(kCpuHasMMI)) {
1314 ABGRToUVRow = ABGRToUVRow_Any_MMI;
1315 if (IS_ALIGNED(width, 16)) {
1316 ABGRToUVRow = ABGRToUVRow_MMI;
1317 }
1318 }
1319 #endif
1320
1321 for (y = 0; y < height - 1; y += 2) {
1322 ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
1323 ABGRToYRow(src_abgr, dst_y, width);
1324 ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
1325 src_abgr += src_stride_abgr * 2;
1326 dst_y += dst_stride_y * 2;
1327 dst_u += dst_stride_u;
1328 dst_v += dst_stride_v;
1329 }
1330 if (height & 1) {
1331 ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
1332 ABGRToYRow(src_abgr, dst_y, width);
1333 }
1334 return 0;
1335 }
1336
1337 // Convert RGBA to I420.
1338 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)1339 int RGBAToI420(const uint8_t* src_rgba,
1340 int src_stride_rgba,
1341 uint8_t* dst_y,
1342 int dst_stride_y,
1343 uint8_t* dst_u,
1344 int dst_stride_u,
1345 uint8_t* dst_v,
1346 int dst_stride_v,
1347 int width,
1348 int height) {
1349 int y;
1350 void (*RGBAToUVRow)(const uint8_t* src_rgba0, int src_stride_rgba,
1351 uint8_t* dst_u, uint8_t* dst_v, int width) =
1352 RGBAToUVRow_C;
1353 void (*RGBAToYRow)(const uint8_t* src_rgba, uint8_t* dst_y, int width) =
1354 RGBAToYRow_C;
1355 if (!src_rgba || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1356 return -1;
1357 }
1358 // Negative height means invert the image.
1359 if (height < 0) {
1360 height = -height;
1361 src_rgba = src_rgba + (height - 1) * src_stride_rgba;
1362 src_stride_rgba = -src_stride_rgba;
1363 }
1364 #if defined(HAS_RGBATOYROW_SSSE3) && defined(HAS_RGBATOUVROW_SSSE3)
1365 if (TestCpuFlag(kCpuHasSSSE3)) {
1366 RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
1367 RGBAToYRow = RGBAToYRow_Any_SSSE3;
1368 if (IS_ALIGNED(width, 16)) {
1369 RGBAToUVRow = RGBAToUVRow_SSSE3;
1370 RGBAToYRow = RGBAToYRow_SSSE3;
1371 }
1372 }
1373 #endif
1374 #if defined(HAS_RGBATOYROW_NEON)
1375 if (TestCpuFlag(kCpuHasNEON)) {
1376 RGBAToYRow = RGBAToYRow_Any_NEON;
1377 if (IS_ALIGNED(width, 8)) {
1378 RGBAToYRow = RGBAToYRow_NEON;
1379 }
1380 }
1381 #endif
1382 #if defined(HAS_RGBATOUVROW_NEON)
1383 if (TestCpuFlag(kCpuHasNEON)) {
1384 RGBAToUVRow = RGBAToUVRow_Any_NEON;
1385 if (IS_ALIGNED(width, 16)) {
1386 RGBAToUVRow = RGBAToUVRow_NEON;
1387 }
1388 }
1389 #endif
1390 #if defined(HAS_RGBATOYROW_MSA)
1391 if (TestCpuFlag(kCpuHasMSA)) {
1392 RGBAToYRow = RGBAToYRow_Any_MSA;
1393 if (IS_ALIGNED(width, 16)) {
1394 RGBAToYRow = RGBAToYRow_MSA;
1395 }
1396 }
1397 #endif
1398 #if defined(HAS_RGBATOUVROW_MSA)
1399 if (TestCpuFlag(kCpuHasMSA)) {
1400 RGBAToUVRow = RGBAToUVRow_Any_MSA;
1401 if (IS_ALIGNED(width, 16)) {
1402 RGBAToUVRow = RGBAToUVRow_MSA;
1403 }
1404 }
1405 #endif
1406 #if defined(HAS_RGBATOYROW_MMI)
1407 if (TestCpuFlag(kCpuHasMMI)) {
1408 RGBAToYRow = RGBAToYRow_Any_MMI;
1409 if (IS_ALIGNED(width, 8)) {
1410 RGBAToYRow = RGBAToYRow_MMI;
1411 }
1412 }
1413 #endif
1414 #if defined(HAS_RGBATOUVROW_MMI)
1415 if (TestCpuFlag(kCpuHasMMI)) {
1416 RGBAToUVRow = RGBAToUVRow_Any_MMI;
1417 if (IS_ALIGNED(width, 16)) {
1418 RGBAToUVRow = RGBAToUVRow_MMI;
1419 }
1420 }
1421 #endif
1422
1423 for (y = 0; y < height - 1; y += 2) {
1424 RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
1425 RGBAToYRow(src_rgba, dst_y, width);
1426 RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
1427 src_rgba += src_stride_rgba * 2;
1428 dst_y += dst_stride_y * 2;
1429 dst_u += dst_stride_u;
1430 dst_v += dst_stride_v;
1431 }
1432 if (height & 1) {
1433 RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
1434 RGBAToYRow(src_rgba, dst_y, width);
1435 }
1436 return 0;
1437 }
1438
1439 // Convert RGB24 to I420.
1440 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)1441 int RGB24ToI420(const uint8_t* src_rgb24,
1442 int src_stride_rgb24,
1443 uint8_t* dst_y,
1444 int dst_stride_y,
1445 uint8_t* dst_u,
1446 int dst_stride_u,
1447 uint8_t* dst_v,
1448 int dst_stride_v,
1449 int width,
1450 int height) {
1451 int y;
1452 #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA) || \
1453 defined(HAS_RGB24TOYROW_MMI))
1454 void (*RGB24ToUVRow)(const uint8_t* src_rgb24, int src_stride_rgb24,
1455 uint8_t* dst_u, uint8_t* dst_v, int width) =
1456 RGB24ToUVRow_C;
1457 void (*RGB24ToYRow)(const uint8_t* src_rgb24, uint8_t* dst_y, int width) =
1458 RGB24ToYRow_C;
1459 #else
1460 void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
1461 RGB24ToARGBRow_C;
1462 void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
1463 uint8_t* dst_u, uint8_t* dst_v, int width) =
1464 ARGBToUVRow_C;
1465 void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
1466 ARGBToYRow_C;
1467 #endif
1468 if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1469 return -1;
1470 }
1471 // Negative height means invert the image.
1472 if (height < 0) {
1473 height = -height;
1474 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
1475 src_stride_rgb24 = -src_stride_rgb24;
1476 }
1477
1478 // Neon version does direct RGB24 to YUV.
1479 #if defined(HAS_RGB24TOYROW_NEON)
1480 if (TestCpuFlag(kCpuHasNEON)) {
1481 RGB24ToUVRow = RGB24ToUVRow_Any_NEON;
1482 RGB24ToYRow = RGB24ToYRow_Any_NEON;
1483 if (IS_ALIGNED(width, 8)) {
1484 RGB24ToYRow = RGB24ToYRow_NEON;
1485 if (IS_ALIGNED(width, 16)) {
1486 RGB24ToUVRow = RGB24ToUVRow_NEON;
1487 }
1488 }
1489 }
1490 #elif defined(HAS_RGB24TOYROW_MSA)
1491 if (TestCpuFlag(kCpuHasMSA)) {
1492 RGB24ToUVRow = RGB24ToUVRow_Any_MSA;
1493 RGB24ToYRow = RGB24ToYRow_Any_MSA;
1494 if (IS_ALIGNED(width, 16)) {
1495 RGB24ToYRow = RGB24ToYRow_MSA;
1496 RGB24ToUVRow = RGB24ToUVRow_MSA;
1497 }
1498 }
1499 #elif defined(HAS_RGB24TOYROW_MMI)
1500 if (TestCpuFlag(kCpuHasMMI)) {
1501 RGB24ToUVRow = RGB24ToUVRow_Any_MMI;
1502 RGB24ToYRow = RGB24ToYRow_Any_MMI;
1503 if (IS_ALIGNED(width, 8)) {
1504 RGB24ToYRow = RGB24ToYRow_MMI;
1505 if (IS_ALIGNED(width, 16)) {
1506 RGB24ToUVRow = RGB24ToUVRow_MMI;
1507 }
1508 }
1509 }
1510 // Other platforms do intermediate conversion from RGB24 to ARGB.
1511 #else
1512 #if defined(HAS_RGB24TOARGBROW_SSSE3)
1513 if (TestCpuFlag(kCpuHasSSSE3)) {
1514 RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
1515 if (IS_ALIGNED(width, 16)) {
1516 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
1517 }
1518 }
1519 #endif
1520 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1521 if (TestCpuFlag(kCpuHasSSSE3)) {
1522 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1523 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1524 if (IS_ALIGNED(width, 16)) {
1525 ARGBToUVRow = ARGBToUVRow_SSSE3;
1526 ARGBToYRow = ARGBToYRow_SSSE3;
1527 }
1528 }
1529 #endif
1530 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1531 if (TestCpuFlag(kCpuHasAVX2)) {
1532 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1533 ARGBToYRow = ARGBToYRow_Any_AVX2;
1534 if (IS_ALIGNED(width, 32)) {
1535 ARGBToUVRow = ARGBToUVRow_AVX2;
1536 ARGBToYRow = ARGBToYRow_AVX2;
1537 }
1538 }
1539 #endif
1540 #endif
1541
1542 {
1543 #if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA) || \
1544 defined(HAS_RGB24TOYROW_MMI))
1545 // Allocate 2 rows of ARGB.
1546 const int kRowSize = (width * 4 + 31) & ~31;
1547 align_buffer_64(row, kRowSize * 2);
1548 #endif
1549
1550 for (y = 0; y < height - 1; y += 2) {
1551 #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA) || \
1552 defined(HAS_RGB24TOYROW_MMI))
1553 RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
1554 RGB24ToYRow(src_rgb24, dst_y, width);
1555 RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
1556 #else
1557 RGB24ToARGBRow(src_rgb24, row, width);
1558 RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
1559 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1560 ARGBToYRow(row, dst_y, width);
1561 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1562 #endif
1563 src_rgb24 += src_stride_rgb24 * 2;
1564 dst_y += dst_stride_y * 2;
1565 dst_u += dst_stride_u;
1566 dst_v += dst_stride_v;
1567 }
1568 if (height & 1) {
1569 #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA) || \
1570 defined(HAS_RGB24TOYROW_MMI))
1571 RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
1572 RGB24ToYRow(src_rgb24, dst_y, width);
1573 #else
1574 RGB24ToARGBRow(src_rgb24, row, width);
1575 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1576 ARGBToYRow(row, dst_y, width);
1577 #endif
1578 }
1579 #if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA) || \
1580 defined(HAS_RGB24TOYROW_MMI))
1581 free_aligned_buffer_64(row);
1582 #endif
1583 }
1584 return 0;
1585 }
1586
1587 // TODO(fbarchard): Use Matrix version to implement I420 and J420.
1588 // Convert RGB24 to J420.
1589 LIBYUV_API
RGB24ToJ420(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)1590 int RGB24ToJ420(const uint8_t* src_rgb24,
1591 int src_stride_rgb24,
1592 uint8_t* dst_y,
1593 int dst_stride_y,
1594 uint8_t* dst_u,
1595 int dst_stride_u,
1596 uint8_t* dst_v,
1597 int dst_stride_v,
1598 int width,
1599 int height) {
1600 int y;
1601 #if (defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
1602 defined(HAS_RGB24TOYJROW_MMI))
1603 void (*RGB24ToUVJRow)(const uint8_t* src_rgb24, int src_stride_rgb24,
1604 uint8_t* dst_u, uint8_t* dst_v, int width) =
1605 RGB24ToUVJRow_C;
1606 void (*RGB24ToYJRow)(const uint8_t* src_rgb24, uint8_t* dst_y, int width) =
1607 RGB24ToYJRow_C;
1608 #else
1609 void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
1610 RGB24ToARGBRow_C;
1611 void (*ARGBToUVJRow)(const uint8_t* src_argb0, int src_stride_argb,
1612 uint8_t* dst_u, uint8_t* dst_v, int width) =
1613 ARGBToUVJRow_C;
1614 void (*ARGBToYJRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
1615 ARGBToYJRow_C;
1616 #endif
1617 if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1618 return -1;
1619 }
1620 // Negative height means invert the image.
1621 if (height < 0) {
1622 height = -height;
1623 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
1624 src_stride_rgb24 = -src_stride_rgb24;
1625 }
1626
1627 // Neon version does direct RGB24 to YUV.
1628 #if defined(HAS_RGB24TOYJROW_NEON)
1629 if (TestCpuFlag(kCpuHasNEON)) {
1630 RGB24ToUVJRow = RGB24ToUVJRow_Any_NEON;
1631 RGB24ToYJRow = RGB24ToYJRow_Any_NEON;
1632 if (IS_ALIGNED(width, 8)) {
1633 RGB24ToYJRow = RGB24ToYJRow_NEON;
1634 if (IS_ALIGNED(width, 16)) {
1635 RGB24ToUVJRow = RGB24ToUVJRow_NEON;
1636 }
1637 }
1638 }
1639 #elif defined(HAS_RGB24TOYJROW_MSA)
1640 if (TestCpuFlag(kCpuHasMSA)) {
1641 RGB24ToUVJRow = RGB24ToUVJRow_Any_MSA;
1642 RGB24ToYJRow = RGB24ToYJRow_Any_MSA;
1643 if (IS_ALIGNED(width, 16)) {
1644 RGB24ToYJRow = RGB24ToYJRow_MSA;
1645 RGB24ToUVJRow = RGB24ToUVJRow_MSA;
1646 }
1647 }
1648 #elif defined(HAS_RGB24TOYJROW_MMI)
1649 if (TestCpuFlag(kCpuHasMMI)) {
1650 RGB24ToUVJRow = RGB24ToUVJRow_Any_MMI;
1651 RGB24ToYJRow = RGB24ToYJRow_Any_MMI;
1652 if (IS_ALIGNED(width, 8)) {
1653 RGB24ToYJRow = RGB24ToYJRow_MMI;
1654 if (IS_ALIGNED(width, 16)) {
1655 RGB24ToUVJRow = RGB24ToUVJRow_MMI;
1656 }
1657 }
1658 }
1659 // Other platforms do intermediate conversion from RGB24 to ARGB.
1660 #else
1661 #if defined(HAS_RGB24TOARGBROW_SSSE3)
1662 if (TestCpuFlag(kCpuHasSSSE3)) {
1663 RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
1664 if (IS_ALIGNED(width, 16)) {
1665 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
1666 }
1667 }
1668 #endif
1669 #if defined(HAS_ARGBTOYJROW_SSSE3) && defined(HAS_ARGBTOUVJROW_SSSE3)
1670 if (TestCpuFlag(kCpuHasSSSE3)) {
1671 ARGBToUVJRow = ARGBToUVJRow_Any_SSSE3;
1672 ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
1673 if (IS_ALIGNED(width, 16)) {
1674 ARGBToUVJRow = ARGBToUVJRow_SSSE3;
1675 ARGBToYJRow = ARGBToYJRow_SSSE3;
1676 }
1677 }
1678 #endif
1679 #if defined(HAS_ARGBTOYJROW_AVX2) && defined(HAS_ARGBTOUVJROW_AVX2)
1680 if (TestCpuFlag(kCpuHasAVX2)) {
1681 ARGBToUVJRow = ARGBToUVJRow_Any_AVX2;
1682 ARGBToYJRow = ARGBToYJRow_Any_AVX2;
1683 if (IS_ALIGNED(width, 32)) {
1684 ARGBToUVJRow = ARGBToUVJRow_AVX2;
1685 ARGBToYJRow = ARGBToYJRow_AVX2;
1686 }
1687 }
1688 #endif
1689 #endif
1690
1691 {
1692 #if !(defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
1693 defined(HAS_RGB24TOYJROW_MMI))
1694 // Allocate 2 rows of ARGB.
1695 const int kRowSize = (width * 4 + 31) & ~31;
1696 align_buffer_64(row, kRowSize * 2);
1697 #endif
1698
1699 for (y = 0; y < height - 1; y += 2) {
1700 #if (defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
1701 defined(HAS_RGB24TOYJROW_MMI))
1702 RGB24ToUVJRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
1703 RGB24ToYJRow(src_rgb24, dst_y, width);
1704 RGB24ToYJRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
1705 #else
1706 RGB24ToARGBRow(src_rgb24, row, width);
1707 RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
1708 ARGBToUVJRow(row, kRowSize, dst_u, dst_v, width);
1709 ARGBToYJRow(row, dst_y, width);
1710 ARGBToYJRow(row + kRowSize, dst_y + dst_stride_y, width);
1711 #endif
1712 src_rgb24 += src_stride_rgb24 * 2;
1713 dst_y += dst_stride_y * 2;
1714 dst_u += dst_stride_u;
1715 dst_v += dst_stride_v;
1716 }
1717 if (height & 1) {
1718 #if (defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
1719 defined(HAS_RGB24TOYJROW_MMI))
1720 RGB24ToUVJRow(src_rgb24, 0, dst_u, dst_v, width);
1721 RGB24ToYJRow(src_rgb24, dst_y, width);
1722 #else
1723 RGB24ToARGBRow(src_rgb24, row, width);
1724 ARGBToUVJRow(row, 0, dst_u, dst_v, width);
1725 ARGBToYJRow(row, dst_y, width);
1726 #endif
1727 }
1728 #if !(defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
1729 defined(HAS_RGB24TOYJROW_MMI))
1730 free_aligned_buffer_64(row);
1731 #endif
1732 }
1733 return 0;
1734 }
1735
1736 // Convert RAW to I420.
1737 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)1738 int RAWToI420(const uint8_t* src_raw,
1739 int src_stride_raw,
1740 uint8_t* dst_y,
1741 int dst_stride_y,
1742 uint8_t* dst_u,
1743 int dst_stride_u,
1744 uint8_t* dst_v,
1745 int dst_stride_v,
1746 int width,
1747 int height) {
1748 int y;
1749 #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA) || \
1750 defined(HAS_RAWTOYROW_MMI))
1751 void (*RAWToUVRow)(const uint8_t* src_raw, int src_stride_raw, uint8_t* dst_u,
1752 uint8_t* dst_v, int width) = RAWToUVRow_C;
1753 void (*RAWToYRow)(const uint8_t* src_raw, uint8_t* dst_y, int width) =
1754 RAWToYRow_C;
1755 #else
1756 void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
1757 RAWToARGBRow_C;
1758 void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
1759 uint8_t* dst_u, uint8_t* dst_v, int width) =
1760 ARGBToUVRow_C;
1761 void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
1762 ARGBToYRow_C;
1763 #endif
1764 if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1765 return -1;
1766 }
1767 // Negative height means invert the image.
1768 if (height < 0) {
1769 height = -height;
1770 src_raw = src_raw + (height - 1) * src_stride_raw;
1771 src_stride_raw = -src_stride_raw;
1772 }
1773
1774 // Neon version does direct RAW to YUV.
1775 #if defined(HAS_RAWTOYROW_NEON)
1776 if (TestCpuFlag(kCpuHasNEON)) {
1777 RAWToUVRow = RAWToUVRow_Any_NEON;
1778 RAWToYRow = RAWToYRow_Any_NEON;
1779 if (IS_ALIGNED(width, 8)) {
1780 RAWToYRow = RAWToYRow_NEON;
1781 if (IS_ALIGNED(width, 16)) {
1782 RAWToUVRow = RAWToUVRow_NEON;
1783 }
1784 }
1785 }
1786 #elif defined(HAS_RAWTOYROW_MSA)
1787 if (TestCpuFlag(kCpuHasMSA)) {
1788 RAWToUVRow = RAWToUVRow_Any_MSA;
1789 RAWToYRow = RAWToYRow_Any_MSA;
1790 if (IS_ALIGNED(width, 16)) {
1791 RAWToYRow = RAWToYRow_MSA;
1792 RAWToUVRow = RAWToUVRow_MSA;
1793 }
1794 }
1795 #elif defined(HAS_RAWTOYROW_MMI)
1796 if (TestCpuFlag(kCpuHasMMI)) {
1797 RAWToUVRow = RAWToUVRow_Any_MMI;
1798 RAWToYRow = RAWToYRow_Any_MMI;
1799 if (IS_ALIGNED(width, 8)) {
1800 RAWToYRow = RAWToYRow_MMI;
1801 if (IS_ALIGNED(width, 16)) {
1802 RAWToUVRow = RAWToUVRow_MMI;
1803 }
1804 }
1805 }
1806 // Other platforms do intermediate conversion from RAW to ARGB.
1807 #else
1808 #if defined(HAS_RAWTOARGBROW_SSSE3)
1809 if (TestCpuFlag(kCpuHasSSSE3)) {
1810 RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
1811 if (IS_ALIGNED(width, 16)) {
1812 RAWToARGBRow = RAWToARGBRow_SSSE3;
1813 }
1814 }
1815 #endif
1816 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1817 if (TestCpuFlag(kCpuHasSSSE3)) {
1818 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1819 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1820 if (IS_ALIGNED(width, 16)) {
1821 ARGBToUVRow = ARGBToUVRow_SSSE3;
1822 ARGBToYRow = ARGBToYRow_SSSE3;
1823 }
1824 }
1825 #endif
1826 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1827 if (TestCpuFlag(kCpuHasAVX2)) {
1828 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1829 ARGBToYRow = ARGBToYRow_Any_AVX2;
1830 if (IS_ALIGNED(width, 32)) {
1831 ARGBToUVRow = ARGBToUVRow_AVX2;
1832 ARGBToYRow = ARGBToYRow_AVX2;
1833 }
1834 }
1835 #endif
1836 #endif
1837
1838 {
1839 #if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA) || \
1840 defined(HAS_RAWTOYROW_MMI))
1841 // Allocate 2 rows of ARGB.
1842 const int kRowSize = (width * 4 + 31) & ~31;
1843 align_buffer_64(row, kRowSize * 2);
1844 #endif
1845
1846 for (y = 0; y < height - 1; y += 2) {
1847 #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA) || \
1848 defined(HAS_RAWTOYROW_MMI))
1849 RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width);
1850 RAWToYRow(src_raw, dst_y, width);
1851 RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
1852 #else
1853 RAWToARGBRow(src_raw, row, width);
1854 RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width);
1855 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1856 ARGBToYRow(row, dst_y, width);
1857 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1858 #endif
1859 src_raw += src_stride_raw * 2;
1860 dst_y += dst_stride_y * 2;
1861 dst_u += dst_stride_u;
1862 dst_v += dst_stride_v;
1863 }
1864 if (height & 1) {
1865 #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA) || \
1866 defined(HAS_RAWTOYROW_MMI))
1867 RAWToUVRow(src_raw, 0, dst_u, dst_v, width);
1868 RAWToYRow(src_raw, dst_y, width);
1869 #else
1870 RAWToARGBRow(src_raw, row, width);
1871 ARGBToUVRow(row, 0, dst_u, dst_v, width);
1872 ARGBToYRow(row, dst_y, width);
1873 #endif
1874 }
1875 #if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA) || \
1876 defined(HAS_RAWTOYROW_MMI))
1877 free_aligned_buffer_64(row);
1878 #endif
1879 }
1880 return 0;
1881 }
1882
1883 // Convert RGB565 to I420.
1884 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)1885 int RGB565ToI420(const uint8_t* src_rgb565,
1886 int src_stride_rgb565,
1887 uint8_t* dst_y,
1888 int dst_stride_y,
1889 uint8_t* dst_u,
1890 int dst_stride_u,
1891 uint8_t* dst_v,
1892 int dst_stride_v,
1893 int width,
1894 int height) {
1895 int y;
1896 #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
1897 defined(HAS_RGB565TOYROW_MMI))
1898 void (*RGB565ToUVRow)(const uint8_t* src_rgb565, int src_stride_rgb565,
1899 uint8_t* dst_u, uint8_t* dst_v, int width) =
1900 RGB565ToUVRow_C;
1901 void (*RGB565ToYRow)(const uint8_t* src_rgb565, uint8_t* dst_y, int width) =
1902 RGB565ToYRow_C;
1903 #else
1904 void (*RGB565ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
1905 int width) = RGB565ToARGBRow_C;
1906 void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
1907 uint8_t* dst_u, uint8_t* dst_v, int width) =
1908 ARGBToUVRow_C;
1909 void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
1910 ARGBToYRow_C;
1911 #endif
1912 if (!src_rgb565 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1913 return -1;
1914 }
1915 // Negative height means invert the image.
1916 if (height < 0) {
1917 height = -height;
1918 src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
1919 src_stride_rgb565 = -src_stride_rgb565;
1920 }
1921
1922 // Neon version does direct RGB565 to YUV.
1923 #if defined(HAS_RGB565TOYROW_NEON)
1924 if (TestCpuFlag(kCpuHasNEON)) {
1925 RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
1926 RGB565ToYRow = RGB565ToYRow_Any_NEON;
1927 if (IS_ALIGNED(width, 8)) {
1928 RGB565ToYRow = RGB565ToYRow_NEON;
1929 if (IS_ALIGNED(width, 16)) {
1930 RGB565ToUVRow = RGB565ToUVRow_NEON;
1931 }
1932 }
1933 }
1934 #elif defined(HAS_RGB565TOYROW_MSA)
1935 if (TestCpuFlag(kCpuHasMSA)) {
1936 RGB565ToUVRow = RGB565ToUVRow_Any_MSA;
1937 RGB565ToYRow = RGB565ToYRow_Any_MSA;
1938 if (IS_ALIGNED(width, 16)) {
1939 RGB565ToYRow = RGB565ToYRow_MSA;
1940 RGB565ToUVRow = RGB565ToUVRow_MSA;
1941 }
1942 }
1943 #elif defined(HAS_RGB565TOYROW_MMI)
1944 if (TestCpuFlag(kCpuHasMMI)) {
1945 RGB565ToUVRow = RGB565ToUVRow_Any_MMI;
1946 RGB565ToYRow = RGB565ToYRow_Any_MMI;
1947 if (IS_ALIGNED(width, 8)) {
1948 RGB565ToYRow = RGB565ToYRow_MMI;
1949 if (IS_ALIGNED(width, 16)) {
1950 RGB565ToUVRow = RGB565ToUVRow_MMI;
1951 }
1952 }
1953 }
1954 // Other platforms do intermediate conversion from RGB565 to ARGB.
1955 #else
1956 #if defined(HAS_RGB565TOARGBROW_SSE2)
1957 if (TestCpuFlag(kCpuHasSSE2)) {
1958 RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
1959 if (IS_ALIGNED(width, 8)) {
1960 RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
1961 }
1962 }
1963 #endif
1964 #if defined(HAS_RGB565TOARGBROW_AVX2)
1965 if (TestCpuFlag(kCpuHasAVX2)) {
1966 RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
1967 if (IS_ALIGNED(width, 16)) {
1968 RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
1969 }
1970 }
1971 #endif
1972 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1973 if (TestCpuFlag(kCpuHasSSSE3)) {
1974 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1975 ARGBToYRow = ARGBToYRow_Any_SSSE3;
1976 if (IS_ALIGNED(width, 16)) {
1977 ARGBToUVRow = ARGBToUVRow_SSSE3;
1978 ARGBToYRow = ARGBToYRow_SSSE3;
1979 }
1980 }
1981 #endif
1982 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1983 if (TestCpuFlag(kCpuHasAVX2)) {
1984 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1985 ARGBToYRow = ARGBToYRow_Any_AVX2;
1986 if (IS_ALIGNED(width, 32)) {
1987 ARGBToUVRow = ARGBToUVRow_AVX2;
1988 ARGBToYRow = ARGBToYRow_AVX2;
1989 }
1990 }
1991 #endif
1992 #endif
1993 {
1994 #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
1995 defined(HAS_RGB565TOYROW_MMI))
1996 // Allocate 2 rows of ARGB.
1997 const int kRowSize = (width * 4 + 31) & ~31;
1998 align_buffer_64(row, kRowSize * 2);
1999 #endif
2000 for (y = 0; y < height - 1; y += 2) {
2001 #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
2002 defined(HAS_RGB565TOYROW_MMI))
2003 RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width);
2004 RGB565ToYRow(src_rgb565, dst_y, width);
2005 RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
2006 #else
2007 RGB565ToARGBRow(src_rgb565, row, width);
2008 RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width);
2009 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
2010 ARGBToYRow(row, dst_y, width);
2011 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
2012 #endif
2013 src_rgb565 += src_stride_rgb565 * 2;
2014 dst_y += dst_stride_y * 2;
2015 dst_u += dst_stride_u;
2016 dst_v += dst_stride_v;
2017 }
2018 if (height & 1) {
2019 #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
2020 defined(HAS_RGB565TOYROW_MMI))
2021 RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width);
2022 RGB565ToYRow(src_rgb565, dst_y, width);
2023 #else
2024 RGB565ToARGBRow(src_rgb565, row, width);
2025 ARGBToUVRow(row, 0, dst_u, dst_v, width);
2026 ARGBToYRow(row, dst_y, width);
2027 #endif
2028 }
2029 #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
2030 defined(HAS_RGB565TOYROW_MMI))
2031 free_aligned_buffer_64(row);
2032 #endif
2033 }
2034 return 0;
2035 }
2036
2037 // Convert ARGB1555 to I420.
2038 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)2039 int ARGB1555ToI420(const uint8_t* src_argb1555,
2040 int src_stride_argb1555,
2041 uint8_t* dst_y,
2042 int dst_stride_y,
2043 uint8_t* dst_u,
2044 int dst_stride_u,
2045 uint8_t* dst_v,
2046 int dst_stride_v,
2047 int width,
2048 int height) {
2049 int y;
2050 #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
2051 defined(HAS_ARGB1555TOYROW_MMI))
2052 void (*ARGB1555ToUVRow)(const uint8_t* src_argb1555, int src_stride_argb1555,
2053 uint8_t* dst_u, uint8_t* dst_v, int width) =
2054 ARGB1555ToUVRow_C;
2055 void (*ARGB1555ToYRow)(const uint8_t* src_argb1555, uint8_t* dst_y,
2056 int width) = ARGB1555ToYRow_C;
2057 #else
2058 void (*ARGB1555ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
2059 int width) = ARGB1555ToARGBRow_C;
2060 void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
2061 uint8_t* dst_u, uint8_t* dst_v, int width) =
2062 ARGBToUVRow_C;
2063 void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
2064 ARGBToYRow_C;
2065 #endif
2066 if (!src_argb1555 || !dst_y || !dst_u || !dst_v || width <= 0 ||
2067 height == 0) {
2068 return -1;
2069 }
2070 // Negative height means invert the image.
2071 if (height < 0) {
2072 height = -height;
2073 src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
2074 src_stride_argb1555 = -src_stride_argb1555;
2075 }
2076
2077 // Neon version does direct ARGB1555 to YUV.
2078 #if defined(HAS_ARGB1555TOYROW_NEON)
2079 if (TestCpuFlag(kCpuHasNEON)) {
2080 ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
2081 ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
2082 if (IS_ALIGNED(width, 8)) {
2083 ARGB1555ToYRow = ARGB1555ToYRow_NEON;
2084 if (IS_ALIGNED(width, 16)) {
2085 ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
2086 }
2087 }
2088 }
2089 #elif defined(HAS_ARGB1555TOYROW_MSA)
2090 if (TestCpuFlag(kCpuHasMSA)) {
2091 ARGB1555ToUVRow = ARGB1555ToUVRow_Any_MSA;
2092 ARGB1555ToYRow = ARGB1555ToYRow_Any_MSA;
2093 if (IS_ALIGNED(width, 16)) {
2094 ARGB1555ToYRow = ARGB1555ToYRow_MSA;
2095 ARGB1555ToUVRow = ARGB1555ToUVRow_MSA;
2096 }
2097 }
2098 #elif defined(HAS_ARGB1555TOYROW_MMI)
2099 if (TestCpuFlag(kCpuHasMMI)) {
2100 ARGB1555ToUVRow = ARGB1555ToUVRow_Any_MMI;
2101 ARGB1555ToYRow = ARGB1555ToYRow_Any_MMI;
2102 if (IS_ALIGNED(width, 8)) {
2103 ARGB1555ToYRow = ARGB1555ToYRow_MMI;
2104 if (IS_ALIGNED(width, 16)) {
2105 ARGB1555ToUVRow = ARGB1555ToUVRow_MMI;
2106 }
2107 }
2108 }
2109 // Other platforms do intermediate conversion from ARGB1555 to ARGB.
2110 #else
2111 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
2112 if (TestCpuFlag(kCpuHasSSE2)) {
2113 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
2114 if (IS_ALIGNED(width, 8)) {
2115 ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
2116 }
2117 }
2118 #endif
2119 #if defined(HAS_ARGB1555TOARGBROW_AVX2)
2120 if (TestCpuFlag(kCpuHasAVX2)) {
2121 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
2122 if (IS_ALIGNED(width, 16)) {
2123 ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
2124 }
2125 }
2126 #endif
2127 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
2128 if (TestCpuFlag(kCpuHasSSSE3)) {
2129 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
2130 ARGBToYRow = ARGBToYRow_Any_SSSE3;
2131 if (IS_ALIGNED(width, 16)) {
2132 ARGBToUVRow = ARGBToUVRow_SSSE3;
2133 ARGBToYRow = ARGBToYRow_SSSE3;
2134 }
2135 }
2136 #endif
2137 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
2138 if (TestCpuFlag(kCpuHasAVX2)) {
2139 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
2140 ARGBToYRow = ARGBToYRow_Any_AVX2;
2141 if (IS_ALIGNED(width, 32)) {
2142 ARGBToUVRow = ARGBToUVRow_AVX2;
2143 ARGBToYRow = ARGBToYRow_AVX2;
2144 }
2145 }
2146 #endif
2147 #endif
2148 {
2149 #if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
2150 defined(HAS_ARGB1555TOYROW_MMI))
2151 // Allocate 2 rows of ARGB.
2152 const int kRowSize = (width * 4 + 31) & ~31;
2153 align_buffer_64(row, kRowSize * 2);
2154 #endif
2155
2156 for (y = 0; y < height - 1; y += 2) {
2157 #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
2158 defined(HAS_ARGB1555TOYROW_MMI))
2159 ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width);
2160 ARGB1555ToYRow(src_argb1555, dst_y, width);
2161 ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y,
2162 width);
2163 #else
2164 ARGB1555ToARGBRow(src_argb1555, row, width);
2165 ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize,
2166 width);
2167 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
2168 ARGBToYRow(row, dst_y, width);
2169 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
2170 #endif
2171 src_argb1555 += src_stride_argb1555 * 2;
2172 dst_y += dst_stride_y * 2;
2173 dst_u += dst_stride_u;
2174 dst_v += dst_stride_v;
2175 }
2176 if (height & 1) {
2177 #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
2178 defined(HAS_ARGB1555TOYROW_MMI))
2179 ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width);
2180 ARGB1555ToYRow(src_argb1555, dst_y, width);
2181 #else
2182 ARGB1555ToARGBRow(src_argb1555, row, width);
2183 ARGBToUVRow(row, 0, dst_u, dst_v, width);
2184 ARGBToYRow(row, dst_y, width);
2185 #endif
2186 }
2187 #if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
2188 defined(HAS_ARGB1555TOYROW_MMI))
2189 free_aligned_buffer_64(row);
2190 #endif
2191 }
2192 return 0;
2193 }
2194
2195 // Convert ARGB4444 to I420.
2196 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)2197 int ARGB4444ToI420(const uint8_t* src_argb4444,
2198 int src_stride_argb4444,
2199 uint8_t* dst_y,
2200 int dst_stride_y,
2201 uint8_t* dst_u,
2202 int dst_stride_u,
2203 uint8_t* dst_v,
2204 int dst_stride_v,
2205 int width,
2206 int height) {
2207 int y;
2208 #if (defined(HAS_ARGB4444TOYROW_NEON) || defined(HAS_ARGB4444TOYROW_MMI))
2209 void (*ARGB4444ToUVRow)(const uint8_t* src_argb4444, int src_stride_argb4444,
2210 uint8_t* dst_u, uint8_t* dst_v, int width) =
2211 ARGB4444ToUVRow_C;
2212 void (*ARGB4444ToYRow)(const uint8_t* src_argb4444, uint8_t* dst_y,
2213 int width) = ARGB4444ToYRow_C;
2214 #else
2215 void (*ARGB4444ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
2216 int width) = ARGB4444ToARGBRow_C;
2217 void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
2218 uint8_t* dst_u, uint8_t* dst_v, int width) =
2219 ARGBToUVRow_C;
2220 void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
2221 ARGBToYRow_C;
2222 #endif
2223 if (!src_argb4444 || !dst_y || !dst_u || !dst_v || width <= 0 ||
2224 height == 0) {
2225 return -1;
2226 }
2227 // Negative height means invert the image.
2228 if (height < 0) {
2229 height = -height;
2230 src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
2231 src_stride_argb4444 = -src_stride_argb4444;
2232 }
2233
2234 // Neon version does direct ARGB4444 to YUV.
2235 #if defined(HAS_ARGB4444TOYROW_NEON)
2236 if (TestCpuFlag(kCpuHasNEON)) {
2237 ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
2238 ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
2239 if (IS_ALIGNED(width, 8)) {
2240 ARGB4444ToYRow = ARGB4444ToYRow_NEON;
2241 if (IS_ALIGNED(width, 16)) {
2242 ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
2243 }
2244 }
2245 }
2246 #elif defined(HAS_ARGB4444TOYROW_MMI)
2247 if (TestCpuFlag(kCpuHasMMI)) {
2248 ARGB4444ToUVRow = ARGB4444ToUVRow_Any_MMI;
2249 ARGB4444ToYRow = ARGB4444ToYRow_Any_MMI;
2250 if (IS_ALIGNED(width, 8)) {
2251 ARGB4444ToYRow = ARGB4444ToYRow_MMI;
2252 if (IS_ALIGNED(width, 16)) {
2253 ARGB4444ToUVRow = ARGB4444ToUVRow_MMI;
2254 }
2255 }
2256 }
2257 // Other platforms do intermediate conversion from ARGB4444 to ARGB.
2258 #else
2259 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
2260 if (TestCpuFlag(kCpuHasSSE2)) {
2261 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
2262 if (IS_ALIGNED(width, 8)) {
2263 ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
2264 }
2265 }
2266 #endif
2267 #if defined(HAS_ARGB4444TOARGBROW_AVX2)
2268 if (TestCpuFlag(kCpuHasAVX2)) {
2269 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
2270 if (IS_ALIGNED(width, 16)) {
2271 ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
2272 }
2273 }
2274 #endif
2275 #if defined(HAS_ARGB4444TOARGBROW_MSA)
2276 if (TestCpuFlag(kCpuHasMSA)) {
2277 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA;
2278 if (IS_ALIGNED(width, 16)) {
2279 ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA;
2280 }
2281 }
2282 #endif
2283 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
2284 if (TestCpuFlag(kCpuHasSSSE3)) {
2285 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
2286 ARGBToYRow = ARGBToYRow_Any_SSSE3;
2287 if (IS_ALIGNED(width, 16)) {
2288 ARGBToUVRow = ARGBToUVRow_SSSE3;
2289 ARGBToYRow = ARGBToYRow_SSSE3;
2290 }
2291 }
2292 #endif
2293 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
2294 if (TestCpuFlag(kCpuHasAVX2)) {
2295 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
2296 ARGBToYRow = ARGBToYRow_Any_AVX2;
2297 if (IS_ALIGNED(width, 32)) {
2298 ARGBToUVRow = ARGBToUVRow_AVX2;
2299 ARGBToYRow = ARGBToYRow_AVX2;
2300 }
2301 }
2302 #endif
2303 #if defined(HAS_ARGBTOYROW_MSA)
2304 if (TestCpuFlag(kCpuHasMSA)) {
2305 ARGBToUVRow = ARGBToUVRow_Any_MSA;
2306 ARGBToYRow = ARGBToYRow_Any_MSA;
2307 if (IS_ALIGNED(width, 16)) {
2308 ARGBToYRow = ARGBToYRow_MSA;
2309 if (IS_ALIGNED(width, 32)) {
2310 ARGBToUVRow = ARGBToUVRow_MSA;
2311 }
2312 }
2313 }
2314 #endif
2315 #if defined(HAS_ARGBTOYROW_MMI)
2316 if (TestCpuFlag(kCpuHasMMI)) {
2317 ARGBToUVRow = ARGBToUVRow_Any_MMI;
2318 ARGBToYRow = ARGBToYRow_Any_MMI;
2319 if (IS_ALIGNED(width, 8)) {
2320 ARGBToYRow = ARGBToYRow_MMI;
2321 if (IS_ALIGNED(width, 16)) {
2322 ARGBToUVRow = ARGBToUVRow_MMI;
2323 }
2324 }
2325 }
2326 #endif
2327 #endif
2328
2329 {
2330 #if !(defined(HAS_ARGB4444TOYROW_NEON) || defined(HAS_ARGB4444TOYROW_MMI))
2331 // Allocate 2 rows of ARGB.
2332 const int kRowSize = (width * 4 + 31) & ~31;
2333 align_buffer_64(row, kRowSize * 2);
2334 #endif
2335
2336 for (y = 0; y < height - 1; y += 2) {
2337 #if (defined(HAS_ARGB4444TOYROW_NEON) || defined(HAS_ARGB4444TOYROW_MMI))
2338 ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width);
2339 ARGB4444ToYRow(src_argb4444, dst_y, width);
2340 ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y,
2341 width);
2342 #else
2343 ARGB4444ToARGBRow(src_argb4444, row, width);
2344 ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize,
2345 width);
2346 ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
2347 ARGBToYRow(row, dst_y, width);
2348 ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
2349 #endif
2350 src_argb4444 += src_stride_argb4444 * 2;
2351 dst_y += dst_stride_y * 2;
2352 dst_u += dst_stride_u;
2353 dst_v += dst_stride_v;
2354 }
2355 if (height & 1) {
2356 #if (defined(HAS_ARGB4444TOYROW_NEON) || defined(HAS_ARGB4444TOYROW_MMI))
2357 ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width);
2358 ARGB4444ToYRow(src_argb4444, dst_y, width);
2359 #else
2360 ARGB4444ToARGBRow(src_argb4444, row, width);
2361 ARGBToUVRow(row, 0, dst_u, dst_v, width);
2362 ARGBToYRow(row, dst_y, width);
2363 #endif
2364 }
2365 #if !(defined(HAS_ARGB4444TOYROW_NEON) || defined(HAS_ARGB4444TOYROW_MMI))
2366 free_aligned_buffer_64(row);
2367 #endif
2368 }
2369 return 0;
2370 }
2371
2372 // Convert RGB24 to J400.
2373 LIBYUV_API
RGB24ToJ400(const uint8_t * src_rgb24,int src_stride_rgb24,uint8_t * dst_yj,int dst_stride_yj,int width,int height)2374 int RGB24ToJ400(const uint8_t* src_rgb24,
2375 int src_stride_rgb24,
2376 uint8_t* dst_yj,
2377 int dst_stride_yj,
2378 int width,
2379 int height) {
2380 int y;
2381 #if (defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
2382 defined(HAS_RGB24TOYJROW_MMI))
2383 void (*RGB24ToYJRow)(const uint8_t* src_rgb24, uint8_t* dst_yj, int width) =
2384 RGB24ToYJRow_C;
2385 #else
2386 void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
2387 RGB24ToARGBRow_C;
2388 void (*ARGBToYJRow)(const uint8_t* src_argb, uint8_t* dst_yj, int width) =
2389 ARGBToYJRow_C;
2390 #endif
2391 if (!src_rgb24 || !dst_yj || width <= 0 || height == 0) {
2392 return -1;
2393 }
2394 // Negative height means invert the image.
2395 if (height < 0) {
2396 height = -height;
2397 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
2398 src_stride_rgb24 = -src_stride_rgb24;
2399 }
2400
2401 // Neon version does direct RGB24 to YUV.
2402 #if defined(HAS_RGB24TOYJROW_NEON)
2403 if (TestCpuFlag(kCpuHasNEON)) {
2404 RGB24ToYJRow = RGB24ToYJRow_Any_NEON;
2405 if (IS_ALIGNED(width, 8)) {
2406 RGB24ToYJRow = RGB24ToYJRow_NEON;
2407 }
2408 }
2409 #elif defined(HAS_RGB24TOYJROW_MSA)
2410 if (TestCpuFlag(kCpuHasMSA)) {
2411 RGB24ToYJRow = RGB24ToYJRow_Any_MSA;
2412 if (IS_ALIGNED(width, 16)) {
2413 RGB24ToYJRow = RGB24ToYJRow_MSA;
2414 }
2415 }
2416 #elif defined(HAS_RGB24TOYJROW_MMI)
2417 if (TestCpuFlag(kCpuHasMMI)) {
2418 RGB24ToYJRow = RGB24ToYJRow_Any_MMI;
2419 if (IS_ALIGNED(width, 8)) {
2420 RGB24ToYJRow = RGB24ToYJRow_MMI;
2421 }
2422 }
2423 // Other platforms do intermediate conversion from RGB24 to ARGB.
2424 #else
2425 #if defined(HAS_RGB24TOARGBROW_SSSE3)
2426 if (TestCpuFlag(kCpuHasSSSE3)) {
2427 RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
2428 if (IS_ALIGNED(width, 16)) {
2429 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
2430 }
2431 }
2432 #endif
2433 #if defined(HAS_ARGBTOYJROW_SSSE3)
2434 if (TestCpuFlag(kCpuHasSSSE3)) {
2435 ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
2436 if (IS_ALIGNED(width, 16)) {
2437 ARGBToYJRow = ARGBToYJRow_SSSE3;
2438 }
2439 }
2440 #endif
2441 #if defined(HAS_ARGBTOYJROW_AVX2)
2442 if (TestCpuFlag(kCpuHasAVX2)) {
2443 ARGBToYJRow = ARGBToYJRow_Any_AVX2;
2444 if (IS_ALIGNED(width, 32)) {
2445 ARGBToYJRow = ARGBToYJRow_AVX2;
2446 }
2447 }
2448 #endif
2449 #endif
2450
2451 {
2452 #if !(defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
2453 defined(HAS_RGB24TOYJROW_MMI))
2454 // Allocate 2 rows of ARGB.
2455 const int kRowSize = (width * 4 + 31) & ~31;
2456 align_buffer_64(row, kRowSize * 2);
2457 #endif
2458
2459 for (y = 0; y < height - 1; y += 2) {
2460 #if (defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
2461 defined(HAS_RGB24TOYJROW_MMI))
2462 RGB24ToYJRow(src_rgb24, dst_yj, width);
2463 RGB24ToYJRow(src_rgb24 + src_stride_rgb24, dst_yj + dst_stride_yj, width);
2464 #else
2465 RGB24ToARGBRow(src_rgb24, row, width);
2466 RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
2467 ARGBToYJRow(row, dst_yj, width);
2468 ARGBToYJRow(row + kRowSize, dst_yj + dst_stride_yj, width);
2469 #endif
2470 src_rgb24 += src_stride_rgb24 * 2;
2471 dst_yj += dst_stride_yj * 2;
2472 }
2473 if (height & 1) {
2474 #if (defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
2475 defined(HAS_RGB24TOYJROW_MMI))
2476 RGB24ToYJRow(src_rgb24, dst_yj, width);
2477 #else
2478 RGB24ToARGBRow(src_rgb24, row, width);
2479 ARGBToYJRow(row, dst_yj, width);
2480 #endif
2481 }
2482 #if !(defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
2483 defined(HAS_RGB24TOYJROW_MMI))
2484 free_aligned_buffer_64(row);
2485 #endif
2486 }
2487 return 0;
2488 }
2489
SplitPixels(const uint8_t * src_u,int src_pixel_stride_uv,uint8_t * dst_u,int width)2490 static void SplitPixels(const uint8_t* src_u,
2491 int src_pixel_stride_uv,
2492 uint8_t* dst_u,
2493 int width) {
2494 int i;
2495 for (i = 0; i < width; ++i) {
2496 *dst_u = *src_u;
2497 ++dst_u;
2498 src_u += src_pixel_stride_uv;
2499 }
2500 }
2501
2502 // Convert Android420 to I420.
2503 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)2504 int Android420ToI420(const uint8_t* src_y,
2505 int src_stride_y,
2506 const uint8_t* src_u,
2507 int src_stride_u,
2508 const uint8_t* src_v,
2509 int src_stride_v,
2510 int src_pixel_stride_uv,
2511 uint8_t* dst_y,
2512 int dst_stride_y,
2513 uint8_t* dst_u,
2514 int dst_stride_u,
2515 uint8_t* dst_v,
2516 int dst_stride_v,
2517 int width,
2518 int height) {
2519 int y;
2520 const ptrdiff_t vu_off = src_v - src_u;
2521 int halfwidth = (width + 1) >> 1;
2522 int halfheight = (height + 1) >> 1;
2523 if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
2524 return -1;
2525 }
2526 // Negative height means invert the image.
2527 if (height < 0) {
2528 height = -height;
2529 halfheight = (height + 1) >> 1;
2530 src_y = src_y + (height - 1) * src_stride_y;
2531 src_u = src_u + (halfheight - 1) * src_stride_u;
2532 src_v = src_v + (halfheight - 1) * src_stride_v;
2533 src_stride_y = -src_stride_y;
2534 src_stride_u = -src_stride_u;
2535 src_stride_v = -src_stride_v;
2536 }
2537
2538 if (dst_y) {
2539 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
2540 }
2541
2542 // Copy UV planes as is - I420
2543 if (src_pixel_stride_uv == 1) {
2544 CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
2545 CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
2546 return 0;
2547 // Split UV planes - NV21
2548 }
2549 if (src_pixel_stride_uv == 2 && vu_off == -1 &&
2550 src_stride_u == src_stride_v) {
2551 SplitUVPlane(src_v, src_stride_v, dst_v, dst_stride_v, dst_u, dst_stride_u,
2552 halfwidth, halfheight);
2553 return 0;
2554 // Split UV planes - NV12
2555 }
2556 if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) {
2557 SplitUVPlane(src_u, src_stride_u, dst_u, dst_stride_u, dst_v, dst_stride_v,
2558 halfwidth, halfheight);
2559 return 0;
2560 }
2561
2562 for (y = 0; y < halfheight; ++y) {
2563 SplitPixels(src_u, src_pixel_stride_uv, dst_u, halfwidth);
2564 SplitPixels(src_v, src_pixel_stride_uv, dst_v, halfwidth);
2565 src_u += src_stride_u;
2566 src_v += src_stride_v;
2567 dst_u += dst_stride_u;
2568 dst_v += dst_stride_v;
2569 }
2570 return 0;
2571 }
2572
2573 #ifdef __cplusplus
2574 } // extern "C"
2575 } // namespace libyuv
2576 #endif
2577