• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * 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* src_y,
34                       int src_stride_y,
35                       const uint8* src_u,
36                       int src_stride_u,
37                       const uint8* src_v,
38                       int src_stride_v,
39                       uint8* dst_y,
40                       int dst_stride_y,
41                       uint8* dst_u,
42                       int dst_stride_u,
43                       uint8* 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 // 420 chroma is 1/2 width, 1/2 height
69 // 422 chroma is 1/2 width, 1x height
70 LIBYUV_API
I420ToI422(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)71 int I420ToI422(const uint8* src_y,
72                int src_stride_y,
73                const uint8* src_u,
74                int src_stride_u,
75                const uint8* src_v,
76                int src_stride_v,
77                uint8* dst_y,
78                int dst_stride_y,
79                uint8* dst_u,
80                int dst_stride_u,
81                uint8* dst_v,
82                int dst_stride_v,
83                int width,
84                int height) {
85   const int dst_uv_width = (Abs(width) + 1) >> 1;
86   const int dst_uv_height = Abs(height);
87   return I420ToI4xx(src_y, src_stride_y, src_u, src_stride_u, src_v,
88                     src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
89                     dst_v, dst_stride_v, width, height, dst_uv_width,
90                     dst_uv_height);
91 }
92 
93 // 420 chroma is 1/2 width, 1/2 height
94 // 444 chroma is 1x width, 1x height
95 LIBYUV_API
I420ToI444(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)96 int I420ToI444(const uint8* src_y,
97                int src_stride_y,
98                const uint8* src_u,
99                int src_stride_u,
100                const uint8* src_v,
101                int src_stride_v,
102                uint8* dst_y,
103                int dst_stride_y,
104                uint8* dst_u,
105                int dst_stride_u,
106                uint8* dst_v,
107                int dst_stride_v,
108                int width,
109                int height) {
110   const int dst_uv_width = Abs(width);
111   const int dst_uv_height = Abs(height);
112   return I420ToI4xx(src_y, src_stride_y, src_u, src_stride_u, src_v,
113                     src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
114                     dst_v, dst_stride_v, width, height, dst_uv_width,
115                     dst_uv_height);
116 }
117 
118 // Copy to I400. Source can be I420,422,444,400,NV12,NV21
119 LIBYUV_API
I400Copy(const uint8 * src_y,int src_stride_y,uint8 * dst_y,int dst_stride_y,int width,int height)120 int I400Copy(const uint8* src_y,
121              int src_stride_y,
122              uint8* dst_y,
123              int dst_stride_y,
124              int width,
125              int height) {
126   if (!src_y || !dst_y || width <= 0 || height == 0) {
127     return -1;
128   }
129   // Negative height means invert the image.
130   if (height < 0) {
131     height = -height;
132     src_y = src_y + (height - 1) * src_stride_y;
133     src_stride_y = -src_stride_y;
134   }
135   CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
136   return 0;
137 }
138 
139 LIBYUV_API
I422ToYUY2(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_yuy2,int dst_stride_yuy2,int width,int height)140 int I422ToYUY2(const uint8* src_y,
141                int src_stride_y,
142                const uint8* src_u,
143                int src_stride_u,
144                const uint8* src_v,
145                int src_stride_v,
146                uint8* dst_yuy2,
147                int dst_stride_yuy2,
148                int width,
149                int height) {
150   int y;
151   void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u,
152                         const uint8* src_v, uint8* dst_yuy2, int width) =
153       I422ToYUY2Row_C;
154   if (!src_y || !src_u || !src_v || !dst_yuy2 || width <= 0 || height == 0) {
155     return -1;
156   }
157   // Negative height means invert the image.
158   if (height < 0) {
159     height = -height;
160     dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
161     dst_stride_yuy2 = -dst_stride_yuy2;
162   }
163   // Coalesce rows.
164   if (src_stride_y == width && src_stride_u * 2 == width &&
165       src_stride_v * 2 == width && dst_stride_yuy2 == width * 2) {
166     width *= height;
167     height = 1;
168     src_stride_y = src_stride_u = src_stride_v = dst_stride_yuy2 = 0;
169   }
170 #if defined(HAS_I422TOYUY2ROW_SSE2)
171   if (TestCpuFlag(kCpuHasSSE2)) {
172     I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
173     if (IS_ALIGNED(width, 16)) {
174       I422ToYUY2Row = I422ToYUY2Row_SSE2;
175     }
176   }
177 #endif
178 #if defined(HAS_I422TOYUY2ROW_NEON)
179   if (TestCpuFlag(kCpuHasNEON)) {
180     I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
181     if (IS_ALIGNED(width, 16)) {
182       I422ToYUY2Row = I422ToYUY2Row_NEON;
183     }
184   }
185 #endif
186 
187   for (y = 0; y < height; ++y) {
188     I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
189     src_y += src_stride_y;
190     src_u += src_stride_u;
191     src_v += src_stride_v;
192     dst_yuy2 += dst_stride_yuy2;
193   }
194   return 0;
195 }
196 
197 LIBYUV_API
I420ToYUY2(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_yuy2,int dst_stride_yuy2,int width,int height)198 int I420ToYUY2(const uint8* src_y,
199                int src_stride_y,
200                const uint8* src_u,
201                int src_stride_u,
202                const uint8* src_v,
203                int src_stride_v,
204                uint8* dst_yuy2,
205                int dst_stride_yuy2,
206                int width,
207                int height) {
208   int y;
209   void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u,
210                         const uint8* src_v, uint8* dst_yuy2, int width) =
211       I422ToYUY2Row_C;
212   if (!src_y || !src_u || !src_v || !dst_yuy2 || width <= 0 || height == 0) {
213     return -1;
214   }
215   // Negative height means invert the image.
216   if (height < 0) {
217     height = -height;
218     dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
219     dst_stride_yuy2 = -dst_stride_yuy2;
220   }
221 #if defined(HAS_I422TOYUY2ROW_SSE2)
222   if (TestCpuFlag(kCpuHasSSE2)) {
223     I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
224     if (IS_ALIGNED(width, 16)) {
225       I422ToYUY2Row = I422ToYUY2Row_SSE2;
226     }
227   }
228 #endif
229 #if defined(HAS_I422TOYUY2ROW_NEON)
230   if (TestCpuFlag(kCpuHasNEON)) {
231     I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
232     if (IS_ALIGNED(width, 16)) {
233       I422ToYUY2Row = I422ToYUY2Row_NEON;
234     }
235   }
236 #endif
237 #if defined(HAS_I422TOYUY2ROW_MSA)
238   if (TestCpuFlag(kCpuHasMSA)) {
239     I422ToYUY2Row = I422ToYUY2Row_Any_MSA;
240     if (IS_ALIGNED(width, 32)) {
241       I422ToYUY2Row = I422ToYUY2Row_MSA;
242     }
243   }
244 #endif
245 
246   for (y = 0; y < height - 1; y += 2) {
247     I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
248     I422ToYUY2Row(src_y + src_stride_y, src_u, src_v,
249                   dst_yuy2 + dst_stride_yuy2, width);
250     src_y += src_stride_y * 2;
251     src_u += src_stride_u;
252     src_v += src_stride_v;
253     dst_yuy2 += dst_stride_yuy2 * 2;
254   }
255   if (height & 1) {
256     I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
257   }
258   return 0;
259 }
260 
261 LIBYUV_API
I422ToUYVY(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_uyvy,int dst_stride_uyvy,int width,int height)262 int I422ToUYVY(const uint8* src_y,
263                int src_stride_y,
264                const uint8* src_u,
265                int src_stride_u,
266                const uint8* src_v,
267                int src_stride_v,
268                uint8* dst_uyvy,
269                int dst_stride_uyvy,
270                int width,
271                int height) {
272   int y;
273   void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u,
274                         const uint8* src_v, uint8* dst_uyvy, int width) =
275       I422ToUYVYRow_C;
276   if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) {
277     return -1;
278   }
279   // Negative height means invert the image.
280   if (height < 0) {
281     height = -height;
282     dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
283     dst_stride_uyvy = -dst_stride_uyvy;
284   }
285   // Coalesce rows.
286   if (src_stride_y == width && src_stride_u * 2 == width &&
287       src_stride_v * 2 == width && dst_stride_uyvy == width * 2) {
288     width *= height;
289     height = 1;
290     src_stride_y = src_stride_u = src_stride_v = dst_stride_uyvy = 0;
291   }
292 #if defined(HAS_I422TOUYVYROW_SSE2)
293   if (TestCpuFlag(kCpuHasSSE2)) {
294     I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
295     if (IS_ALIGNED(width, 16)) {
296       I422ToUYVYRow = I422ToUYVYRow_SSE2;
297     }
298   }
299 #endif
300 #if defined(HAS_I422TOUYVYROW_NEON)
301   if (TestCpuFlag(kCpuHasNEON)) {
302     I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
303     if (IS_ALIGNED(width, 16)) {
304       I422ToUYVYRow = I422ToUYVYRow_NEON;
305     }
306   }
307 #endif
308 #if defined(HAS_I422TOUYVYROW_MSA)
309   if (TestCpuFlag(kCpuHasMSA)) {
310     I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
311     if (IS_ALIGNED(width, 32)) {
312       I422ToUYVYRow = I422ToUYVYRow_MSA;
313     }
314   }
315 #endif
316 
317   for (y = 0; y < height; ++y) {
318     I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
319     src_y += src_stride_y;
320     src_u += src_stride_u;
321     src_v += src_stride_v;
322     dst_uyvy += dst_stride_uyvy;
323   }
324   return 0;
325 }
326 
327 LIBYUV_API
I420ToUYVY(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_uyvy,int dst_stride_uyvy,int width,int height)328 int I420ToUYVY(const uint8* src_y,
329                int src_stride_y,
330                const uint8* src_u,
331                int src_stride_u,
332                const uint8* src_v,
333                int src_stride_v,
334                uint8* dst_uyvy,
335                int dst_stride_uyvy,
336                int width,
337                int height) {
338   int y;
339   void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u,
340                         const uint8* src_v, uint8* dst_uyvy, int width) =
341       I422ToUYVYRow_C;
342   if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) {
343     return -1;
344   }
345   // Negative height means invert the image.
346   if (height < 0) {
347     height = -height;
348     dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
349     dst_stride_uyvy = -dst_stride_uyvy;
350   }
351 #if defined(HAS_I422TOUYVYROW_SSE2)
352   if (TestCpuFlag(kCpuHasSSE2)) {
353     I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
354     if (IS_ALIGNED(width, 16)) {
355       I422ToUYVYRow = I422ToUYVYRow_SSE2;
356     }
357   }
358 #endif
359 #if defined(HAS_I422TOUYVYROW_NEON)
360   if (TestCpuFlag(kCpuHasNEON)) {
361     I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
362     if (IS_ALIGNED(width, 16)) {
363       I422ToUYVYRow = I422ToUYVYRow_NEON;
364     }
365   }
366 #endif
367 #if defined(HAS_I422TOUYVYROW_MSA)
368   if (TestCpuFlag(kCpuHasMSA)) {
369     I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
370     if (IS_ALIGNED(width, 32)) {
371       I422ToUYVYRow = I422ToUYVYRow_MSA;
372     }
373   }
374 #endif
375 
376   for (y = 0; y < height - 1; y += 2) {
377     I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
378     I422ToUYVYRow(src_y + src_stride_y, src_u, src_v,
379                   dst_uyvy + dst_stride_uyvy, width);
380     src_y += src_stride_y * 2;
381     src_u += src_stride_u;
382     src_v += src_stride_v;
383     dst_uyvy += dst_stride_uyvy * 2;
384   }
385   if (height & 1) {
386     I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
387   }
388   return 0;
389 }
390 
391 // TODO(fbarchard): test negative height for invert.
392 LIBYUV_API
I420ToNV12(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_y,int dst_stride_y,uint8 * dst_uv,int dst_stride_uv,int width,int height)393 int I420ToNV12(const uint8* src_y,
394                int src_stride_y,
395                const uint8* src_u,
396                int src_stride_u,
397                const uint8* src_v,
398                int src_stride_v,
399                uint8* dst_y,
400                int dst_stride_y,
401                uint8* dst_uv,
402                int dst_stride_uv,
403                int width,
404                int height) {
405   if (!src_y || !src_u || !src_v || !dst_y || !dst_uv || width <= 0 ||
406       height == 0) {
407     return -1;
408   }
409   int halfwidth = (width + 1) / 2;
410   int halfheight = height > 0 ? (height + 1) / 2 : (height - 1) / 2;
411   if (dst_y) {
412     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
413   }
414   MergeUVPlane(src_u, src_stride_u, src_v, src_stride_v, dst_uv, dst_stride_uv,
415                halfwidth, halfheight);
416   return 0;
417 }
418 
419 LIBYUV_API
I420ToNV21(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_y,int dst_stride_y,uint8 * dst_vu,int dst_stride_vu,int width,int height)420 int I420ToNV21(const uint8* src_y,
421                int src_stride_y,
422                const uint8* src_u,
423                int src_stride_u,
424                const uint8* src_v,
425                int src_stride_v,
426                uint8* dst_y,
427                int dst_stride_y,
428                uint8* dst_vu,
429                int dst_stride_vu,
430                int width,
431                int height) {
432   return I420ToNV12(src_y, src_stride_y, src_v, src_stride_v, src_u,
433                     src_stride_u, dst_y, dst_stride_y, dst_vu, dst_stride_vu,
434                     width, height);
435 }
436 
437 // Convert I422 to RGBA with matrix
I420ToRGBAMatrix(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_rgba,int dst_stride_rgba,const struct YuvConstants * yuvconstants,int width,int height)438 static int I420ToRGBAMatrix(const uint8* src_y,
439                             int src_stride_y,
440                             const uint8* src_u,
441                             int src_stride_u,
442                             const uint8* src_v,
443                             int src_stride_v,
444                             uint8* dst_rgba,
445                             int dst_stride_rgba,
446                             const struct YuvConstants* yuvconstants,
447                             int width,
448                             int height) {
449   int y;
450   void (*I422ToRGBARow)(const uint8* y_buf, const uint8* u_buf,
451                         const uint8* v_buf, uint8* rgb_buf,
452                         const struct YuvConstants* yuvconstants, int width) =
453       I422ToRGBARow_C;
454   if (!src_y || !src_u || !src_v || !dst_rgba || width <= 0 || height == 0) {
455     return -1;
456   }
457   // Negative height means invert the image.
458   if (height < 0) {
459     height = -height;
460     dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
461     dst_stride_rgba = -dst_stride_rgba;
462   }
463 #if defined(HAS_I422TORGBAROW_SSSE3)
464   if (TestCpuFlag(kCpuHasSSSE3)) {
465     I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
466     if (IS_ALIGNED(width, 8)) {
467       I422ToRGBARow = I422ToRGBARow_SSSE3;
468     }
469   }
470 #endif
471 #if defined(HAS_I422TORGBAROW_AVX2)
472   if (TestCpuFlag(kCpuHasAVX2)) {
473     I422ToRGBARow = I422ToRGBARow_Any_AVX2;
474     if (IS_ALIGNED(width, 16)) {
475       I422ToRGBARow = I422ToRGBARow_AVX2;
476     }
477   }
478 #endif
479 #if defined(HAS_I422TORGBAROW_NEON)
480   if (TestCpuFlag(kCpuHasNEON)) {
481     I422ToRGBARow = I422ToRGBARow_Any_NEON;
482     if (IS_ALIGNED(width, 8)) {
483       I422ToRGBARow = I422ToRGBARow_NEON;
484     }
485   }
486 #endif
487 #if defined(HAS_I422TORGBAROW_DSPR2)
488   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) &&
489       IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
490       IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
491       IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
492       IS_ALIGNED(dst_rgba, 4) && IS_ALIGNED(dst_stride_rgba, 4)) {
493     I422ToRGBARow = I422ToRGBARow_DSPR2;
494   }
495 #endif
496 #if defined(HAS_I422TORGBAROW_MSA)
497   if (TestCpuFlag(kCpuHasMSA)) {
498     I422ToRGBARow = I422ToRGBARow_Any_MSA;
499     if (IS_ALIGNED(width, 8)) {
500       I422ToRGBARow = I422ToRGBARow_MSA;
501     }
502   }
503 #endif
504 
505   for (y = 0; y < height; ++y) {
506     I422ToRGBARow(src_y, src_u, src_v, dst_rgba, yuvconstants, width);
507     dst_rgba += dst_stride_rgba;
508     src_y += src_stride_y;
509     if (y & 1) {
510       src_u += src_stride_u;
511       src_v += src_stride_v;
512     }
513   }
514   return 0;
515 }
516 
517 // Convert I420 to RGBA.
518 LIBYUV_API
I420ToRGBA(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_rgba,int dst_stride_rgba,int width,int height)519 int I420ToRGBA(const uint8* src_y,
520                int src_stride_y,
521                const uint8* src_u,
522                int src_stride_u,
523                const uint8* src_v,
524                int src_stride_v,
525                uint8* dst_rgba,
526                int dst_stride_rgba,
527                int width,
528                int height) {
529   return I420ToRGBAMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
530                           src_stride_v, dst_rgba, dst_stride_rgba,
531                           &kYuvI601Constants, width, height);
532 }
533 
534 // Convert I420 to BGRA.
535 LIBYUV_API
I420ToBGRA(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_bgra,int dst_stride_bgra,int width,int height)536 int I420ToBGRA(const uint8* src_y,
537                int src_stride_y,
538                const uint8* src_u,
539                int src_stride_u,
540                const uint8* src_v,
541                int src_stride_v,
542                uint8* dst_bgra,
543                int dst_stride_bgra,
544                int width,
545                int height) {
546   return I420ToRGBAMatrix(src_y, src_stride_y, src_v,
547                           src_stride_v,  // Swap U and V
548                           src_u, src_stride_u, dst_bgra, dst_stride_bgra,
549                           &kYvuI601Constants,  // Use Yvu matrix
550                           width, height);
551 }
552 
553 // Convert I420 to RGB24 with matrix
I420ToRGB24Matrix(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_rgb24,int dst_stride_rgb24,const struct YuvConstants * yuvconstants,int width,int height)554 static int I420ToRGB24Matrix(const uint8* src_y,
555                              int src_stride_y,
556                              const uint8* src_u,
557                              int src_stride_u,
558                              const uint8* src_v,
559                              int src_stride_v,
560                              uint8* dst_rgb24,
561                              int dst_stride_rgb24,
562                              const struct YuvConstants* yuvconstants,
563                              int width,
564                              int height) {
565   int y;
566   void (*I422ToRGB24Row)(const uint8* y_buf, const uint8* u_buf,
567                          const uint8* v_buf, uint8* rgb_buf,
568                          const struct YuvConstants* yuvconstants, int width) =
569       I422ToRGB24Row_C;
570   if (!src_y || !src_u || !src_v || !dst_rgb24 || width <= 0 || height == 0) {
571     return -1;
572   }
573   // Negative height means invert the image.
574   if (height < 0) {
575     height = -height;
576     dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
577     dst_stride_rgb24 = -dst_stride_rgb24;
578   }
579 #if defined(HAS_I422TORGB24ROW_SSSE3)
580   if (TestCpuFlag(kCpuHasSSSE3)) {
581     I422ToRGB24Row = I422ToRGB24Row_Any_SSSE3;
582     if (IS_ALIGNED(width, 8)) {
583       I422ToRGB24Row = I422ToRGB24Row_SSSE3;
584     }
585   }
586 #endif
587 #if defined(HAS_I422TORGB24ROW_AVX2)
588   if (TestCpuFlag(kCpuHasAVX2)) {
589     I422ToRGB24Row = I422ToRGB24Row_Any_AVX2;
590     if (IS_ALIGNED(width, 16)) {
591       I422ToRGB24Row = I422ToRGB24Row_AVX2;
592     }
593   }
594 #endif
595 #if defined(HAS_I422TORGB24ROW_NEON)
596   if (TestCpuFlag(kCpuHasNEON)) {
597     I422ToRGB24Row = I422ToRGB24Row_Any_NEON;
598     if (IS_ALIGNED(width, 8)) {
599       I422ToRGB24Row = I422ToRGB24Row_NEON;
600     }
601   }
602 #endif
603 #if defined(HAS_I422TORGB24ROW_MSA)
604   if (TestCpuFlag(kCpuHasMSA)) {
605     I422ToRGB24Row = I422ToRGB24Row_Any_MSA;
606     if (IS_ALIGNED(width, 16)) {
607       I422ToRGB24Row = I422ToRGB24Row_MSA;
608     }
609   }
610 #endif
611 
612   for (y = 0; y < height; ++y) {
613     I422ToRGB24Row(src_y, src_u, src_v, dst_rgb24, yuvconstants, width);
614     dst_rgb24 += dst_stride_rgb24;
615     src_y += src_stride_y;
616     if (y & 1) {
617       src_u += src_stride_u;
618       src_v += src_stride_v;
619     }
620   }
621   return 0;
622 }
623 
624 // Convert I420 to RGB24.
625 LIBYUV_API
I420ToRGB24(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_rgb24,int dst_stride_rgb24,int width,int height)626 int I420ToRGB24(const uint8* src_y,
627                 int src_stride_y,
628                 const uint8* src_u,
629                 int src_stride_u,
630                 const uint8* src_v,
631                 int src_stride_v,
632                 uint8* dst_rgb24,
633                 int dst_stride_rgb24,
634                 int width,
635                 int height) {
636   return I420ToRGB24Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
637                            src_stride_v, dst_rgb24, dst_stride_rgb24,
638                            &kYuvI601Constants, width, height);
639 }
640 
641 // Convert I420 to RAW.
642 LIBYUV_API
I420ToRAW(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_raw,int dst_stride_raw,int width,int height)643 int I420ToRAW(const uint8* src_y,
644               int src_stride_y,
645               const uint8* src_u,
646               int src_stride_u,
647               const uint8* src_v,
648               int src_stride_v,
649               uint8* dst_raw,
650               int dst_stride_raw,
651               int width,
652               int height) {
653   return I420ToRGB24Matrix(src_y, src_stride_y, src_v,
654                            src_stride_v,  // Swap U and V
655                            src_u, src_stride_u, dst_raw, dst_stride_raw,
656                            &kYvuI601Constants,  // Use Yvu matrix
657                            width, height);
658 }
659 
660 // Convert I420 to ARGB1555.
661 LIBYUV_API
I420ToARGB1555(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_argb1555,int dst_stride_argb1555,int width,int height)662 int I420ToARGB1555(const uint8* src_y,
663                    int src_stride_y,
664                    const uint8* src_u,
665                    int src_stride_u,
666                    const uint8* src_v,
667                    int src_stride_v,
668                    uint8* dst_argb1555,
669                    int dst_stride_argb1555,
670                    int width,
671                    int height) {
672   int y;
673   void (*I422ToARGB1555Row)(const uint8* y_buf, const uint8* u_buf,
674                             const uint8* v_buf, uint8* rgb_buf,
675                             const struct YuvConstants* yuvconstants,
676                             int width) = I422ToARGB1555Row_C;
677   if (!src_y || !src_u || !src_v || !dst_argb1555 || width <= 0 ||
678       height == 0) {
679     return -1;
680   }
681   // Negative height means invert the image.
682   if (height < 0) {
683     height = -height;
684     dst_argb1555 = dst_argb1555 + (height - 1) * dst_stride_argb1555;
685     dst_stride_argb1555 = -dst_stride_argb1555;
686   }
687 #if defined(HAS_I422TOARGB1555ROW_SSSE3)
688   if (TestCpuFlag(kCpuHasSSSE3)) {
689     I422ToARGB1555Row = I422ToARGB1555Row_Any_SSSE3;
690     if (IS_ALIGNED(width, 8)) {
691       I422ToARGB1555Row = I422ToARGB1555Row_SSSE3;
692     }
693   }
694 #endif
695 #if defined(HAS_I422TOARGB1555ROW_AVX2)
696   if (TestCpuFlag(kCpuHasAVX2)) {
697     I422ToARGB1555Row = I422ToARGB1555Row_Any_AVX2;
698     if (IS_ALIGNED(width, 16)) {
699       I422ToARGB1555Row = I422ToARGB1555Row_AVX2;
700     }
701   }
702 #endif
703 #if defined(HAS_I422TOARGB1555ROW_NEON)
704   if (TestCpuFlag(kCpuHasNEON)) {
705     I422ToARGB1555Row = I422ToARGB1555Row_Any_NEON;
706     if (IS_ALIGNED(width, 8)) {
707       I422ToARGB1555Row = I422ToARGB1555Row_NEON;
708     }
709   }
710 #endif
711 #if defined(HAS_I422TOARGB1555ROW_DSPR2)
712   if (TestCpuFlag(kCpuHasDSPR2)) {
713     I422ToARGB1555Row = I422ToARGB1555Row_Any_DSPR2;
714     if (IS_ALIGNED(width, 4)) {
715       I422ToARGB1555Row = I422ToARGB1555Row_DSPR2;
716     }
717   }
718 #endif
719 #if defined(HAS_I422TOARGB1555ROW_MSA)
720   if (TestCpuFlag(kCpuHasMSA)) {
721     I422ToARGB1555Row = I422ToARGB1555Row_Any_MSA;
722     if (IS_ALIGNED(width, 8)) {
723       I422ToARGB1555Row = I422ToARGB1555Row_MSA;
724     }
725   }
726 #endif
727 
728   for (y = 0; y < height; ++y) {
729     I422ToARGB1555Row(src_y, src_u, src_v, dst_argb1555, &kYuvI601Constants,
730                       width);
731     dst_argb1555 += dst_stride_argb1555;
732     src_y += src_stride_y;
733     if (y & 1) {
734       src_u += src_stride_u;
735       src_v += src_stride_v;
736     }
737   }
738   return 0;
739 }
740 
741 // Convert I420 to ARGB4444.
742 LIBYUV_API
I420ToARGB4444(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_argb4444,int dst_stride_argb4444,int width,int height)743 int I420ToARGB4444(const uint8* src_y,
744                    int src_stride_y,
745                    const uint8* src_u,
746                    int src_stride_u,
747                    const uint8* src_v,
748                    int src_stride_v,
749                    uint8* dst_argb4444,
750                    int dst_stride_argb4444,
751                    int width,
752                    int height) {
753   int y;
754   void (*I422ToARGB4444Row)(const uint8* y_buf, const uint8* u_buf,
755                             const uint8* v_buf, uint8* rgb_buf,
756                             const struct YuvConstants* yuvconstants,
757                             int width) = I422ToARGB4444Row_C;
758   if (!src_y || !src_u || !src_v || !dst_argb4444 || width <= 0 ||
759       height == 0) {
760     return -1;
761   }
762   // Negative height means invert the image.
763   if (height < 0) {
764     height = -height;
765     dst_argb4444 = dst_argb4444 + (height - 1) * dst_stride_argb4444;
766     dst_stride_argb4444 = -dst_stride_argb4444;
767   }
768 #if defined(HAS_I422TOARGB4444ROW_SSSE3)
769   if (TestCpuFlag(kCpuHasSSSE3)) {
770     I422ToARGB4444Row = I422ToARGB4444Row_Any_SSSE3;
771     if (IS_ALIGNED(width, 8)) {
772       I422ToARGB4444Row = I422ToARGB4444Row_SSSE3;
773     }
774   }
775 #endif
776 #if defined(HAS_I422TOARGB4444ROW_AVX2)
777   if (TestCpuFlag(kCpuHasAVX2)) {
778     I422ToARGB4444Row = I422ToARGB4444Row_Any_AVX2;
779     if (IS_ALIGNED(width, 16)) {
780       I422ToARGB4444Row = I422ToARGB4444Row_AVX2;
781     }
782   }
783 #endif
784 #if defined(HAS_I422TOARGB4444ROW_NEON)
785   if (TestCpuFlag(kCpuHasNEON)) {
786     I422ToARGB4444Row = I422ToARGB4444Row_Any_NEON;
787     if (IS_ALIGNED(width, 8)) {
788       I422ToARGB4444Row = I422ToARGB4444Row_NEON;
789     }
790   }
791 #endif
792 #if defined(HAS_I422TOARGB4444ROW_DSPR2)
793   if (TestCpuFlag(kCpuHasDSPR2)) {
794     I422ToARGB4444Row = I422ToARGB4444Row_Any_DSPR2;
795     if (IS_ALIGNED(width, 4)) {
796       I422ToARGB4444Row = I422ToARGB4444Row_DSPR2;
797     }
798   }
799 #endif
800 #if defined(HAS_I422TOARGB4444ROW_MSA)
801   if (TestCpuFlag(kCpuHasMSA)) {
802     I422ToARGB4444Row = I422ToARGB4444Row_Any_MSA;
803     if (IS_ALIGNED(width, 8)) {
804       I422ToARGB4444Row = I422ToARGB4444Row_MSA;
805     }
806   }
807 #endif
808 
809   for (y = 0; y < height; ++y) {
810     I422ToARGB4444Row(src_y, src_u, src_v, dst_argb4444, &kYuvI601Constants,
811                       width);
812     dst_argb4444 += dst_stride_argb4444;
813     src_y += src_stride_y;
814     if (y & 1) {
815       src_u += src_stride_u;
816       src_v += src_stride_v;
817     }
818   }
819   return 0;
820 }
821 
822 // Convert I420 to RGB565.
823 LIBYUV_API
I420ToRGB565(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_rgb565,int dst_stride_rgb565,int width,int height)824 int I420ToRGB565(const uint8* src_y,
825                  int src_stride_y,
826                  const uint8* src_u,
827                  int src_stride_u,
828                  const uint8* src_v,
829                  int src_stride_v,
830                  uint8* dst_rgb565,
831                  int dst_stride_rgb565,
832                  int width,
833                  int height) {
834   int y;
835   void (*I422ToRGB565Row)(const uint8* y_buf, const uint8* u_buf,
836                           const uint8* v_buf, uint8* rgb_buf,
837                           const struct YuvConstants* yuvconstants, int width) =
838       I422ToRGB565Row_C;
839   if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
840     return -1;
841   }
842   // Negative height means invert the image.
843   if (height < 0) {
844     height = -height;
845     dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
846     dst_stride_rgb565 = -dst_stride_rgb565;
847   }
848 #if defined(HAS_I422TORGB565ROW_SSSE3)
849   if (TestCpuFlag(kCpuHasSSSE3)) {
850     I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
851     if (IS_ALIGNED(width, 8)) {
852       I422ToRGB565Row = I422ToRGB565Row_SSSE3;
853     }
854   }
855 #endif
856 #if defined(HAS_I422TORGB565ROW_AVX2)
857   if (TestCpuFlag(kCpuHasAVX2)) {
858     I422ToRGB565Row = I422ToRGB565Row_Any_AVX2;
859     if (IS_ALIGNED(width, 16)) {
860       I422ToRGB565Row = I422ToRGB565Row_AVX2;
861     }
862   }
863 #endif
864 #if defined(HAS_I422TORGB565ROW_NEON)
865   if (TestCpuFlag(kCpuHasNEON)) {
866     I422ToRGB565Row = I422ToRGB565Row_Any_NEON;
867     if (IS_ALIGNED(width, 8)) {
868       I422ToRGB565Row = I422ToRGB565Row_NEON;
869     }
870   }
871 #endif
872 #if defined(HAS_I422TORGB565ROW_MSA)
873   if (TestCpuFlag(kCpuHasMSA)) {
874     I422ToRGB565Row = I422ToRGB565Row_Any_MSA;
875     if (IS_ALIGNED(width, 8)) {
876       I422ToRGB565Row = I422ToRGB565Row_MSA;
877     }
878   }
879 #endif
880 
881   for (y = 0; y < height; ++y) {
882     I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, &kYuvI601Constants, width);
883     dst_rgb565 += dst_stride_rgb565;
884     src_y += src_stride_y;
885     if (y & 1) {
886       src_u += src_stride_u;
887       src_v += src_stride_v;
888     }
889   }
890   return 0;
891 }
892 
893 // Ordered 8x8 dither for 888 to 565.  Values from 0 to 7.
894 static const uint8 kDither565_4x4[16] = {
895     0, 4, 1, 5, 6, 2, 7, 3, 1, 5, 0, 4, 7, 3, 6, 2,
896 };
897 
898 // Convert I420 to RGB565 with dithering.
899 LIBYUV_API
I420ToRGB565Dither(const uint8 * src_y,int src_stride_y,const uint8 * src_u,int src_stride_u,const uint8 * src_v,int src_stride_v,uint8 * dst_rgb565,int dst_stride_rgb565,const uint8 * dither4x4,int width,int height)900 int I420ToRGB565Dither(const uint8* src_y,
901                        int src_stride_y,
902                        const uint8* src_u,
903                        int src_stride_u,
904                        const uint8* src_v,
905                        int src_stride_v,
906                        uint8* dst_rgb565,
907                        int dst_stride_rgb565,
908                        const uint8* dither4x4,
909                        int width,
910                        int height) {
911   int y;
912   void (*I422ToARGBRow)(const uint8* y_buf, const uint8* u_buf,
913                         const uint8* v_buf, uint8* rgb_buf,
914                         const struct YuvConstants* yuvconstants, int width) =
915       I422ToARGBRow_C;
916   void (*ARGBToRGB565DitherRow)(const uint8* src_argb, uint8* dst_rgb,
917                                 const uint32 dither4, int width) =
918       ARGBToRGB565DitherRow_C;
919   if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
920     return -1;
921   }
922   // Negative height means invert the image.
923   if (height < 0) {
924     height = -height;
925     dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
926     dst_stride_rgb565 = -dst_stride_rgb565;
927   }
928   if (!dither4x4) {
929     dither4x4 = kDither565_4x4;
930   }
931 #if defined(HAS_I422TOARGBROW_SSSE3)
932   if (TestCpuFlag(kCpuHasSSSE3)) {
933     I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
934     if (IS_ALIGNED(width, 8)) {
935       I422ToARGBRow = I422ToARGBRow_SSSE3;
936     }
937   }
938 #endif
939 #if defined(HAS_I422TOARGBROW_AVX2)
940   if (TestCpuFlag(kCpuHasAVX2)) {
941     I422ToARGBRow = I422ToARGBRow_Any_AVX2;
942     if (IS_ALIGNED(width, 16)) {
943       I422ToARGBRow = I422ToARGBRow_AVX2;
944     }
945   }
946 #endif
947 #if defined(HAS_I422TOARGBROW_NEON)
948   if (TestCpuFlag(kCpuHasNEON)) {
949     I422ToARGBRow = I422ToARGBRow_Any_NEON;
950     if (IS_ALIGNED(width, 8)) {
951       I422ToARGBRow = I422ToARGBRow_NEON;
952     }
953   }
954 #endif
955 #if defined(HAS_I422TOARGBROW_DSPR2)
956   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) &&
957       IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
958       IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
959       IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2)) {
960     I422ToARGBRow = I422ToARGBRow_DSPR2;
961   }
962 #endif
963 #if defined(HAS_I422TOARGBROW_MSA)
964   if (TestCpuFlag(kCpuHasMSA)) {
965     I422ToARGBRow = I422ToARGBRow_Any_MSA;
966     if (IS_ALIGNED(width, 8)) {
967       I422ToARGBRow = I422ToARGBRow_MSA;
968     }
969   }
970 #endif
971 #if defined(HAS_ARGBTORGB565DITHERROW_SSE2)
972   if (TestCpuFlag(kCpuHasSSE2)) {
973     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_SSE2;
974     if (IS_ALIGNED(width, 4)) {
975       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_SSE2;
976     }
977   }
978 #endif
979 #if defined(HAS_ARGBTORGB565DITHERROW_AVX2)
980   if (TestCpuFlag(kCpuHasAVX2)) {
981     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_AVX2;
982     if (IS_ALIGNED(width, 8)) {
983       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_AVX2;
984     }
985   }
986 #endif
987 #if defined(HAS_ARGBTORGB565DITHERROW_NEON)
988   if (TestCpuFlag(kCpuHasNEON)) {
989     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_NEON;
990     if (IS_ALIGNED(width, 8)) {
991       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_NEON;
992     }
993   }
994 #endif
995 #if defined(HAS_ARGBTORGB565DITHERROW_MSA)
996   if (TestCpuFlag(kCpuHasMSA)) {
997     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_MSA;
998     if (IS_ALIGNED(width, 8)) {
999       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_MSA;
1000     }
1001   }
1002 #endif
1003   {
1004     // Allocate a row of argb.
1005     align_buffer_64(row_argb, width * 4);
1006     for (y = 0; y < height; ++y) {
1007       I422ToARGBRow(src_y, src_u, src_v, row_argb, &kYuvI601Constants, width);
1008       ARGBToRGB565DitherRow(row_argb, dst_rgb565,
1009                             *(uint32*)(dither4x4 + ((y & 3) << 2)),
1010                             width);  // NOLINT
1011       dst_rgb565 += dst_stride_rgb565;
1012       src_y += src_stride_y;
1013       if (y & 1) {
1014         src_u += src_stride_u;
1015         src_v += src_stride_v;
1016       }
1017     }
1018     free_aligned_buffer_64(row_argb);
1019   }
1020   return 0;
1021 }
1022 
1023 // Convert I420 to specified format
1024 LIBYUV_API
ConvertFromI420(const uint8 * y,int y_stride,const uint8 * u,int u_stride,const uint8 * v,int v_stride,uint8 * dst_sample,int dst_sample_stride,int width,int height,uint32 fourcc)1025 int ConvertFromI420(const uint8* y,
1026                     int y_stride,
1027                     const uint8* u,
1028                     int u_stride,
1029                     const uint8* v,
1030                     int v_stride,
1031                     uint8* dst_sample,
1032                     int dst_sample_stride,
1033                     int width,
1034                     int height,
1035                     uint32 fourcc) {
1036   uint32 format = CanonicalFourCC(fourcc);
1037   int r = 0;
1038   if (!y || !u || !v || !dst_sample || width <= 0 || height == 0) {
1039     return -1;
1040   }
1041   switch (format) {
1042     // Single plane formats
1043     case FOURCC_YUY2:
1044       r = I420ToYUY2(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1045                      dst_sample_stride ? dst_sample_stride : width * 2, width,
1046                      height);
1047       break;
1048     case FOURCC_UYVY:
1049       r = I420ToUYVY(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1050                      dst_sample_stride ? dst_sample_stride : width * 2, width,
1051                      height);
1052       break;
1053     case FOURCC_RGBP:
1054       r = I420ToRGB565(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1055                        dst_sample_stride ? dst_sample_stride : width * 2, width,
1056                        height);
1057       break;
1058     case FOURCC_RGBO:
1059       r = I420ToARGB1555(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1060                          dst_sample_stride ? dst_sample_stride : width * 2,
1061                          width, height);
1062       break;
1063     case FOURCC_R444:
1064       r = I420ToARGB4444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1065                          dst_sample_stride ? dst_sample_stride : width * 2,
1066                          width, height);
1067       break;
1068     case FOURCC_24BG:
1069       r = I420ToRGB24(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1070                       dst_sample_stride ? dst_sample_stride : width * 3, width,
1071                       height);
1072       break;
1073     case FOURCC_RAW:
1074       r = I420ToRAW(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1075                     dst_sample_stride ? dst_sample_stride : width * 3, width,
1076                     height);
1077       break;
1078     case FOURCC_ARGB:
1079       r = I420ToARGB(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1080                      dst_sample_stride ? dst_sample_stride : width * 4, width,
1081                      height);
1082       break;
1083     case FOURCC_BGRA:
1084       r = I420ToBGRA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1085                      dst_sample_stride ? dst_sample_stride : width * 4, width,
1086                      height);
1087       break;
1088     case FOURCC_ABGR:
1089       r = I420ToABGR(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1090                      dst_sample_stride ? dst_sample_stride : width * 4, width,
1091                      height);
1092       break;
1093     case FOURCC_RGBA:
1094       r = I420ToRGBA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1095                      dst_sample_stride ? dst_sample_stride : width * 4, width,
1096                      height);
1097       break;
1098     case FOURCC_I400:
1099       r = I400Copy(y, y_stride, dst_sample,
1100                    dst_sample_stride ? dst_sample_stride : width, width,
1101                    height);
1102       break;
1103     case FOURCC_NV12: {
1104       uint8* dst_uv = dst_sample + width * height;
1105       r = I420ToNV12(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1106                      dst_sample_stride ? dst_sample_stride : width, dst_uv,
1107                      dst_sample_stride ? dst_sample_stride : width, width,
1108                      height);
1109       break;
1110     }
1111     case FOURCC_NV21: {
1112       uint8* dst_vu = dst_sample + width * height;
1113       r = I420ToNV21(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1114                      dst_sample_stride ? dst_sample_stride : width, dst_vu,
1115                      dst_sample_stride ? dst_sample_stride : width, width,
1116                      height);
1117       break;
1118     }
1119     // TODO(fbarchard): Add M420.
1120     // Triplanar formats
1121     case FOURCC_I420:
1122     case FOURCC_YV12: {
1123       dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1124       int halfstride = (dst_sample_stride + 1) / 2;
1125       int halfheight = (height + 1) / 2;
1126       uint8* dst_u;
1127       uint8* dst_v;
1128       if (format == FOURCC_YV12) {
1129         dst_v = dst_sample + dst_sample_stride * height;
1130         dst_u = dst_v + halfstride * halfheight;
1131       } else {
1132         dst_u = dst_sample + dst_sample_stride * height;
1133         dst_v = dst_u + halfstride * halfheight;
1134       }
1135       r = I420Copy(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1136                    dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
1137                    width, height);
1138       break;
1139     }
1140     case FOURCC_I422:
1141     case FOURCC_YV16: {
1142       dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1143       int halfstride = (dst_sample_stride + 1) / 2;
1144       uint8* dst_u;
1145       uint8* dst_v;
1146       if (format == FOURCC_YV16) {
1147         dst_v = dst_sample + dst_sample_stride * height;
1148         dst_u = dst_v + halfstride * height;
1149       } else {
1150         dst_u = dst_sample + dst_sample_stride * height;
1151         dst_v = dst_u + halfstride * height;
1152       }
1153       r = I420ToI422(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1154                      dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
1155                      width, height);
1156       break;
1157     }
1158     case FOURCC_I444:
1159     case FOURCC_YV24: {
1160       dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1161       uint8* dst_u;
1162       uint8* dst_v;
1163       if (format == FOURCC_YV24) {
1164         dst_v = dst_sample + dst_sample_stride * height;
1165         dst_u = dst_v + dst_sample_stride * height;
1166       } else {
1167         dst_u = dst_sample + dst_sample_stride * height;
1168         dst_v = dst_u + dst_sample_stride * height;
1169       }
1170       r = I420ToI444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1171                      dst_sample_stride, dst_u, dst_sample_stride, dst_v,
1172                      dst_sample_stride, width, height);
1173       break;
1174     }
1175     // Formats not supported - MJPG, biplanar, some rgb formats.
1176     default:
1177       return -1;  // unknown fourcc - return failure code.
1178   }
1179   return r;
1180 }
1181 
1182 #ifdef __cplusplus
1183 }  // extern "C"
1184 }  // namespace libyuv
1185 #endif
1186