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