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