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