1 /*
2 * Copyright 2012 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_from.h"
12
13 #include "libyuv/basic_types.h"
14 #include "libyuv/convert.h" // For I420Copy
15 #include "libyuv/cpu_id.h"
16 #include "libyuv/planar_functions.h"
17 #include "libyuv/rotate.h"
18 #include "libyuv/row.h"
19 #include "libyuv/scale.h" // For ScalePlane()
20 #include "libyuv/video_common.h"
21
22 #ifdef __cplusplus
23 namespace libyuv {
24 extern "C" {
25 #endif
26
27 #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
Abs(int v)28 static __inline int Abs(int v) {
29 return v >= 0 ? v : -v;
30 }
31
32 // I420 To any I4xx YUV format with mirroring.
33 // TODO(fbarchard): Consider kFilterNone for Y, or CopyPlane
34
I420ToI4xx(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 dst_uv_width,int dst_uv_height)35 static int I420ToI4xx(const uint8_t* src_y,
36 int src_stride_y,
37 const uint8_t* src_u,
38 int src_stride_u,
39 const uint8_t* src_v,
40 int src_stride_v,
41 uint8_t* dst_y,
42 int dst_stride_y,
43 uint8_t* dst_u,
44 int dst_stride_u,
45 uint8_t* dst_v,
46 int dst_stride_v,
47 int src_y_width,
48 int src_y_height,
49 int dst_uv_width,
50 int dst_uv_height) {
51 const int dst_y_width = Abs(src_y_width);
52 const int dst_y_height = Abs(src_y_height);
53 const int src_uv_width = SUBSAMPLE(src_y_width, 1, 1);
54 const int src_uv_height = SUBSAMPLE(src_y_height, 1, 1);
55 int r;
56 if (src_y_width == 0 || src_y_height == 0 || dst_uv_width <= 0 ||
57 dst_uv_height <= 0) {
58 return -1;
59 }
60 if (dst_y) {
61 r = ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, dst_y,
62 dst_stride_y, dst_y_width, dst_y_height, kFilterBilinear);
63 if (r != 0) {
64 return r;
65 }
66 }
67 r = ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
68 dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
69 if (r != 0) {
70 return r;
71 }
72 r = ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
73 dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
74 return r;
75 }
76
77 // Convert 8 bit YUV to 10 bit.
78 LIBYUV_API
I420ToI010(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,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)79 int I420ToI010(const uint8_t* src_y,
80 int src_stride_y,
81 const uint8_t* src_u,
82 int src_stride_u,
83 const uint8_t* src_v,
84 int src_stride_v,
85 uint16_t* dst_y,
86 int dst_stride_y,
87 uint16_t* dst_u,
88 int dst_stride_u,
89 uint16_t* dst_v,
90 int dst_stride_v,
91 int width,
92 int height) {
93 int halfwidth = (width + 1) >> 1;
94 int halfheight = (height + 1) >> 1;
95 if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
96 height == 0) {
97 return -1;
98 }
99 // Negative height means invert the image.
100 if (height < 0) {
101 height = -height;
102 halfheight = (height + 1) >> 1;
103 src_y = src_y + (height - 1) * src_stride_y;
104 src_u = src_u + (halfheight - 1) * src_stride_u;
105 src_v = src_v + (halfheight - 1) * src_stride_v;
106 src_stride_y = -src_stride_y;
107 src_stride_u = -src_stride_u;
108 src_stride_v = -src_stride_v;
109 }
110
111 // Convert Y plane.
112 Convert8To16Plane(src_y, src_stride_y, dst_y, dst_stride_y, 1024, width,
113 height);
114 // Convert UV planes.
115 Convert8To16Plane(src_u, src_stride_u, dst_u, dst_stride_u, 1024, halfwidth,
116 halfheight);
117 Convert8To16Plane(src_v, src_stride_v, dst_v, dst_stride_v, 1024, halfwidth,
118 halfheight);
119 return 0;
120 }
121
122 // Convert 8 bit YUV to 12 bit.
123 LIBYUV_API
I420ToI012(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,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)124 int I420ToI012(const uint8_t* src_y,
125 int src_stride_y,
126 const uint8_t* src_u,
127 int src_stride_u,
128 const uint8_t* src_v,
129 int src_stride_v,
130 uint16_t* dst_y,
131 int dst_stride_y,
132 uint16_t* dst_u,
133 int dst_stride_u,
134 uint16_t* dst_v,
135 int dst_stride_v,
136 int width,
137 int height) {
138 int halfwidth = (width + 1) >> 1;
139 int halfheight = (height + 1) >> 1;
140 if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
141 height == 0) {
142 return -1;
143 }
144 // Negative height means invert the image.
145 if (height < 0) {
146 height = -height;
147 halfheight = (height + 1) >> 1;
148 src_y = src_y + (height - 1) * src_stride_y;
149 src_u = src_u + (halfheight - 1) * src_stride_u;
150 src_v = src_v + (halfheight - 1) * src_stride_v;
151 src_stride_y = -src_stride_y;
152 src_stride_u = -src_stride_u;
153 src_stride_v = -src_stride_v;
154 }
155
156 // Convert Y plane.
157 Convert8To16Plane(src_y, src_stride_y, dst_y, dst_stride_y, 4096, width,
158 height);
159 // Convert UV planes.
160 Convert8To16Plane(src_u, src_stride_u, dst_u, dst_stride_u, 4096, halfwidth,
161 halfheight);
162 Convert8To16Plane(src_v, src_stride_v, dst_v, dst_stride_v, 4096, halfwidth,
163 halfheight);
164 return 0;
165 }
166
167 // 420 chroma is 1/2 width, 1/2 height
168 // 422 chroma is 1/2 width, 1x height
169 LIBYUV_API
I420ToI422(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)170 int I420ToI422(const uint8_t* src_y,
171 int src_stride_y,
172 const uint8_t* src_u,
173 int src_stride_u,
174 const uint8_t* src_v,
175 int src_stride_v,
176 uint8_t* dst_y,
177 int dst_stride_y,
178 uint8_t* dst_u,
179 int dst_stride_u,
180 uint8_t* dst_v,
181 int dst_stride_v,
182 int width,
183 int height) {
184 const int dst_uv_width = (Abs(width) + 1) >> 1;
185 const int dst_uv_height = Abs(height);
186 return I420ToI4xx(src_y, src_stride_y, src_u, src_stride_u, src_v,
187 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
188 dst_v, dst_stride_v, width, height, dst_uv_width,
189 dst_uv_height);
190 }
191
192 // 420 chroma is 1/2 width, 1/2 height
193 // 444 chroma is 1x width, 1x height
194 LIBYUV_API
I420ToI444(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)195 int I420ToI444(const uint8_t* src_y,
196 int src_stride_y,
197 const uint8_t* src_u,
198 int src_stride_u,
199 const uint8_t* src_v,
200 int src_stride_v,
201 uint8_t* dst_y,
202 int dst_stride_y,
203 uint8_t* dst_u,
204 int dst_stride_u,
205 uint8_t* dst_v,
206 int dst_stride_v,
207 int width,
208 int height) {
209 const int dst_uv_width = Abs(width);
210 const int dst_uv_height = Abs(height);
211 return I420ToI4xx(src_y, src_stride_y, src_u, src_stride_u, src_v,
212 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
213 dst_v, dst_stride_v, width, height, dst_uv_width,
214 dst_uv_height);
215 }
216
217 // 420 chroma to 444 chroma, 10/12 bit version
218 LIBYUV_API
I010ToI410(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)219 int I010ToI410(const uint16_t* src_y,
220 int src_stride_y,
221 const uint16_t* src_u,
222 int src_stride_u,
223 const uint16_t* src_v,
224 int src_stride_v,
225 uint16_t* dst_y,
226 int dst_stride_y,
227 uint16_t* dst_u,
228 int dst_stride_u,
229 uint16_t* dst_v,
230 int dst_stride_v,
231 int width,
232 int height) {
233 int r;
234 if (width == 0 || height == 0) {
235 return -1;
236 }
237
238 if (dst_y) {
239 r = ScalePlane_12(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
240 Abs(width), Abs(height), kFilterBilinear);
241 if (r != 0) {
242 return r;
243 }
244 }
245 r = ScalePlane_12(src_u, src_stride_u, SUBSAMPLE(width, 1, 1),
246 SUBSAMPLE(height, 1, 1), dst_u, dst_stride_u, Abs(width),
247 Abs(height), kFilterBilinear);
248 if (r != 0) {
249 return r;
250 }
251 r = ScalePlane_12(src_v, src_stride_v, SUBSAMPLE(width, 1, 1),
252 SUBSAMPLE(height, 1, 1), dst_v, dst_stride_v, Abs(width),
253 Abs(height), kFilterBilinear);
254 return r;
255 }
256
257 // 422 chroma to 444 chroma, 10/12 bit version
258 LIBYUV_API
I210ToI410(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)259 int I210ToI410(const uint16_t* src_y,
260 int src_stride_y,
261 const uint16_t* src_u,
262 int src_stride_u,
263 const uint16_t* src_v,
264 int src_stride_v,
265 uint16_t* dst_y,
266 int dst_stride_y,
267 uint16_t* dst_u,
268 int dst_stride_u,
269 uint16_t* dst_v,
270 int dst_stride_v,
271 int width,
272 int height) {
273 int r;
274 if (width == 0 || height == 0) {
275 return -1;
276 }
277
278 if (dst_y) {
279 r = ScalePlane_12(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
280 Abs(width), Abs(height), kFilterBilinear);
281 if (r != 0) {
282 return r;
283 }
284 }
285 r = ScalePlane_12(src_u, src_stride_u, SUBSAMPLE(width, 1, 1), height, dst_u,
286 dst_stride_u, Abs(width), Abs(height), kFilterBilinear);
287 if (r != 0) {
288 return r;
289 }
290 r = ScalePlane_12(src_v, src_stride_v, SUBSAMPLE(width, 1, 1), height, dst_v,
291 dst_stride_v, Abs(width), Abs(height), kFilterBilinear);
292 return r;
293 }
294
295 // 422 chroma is 1/2 width, 1x height
296 // 444 chroma is 1x width, 1x height
297 LIBYUV_API
I422ToI444(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)298 int I422ToI444(const uint8_t* src_y,
299 int src_stride_y,
300 const uint8_t* src_u,
301 int src_stride_u,
302 const uint8_t* src_v,
303 int src_stride_v,
304 uint8_t* dst_y,
305 int dst_stride_y,
306 uint8_t* dst_u,
307 int dst_stride_u,
308 uint8_t* dst_v,
309 int dst_stride_v,
310 int width,
311 int height) {
312 int r;
313 if (width == 0 || height == 0) {
314 return -1;
315 }
316
317 if (dst_y) {
318 r = ScalePlane(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
319 Abs(width), Abs(height), kFilterBilinear);
320 if (r != 0) {
321 return r;
322 }
323 }
324 r = ScalePlane(src_u, src_stride_u, SUBSAMPLE(width, 1, 1), height, dst_u,
325 dst_stride_u, Abs(width), Abs(height), kFilterBilinear);
326 if (r != 0) {
327 return r;
328 }
329 r = ScalePlane(src_v, src_stride_v, SUBSAMPLE(width, 1, 1), height, dst_v,
330 dst_stride_v, Abs(width), Abs(height), kFilterBilinear);
331 return r;
332 }
333
334 // Copy to I400. Source can be I420,422,444,400,NV12,NV21
335 LIBYUV_API
I400Copy(const uint8_t * src_y,int src_stride_y,uint8_t * dst_y,int dst_stride_y,int width,int height)336 int I400Copy(const uint8_t* src_y,
337 int src_stride_y,
338 uint8_t* dst_y,
339 int dst_stride_y,
340 int width,
341 int height) {
342 if (!src_y || !dst_y || width <= 0 || height == 0) {
343 return -1;
344 }
345 // Negative height means invert the image.
346 if (height < 0) {
347 height = -height;
348 src_y = src_y + (height - 1) * src_stride_y;
349 src_stride_y = -src_stride_y;
350 }
351 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
352 return 0;
353 }
354
355 LIBYUV_API
I422ToYUY2(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_yuy2,int dst_stride_yuy2,int width,int height)356 int I422ToYUY2(const uint8_t* src_y,
357 int src_stride_y,
358 const uint8_t* src_u,
359 int src_stride_u,
360 const uint8_t* src_v,
361 int src_stride_v,
362 uint8_t* dst_yuy2,
363 int dst_stride_yuy2,
364 int width,
365 int height) {
366 int y;
367 void (*I422ToYUY2Row)(const uint8_t* src_y, const uint8_t* src_u,
368 const uint8_t* src_v, uint8_t* dst_yuy2, int width) =
369 I422ToYUY2Row_C;
370 if (!src_y || !src_u || !src_v || !dst_yuy2 || width <= 0 || height == 0) {
371 return -1;
372 }
373 // Negative height means invert the image.
374 if (height < 0) {
375 height = -height;
376 dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
377 dst_stride_yuy2 = -dst_stride_yuy2;
378 }
379 // Coalesce rows.
380 if (src_stride_y == width && src_stride_u * 2 == width &&
381 src_stride_v * 2 == width && dst_stride_yuy2 == width * 2) {
382 width *= height;
383 height = 1;
384 src_stride_y = src_stride_u = src_stride_v = dst_stride_yuy2 = 0;
385 }
386 #if defined(HAS_I422TOYUY2ROW_SSE2)
387 if (TestCpuFlag(kCpuHasSSE2)) {
388 I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
389 if (IS_ALIGNED(width, 16)) {
390 I422ToYUY2Row = I422ToYUY2Row_SSE2;
391 }
392 }
393 #endif
394 #if defined(HAS_I422TOYUY2ROW_AVX2)
395 if (TestCpuFlag(kCpuHasAVX2)) {
396 I422ToYUY2Row = I422ToYUY2Row_Any_AVX2;
397 if (IS_ALIGNED(width, 32)) {
398 I422ToYUY2Row = I422ToYUY2Row_AVX2;
399 }
400 }
401 #endif
402 #if defined(HAS_I422TOYUY2ROW_NEON)
403 if (TestCpuFlag(kCpuHasNEON)) {
404 I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
405 if (IS_ALIGNED(width, 16)) {
406 I422ToYUY2Row = I422ToYUY2Row_NEON;
407 }
408 }
409 #endif
410
411 for (y = 0; y < height; ++y) {
412 I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
413 src_y += src_stride_y;
414 src_u += src_stride_u;
415 src_v += src_stride_v;
416 dst_yuy2 += dst_stride_yuy2;
417 }
418 return 0;
419 }
420
421 LIBYUV_API
I420ToYUY2(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_yuy2,int dst_stride_yuy2,int width,int height)422 int I420ToYUY2(const uint8_t* src_y,
423 int src_stride_y,
424 const uint8_t* src_u,
425 int src_stride_u,
426 const uint8_t* src_v,
427 int src_stride_v,
428 uint8_t* dst_yuy2,
429 int dst_stride_yuy2,
430 int width,
431 int height) {
432 int y;
433 void (*I422ToYUY2Row)(const uint8_t* src_y, const uint8_t* src_u,
434 const uint8_t* src_v, uint8_t* dst_yuy2, int width) =
435 I422ToYUY2Row_C;
436 if (!src_y || !src_u || !src_v || !dst_yuy2 || width <= 0 || height == 0) {
437 return -1;
438 }
439 // Negative height means invert the image.
440 if (height < 0) {
441 height = -height;
442 dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
443 dst_stride_yuy2 = -dst_stride_yuy2;
444 }
445 #if defined(HAS_I422TOYUY2ROW_SSE2)
446 if (TestCpuFlag(kCpuHasSSE2)) {
447 I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
448 if (IS_ALIGNED(width, 16)) {
449 I422ToYUY2Row = I422ToYUY2Row_SSE2;
450 }
451 }
452 #endif
453 #if defined(HAS_I422TOYUY2ROW_AVX2)
454 if (TestCpuFlag(kCpuHasAVX2)) {
455 I422ToYUY2Row = I422ToYUY2Row_Any_AVX2;
456 if (IS_ALIGNED(width, 32)) {
457 I422ToYUY2Row = I422ToYUY2Row_AVX2;
458 }
459 }
460 #endif
461 #if defined(HAS_I422TOYUY2ROW_NEON)
462 if (TestCpuFlag(kCpuHasNEON)) {
463 I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
464 if (IS_ALIGNED(width, 16)) {
465 I422ToYUY2Row = I422ToYUY2Row_NEON;
466 }
467 }
468 #endif
469 #if defined(HAS_I422TOYUY2ROW_MSA)
470 if (TestCpuFlag(kCpuHasMSA)) {
471 I422ToYUY2Row = I422ToYUY2Row_Any_MSA;
472 if (IS_ALIGNED(width, 32)) {
473 I422ToYUY2Row = I422ToYUY2Row_MSA;
474 }
475 }
476 #endif
477 #if defined(HAS_I422TOYUY2ROW_LSX)
478 if (TestCpuFlag(kCpuHasLSX)) {
479 I422ToYUY2Row = I422ToYUY2Row_Any_LSX;
480 if (IS_ALIGNED(width, 16)) {
481 I422ToYUY2Row = I422ToYUY2Row_LSX;
482 }
483 }
484 #endif
485 #if defined(HAS_I422TOYUY2ROW_LASX)
486 if (TestCpuFlag(kCpuHasLASX)) {
487 I422ToYUY2Row = I422ToYUY2Row_Any_LASX;
488 if (IS_ALIGNED(width, 32)) {
489 I422ToYUY2Row = I422ToYUY2Row_LASX;
490 }
491 }
492 #endif
493
494 for (y = 0; y < height - 1; y += 2) {
495 I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
496 I422ToYUY2Row(src_y + src_stride_y, src_u, src_v,
497 dst_yuy2 + dst_stride_yuy2, width);
498 src_y += src_stride_y * 2;
499 src_u += src_stride_u;
500 src_v += src_stride_v;
501 dst_yuy2 += dst_stride_yuy2 * 2;
502 }
503 if (height & 1) {
504 I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
505 }
506 return 0;
507 }
508
509 LIBYUV_API
I422ToUYVY(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_uyvy,int dst_stride_uyvy,int width,int height)510 int I422ToUYVY(const uint8_t* src_y,
511 int src_stride_y,
512 const uint8_t* src_u,
513 int src_stride_u,
514 const uint8_t* src_v,
515 int src_stride_v,
516 uint8_t* dst_uyvy,
517 int dst_stride_uyvy,
518 int width,
519 int height) {
520 int y;
521 void (*I422ToUYVYRow)(const uint8_t* src_y, const uint8_t* src_u,
522 const uint8_t* src_v, uint8_t* dst_uyvy, int width) =
523 I422ToUYVYRow_C;
524 if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) {
525 return -1;
526 }
527 // Negative height means invert the image.
528 if (height < 0) {
529 height = -height;
530 dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
531 dst_stride_uyvy = -dst_stride_uyvy;
532 }
533 // Coalesce rows.
534 if (src_stride_y == width && src_stride_u * 2 == width &&
535 src_stride_v * 2 == width && dst_stride_uyvy == width * 2) {
536 width *= height;
537 height = 1;
538 src_stride_y = src_stride_u = src_stride_v = dst_stride_uyvy = 0;
539 }
540 #if defined(HAS_I422TOUYVYROW_SSE2)
541 if (TestCpuFlag(kCpuHasSSE2)) {
542 I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
543 if (IS_ALIGNED(width, 16)) {
544 I422ToUYVYRow = I422ToUYVYRow_SSE2;
545 }
546 }
547 #endif
548 #if defined(HAS_I422TOUYVYROW_AVX2)
549 if (TestCpuFlag(kCpuHasAVX2)) {
550 I422ToUYVYRow = I422ToUYVYRow_Any_AVX2;
551 if (IS_ALIGNED(width, 32)) {
552 I422ToUYVYRow = I422ToUYVYRow_AVX2;
553 }
554 }
555 #endif
556 #if defined(HAS_I422TOUYVYROW_NEON)
557 if (TestCpuFlag(kCpuHasNEON)) {
558 I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
559 if (IS_ALIGNED(width, 16)) {
560 I422ToUYVYRow = I422ToUYVYRow_NEON;
561 }
562 }
563 #endif
564 #if defined(HAS_I422TOUYVYROW_MSA)
565 if (TestCpuFlag(kCpuHasMSA)) {
566 I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
567 if (IS_ALIGNED(width, 32)) {
568 I422ToUYVYRow = I422ToUYVYRow_MSA;
569 }
570 }
571 #endif
572 #if defined(HAS_I422TOUYVYROW_LSX)
573 if (TestCpuFlag(kCpuHasLSX)) {
574 I422ToUYVYRow = I422ToUYVYRow_Any_LSX;
575 if (IS_ALIGNED(width, 16)) {
576 I422ToUYVYRow = I422ToUYVYRow_LSX;
577 }
578 }
579 #endif
580 #if defined(HAS_I422TOUYVYROW_LASX)
581 if (TestCpuFlag(kCpuHasLASX)) {
582 I422ToUYVYRow = I422ToUYVYRow_Any_LASX;
583 if (IS_ALIGNED(width, 32)) {
584 I422ToUYVYRow = I422ToUYVYRow_LASX;
585 }
586 }
587 #endif
588
589 for (y = 0; y < height; ++y) {
590 I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
591 src_y += src_stride_y;
592 src_u += src_stride_u;
593 src_v += src_stride_v;
594 dst_uyvy += dst_stride_uyvy;
595 }
596 return 0;
597 }
598
599 LIBYUV_API
I420ToUYVY(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_uyvy,int dst_stride_uyvy,int width,int height)600 int I420ToUYVY(const uint8_t* src_y,
601 int src_stride_y,
602 const uint8_t* src_u,
603 int src_stride_u,
604 const uint8_t* src_v,
605 int src_stride_v,
606 uint8_t* dst_uyvy,
607 int dst_stride_uyvy,
608 int width,
609 int height) {
610 int y;
611 void (*I422ToUYVYRow)(const uint8_t* src_y, const uint8_t* src_u,
612 const uint8_t* src_v, uint8_t* dst_uyvy, int width) =
613 I422ToUYVYRow_C;
614 if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) {
615 return -1;
616 }
617 // Negative height means invert the image.
618 if (height < 0) {
619 height = -height;
620 dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
621 dst_stride_uyvy = -dst_stride_uyvy;
622 }
623 #if defined(HAS_I422TOUYVYROW_SSE2)
624 if (TestCpuFlag(kCpuHasSSE2)) {
625 I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
626 if (IS_ALIGNED(width, 16)) {
627 I422ToUYVYRow = I422ToUYVYRow_SSE2;
628 }
629 }
630 #endif
631 #if defined(HAS_I422TOUYVYROW_AVX2)
632 if (TestCpuFlag(kCpuHasAVX2)) {
633 I422ToUYVYRow = I422ToUYVYRow_Any_AVX2;
634 if (IS_ALIGNED(width, 32)) {
635 I422ToUYVYRow = I422ToUYVYRow_AVX2;
636 }
637 }
638 #endif
639 #if defined(HAS_I422TOUYVYROW_NEON)
640 if (TestCpuFlag(kCpuHasNEON)) {
641 I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
642 if (IS_ALIGNED(width, 16)) {
643 I422ToUYVYRow = I422ToUYVYRow_NEON;
644 }
645 }
646 #endif
647 #if defined(HAS_I422TOUYVYROW_MSA)
648 if (TestCpuFlag(kCpuHasMSA)) {
649 I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
650 if (IS_ALIGNED(width, 32)) {
651 I422ToUYVYRow = I422ToUYVYRow_MSA;
652 }
653 }
654 #endif
655 #if defined(HAS_I422TOUYVYROW_LSX)
656 if (TestCpuFlag(kCpuHasLSX)) {
657 I422ToUYVYRow = I422ToUYVYRow_Any_LSX;
658 if (IS_ALIGNED(width, 16)) {
659 I422ToUYVYRow = I422ToUYVYRow_LSX;
660 }
661 }
662 #endif
663 #if defined(HAS_I422TOUYVYROW_LASX)
664 if (TestCpuFlag(kCpuHasLASX)) {
665 I422ToUYVYRow = I422ToUYVYRow_Any_LASX;
666 if (IS_ALIGNED(width, 32)) {
667 I422ToUYVYRow = I422ToUYVYRow_LASX;
668 }
669 }
670 #endif
671
672 for (y = 0; y < height - 1; y += 2) {
673 I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
674 I422ToUYVYRow(src_y + src_stride_y, src_u, src_v,
675 dst_uyvy + dst_stride_uyvy, width);
676 src_y += src_stride_y * 2;
677 src_u += src_stride_u;
678 src_v += src_stride_v;
679 dst_uyvy += dst_stride_uyvy * 2;
680 }
681 if (height & 1) {
682 I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
683 }
684 return 0;
685 }
686
687 LIBYUV_API
I420ToNV12(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)688 int I420ToNV12(const uint8_t* src_y,
689 int src_stride_y,
690 const uint8_t* src_u,
691 int src_stride_u,
692 const uint8_t* src_v,
693 int src_stride_v,
694 uint8_t* dst_y,
695 int dst_stride_y,
696 uint8_t* dst_uv,
697 int dst_stride_uv,
698 int width,
699 int height) {
700 int halfwidth = (width + 1) / 2;
701 int halfheight = (height + 1) / 2;
702 if (!src_y || !src_u || !src_v || !dst_uv || width <= 0 || height == 0) {
703 return -1;
704 }
705 // Negative height means invert the image.
706 if (height < 0) {
707 height = -height;
708 halfheight = (height + 1) >> 1;
709 src_y = src_y + (height - 1) * src_stride_y;
710 src_u = src_u + (halfheight - 1) * src_stride_u;
711 src_v = src_v + (halfheight - 1) * src_stride_v;
712 src_stride_y = -src_stride_y;
713 src_stride_u = -src_stride_u;
714 src_stride_v = -src_stride_v;
715 }
716 if (dst_y) {
717 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
718 }
719 MergeUVPlane(src_u, src_stride_u, src_v, src_stride_v, dst_uv, dst_stride_uv,
720 halfwidth, halfheight);
721 return 0;
722 }
723
724 LIBYUV_API
I420ToNV21(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)725 int I420ToNV21(const uint8_t* src_y,
726 int src_stride_y,
727 const uint8_t* src_u,
728 int src_stride_u,
729 const uint8_t* src_v,
730 int src_stride_v,
731 uint8_t* dst_y,
732 int dst_stride_y,
733 uint8_t* dst_vu,
734 int dst_stride_vu,
735 int width,
736 int height) {
737 return I420ToNV12(src_y, src_stride_y, src_v, src_stride_v, src_u,
738 src_stride_u, dst_y, dst_stride_y, dst_vu, dst_stride_vu,
739 width, height);
740 }
741
742 // Convert I420 to specified format
743 LIBYUV_API
ConvertFromI420(const uint8_t * y,int y_stride,const uint8_t * u,int u_stride,const uint8_t * v,int v_stride,uint8_t * dst_sample,int dst_sample_stride,int width,int height,uint32_t fourcc)744 int ConvertFromI420(const uint8_t* y,
745 int y_stride,
746 const uint8_t* u,
747 int u_stride,
748 const uint8_t* v,
749 int v_stride,
750 uint8_t* dst_sample,
751 int dst_sample_stride,
752 int width,
753 int height,
754 uint32_t fourcc) {
755 uint32_t format = CanonicalFourCC(fourcc);
756 int r = 0;
757 if (!y || !u || !v || !dst_sample || width <= 0 || height == 0) {
758 return -1;
759 }
760 switch (format) {
761 // Single plane formats
762 case FOURCC_YUY2:
763 r = I420ToYUY2(y, y_stride, u, u_stride, v, v_stride, dst_sample,
764 dst_sample_stride ? dst_sample_stride : width * 2, width,
765 height);
766 break;
767 case FOURCC_UYVY:
768 r = I420ToUYVY(y, y_stride, u, u_stride, v, v_stride, dst_sample,
769 dst_sample_stride ? dst_sample_stride : width * 2, width,
770 height);
771 break;
772 case FOURCC_RGBP:
773 r = I420ToRGB565(y, y_stride, u, u_stride, v, v_stride, dst_sample,
774 dst_sample_stride ? dst_sample_stride : width * 2, width,
775 height);
776 break;
777 case FOURCC_RGBO:
778 r = I420ToARGB1555(y, y_stride, u, u_stride, v, v_stride, dst_sample,
779 dst_sample_stride ? dst_sample_stride : width * 2,
780 width, height);
781 break;
782 case FOURCC_R444:
783 r = I420ToARGB4444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
784 dst_sample_stride ? dst_sample_stride : width * 2,
785 width, height);
786 break;
787 case FOURCC_24BG:
788 r = I420ToRGB24(y, y_stride, u, u_stride, v, v_stride, dst_sample,
789 dst_sample_stride ? dst_sample_stride : width * 3, width,
790 height);
791 break;
792 case FOURCC_RAW:
793 r = I420ToRAW(y, y_stride, u, u_stride, v, v_stride, dst_sample,
794 dst_sample_stride ? dst_sample_stride : width * 3, width,
795 height);
796 break;
797 case FOURCC_ARGB:
798 r = I420ToARGB(y, y_stride, u, u_stride, v, v_stride, dst_sample,
799 dst_sample_stride ? dst_sample_stride : width * 4, width,
800 height);
801 break;
802 case FOURCC_BGRA:
803 r = I420ToBGRA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
804 dst_sample_stride ? dst_sample_stride : width * 4, width,
805 height);
806 break;
807 case FOURCC_ABGR:
808 r = I420ToABGR(y, y_stride, u, u_stride, v, v_stride, dst_sample,
809 dst_sample_stride ? dst_sample_stride : width * 4, width,
810 height);
811 break;
812 case FOURCC_RGBA:
813 r = I420ToRGBA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
814 dst_sample_stride ? dst_sample_stride : width * 4, width,
815 height);
816 break;
817 case FOURCC_AR30:
818 r = I420ToAR30(y, y_stride, u, u_stride, v, v_stride, dst_sample,
819 dst_sample_stride ? dst_sample_stride : width * 4, width,
820 height);
821 break;
822 case FOURCC_I400:
823 r = I400Copy(y, y_stride, dst_sample,
824 dst_sample_stride ? dst_sample_stride : width, width,
825 height);
826 break;
827 case FOURCC_NV12: {
828 int dst_y_stride = dst_sample_stride ? dst_sample_stride : width;
829 uint8_t* dst_uv = dst_sample + dst_y_stride * height;
830 r = I420ToNV12(y, y_stride, u, u_stride, v, v_stride, dst_sample,
831 dst_sample_stride ? dst_sample_stride : width, dst_uv,
832 dst_sample_stride ? dst_sample_stride : width, width,
833 height);
834 break;
835 }
836 case FOURCC_NV21: {
837 int dst_y_stride = dst_sample_stride ? dst_sample_stride : width;
838 uint8_t* dst_vu = dst_sample + dst_y_stride * height;
839 r = I420ToNV21(y, y_stride, u, u_stride, v, v_stride, dst_sample,
840 dst_sample_stride ? dst_sample_stride : width, dst_vu,
841 dst_sample_stride ? dst_sample_stride : width, width,
842 height);
843 break;
844 }
845 // Triplanar formats
846 case FOURCC_I420:
847 case FOURCC_YV12: {
848 dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
849 int halfstride = (dst_sample_stride + 1) / 2;
850 int halfheight = (height + 1) / 2;
851 uint8_t* dst_u;
852 uint8_t* dst_v;
853 if (format == FOURCC_YV12) {
854 dst_v = dst_sample + dst_sample_stride * height;
855 dst_u = dst_v + halfstride * halfheight;
856 } else {
857 dst_u = dst_sample + dst_sample_stride * height;
858 dst_v = dst_u + halfstride * halfheight;
859 }
860 r = I420Copy(y, y_stride, u, u_stride, v, v_stride, dst_sample,
861 dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
862 width, height);
863 break;
864 }
865 case FOURCC_I422:
866 case FOURCC_YV16: {
867 dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
868 int halfstride = (dst_sample_stride + 1) / 2;
869 uint8_t* dst_u;
870 uint8_t* dst_v;
871 if (format == FOURCC_YV16) {
872 dst_v = dst_sample + dst_sample_stride * height;
873 dst_u = dst_v + halfstride * height;
874 } else {
875 dst_u = dst_sample + dst_sample_stride * height;
876 dst_v = dst_u + halfstride * height;
877 }
878 r = I420ToI422(y, y_stride, u, u_stride, v, v_stride, dst_sample,
879 dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
880 width, height);
881 break;
882 }
883 case FOURCC_I444:
884 case FOURCC_YV24: {
885 dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
886 uint8_t* dst_u;
887 uint8_t* dst_v;
888 if (format == FOURCC_YV24) {
889 dst_v = dst_sample + dst_sample_stride * height;
890 dst_u = dst_v + dst_sample_stride * height;
891 } else {
892 dst_u = dst_sample + dst_sample_stride * height;
893 dst_v = dst_u + dst_sample_stride * height;
894 }
895 r = I420ToI444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
896 dst_sample_stride, dst_u, dst_sample_stride, dst_v,
897 dst_sample_stride, width, height);
898 break;
899 }
900 // Formats not supported - MJPG, biplanar, some rgb formats.
901 default:
902 return -1; // unknown fourcc - return failure code.
903 }
904 return r;
905 }
906
907 #ifdef __cplusplus
908 } // extern "C"
909 } // namespace libyuv
910 #endif
911