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