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