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_MSA)
298   if (TestCpuFlag(kCpuHasMSA)) {
299     I422ToYUY2Row = I422ToYUY2Row_Any_MSA;
300     if (IS_ALIGNED(width, 32)) {
301       I422ToYUY2Row = I422ToYUY2Row_MSA;
302     }
303   }
304 #endif
305 #if defined(HAS_I422TOYUY2ROW_MMI)
306   if (TestCpuFlag(kCpuHasMMI)) {
307     I422ToYUY2Row = I422ToYUY2Row_Any_MMI;
308     if (IS_ALIGNED(width, 8)) {
309       I422ToYUY2Row = I422ToYUY2Row_MMI;
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_MSA)
385   if (TestCpuFlag(kCpuHasMSA)) {
386     I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
387     if (IS_ALIGNED(width, 32)) {
388       I422ToUYVYRow = I422ToUYVYRow_MSA;
389     }
390   }
391 #endif
392 #if defined(HAS_I422TOUYVYROW_MMI)
393   if (TestCpuFlag(kCpuHasMMI)) {
394     I422ToUYVYRow = I422ToUYVYRow_Any_MMI;
395     if (IS_ALIGNED(width, 8)) {
396       I422ToUYVYRow = I422ToUYVYRow_MMI;
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_MSA)
460   if (TestCpuFlag(kCpuHasMSA)) {
461     I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
462     if (IS_ALIGNED(width, 32)) {
463       I422ToUYVYRow = I422ToUYVYRow_MSA;
464     }
465   }
466 #endif
467 #if defined(HAS_I422TOUYVYROW_MMI)
468   if (TestCpuFlag(kCpuHasMMI)) {
469     I422ToUYVYRow = I422ToUYVYRow_Any_MMI;
470     if (IS_ALIGNED(width, 8)) {
471       I422ToUYVYRow = I422ToUYVYRow_MMI;
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 // TODO(fbarchard): test negative height for invert.
492 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)493 int I420ToNV12(const uint8_t* src_y,
494                int src_stride_y,
495                const uint8_t* src_u,
496                int src_stride_u,
497                const uint8_t* src_v,
498                int src_stride_v,
499                uint8_t* dst_y,
500                int dst_stride_y,
501                uint8_t* dst_uv,
502                int dst_stride_uv,
503                int width,
504                int height) {
505   if (!src_y || !src_u || !src_v || !dst_y || !dst_uv || width <= 0 ||
506       height == 0) {
507     return -1;
508   }
509   int halfwidth = (width + 1) / 2;
510   int halfheight = height > 0 ? (height + 1) / 2 : (height - 1) / 2;
511   if (dst_y) {
512     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
513   }
514   MergeUVPlane(src_u, src_stride_u, src_v, src_stride_v, dst_uv, dst_stride_uv,
515                halfwidth, halfheight);
516   return 0;
517 }
518 
519 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)520 int I420ToNV21(const uint8_t* src_y,
521                int src_stride_y,
522                const uint8_t* src_u,
523                int src_stride_u,
524                const uint8_t* src_v,
525                int src_stride_v,
526                uint8_t* dst_y,
527                int dst_stride_y,
528                uint8_t* dst_vu,
529                int dst_stride_vu,
530                int width,
531                int height) {
532   return I420ToNV12(src_y, src_stride_y, src_v, src_stride_v, src_u,
533                     src_stride_u, dst_y, dst_stride_y, dst_vu, dst_stride_vu,
534                     width, height);
535 }
536 
537 // Convert I422 to RGBA with matrix
I420ToRGBAMatrix(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_rgba,int dst_stride_rgba,const struct YuvConstants * yuvconstants,int width,int height)538 static int I420ToRGBAMatrix(const uint8_t* src_y,
539                             int src_stride_y,
540                             const uint8_t* src_u,
541                             int src_stride_u,
542                             const uint8_t* src_v,
543                             int src_stride_v,
544                             uint8_t* dst_rgba,
545                             int dst_stride_rgba,
546                             const struct YuvConstants* yuvconstants,
547                             int width,
548                             int height) {
549   int y;
550   void (*I422ToRGBARow)(const uint8_t* y_buf, const uint8_t* u_buf,
551                         const uint8_t* v_buf, uint8_t* rgb_buf,
552                         const struct YuvConstants* yuvconstants, int width) =
553       I422ToRGBARow_C;
554   if (!src_y || !src_u || !src_v || !dst_rgba || width <= 0 || height == 0) {
555     return -1;
556   }
557   // Negative height means invert the image.
558   if (height < 0) {
559     height = -height;
560     dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
561     dst_stride_rgba = -dst_stride_rgba;
562   }
563 #if defined(HAS_I422TORGBAROW_SSSE3)
564   if (TestCpuFlag(kCpuHasSSSE3)) {
565     I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
566     if (IS_ALIGNED(width, 8)) {
567       I422ToRGBARow = I422ToRGBARow_SSSE3;
568     }
569   }
570 #endif
571 #if defined(HAS_I422TORGBAROW_AVX2)
572   if (TestCpuFlag(kCpuHasAVX2)) {
573     I422ToRGBARow = I422ToRGBARow_Any_AVX2;
574     if (IS_ALIGNED(width, 16)) {
575       I422ToRGBARow = I422ToRGBARow_AVX2;
576     }
577   }
578 #endif
579 #if defined(HAS_I422TORGBAROW_NEON)
580   if (TestCpuFlag(kCpuHasNEON)) {
581     I422ToRGBARow = I422ToRGBARow_Any_NEON;
582     if (IS_ALIGNED(width, 8)) {
583       I422ToRGBARow = I422ToRGBARow_NEON;
584     }
585   }
586 #endif
587 #if defined(HAS_I422TORGBAROW_MSA)
588   if (TestCpuFlag(kCpuHasMSA)) {
589     I422ToRGBARow = I422ToRGBARow_Any_MSA;
590     if (IS_ALIGNED(width, 8)) {
591       I422ToRGBARow = I422ToRGBARow_MSA;
592     }
593   }
594 #endif
595 #if defined(HAS_I422TORGBAROW_MMI)
596   if (TestCpuFlag(kCpuHasMMI)) {
597     I422ToRGBARow = I422ToRGBARow_Any_MMI;
598     if (IS_ALIGNED(width, 4)) {
599       I422ToRGBARow = I422ToRGBARow_MMI;
600     }
601   }
602 #endif
603 
604   for (y = 0; y < height; ++y) {
605     I422ToRGBARow(src_y, src_u, src_v, dst_rgba, yuvconstants, width);
606     dst_rgba += dst_stride_rgba;
607     src_y += src_stride_y;
608     if (y & 1) {
609       src_u += src_stride_u;
610       src_v += src_stride_v;
611     }
612   }
613   return 0;
614 }
615 
616 // Convert I420 to RGBA.
617 LIBYUV_API
I420ToRGBA(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_rgba,int dst_stride_rgba,int width,int height)618 int I420ToRGBA(const uint8_t* src_y,
619                int src_stride_y,
620                const uint8_t* src_u,
621                int src_stride_u,
622                const uint8_t* src_v,
623                int src_stride_v,
624                uint8_t* dst_rgba,
625                int dst_stride_rgba,
626                int width,
627                int height) {
628   return I420ToRGBAMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
629                           src_stride_v, dst_rgba, dst_stride_rgba,
630                           &kYuvI601Constants, width, height);
631 }
632 
633 // Convert I420 to BGRA.
634 LIBYUV_API
I420ToBGRA(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_bgra,int dst_stride_bgra,int width,int height)635 int I420ToBGRA(const uint8_t* src_y,
636                int src_stride_y,
637                const uint8_t* src_u,
638                int src_stride_u,
639                const uint8_t* src_v,
640                int src_stride_v,
641                uint8_t* dst_bgra,
642                int dst_stride_bgra,
643                int width,
644                int height) {
645   return I420ToRGBAMatrix(src_y, src_stride_y, src_v,
646                           src_stride_v,  // Swap U and V
647                           src_u, src_stride_u, dst_bgra, dst_stride_bgra,
648                           &kYvuI601Constants,  // Use Yvu matrix
649                           width, height);
650 }
651 
652 // Convert I420 to RGB24 with matrix
I420ToRGB24Matrix(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_rgb24,int dst_stride_rgb24,const struct YuvConstants * yuvconstants,int width,int height)653 static int I420ToRGB24Matrix(const uint8_t* src_y,
654                              int src_stride_y,
655                              const uint8_t* src_u,
656                              int src_stride_u,
657                              const uint8_t* src_v,
658                              int src_stride_v,
659                              uint8_t* dst_rgb24,
660                              int dst_stride_rgb24,
661                              const struct YuvConstants* yuvconstants,
662                              int width,
663                              int height) {
664   int y;
665   void (*I422ToRGB24Row)(const uint8_t* y_buf, const uint8_t* u_buf,
666                          const uint8_t* v_buf, uint8_t* rgb_buf,
667                          const struct YuvConstants* yuvconstants, int width) =
668       I422ToRGB24Row_C;
669   if (!src_y || !src_u || !src_v || !dst_rgb24 || width <= 0 || height == 0) {
670     return -1;
671   }
672   // Negative height means invert the image.
673   if (height < 0) {
674     height = -height;
675     dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
676     dst_stride_rgb24 = -dst_stride_rgb24;
677   }
678 #if defined(HAS_I422TORGB24ROW_SSSE3)
679   if (TestCpuFlag(kCpuHasSSSE3)) {
680     I422ToRGB24Row = I422ToRGB24Row_Any_SSSE3;
681     if (IS_ALIGNED(width, 16)) {
682       I422ToRGB24Row = I422ToRGB24Row_SSSE3;
683     }
684   }
685 #endif
686 #if defined(HAS_I422TORGB24ROW_AVX2)
687   if (TestCpuFlag(kCpuHasAVX2)) {
688     I422ToRGB24Row = I422ToRGB24Row_Any_AVX2;
689     if (IS_ALIGNED(width, 32)) {
690       I422ToRGB24Row = I422ToRGB24Row_AVX2;
691     }
692   }
693 #endif
694 #if defined(HAS_I422TORGB24ROW_NEON)
695   if (TestCpuFlag(kCpuHasNEON)) {
696     I422ToRGB24Row = I422ToRGB24Row_Any_NEON;
697     if (IS_ALIGNED(width, 8)) {
698       I422ToRGB24Row = I422ToRGB24Row_NEON;
699     }
700   }
701 #endif
702 #if defined(HAS_I422TORGB24ROW_MSA)
703   if (TestCpuFlag(kCpuHasMSA)) {
704     I422ToRGB24Row = I422ToRGB24Row_Any_MSA;
705     if (IS_ALIGNED(width, 16)) {
706       I422ToRGB24Row = I422ToRGB24Row_MSA;
707     }
708   }
709 #endif
710 #if defined(HAS_I422TORGB24ROW_MMI)
711   if (TestCpuFlag(kCpuHasMMI)) {
712     I422ToRGB24Row = I422ToRGB24Row_Any_MMI;
713     if (IS_ALIGNED(width, 4)) {
714       I422ToRGB24Row = I422ToRGB24Row_MMI;
715     }
716   }
717 #endif
718 
719   for (y = 0; y < height; ++y) {
720     I422ToRGB24Row(src_y, src_u, src_v, dst_rgb24, yuvconstants, width);
721     dst_rgb24 += dst_stride_rgb24;
722     src_y += src_stride_y;
723     if (y & 1) {
724       src_u += src_stride_u;
725       src_v += src_stride_v;
726     }
727   }
728   return 0;
729 }
730 
731 // Convert I420 to RGB24.
732 LIBYUV_API
I420ToRGB24(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_rgb24,int dst_stride_rgb24,int width,int height)733 int I420ToRGB24(const uint8_t* src_y,
734                 int src_stride_y,
735                 const uint8_t* src_u,
736                 int src_stride_u,
737                 const uint8_t* src_v,
738                 int src_stride_v,
739                 uint8_t* dst_rgb24,
740                 int dst_stride_rgb24,
741                 int width,
742                 int height) {
743   return I420ToRGB24Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
744                            src_stride_v, dst_rgb24, dst_stride_rgb24,
745                            &kYuvI601Constants, width, height);
746 }
747 
748 // Convert I420 to RAW.
749 LIBYUV_API
I420ToRAW(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_raw,int dst_stride_raw,int width,int height)750 int I420ToRAW(const uint8_t* src_y,
751               int src_stride_y,
752               const uint8_t* src_u,
753               int src_stride_u,
754               const uint8_t* src_v,
755               int src_stride_v,
756               uint8_t* dst_raw,
757               int dst_stride_raw,
758               int width,
759               int height) {
760   return I420ToRGB24Matrix(src_y, src_stride_y, src_v,
761                            src_stride_v,  // Swap U and V
762                            src_u, src_stride_u, dst_raw, dst_stride_raw,
763                            &kYvuI601Constants,  // Use Yvu matrix
764                            width, height);
765 }
766 
767 // Convert J420 to RGB24.
768 LIBYUV_API
J420ToRGB24(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_rgb24,int dst_stride_rgb24,int width,int height)769 int J420ToRGB24(const uint8_t* src_y,
770                 int src_stride_y,
771                 const uint8_t* src_u,
772                 int src_stride_u,
773                 const uint8_t* src_v,
774                 int src_stride_v,
775                 uint8_t* dst_rgb24,
776                 int dst_stride_rgb24,
777                 int width,
778                 int height) {
779   return I420ToRGB24Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
780                            src_stride_v, dst_rgb24, dst_stride_rgb24,
781                            &kYuvJPEGConstants, width, height);
782 }
783 
784 // Convert J420 to RAW.
785 LIBYUV_API
J420ToRAW(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_raw,int dst_stride_raw,int width,int height)786 int J420ToRAW(const uint8_t* src_y,
787               int src_stride_y,
788               const uint8_t* src_u,
789               int src_stride_u,
790               const uint8_t* src_v,
791               int src_stride_v,
792               uint8_t* dst_raw,
793               int dst_stride_raw,
794               int width,
795               int height) {
796   return I420ToRGB24Matrix(src_y, src_stride_y, src_v,
797                            src_stride_v,  // Swap U and V
798                            src_u, src_stride_u, dst_raw, dst_stride_raw,
799                            &kYvuJPEGConstants,  // Use Yvu matrix
800                            width, height);
801 }
802 
803 // Convert H420 to RGB24.
804 LIBYUV_API
H420ToRGB24(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_rgb24,int dst_stride_rgb24,int width,int height)805 int H420ToRGB24(const uint8_t* src_y,
806                 int src_stride_y,
807                 const uint8_t* src_u,
808                 int src_stride_u,
809                 const uint8_t* src_v,
810                 int src_stride_v,
811                 uint8_t* dst_rgb24,
812                 int dst_stride_rgb24,
813                 int width,
814                 int height) {
815   return I420ToRGB24Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
816                            src_stride_v, dst_rgb24, dst_stride_rgb24,
817                            &kYuvH709Constants, width, height);
818 }
819 
820 // Convert H420 to RAW.
821 LIBYUV_API
H420ToRAW(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_raw,int dst_stride_raw,int width,int height)822 int H420ToRAW(const uint8_t* src_y,
823               int src_stride_y,
824               const uint8_t* src_u,
825               int src_stride_u,
826               const uint8_t* src_v,
827               int src_stride_v,
828               uint8_t* dst_raw,
829               int dst_stride_raw,
830               int width,
831               int height) {
832   return I420ToRGB24Matrix(src_y, src_stride_y, src_v,
833                            src_stride_v,  // Swap U and V
834                            src_u, src_stride_u, dst_raw, dst_stride_raw,
835                            &kYvuH709Constants,  // Use Yvu matrix
836                            width, height);
837 }
838 
839 // Convert I420 to ARGB1555.
840 LIBYUV_API
I420ToARGB1555(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_argb1555,int dst_stride_argb1555,int width,int height)841 int I420ToARGB1555(const uint8_t* src_y,
842                    int src_stride_y,
843                    const uint8_t* src_u,
844                    int src_stride_u,
845                    const uint8_t* src_v,
846                    int src_stride_v,
847                    uint8_t* dst_argb1555,
848                    int dst_stride_argb1555,
849                    int width,
850                    int height) {
851   int y;
852   void (*I422ToARGB1555Row)(const uint8_t* y_buf, const uint8_t* u_buf,
853                             const uint8_t* v_buf, uint8_t* rgb_buf,
854                             const struct YuvConstants* yuvconstants,
855                             int width) = I422ToARGB1555Row_C;
856   if (!src_y || !src_u || !src_v || !dst_argb1555 || width <= 0 ||
857       height == 0) {
858     return -1;
859   }
860   // Negative height means invert the image.
861   if (height < 0) {
862     height = -height;
863     dst_argb1555 = dst_argb1555 + (height - 1) * dst_stride_argb1555;
864     dst_stride_argb1555 = -dst_stride_argb1555;
865   }
866 #if defined(HAS_I422TOARGB1555ROW_SSSE3)
867   if (TestCpuFlag(kCpuHasSSSE3)) {
868     I422ToARGB1555Row = I422ToARGB1555Row_Any_SSSE3;
869     if (IS_ALIGNED(width, 8)) {
870       I422ToARGB1555Row = I422ToARGB1555Row_SSSE3;
871     }
872   }
873 #endif
874 #if defined(HAS_I422TOARGB1555ROW_AVX2)
875   if (TestCpuFlag(kCpuHasAVX2)) {
876     I422ToARGB1555Row = I422ToARGB1555Row_Any_AVX2;
877     if (IS_ALIGNED(width, 16)) {
878       I422ToARGB1555Row = I422ToARGB1555Row_AVX2;
879     }
880   }
881 #endif
882 #if defined(HAS_I422TOARGB1555ROW_NEON)
883   if (TestCpuFlag(kCpuHasNEON)) {
884     I422ToARGB1555Row = I422ToARGB1555Row_Any_NEON;
885     if (IS_ALIGNED(width, 8)) {
886       I422ToARGB1555Row = I422ToARGB1555Row_NEON;
887     }
888   }
889 #endif
890 #if defined(HAS_I422TOARGB1555ROW_MSA)
891   if (TestCpuFlag(kCpuHasMSA)) {
892     I422ToARGB1555Row = I422ToARGB1555Row_Any_MSA;
893     if (IS_ALIGNED(width, 8)) {
894       I422ToARGB1555Row = I422ToARGB1555Row_MSA;
895     }
896   }
897 #endif
898 #if defined(HAS_I422TOARGB1555ROW_MMI)
899   if (TestCpuFlag(kCpuHasMMI)) {
900     I422ToARGB1555Row = I422ToARGB1555Row_Any_MMI;
901     if (IS_ALIGNED(width, 4)) {
902       I422ToARGB1555Row = I422ToARGB1555Row_MMI;
903     }
904   }
905 #endif
906 
907   for (y = 0; y < height; ++y) {
908     I422ToARGB1555Row(src_y, src_u, src_v, dst_argb1555, &kYuvI601Constants,
909                       width);
910     dst_argb1555 += dst_stride_argb1555;
911     src_y += src_stride_y;
912     if (y & 1) {
913       src_u += src_stride_u;
914       src_v += src_stride_v;
915     }
916   }
917   return 0;
918 }
919 
920 // Convert I420 to ARGB4444.
921 LIBYUV_API
I420ToARGB4444(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_argb4444,int dst_stride_argb4444,int width,int height)922 int I420ToARGB4444(const uint8_t* src_y,
923                    int src_stride_y,
924                    const uint8_t* src_u,
925                    int src_stride_u,
926                    const uint8_t* src_v,
927                    int src_stride_v,
928                    uint8_t* dst_argb4444,
929                    int dst_stride_argb4444,
930                    int width,
931                    int height) {
932   int y;
933   void (*I422ToARGB4444Row)(const uint8_t* y_buf, const uint8_t* u_buf,
934                             const uint8_t* v_buf, uint8_t* rgb_buf,
935                             const struct YuvConstants* yuvconstants,
936                             int width) = I422ToARGB4444Row_C;
937   if (!src_y || !src_u || !src_v || !dst_argb4444 || width <= 0 ||
938       height == 0) {
939     return -1;
940   }
941   // Negative height means invert the image.
942   if (height < 0) {
943     height = -height;
944     dst_argb4444 = dst_argb4444 + (height - 1) * dst_stride_argb4444;
945     dst_stride_argb4444 = -dst_stride_argb4444;
946   }
947 #if defined(HAS_I422TOARGB4444ROW_SSSE3)
948   if (TestCpuFlag(kCpuHasSSSE3)) {
949     I422ToARGB4444Row = I422ToARGB4444Row_Any_SSSE3;
950     if (IS_ALIGNED(width, 8)) {
951       I422ToARGB4444Row = I422ToARGB4444Row_SSSE3;
952     }
953   }
954 #endif
955 #if defined(HAS_I422TOARGB4444ROW_AVX2)
956   if (TestCpuFlag(kCpuHasAVX2)) {
957     I422ToARGB4444Row = I422ToARGB4444Row_Any_AVX2;
958     if (IS_ALIGNED(width, 16)) {
959       I422ToARGB4444Row = I422ToARGB4444Row_AVX2;
960     }
961   }
962 #endif
963 #if defined(HAS_I422TOARGB4444ROW_NEON)
964   if (TestCpuFlag(kCpuHasNEON)) {
965     I422ToARGB4444Row = I422ToARGB4444Row_Any_NEON;
966     if (IS_ALIGNED(width, 8)) {
967       I422ToARGB4444Row = I422ToARGB4444Row_NEON;
968     }
969   }
970 #endif
971 #if defined(HAS_I422TOARGB4444ROW_MSA)
972   if (TestCpuFlag(kCpuHasMSA)) {
973     I422ToARGB4444Row = I422ToARGB4444Row_Any_MSA;
974     if (IS_ALIGNED(width, 8)) {
975       I422ToARGB4444Row = I422ToARGB4444Row_MSA;
976     }
977   }
978 #endif
979 #if defined(HAS_I422TOARGB4444ROW_MMI)
980   if (TestCpuFlag(kCpuHasMMI)) {
981     I422ToARGB4444Row = I422ToARGB4444Row_Any_MMI;
982     if (IS_ALIGNED(width, 4)) {
983       I422ToARGB4444Row = I422ToARGB4444Row_MMI;
984     }
985   }
986 #endif
987 
988   for (y = 0; y < height; ++y) {
989     I422ToARGB4444Row(src_y, src_u, src_v, dst_argb4444, &kYuvI601Constants,
990                       width);
991     dst_argb4444 += dst_stride_argb4444;
992     src_y += src_stride_y;
993     if (y & 1) {
994       src_u += src_stride_u;
995       src_v += src_stride_v;
996     }
997   }
998   return 0;
999 }
1000 
1001 // Convert I420 to RGB565 with specified color matrix.
1002 LIBYUV_API
I420ToRGB565Matrix(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_rgb565,int dst_stride_rgb565,const struct YuvConstants * yuvconstants,int width,int height)1003 int I420ToRGB565Matrix(const uint8_t* src_y,
1004                        int src_stride_y,
1005                        const uint8_t* src_u,
1006                        int src_stride_u,
1007                        const uint8_t* src_v,
1008                        int src_stride_v,
1009                        uint8_t* dst_rgb565,
1010                        int dst_stride_rgb565,
1011                        const struct YuvConstants* yuvconstants,
1012                        int width,
1013                        int height) {
1014   int y;
1015   void (*I422ToRGB565Row)(const uint8_t* y_buf, const uint8_t* u_buf,
1016                           const uint8_t* v_buf, uint8_t* rgb_buf,
1017                           const struct YuvConstants* yuvconstants, int width) =
1018       I422ToRGB565Row_C;
1019   if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
1020     return -1;
1021   }
1022   // Negative height means invert the image.
1023   if (height < 0) {
1024     height = -height;
1025     dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
1026     dst_stride_rgb565 = -dst_stride_rgb565;
1027   }
1028 #if defined(HAS_I422TORGB565ROW_SSSE3)
1029   if (TestCpuFlag(kCpuHasSSSE3)) {
1030     I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
1031     if (IS_ALIGNED(width, 8)) {
1032       I422ToRGB565Row = I422ToRGB565Row_SSSE3;
1033     }
1034   }
1035 #endif
1036 #if defined(HAS_I422TORGB565ROW_AVX2)
1037   if (TestCpuFlag(kCpuHasAVX2)) {
1038     I422ToRGB565Row = I422ToRGB565Row_Any_AVX2;
1039     if (IS_ALIGNED(width, 16)) {
1040       I422ToRGB565Row = I422ToRGB565Row_AVX2;
1041     }
1042   }
1043 #endif
1044 #if defined(HAS_I422TORGB565ROW_NEON)
1045   if (TestCpuFlag(kCpuHasNEON)) {
1046     I422ToRGB565Row = I422ToRGB565Row_Any_NEON;
1047     if (IS_ALIGNED(width, 8)) {
1048       I422ToRGB565Row = I422ToRGB565Row_NEON;
1049     }
1050   }
1051 #endif
1052 #if defined(HAS_I422TORGB565ROW_MSA)
1053   if (TestCpuFlag(kCpuHasMSA)) {
1054     I422ToRGB565Row = I422ToRGB565Row_Any_MSA;
1055     if (IS_ALIGNED(width, 8)) {
1056       I422ToRGB565Row = I422ToRGB565Row_MSA;
1057     }
1058   }
1059 #endif
1060 #if defined(HAS_I422TORGB565ROW_MMI)
1061   if (TestCpuFlag(kCpuHasMMI)) {
1062     I422ToRGB565Row = I422ToRGB565Row_Any_MMI;
1063     if (IS_ALIGNED(width, 4)) {
1064       I422ToRGB565Row = I422ToRGB565Row_MMI;
1065     }
1066   }
1067 #endif
1068 
1069   for (y = 0; y < height; ++y) {
1070     I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, yuvconstants, width);
1071     dst_rgb565 += dst_stride_rgb565;
1072     src_y += src_stride_y;
1073     if (y & 1) {
1074       src_u += src_stride_u;
1075       src_v += src_stride_v;
1076     }
1077   }
1078   return 0;
1079 }
1080 
1081 // Convert I420 to RGB565.
1082 LIBYUV_API
I420ToRGB565(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_rgb565,int dst_stride_rgb565,int width,int height)1083 int I420ToRGB565(const uint8_t* src_y,
1084                  int src_stride_y,
1085                  const uint8_t* src_u,
1086                  int src_stride_u,
1087                  const uint8_t* src_v,
1088                  int src_stride_v,
1089                  uint8_t* dst_rgb565,
1090                  int dst_stride_rgb565,
1091                  int width,
1092                  int height) {
1093   return I420ToRGB565Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1094                             src_stride_v, dst_rgb565, dst_stride_rgb565,
1095                             &kYuvI601Constants, width, height);
1096 }
1097 
1098 // Convert J420 to RGB565.
1099 LIBYUV_API
J420ToRGB565(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_rgb565,int dst_stride_rgb565,int width,int height)1100 int J420ToRGB565(const uint8_t* src_y,
1101                  int src_stride_y,
1102                  const uint8_t* src_u,
1103                  int src_stride_u,
1104                  const uint8_t* src_v,
1105                  int src_stride_v,
1106                  uint8_t* dst_rgb565,
1107                  int dst_stride_rgb565,
1108                  int width,
1109                  int height) {
1110   return I420ToRGB565Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1111                             src_stride_v, dst_rgb565, dst_stride_rgb565,
1112                             &kYuvJPEGConstants, width, height);
1113 }
1114 
1115 // Convert H420 to RGB565.
1116 LIBYUV_API
H420ToRGB565(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_rgb565,int dst_stride_rgb565,int width,int height)1117 int H420ToRGB565(const uint8_t* src_y,
1118                  int src_stride_y,
1119                  const uint8_t* src_u,
1120                  int src_stride_u,
1121                  const uint8_t* src_v,
1122                  int src_stride_v,
1123                  uint8_t* dst_rgb565,
1124                  int dst_stride_rgb565,
1125                  int width,
1126                  int height) {
1127   return I420ToRGB565Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1128                             src_stride_v, dst_rgb565, dst_stride_rgb565,
1129                             &kYuvH709Constants, width, height);
1130 }
1131 
1132 // Convert I422 to RGB565.
1133 LIBYUV_API
I422ToRGB565(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_rgb565,int dst_stride_rgb565,int width,int height)1134 int I422ToRGB565(const uint8_t* src_y,
1135                  int src_stride_y,
1136                  const uint8_t* src_u,
1137                  int src_stride_u,
1138                  const uint8_t* src_v,
1139                  int src_stride_v,
1140                  uint8_t* dst_rgb565,
1141                  int dst_stride_rgb565,
1142                  int width,
1143                  int height) {
1144   int y;
1145   void (*I422ToRGB565Row)(const uint8_t* y_buf, const uint8_t* u_buf,
1146                           const uint8_t* v_buf, uint8_t* rgb_buf,
1147                           const struct YuvConstants* yuvconstants, int width) =
1148       I422ToRGB565Row_C;
1149   if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
1150     return -1;
1151   }
1152   // Negative height means invert the image.
1153   if (height < 0) {
1154     height = -height;
1155     dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
1156     dst_stride_rgb565 = -dst_stride_rgb565;
1157   }
1158 #if defined(HAS_I422TORGB565ROW_SSSE3)
1159   if (TestCpuFlag(kCpuHasSSSE3)) {
1160     I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
1161     if (IS_ALIGNED(width, 8)) {
1162       I422ToRGB565Row = I422ToRGB565Row_SSSE3;
1163     }
1164   }
1165 #endif
1166 #if defined(HAS_I422TORGB565ROW_AVX2)
1167   if (TestCpuFlag(kCpuHasAVX2)) {
1168     I422ToRGB565Row = I422ToRGB565Row_Any_AVX2;
1169     if (IS_ALIGNED(width, 16)) {
1170       I422ToRGB565Row = I422ToRGB565Row_AVX2;
1171     }
1172   }
1173 #endif
1174 #if defined(HAS_I422TORGB565ROW_NEON)
1175   if (TestCpuFlag(kCpuHasNEON)) {
1176     I422ToRGB565Row = I422ToRGB565Row_Any_NEON;
1177     if (IS_ALIGNED(width, 8)) {
1178       I422ToRGB565Row = I422ToRGB565Row_NEON;
1179     }
1180   }
1181 #endif
1182 #if defined(HAS_I422TORGB565ROW_MSA)
1183   if (TestCpuFlag(kCpuHasMSA)) {
1184     I422ToRGB565Row = I422ToRGB565Row_Any_MSA;
1185     if (IS_ALIGNED(width, 8)) {
1186       I422ToRGB565Row = I422ToRGB565Row_MSA;
1187     }
1188   }
1189 #endif
1190 
1191   for (y = 0; y < height; ++y) {
1192     I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, &kYuvI601Constants, width);
1193     dst_rgb565 += dst_stride_rgb565;
1194     src_y += src_stride_y;
1195     src_u += src_stride_u;
1196     src_v += src_stride_v;
1197   }
1198   return 0;
1199 }
1200 
1201 // Ordered 8x8 dither for 888 to 565.  Values from 0 to 7.
1202 static const uint8_t kDither565_4x4[16] = {
1203     0, 4, 1, 5, 6, 2, 7, 3, 1, 5, 0, 4, 7, 3, 6, 2,
1204 };
1205 
1206 // Convert I420 to RGB565 with dithering.
1207 LIBYUV_API
I420ToRGB565Dither(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_rgb565,int dst_stride_rgb565,const uint8_t * dither4x4,int width,int height)1208 int I420ToRGB565Dither(const uint8_t* src_y,
1209                        int src_stride_y,
1210                        const uint8_t* src_u,
1211                        int src_stride_u,
1212                        const uint8_t* src_v,
1213                        int src_stride_v,
1214                        uint8_t* dst_rgb565,
1215                        int dst_stride_rgb565,
1216                        const uint8_t* dither4x4,
1217                        int width,
1218                        int height) {
1219   int y;
1220   void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
1221                         const uint8_t* v_buf, uint8_t* rgb_buf,
1222                         const struct YuvConstants* yuvconstants, int width) =
1223       I422ToARGBRow_C;
1224   void (*ARGBToRGB565DitherRow)(const uint8_t* src_argb, uint8_t* dst_rgb,
1225                                 const uint32_t dither4, int width) =
1226       ARGBToRGB565DitherRow_C;
1227   if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
1228     return -1;
1229   }
1230   // Negative height means invert the image.
1231   if (height < 0) {
1232     height = -height;
1233     dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
1234     dst_stride_rgb565 = -dst_stride_rgb565;
1235   }
1236   if (!dither4x4) {
1237     dither4x4 = kDither565_4x4;
1238   }
1239 #if defined(HAS_I422TOARGBROW_SSSE3)
1240   if (TestCpuFlag(kCpuHasSSSE3)) {
1241     I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
1242     if (IS_ALIGNED(width, 8)) {
1243       I422ToARGBRow = I422ToARGBRow_SSSE3;
1244     }
1245   }
1246 #endif
1247 #if defined(HAS_I422TOARGBROW_AVX2)
1248   if (TestCpuFlag(kCpuHasAVX2)) {
1249     I422ToARGBRow = I422ToARGBRow_Any_AVX2;
1250     if (IS_ALIGNED(width, 16)) {
1251       I422ToARGBRow = I422ToARGBRow_AVX2;
1252     }
1253   }
1254 #endif
1255 #if defined(HAS_I422TOARGBROW_NEON)
1256   if (TestCpuFlag(kCpuHasNEON)) {
1257     I422ToARGBRow = I422ToARGBRow_Any_NEON;
1258     if (IS_ALIGNED(width, 8)) {
1259       I422ToARGBRow = I422ToARGBRow_NEON;
1260     }
1261   }
1262 #endif
1263 #if defined(HAS_I422TOARGBROW_MSA)
1264   if (TestCpuFlag(kCpuHasMSA)) {
1265     I422ToARGBRow = I422ToARGBRow_Any_MSA;
1266     if (IS_ALIGNED(width, 8)) {
1267       I422ToARGBRow = I422ToARGBRow_MSA;
1268     }
1269   }
1270 #endif
1271 #if defined(HAS_I422TOARGBROW_MMI)
1272   if (TestCpuFlag(kCpuHasMMI)) {
1273     I422ToARGBRow = I422ToARGBRow_Any_MMI;
1274     if (IS_ALIGNED(width, 4)) {
1275       I422ToARGBRow = I422ToARGBRow_MMI;
1276     }
1277   }
1278 #endif
1279 #if defined(HAS_ARGBTORGB565DITHERROW_SSE2)
1280   if (TestCpuFlag(kCpuHasSSE2)) {
1281     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_SSE2;
1282     if (IS_ALIGNED(width, 4)) {
1283       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_SSE2;
1284     }
1285   }
1286 #endif
1287 #if defined(HAS_ARGBTORGB565DITHERROW_AVX2)
1288   if (TestCpuFlag(kCpuHasAVX2)) {
1289     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_AVX2;
1290     if (IS_ALIGNED(width, 8)) {
1291       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_AVX2;
1292     }
1293   }
1294 #endif
1295 #if defined(HAS_ARGBTORGB565DITHERROW_NEON)
1296   if (TestCpuFlag(kCpuHasNEON)) {
1297     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_NEON;
1298     if (IS_ALIGNED(width, 8)) {
1299       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_NEON;
1300     }
1301   }
1302 #endif
1303 #if defined(HAS_ARGBTORGB565DITHERROW_MSA)
1304   if (TestCpuFlag(kCpuHasMSA)) {
1305     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_MSA;
1306     if (IS_ALIGNED(width, 8)) {
1307       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_MSA;
1308     }
1309   }
1310 #endif
1311 #if defined(HAS_ARGBTORGB565DITHERROW_MMI)
1312   if (TestCpuFlag(kCpuHasMMI)) {
1313     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_MMI;
1314     if (IS_ALIGNED(width, 4)) {
1315       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_MMI;
1316     }
1317   }
1318 #endif
1319   {
1320     // Allocate a row of argb.
1321     align_buffer_64(row_argb, width * 4);
1322     for (y = 0; y < height; ++y) {
1323       I422ToARGBRow(src_y, src_u, src_v, row_argb, &kYuvI601Constants, width);
1324       ARGBToRGB565DitherRow(row_argb, dst_rgb565,
1325                             *(const uint32_t*)(dither4x4 + ((y & 3) << 2)),
1326                             width);
1327       dst_rgb565 += dst_stride_rgb565;
1328       src_y += src_stride_y;
1329       if (y & 1) {
1330         src_u += src_stride_u;
1331         src_v += src_stride_v;
1332       }
1333     }
1334     free_aligned_buffer_64(row_argb);
1335   }
1336   return 0;
1337 }
1338 
1339 // Convert I420 to AR30 with matrix
I420ToAR30Matrix(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_ar30,int dst_stride_ar30,const struct YuvConstants * yuvconstants,int width,int height)1340 static int I420ToAR30Matrix(const uint8_t* src_y,
1341                             int src_stride_y,
1342                             const uint8_t* src_u,
1343                             int src_stride_u,
1344                             const uint8_t* src_v,
1345                             int src_stride_v,
1346                             uint8_t* dst_ar30,
1347                             int dst_stride_ar30,
1348                             const struct YuvConstants* yuvconstants,
1349                             int width,
1350                             int height) {
1351   int y;
1352   void (*I422ToAR30Row)(const uint8_t* y_buf, const uint8_t* u_buf,
1353                         const uint8_t* v_buf, uint8_t* rgb_buf,
1354                         const struct YuvConstants* yuvconstants, int width) =
1355       I422ToAR30Row_C;
1356 
1357   if (!src_y || !src_u || !src_v || !dst_ar30 || width <= 0 || height == 0) {
1358     return -1;
1359   }
1360   // Negative height means invert the image.
1361   if (height < 0) {
1362     height = -height;
1363     dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30;
1364     dst_stride_ar30 = -dst_stride_ar30;
1365   }
1366 
1367 #if defined(HAS_I422TOAR30ROW_SSSE3)
1368   if (TestCpuFlag(kCpuHasSSSE3)) {
1369     I422ToAR30Row = I422ToAR30Row_Any_SSSE3;
1370     if (IS_ALIGNED(width, 8)) {
1371       I422ToAR30Row = I422ToAR30Row_SSSE3;
1372     }
1373   }
1374 #endif
1375 #if defined(HAS_I422TOAR30ROW_AVX2)
1376   if (TestCpuFlag(kCpuHasAVX2)) {
1377     I422ToAR30Row = I422ToAR30Row_Any_AVX2;
1378     if (IS_ALIGNED(width, 16)) {
1379       I422ToAR30Row = I422ToAR30Row_AVX2;
1380     }
1381   }
1382 #endif
1383 
1384   for (y = 0; y < height; ++y) {
1385     I422ToAR30Row(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
1386     dst_ar30 += dst_stride_ar30;
1387     src_y += src_stride_y;
1388     if (y & 1) {
1389       src_u += src_stride_u;
1390       src_v += src_stride_v;
1391     }
1392   }
1393   return 0;
1394 }
1395 
1396 // Convert I420 to AR30.
1397 LIBYUV_API
I420ToAR30(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_ar30,int dst_stride_ar30,int width,int height)1398 int I420ToAR30(const uint8_t* src_y,
1399                int src_stride_y,
1400                const uint8_t* src_u,
1401                int src_stride_u,
1402                const uint8_t* src_v,
1403                int src_stride_v,
1404                uint8_t* dst_ar30,
1405                int dst_stride_ar30,
1406                int width,
1407                int height) {
1408   return I420ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1409                           src_stride_v, dst_ar30, dst_stride_ar30,
1410                           &kYuvI601Constants, width, height);
1411 }
1412 
1413 // Convert H420 to AR30.
1414 LIBYUV_API
H420ToAR30(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_ar30,int dst_stride_ar30,int width,int height)1415 int H420ToAR30(const uint8_t* src_y,
1416                int src_stride_y,
1417                const uint8_t* src_u,
1418                int src_stride_u,
1419                const uint8_t* src_v,
1420                int src_stride_v,
1421                uint8_t* dst_ar30,
1422                int dst_stride_ar30,
1423                int width,
1424                int height) {
1425   return I420ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1426                           src_stride_v, dst_ar30, dst_stride_ar30,
1427                           &kYvuH709Constants, width, height);
1428 }
1429 
1430 // Convert I420 to specified format
1431 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)1432 int ConvertFromI420(const uint8_t* y,
1433                     int y_stride,
1434                     const uint8_t* u,
1435                     int u_stride,
1436                     const uint8_t* v,
1437                     int v_stride,
1438                     uint8_t* dst_sample,
1439                     int dst_sample_stride,
1440                     int width,
1441                     int height,
1442                     uint32_t fourcc) {
1443   uint32_t format = CanonicalFourCC(fourcc);
1444   int r = 0;
1445   if (!y || !u || !v || !dst_sample || width <= 0 || height == 0) {
1446     return -1;
1447   }
1448   switch (format) {
1449     // Single plane formats
1450     case FOURCC_YUY2:
1451       r = I420ToYUY2(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1452                      dst_sample_stride ? dst_sample_stride : width * 2, width,
1453                      height);
1454       break;
1455     case FOURCC_UYVY:
1456       r = I420ToUYVY(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1457                      dst_sample_stride ? dst_sample_stride : width * 2, width,
1458                      height);
1459       break;
1460     case FOURCC_RGBP:
1461       r = I420ToRGB565(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1462                        dst_sample_stride ? dst_sample_stride : width * 2, width,
1463                        height);
1464       break;
1465     case FOURCC_RGBO:
1466       r = I420ToARGB1555(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1467                          dst_sample_stride ? dst_sample_stride : width * 2,
1468                          width, height);
1469       break;
1470     case FOURCC_R444:
1471       r = I420ToARGB4444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1472                          dst_sample_stride ? dst_sample_stride : width * 2,
1473                          width, height);
1474       break;
1475     case FOURCC_24BG:
1476       r = I420ToRGB24(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1477                       dst_sample_stride ? dst_sample_stride : width * 3, width,
1478                       height);
1479       break;
1480     case FOURCC_RAW:
1481       r = I420ToRAW(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1482                     dst_sample_stride ? dst_sample_stride : width * 3, width,
1483                     height);
1484       break;
1485     case FOURCC_ARGB:
1486       r = I420ToARGB(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1487                      dst_sample_stride ? dst_sample_stride : width * 4, width,
1488                      height);
1489       break;
1490     case FOURCC_BGRA:
1491       r = I420ToBGRA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1492                      dst_sample_stride ? dst_sample_stride : width * 4, width,
1493                      height);
1494       break;
1495     case FOURCC_ABGR:
1496       r = I420ToABGR(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1497                      dst_sample_stride ? dst_sample_stride : width * 4, width,
1498                      height);
1499       break;
1500     case FOURCC_RGBA:
1501       r = I420ToRGBA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1502                      dst_sample_stride ? dst_sample_stride : width * 4, width,
1503                      height);
1504       break;
1505     case FOURCC_AR30:
1506       r = I420ToAR30(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1507                      dst_sample_stride ? dst_sample_stride : width * 4, width,
1508                      height);
1509       break;
1510     case FOURCC_I400:
1511       r = I400Copy(y, y_stride, dst_sample,
1512                    dst_sample_stride ? dst_sample_stride : width, width,
1513                    height);
1514       break;
1515     case FOURCC_NV12: {
1516       uint8_t* dst_uv = dst_sample + width * height;
1517       r = I420ToNV12(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1518                      dst_sample_stride ? dst_sample_stride : width, dst_uv,
1519                      dst_sample_stride ? dst_sample_stride : width, width,
1520                      height);
1521       break;
1522     }
1523     case FOURCC_NV21: {
1524       uint8_t* dst_vu = dst_sample + width * height;
1525       r = I420ToNV21(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1526                      dst_sample_stride ? dst_sample_stride : width, dst_vu,
1527                      dst_sample_stride ? dst_sample_stride : width, width,
1528                      height);
1529       break;
1530     }
1531     // TODO(fbarchard): Add M420.
1532     // Triplanar formats
1533     case FOURCC_I420:
1534     case FOURCC_YV12: {
1535       dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1536       int halfstride = (dst_sample_stride + 1) / 2;
1537       int halfheight = (height + 1) / 2;
1538       uint8_t* dst_u;
1539       uint8_t* dst_v;
1540       if (format == FOURCC_YV12) {
1541         dst_v = dst_sample + dst_sample_stride * height;
1542         dst_u = dst_v + halfstride * halfheight;
1543       } else {
1544         dst_u = dst_sample + dst_sample_stride * height;
1545         dst_v = dst_u + halfstride * halfheight;
1546       }
1547       r = I420Copy(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1548                    dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
1549                    width, height);
1550       break;
1551     }
1552     case FOURCC_I422:
1553     case FOURCC_YV16: {
1554       dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1555       int halfstride = (dst_sample_stride + 1) / 2;
1556       uint8_t* dst_u;
1557       uint8_t* dst_v;
1558       if (format == FOURCC_YV16) {
1559         dst_v = dst_sample + dst_sample_stride * height;
1560         dst_u = dst_v + halfstride * height;
1561       } else {
1562         dst_u = dst_sample + dst_sample_stride * height;
1563         dst_v = dst_u + halfstride * height;
1564       }
1565       r = I420ToI422(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1566                      dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
1567                      width, height);
1568       break;
1569     }
1570     case FOURCC_I444:
1571     case FOURCC_YV24: {
1572       dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1573       uint8_t* dst_u;
1574       uint8_t* dst_v;
1575       if (format == FOURCC_YV24) {
1576         dst_v = dst_sample + dst_sample_stride * height;
1577         dst_u = dst_v + dst_sample_stride * height;
1578       } else {
1579         dst_u = dst_sample + dst_sample_stride * height;
1580         dst_v = dst_u + dst_sample_stride * height;
1581       }
1582       r = I420ToI444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1583                      dst_sample_stride, dst_u, dst_sample_stride, dst_v,
1584                      dst_sample_stride, width, height);
1585       break;
1586     }
1587     // Formats not supported - MJPG, biplanar, some rgb formats.
1588     default:
1589       return -1;  // unknown fourcc - return failure code.
1590   }
1591   return r;
1592 }
1593 
1594 #ifdef __cplusplus
1595 }  // extern "C"
1596 }  // namespace libyuv
1597 #endif
1598