• 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 // Convert I422 to RGB565.
894 LIBYUV_API
I422ToRGB565(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)895 int I422ToRGB565(const uint8* src_y,
896                  int src_stride_y,
897                  const uint8* src_u,
898                  int src_stride_u,
899                  const uint8* src_v,
900                  int src_stride_v,
901                  uint8* dst_rgb565,
902                  int dst_stride_rgb565,
903                  int width,
904                  int height) {
905   int y;
906   void (*I422ToRGB565Row)(const uint8* y_buf, const uint8* u_buf,
907                           const uint8* v_buf, uint8* rgb_buf,
908                           const struct YuvConstants* yuvconstants, int width) =
909       I422ToRGB565Row_C;
910   if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
911     return -1;
912   }
913   // Negative height means invert the image.
914   if (height < 0) {
915     height = -height;
916     dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
917     dst_stride_rgb565 = -dst_stride_rgb565;
918   }
919 #if defined(HAS_I422TORGB565ROW_SSSE3)
920   if (TestCpuFlag(kCpuHasSSSE3)) {
921     I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
922     if (IS_ALIGNED(width, 8)) {
923       I422ToRGB565Row = I422ToRGB565Row_SSSE3;
924     }
925   }
926 #endif
927 #if defined(HAS_I422TORGB565ROW_AVX2)
928   if (TestCpuFlag(kCpuHasAVX2)) {
929     I422ToRGB565Row = I422ToRGB565Row_Any_AVX2;
930     if (IS_ALIGNED(width, 16)) {
931       I422ToRGB565Row = I422ToRGB565Row_AVX2;
932     }
933   }
934 #endif
935 #if defined(HAS_I422TORGB565ROW_NEON)
936   if (TestCpuFlag(kCpuHasNEON)) {
937     I422ToRGB565Row = I422ToRGB565Row_Any_NEON;
938     if (IS_ALIGNED(width, 8)) {
939       I422ToRGB565Row = I422ToRGB565Row_NEON;
940     }
941   }
942 #endif
943 #if defined(HAS_I422TORGB565ROW_MSA)
944   if (TestCpuFlag(kCpuHasMSA)) {
945     I422ToRGB565Row = I422ToRGB565Row_Any_MSA;
946     if (IS_ALIGNED(width, 8)) {
947       I422ToRGB565Row = I422ToRGB565Row_MSA;
948     }
949   }
950 #endif
951 
952   for (y = 0; y < height; ++y) {
953     I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, &kYuvI601Constants, width);
954     dst_rgb565 += dst_stride_rgb565;
955     src_y += src_stride_y;
956     src_u += src_stride_u;
957     src_v += src_stride_v;
958   }
959   return 0;
960 }
961 
962 // Ordered 8x8 dither for 888 to 565.  Values from 0 to 7.
963 static const uint8 kDither565_4x4[16] = {
964     0, 4, 1, 5, 6, 2, 7, 3, 1, 5, 0, 4, 7, 3, 6, 2,
965 };
966 
967 // Convert I420 to RGB565 with dithering.
968 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)969 int I420ToRGB565Dither(const uint8* src_y,
970                        int src_stride_y,
971                        const uint8* src_u,
972                        int src_stride_u,
973                        const uint8* src_v,
974                        int src_stride_v,
975                        uint8* dst_rgb565,
976                        int dst_stride_rgb565,
977                        const uint8* dither4x4,
978                        int width,
979                        int height) {
980   int y;
981   void (*I422ToARGBRow)(const uint8* y_buf, const uint8* u_buf,
982                         const uint8* v_buf, uint8* rgb_buf,
983                         const struct YuvConstants* yuvconstants, int width) =
984       I422ToARGBRow_C;
985   void (*ARGBToRGB565DitherRow)(const uint8* src_argb, uint8* dst_rgb,
986                                 const uint32 dither4, int width) =
987       ARGBToRGB565DitherRow_C;
988   if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
989     return -1;
990   }
991   // Negative height means invert the image.
992   if (height < 0) {
993     height = -height;
994     dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
995     dst_stride_rgb565 = -dst_stride_rgb565;
996   }
997   if (!dither4x4) {
998     dither4x4 = kDither565_4x4;
999   }
1000 #if defined(HAS_I422TOARGBROW_SSSE3)
1001   if (TestCpuFlag(kCpuHasSSSE3)) {
1002     I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
1003     if (IS_ALIGNED(width, 8)) {
1004       I422ToARGBRow = I422ToARGBRow_SSSE3;
1005     }
1006   }
1007 #endif
1008 #if defined(HAS_I422TOARGBROW_AVX2)
1009   if (TestCpuFlag(kCpuHasAVX2)) {
1010     I422ToARGBRow = I422ToARGBRow_Any_AVX2;
1011     if (IS_ALIGNED(width, 16)) {
1012       I422ToARGBRow = I422ToARGBRow_AVX2;
1013     }
1014   }
1015 #endif
1016 #if defined(HAS_I422TOARGBROW_NEON)
1017   if (TestCpuFlag(kCpuHasNEON)) {
1018     I422ToARGBRow = I422ToARGBRow_Any_NEON;
1019     if (IS_ALIGNED(width, 8)) {
1020       I422ToARGBRow = I422ToARGBRow_NEON;
1021     }
1022   }
1023 #endif
1024 #if defined(HAS_I422TOARGBROW_DSPR2)
1025   if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) &&
1026       IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
1027       IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
1028       IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2)) {
1029     I422ToARGBRow = I422ToARGBRow_DSPR2;
1030   }
1031 #endif
1032 #if defined(HAS_I422TOARGBROW_MSA)
1033   if (TestCpuFlag(kCpuHasMSA)) {
1034     I422ToARGBRow = I422ToARGBRow_Any_MSA;
1035     if (IS_ALIGNED(width, 8)) {
1036       I422ToARGBRow = I422ToARGBRow_MSA;
1037     }
1038   }
1039 #endif
1040 #if defined(HAS_ARGBTORGB565DITHERROW_SSE2)
1041   if (TestCpuFlag(kCpuHasSSE2)) {
1042     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_SSE2;
1043     if (IS_ALIGNED(width, 4)) {
1044       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_SSE2;
1045     }
1046   }
1047 #endif
1048 #if defined(HAS_ARGBTORGB565DITHERROW_AVX2)
1049   if (TestCpuFlag(kCpuHasAVX2)) {
1050     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_AVX2;
1051     if (IS_ALIGNED(width, 8)) {
1052       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_AVX2;
1053     }
1054   }
1055 #endif
1056 #if defined(HAS_ARGBTORGB565DITHERROW_NEON)
1057   if (TestCpuFlag(kCpuHasNEON)) {
1058     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_NEON;
1059     if (IS_ALIGNED(width, 8)) {
1060       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_NEON;
1061     }
1062   }
1063 #endif
1064 #if defined(HAS_ARGBTORGB565DITHERROW_MSA)
1065   if (TestCpuFlag(kCpuHasMSA)) {
1066     ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_MSA;
1067     if (IS_ALIGNED(width, 8)) {
1068       ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_MSA;
1069     }
1070   }
1071 #endif
1072   {
1073     // Allocate a row of argb.
1074     align_buffer_64(row_argb, width * 4);
1075     for (y = 0; y < height; ++y) {
1076       I422ToARGBRow(src_y, src_u, src_v, row_argb, &kYuvI601Constants, width);
1077       ARGBToRGB565DitherRow(row_argb, dst_rgb565,
1078                             *(uint32*)(dither4x4 + ((y & 3) << 2)),
1079                             width);  // NOLINT
1080       dst_rgb565 += dst_stride_rgb565;
1081       src_y += src_stride_y;
1082       if (y & 1) {
1083         src_u += src_stride_u;
1084         src_v += src_stride_v;
1085       }
1086     }
1087     free_aligned_buffer_64(row_argb);
1088   }
1089   return 0;
1090 }
1091 
1092 // Convert I420 to specified format
1093 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)1094 int ConvertFromI420(const uint8* y,
1095                     int y_stride,
1096                     const uint8* u,
1097                     int u_stride,
1098                     const uint8* v,
1099                     int v_stride,
1100                     uint8* dst_sample,
1101                     int dst_sample_stride,
1102                     int width,
1103                     int height,
1104                     uint32 fourcc) {
1105   uint32 format = CanonicalFourCC(fourcc);
1106   int r = 0;
1107   if (!y || !u || !v || !dst_sample || width <= 0 || height == 0) {
1108     return -1;
1109   }
1110   switch (format) {
1111     // Single plane formats
1112     case FOURCC_YUY2:
1113       r = I420ToYUY2(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1114                      dst_sample_stride ? dst_sample_stride : width * 2, width,
1115                      height);
1116       break;
1117     case FOURCC_UYVY:
1118       r = I420ToUYVY(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1119                      dst_sample_stride ? dst_sample_stride : width * 2, width,
1120                      height);
1121       break;
1122     case FOURCC_RGBP:
1123       r = I420ToRGB565(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1124                        dst_sample_stride ? dst_sample_stride : width * 2, width,
1125                        height);
1126       break;
1127     case FOURCC_RGBO:
1128       r = I420ToARGB1555(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1129                          dst_sample_stride ? dst_sample_stride : width * 2,
1130                          width, height);
1131       break;
1132     case FOURCC_R444:
1133       r = I420ToARGB4444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1134                          dst_sample_stride ? dst_sample_stride : width * 2,
1135                          width, height);
1136       break;
1137     case FOURCC_24BG:
1138       r = I420ToRGB24(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1139                       dst_sample_stride ? dst_sample_stride : width * 3, width,
1140                       height);
1141       break;
1142     case FOURCC_RAW:
1143       r = I420ToRAW(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1144                     dst_sample_stride ? dst_sample_stride : width * 3, width,
1145                     height);
1146       break;
1147     case FOURCC_ARGB:
1148       r = I420ToARGB(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1149                      dst_sample_stride ? dst_sample_stride : width * 4, width,
1150                      height);
1151       break;
1152     case FOURCC_BGRA:
1153       r = I420ToBGRA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1154                      dst_sample_stride ? dst_sample_stride : width * 4, width,
1155                      height);
1156       break;
1157     case FOURCC_ABGR:
1158       r = I420ToABGR(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1159                      dst_sample_stride ? dst_sample_stride : width * 4, width,
1160                      height);
1161       break;
1162     case FOURCC_RGBA:
1163       r = I420ToRGBA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1164                      dst_sample_stride ? dst_sample_stride : width * 4, width,
1165                      height);
1166       break;
1167     case FOURCC_I400:
1168       r = I400Copy(y, y_stride, dst_sample,
1169                    dst_sample_stride ? dst_sample_stride : width, width,
1170                    height);
1171       break;
1172     case FOURCC_NV12: {
1173       uint8* dst_uv = dst_sample + width * height;
1174       r = I420ToNV12(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1175                      dst_sample_stride ? dst_sample_stride : width, dst_uv,
1176                      dst_sample_stride ? dst_sample_stride : width, width,
1177                      height);
1178       break;
1179     }
1180     case FOURCC_NV21: {
1181       uint8* dst_vu = dst_sample + width * height;
1182       r = I420ToNV21(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1183                      dst_sample_stride ? dst_sample_stride : width, dst_vu,
1184                      dst_sample_stride ? dst_sample_stride : width, width,
1185                      height);
1186       break;
1187     }
1188     // TODO(fbarchard): Add M420.
1189     // Triplanar formats
1190     case FOURCC_I420:
1191     case FOURCC_YV12: {
1192       dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1193       int halfstride = (dst_sample_stride + 1) / 2;
1194       int halfheight = (height + 1) / 2;
1195       uint8* dst_u;
1196       uint8* dst_v;
1197       if (format == FOURCC_YV12) {
1198         dst_v = dst_sample + dst_sample_stride * height;
1199         dst_u = dst_v + halfstride * halfheight;
1200       } else {
1201         dst_u = dst_sample + dst_sample_stride * height;
1202         dst_v = dst_u + halfstride * halfheight;
1203       }
1204       r = I420Copy(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1205                    dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
1206                    width, height);
1207       break;
1208     }
1209     case FOURCC_I422:
1210     case FOURCC_YV16: {
1211       dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1212       int halfstride = (dst_sample_stride + 1) / 2;
1213       uint8* dst_u;
1214       uint8* dst_v;
1215       if (format == FOURCC_YV16) {
1216         dst_v = dst_sample + dst_sample_stride * height;
1217         dst_u = dst_v + halfstride * height;
1218       } else {
1219         dst_u = dst_sample + dst_sample_stride * height;
1220         dst_v = dst_u + halfstride * height;
1221       }
1222       r = I420ToI422(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1223                      dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
1224                      width, height);
1225       break;
1226     }
1227     case FOURCC_I444:
1228     case FOURCC_YV24: {
1229       dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1230       uint8* dst_u;
1231       uint8* dst_v;
1232       if (format == FOURCC_YV24) {
1233         dst_v = dst_sample + dst_sample_stride * height;
1234         dst_u = dst_v + dst_sample_stride * height;
1235       } else {
1236         dst_u = dst_sample + dst_sample_stride * height;
1237         dst_v = dst_u + dst_sample_stride * height;
1238       }
1239       r = I420ToI444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1240                      dst_sample_stride, dst_u, dst_sample_stride, dst_v,
1241                      dst_sample_stride, width, height);
1242       break;
1243     }
1244     // Formats not supported - MJPG, biplanar, some rgb formats.
1245     default:
1246       return -1;  // unknown fourcc - return failure code.
1247   }
1248   return r;
1249 }
1250 
1251 #ifdef __cplusplus
1252 }  // extern "C"
1253 }  // namespace libyuv
1254 #endif
1255