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