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