• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2012 The LibYuv Project Authors. All rights reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS. All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10 
11 #include "libyuv/convert_from.h"
12 
13 #include "libyuv/basic_types.h"
14 #include "libyuv/convert.h"  // For I420Copy
15 #include "libyuv/cpu_id.h"
16 #include "libyuv/planar_functions.h"
17 #include "libyuv/rotate.h"
18 #include "libyuv/row.h"
19 #include "libyuv/scale.h"  // For ScalePlane()
20 #include "libyuv/video_common.h"
21 
22 #ifdef __cplusplus
23 namespace libyuv {
24 extern "C" {
25 #endif
26 
27 #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
Abs(int v)28 static __inline int Abs(int v) {
29   return v >= 0 ? v : -v;
30 }
31 
32 // I420 To any I4xx YUV format with mirroring.
33 // TODO(fbarchard): Consider kFilterNone for Y, or CopyPlane
34 
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)35 static int I420ToI4xx(const uint8_t* src_y,
36                       int src_stride_y,
37                       const uint8_t* src_u,
38                       int src_stride_u,
39                       const uint8_t* src_v,
40                       int src_stride_v,
41                       uint8_t* dst_y,
42                       int dst_stride_y,
43                       uint8_t* dst_u,
44                       int dst_stride_u,
45                       uint8_t* dst_v,
46                       int dst_stride_v,
47                       int src_y_width,
48                       int src_y_height,
49                       int dst_uv_width,
50                       int dst_uv_height) {
51   const int dst_y_width = Abs(src_y_width);
52   const int dst_y_height = Abs(src_y_height);
53   const int src_uv_width = SUBSAMPLE(src_y_width, 1, 1);
54   const int src_uv_height = SUBSAMPLE(src_y_height, 1, 1);
55   int r;
56   if (src_y_width == 0 || src_y_height == 0 || dst_uv_width <= 0 ||
57       dst_uv_height <= 0) {
58     return -1;
59   }
60   if (dst_y) {
61     r = ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, dst_y,
62                    dst_stride_y, dst_y_width, dst_y_height, kFilterBilinear);
63     if (r != 0) {
64       return r;
65     }
66   }
67   r = ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
68                  dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
69   if (r != 0) {
70     return r;
71   }
72   r = ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
73                  dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
74   return r;
75 }
76 
77 // Convert 8 bit YUV to 10 bit.
78 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)79 int I420ToI010(const uint8_t* src_y,
80                int src_stride_y,
81                const uint8_t* src_u,
82                int src_stride_u,
83                const uint8_t* src_v,
84                int src_stride_v,
85                uint16_t* dst_y,
86                int dst_stride_y,
87                uint16_t* dst_u,
88                int dst_stride_u,
89                uint16_t* dst_v,
90                int dst_stride_v,
91                int width,
92                int height) {
93   int halfwidth = (width + 1) >> 1;
94   int halfheight = (height + 1) >> 1;
95   if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
96       height == 0) {
97     return -1;
98   }
99   // Negative height means invert the image.
100   if (height < 0) {
101     height = -height;
102     halfheight = (height + 1) >> 1;
103     src_y = src_y + (height - 1) * src_stride_y;
104     src_u = src_u + (halfheight - 1) * src_stride_u;
105     src_v = src_v + (halfheight - 1) * src_stride_v;
106     src_stride_y = -src_stride_y;
107     src_stride_u = -src_stride_u;
108     src_stride_v = -src_stride_v;
109   }
110 
111   // Convert Y plane.
112   Convert8To16Plane(src_y, src_stride_y, dst_y, dst_stride_y, 1024, width,
113                     height);
114   // Convert UV planes.
115   Convert8To16Plane(src_u, src_stride_u, dst_u, dst_stride_u, 1024, halfwidth,
116                     halfheight);
117   Convert8To16Plane(src_v, src_stride_v, dst_v, dst_stride_v, 1024, halfwidth,
118                     halfheight);
119   return 0;
120 }
121 
122 // Convert 8 bit YUV to 12 bit.
123 LIBYUV_API
I420ToI012(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)124 int I420ToI012(const uint8_t* src_y,
125                int src_stride_y,
126                const uint8_t* src_u,
127                int src_stride_u,
128                const uint8_t* src_v,
129                int src_stride_v,
130                uint16_t* dst_y,
131                int dst_stride_y,
132                uint16_t* dst_u,
133                int dst_stride_u,
134                uint16_t* dst_v,
135                int dst_stride_v,
136                int width,
137                int height) {
138   int halfwidth = (width + 1) >> 1;
139   int halfheight = (height + 1) >> 1;
140   if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
141       height == 0) {
142     return -1;
143   }
144   // Negative height means invert the image.
145   if (height < 0) {
146     height = -height;
147     halfheight = (height + 1) >> 1;
148     src_y = src_y + (height - 1) * src_stride_y;
149     src_u = src_u + (halfheight - 1) * src_stride_u;
150     src_v = src_v + (halfheight - 1) * src_stride_v;
151     src_stride_y = -src_stride_y;
152     src_stride_u = -src_stride_u;
153     src_stride_v = -src_stride_v;
154   }
155 
156   // Convert Y plane.
157   Convert8To16Plane(src_y, src_stride_y, dst_y, dst_stride_y, 4096, width,
158                     height);
159   // Convert UV planes.
160   Convert8To16Plane(src_u, src_stride_u, dst_u, dst_stride_u, 4096, halfwidth,
161                     halfheight);
162   Convert8To16Plane(src_v, src_stride_v, dst_v, dst_stride_v, 4096, halfwidth,
163                     halfheight);
164   return 0;
165 }
166 
167 // 420 chroma is 1/2 width, 1/2 height
168 // 422 chroma is 1/2 width, 1x height
169 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)170 int I420ToI422(const uint8_t* src_y,
171                int src_stride_y,
172                const uint8_t* src_u,
173                int src_stride_u,
174                const uint8_t* src_v,
175                int src_stride_v,
176                uint8_t* dst_y,
177                int dst_stride_y,
178                uint8_t* dst_u,
179                int dst_stride_u,
180                uint8_t* dst_v,
181                int dst_stride_v,
182                int width,
183                int height) {
184   const int dst_uv_width = (Abs(width) + 1) >> 1;
185   const int dst_uv_height = Abs(height);
186   return I420ToI4xx(src_y, src_stride_y, src_u, src_stride_u, src_v,
187                     src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
188                     dst_v, dst_stride_v, width, height, dst_uv_width,
189                     dst_uv_height);
190 }
191 
192 // 420 chroma is 1/2 width, 1/2 height
193 // 444 chroma is 1x width, 1x height
194 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)195 int I420ToI444(const uint8_t* src_y,
196                int src_stride_y,
197                const uint8_t* src_u,
198                int src_stride_u,
199                const uint8_t* src_v,
200                int src_stride_v,
201                uint8_t* dst_y,
202                int dst_stride_y,
203                uint8_t* dst_u,
204                int dst_stride_u,
205                uint8_t* dst_v,
206                int dst_stride_v,
207                int width,
208                int height) {
209   const int dst_uv_width = Abs(width);
210   const int dst_uv_height = Abs(height);
211   return I420ToI4xx(src_y, src_stride_y, src_u, src_stride_u, src_v,
212                     src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
213                     dst_v, dst_stride_v, width, height, dst_uv_width,
214                     dst_uv_height);
215 }
216 
217 // 420 chroma to 444 chroma, 10/12 bit version
218 LIBYUV_API
I010ToI410(const uint16_t * src_y,int src_stride_y,const uint16_t * src_u,int src_stride_u,const uint16_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)219 int I010ToI410(const uint16_t* src_y,
220                int src_stride_y,
221                const uint16_t* src_u,
222                int src_stride_u,
223                const uint16_t* src_v,
224                int src_stride_v,
225                uint16_t* dst_y,
226                int dst_stride_y,
227                uint16_t* dst_u,
228                int dst_stride_u,
229                uint16_t* dst_v,
230                int dst_stride_v,
231                int width,
232                int height) {
233   int r;
234   if (width == 0 || height == 0) {
235     return -1;
236   }
237 
238   if (dst_y) {
239     r = ScalePlane_12(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
240                       Abs(width), Abs(height), kFilterBilinear);
241     if (r != 0) {
242       return r;
243     }
244   }
245   r = ScalePlane_12(src_u, src_stride_u, SUBSAMPLE(width, 1, 1),
246                     SUBSAMPLE(height, 1, 1), dst_u, dst_stride_u, Abs(width),
247                     Abs(height), kFilterBilinear);
248   if (r != 0) {
249     return r;
250   }
251   r = ScalePlane_12(src_v, src_stride_v, SUBSAMPLE(width, 1, 1),
252                     SUBSAMPLE(height, 1, 1), dst_v, dst_stride_v, Abs(width),
253                     Abs(height), kFilterBilinear);
254   return r;
255 }
256 
257 // 422 chroma to 444 chroma, 10/12 bit version
258 LIBYUV_API
I210ToI410(const uint16_t * src_y,int src_stride_y,const uint16_t * src_u,int src_stride_u,const uint16_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)259 int I210ToI410(const uint16_t* src_y,
260                int src_stride_y,
261                const uint16_t* src_u,
262                int src_stride_u,
263                const uint16_t* src_v,
264                int src_stride_v,
265                uint16_t* dst_y,
266                int dst_stride_y,
267                uint16_t* dst_u,
268                int dst_stride_u,
269                uint16_t* dst_v,
270                int dst_stride_v,
271                int width,
272                int height) {
273   int r;
274   if (width == 0 || height == 0) {
275     return -1;
276   }
277 
278   if (dst_y) {
279     r = ScalePlane_12(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
280                       Abs(width), Abs(height), kFilterBilinear);
281     if (r != 0) {
282       return r;
283     }
284   }
285   r = ScalePlane_12(src_u, src_stride_u, SUBSAMPLE(width, 1, 1), height, dst_u,
286                     dst_stride_u, Abs(width), Abs(height), kFilterBilinear);
287   if (r != 0) {
288     return r;
289   }
290   r = ScalePlane_12(src_v, src_stride_v, SUBSAMPLE(width, 1, 1), height, dst_v,
291                     dst_stride_v, Abs(width), Abs(height), kFilterBilinear);
292   return r;
293 }
294 
295 // 422 chroma is 1/2 width, 1x height
296 // 444 chroma is 1x width, 1x height
297 LIBYUV_API
I422ToI444(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)298 int I422ToI444(const uint8_t* src_y,
299                int src_stride_y,
300                const uint8_t* src_u,
301                int src_stride_u,
302                const uint8_t* src_v,
303                int src_stride_v,
304                uint8_t* dst_y,
305                int dst_stride_y,
306                uint8_t* dst_u,
307                int dst_stride_u,
308                uint8_t* dst_v,
309                int dst_stride_v,
310                int width,
311                int height) {
312   int r;
313   if (width == 0 || height == 0) {
314     return -1;
315   }
316 
317   if (dst_y) {
318     r = ScalePlane(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
319                    Abs(width), Abs(height), kFilterBilinear);
320     if (r != 0) {
321       return r;
322     }
323   }
324   r = ScalePlane(src_u, src_stride_u, SUBSAMPLE(width, 1, 1), height, dst_u,
325                  dst_stride_u, Abs(width), Abs(height), kFilterBilinear);
326   if (r != 0) {
327     return r;
328   }
329   r = ScalePlane(src_v, src_stride_v, SUBSAMPLE(width, 1, 1), height, dst_v,
330                  dst_stride_v, Abs(width), Abs(height), kFilterBilinear);
331   return r;
332 }
333 
334 // Copy to I400. Source can be I420,422,444,400,NV12,NV21
335 LIBYUV_API
I400Copy(const uint8_t * src_y,int src_stride_y,uint8_t * dst_y,int dst_stride_y,int width,int height)336 int I400Copy(const uint8_t* src_y,
337              int src_stride_y,
338              uint8_t* dst_y,
339              int dst_stride_y,
340              int width,
341              int height) {
342   if (!src_y || !dst_y || width <= 0 || height == 0) {
343     return -1;
344   }
345   // Negative height means invert the image.
346   if (height < 0) {
347     height = -height;
348     src_y = src_y + (height - 1) * src_stride_y;
349     src_stride_y = -src_stride_y;
350   }
351   CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
352   return 0;
353 }
354 
355 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)356 int I422ToYUY2(const uint8_t* src_y,
357                int src_stride_y,
358                const uint8_t* src_u,
359                int src_stride_u,
360                const uint8_t* src_v,
361                int src_stride_v,
362                uint8_t* dst_yuy2,
363                int dst_stride_yuy2,
364                int width,
365                int height) {
366   int y;
367   void (*I422ToYUY2Row)(const uint8_t* src_y, const uint8_t* src_u,
368                         const uint8_t* src_v, uint8_t* dst_yuy2, int width) =
369       I422ToYUY2Row_C;
370   if (!src_y || !src_u || !src_v || !dst_yuy2 || width <= 0 || height == 0) {
371     return -1;
372   }
373   // Negative height means invert the image.
374   if (height < 0) {
375     height = -height;
376     dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
377     dst_stride_yuy2 = -dst_stride_yuy2;
378   }
379   // Coalesce rows.
380   if (src_stride_y == width && src_stride_u * 2 == width &&
381       src_stride_v * 2 == width && dst_stride_yuy2 == width * 2) {
382     width *= height;
383     height = 1;
384     src_stride_y = src_stride_u = src_stride_v = dst_stride_yuy2 = 0;
385   }
386 #if defined(HAS_I422TOYUY2ROW_SSE2)
387   if (TestCpuFlag(kCpuHasSSE2)) {
388     I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
389     if (IS_ALIGNED(width, 16)) {
390       I422ToYUY2Row = I422ToYUY2Row_SSE2;
391     }
392   }
393 #endif
394 #if defined(HAS_I422TOYUY2ROW_AVX2)
395   if (TestCpuFlag(kCpuHasAVX2)) {
396     I422ToYUY2Row = I422ToYUY2Row_Any_AVX2;
397     if (IS_ALIGNED(width, 32)) {
398       I422ToYUY2Row = I422ToYUY2Row_AVX2;
399     }
400   }
401 #endif
402 #if defined(HAS_I422TOYUY2ROW_NEON)
403   if (TestCpuFlag(kCpuHasNEON)) {
404     I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
405     if (IS_ALIGNED(width, 16)) {
406       I422ToYUY2Row = I422ToYUY2Row_NEON;
407     }
408   }
409 #endif
410 
411   for (y = 0; y < height; ++y) {
412     I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
413     src_y += src_stride_y;
414     src_u += src_stride_u;
415     src_v += src_stride_v;
416     dst_yuy2 += dst_stride_yuy2;
417   }
418   return 0;
419 }
420 
421 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)422 int I420ToYUY2(const uint8_t* src_y,
423                int src_stride_y,
424                const uint8_t* src_u,
425                int src_stride_u,
426                const uint8_t* src_v,
427                int src_stride_v,
428                uint8_t* dst_yuy2,
429                int dst_stride_yuy2,
430                int width,
431                int height) {
432   int y;
433   void (*I422ToYUY2Row)(const uint8_t* src_y, const uint8_t* src_u,
434                         const uint8_t* src_v, uint8_t* dst_yuy2, int width) =
435       I422ToYUY2Row_C;
436   if (!src_y || !src_u || !src_v || !dst_yuy2 || width <= 0 || height == 0) {
437     return -1;
438   }
439   // Negative height means invert the image.
440   if (height < 0) {
441     height = -height;
442     dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
443     dst_stride_yuy2 = -dst_stride_yuy2;
444   }
445 #if defined(HAS_I422TOYUY2ROW_SSE2)
446   if (TestCpuFlag(kCpuHasSSE2)) {
447     I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
448     if (IS_ALIGNED(width, 16)) {
449       I422ToYUY2Row = I422ToYUY2Row_SSE2;
450     }
451   }
452 #endif
453 #if defined(HAS_I422TOYUY2ROW_AVX2)
454   if (TestCpuFlag(kCpuHasAVX2)) {
455     I422ToYUY2Row = I422ToYUY2Row_Any_AVX2;
456     if (IS_ALIGNED(width, 32)) {
457       I422ToYUY2Row = I422ToYUY2Row_AVX2;
458     }
459   }
460 #endif
461 #if defined(HAS_I422TOYUY2ROW_NEON)
462   if (TestCpuFlag(kCpuHasNEON)) {
463     I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
464     if (IS_ALIGNED(width, 16)) {
465       I422ToYUY2Row = I422ToYUY2Row_NEON;
466     }
467   }
468 #endif
469 #if defined(HAS_I422TOYUY2ROW_MSA)
470   if (TestCpuFlag(kCpuHasMSA)) {
471     I422ToYUY2Row = I422ToYUY2Row_Any_MSA;
472     if (IS_ALIGNED(width, 32)) {
473       I422ToYUY2Row = I422ToYUY2Row_MSA;
474     }
475   }
476 #endif
477 #if defined(HAS_I422TOYUY2ROW_LSX)
478   if (TestCpuFlag(kCpuHasLSX)) {
479     I422ToYUY2Row = I422ToYUY2Row_Any_LSX;
480     if (IS_ALIGNED(width, 16)) {
481       I422ToYUY2Row = I422ToYUY2Row_LSX;
482     }
483   }
484 #endif
485 #if defined(HAS_I422TOYUY2ROW_LASX)
486   if (TestCpuFlag(kCpuHasLASX)) {
487     I422ToYUY2Row = I422ToYUY2Row_Any_LASX;
488     if (IS_ALIGNED(width, 32)) {
489       I422ToYUY2Row = I422ToYUY2Row_LASX;
490     }
491   }
492 #endif
493 
494   for (y = 0; y < height - 1; y += 2) {
495     I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
496     I422ToYUY2Row(src_y + src_stride_y, src_u, src_v,
497                   dst_yuy2 + dst_stride_yuy2, width);
498     src_y += src_stride_y * 2;
499     src_u += src_stride_u;
500     src_v += src_stride_v;
501     dst_yuy2 += dst_stride_yuy2 * 2;
502   }
503   if (height & 1) {
504     I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
505   }
506   return 0;
507 }
508 
509 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)510 int I422ToUYVY(const uint8_t* src_y,
511                int src_stride_y,
512                const uint8_t* src_u,
513                int src_stride_u,
514                const uint8_t* src_v,
515                int src_stride_v,
516                uint8_t* dst_uyvy,
517                int dst_stride_uyvy,
518                int width,
519                int height) {
520   int y;
521   void (*I422ToUYVYRow)(const uint8_t* src_y, const uint8_t* src_u,
522                         const uint8_t* src_v, uint8_t* dst_uyvy, int width) =
523       I422ToUYVYRow_C;
524   if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) {
525     return -1;
526   }
527   // Negative height means invert the image.
528   if (height < 0) {
529     height = -height;
530     dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
531     dst_stride_uyvy = -dst_stride_uyvy;
532   }
533   // Coalesce rows.
534   if (src_stride_y == width && src_stride_u * 2 == width &&
535       src_stride_v * 2 == width && dst_stride_uyvy == width * 2) {
536     width *= height;
537     height = 1;
538     src_stride_y = src_stride_u = src_stride_v = dst_stride_uyvy = 0;
539   }
540 #if defined(HAS_I422TOUYVYROW_SSE2)
541   if (TestCpuFlag(kCpuHasSSE2)) {
542     I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
543     if (IS_ALIGNED(width, 16)) {
544       I422ToUYVYRow = I422ToUYVYRow_SSE2;
545     }
546   }
547 #endif
548 #if defined(HAS_I422TOUYVYROW_AVX2)
549   if (TestCpuFlag(kCpuHasAVX2)) {
550     I422ToUYVYRow = I422ToUYVYRow_Any_AVX2;
551     if (IS_ALIGNED(width, 32)) {
552       I422ToUYVYRow = I422ToUYVYRow_AVX2;
553     }
554   }
555 #endif
556 #if defined(HAS_I422TOUYVYROW_NEON)
557   if (TestCpuFlag(kCpuHasNEON)) {
558     I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
559     if (IS_ALIGNED(width, 16)) {
560       I422ToUYVYRow = I422ToUYVYRow_NEON;
561     }
562   }
563 #endif
564 #if defined(HAS_I422TOUYVYROW_MSA)
565   if (TestCpuFlag(kCpuHasMSA)) {
566     I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
567     if (IS_ALIGNED(width, 32)) {
568       I422ToUYVYRow = I422ToUYVYRow_MSA;
569     }
570   }
571 #endif
572 #if defined(HAS_I422TOUYVYROW_LSX)
573   if (TestCpuFlag(kCpuHasLSX)) {
574     I422ToUYVYRow = I422ToUYVYRow_Any_LSX;
575     if (IS_ALIGNED(width, 16)) {
576       I422ToUYVYRow = I422ToUYVYRow_LSX;
577     }
578   }
579 #endif
580 #if defined(HAS_I422TOUYVYROW_LASX)
581   if (TestCpuFlag(kCpuHasLASX)) {
582     I422ToUYVYRow = I422ToUYVYRow_Any_LASX;
583     if (IS_ALIGNED(width, 32)) {
584       I422ToUYVYRow = I422ToUYVYRow_LASX;
585     }
586   }
587 #endif
588 
589   for (y = 0; y < height; ++y) {
590     I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
591     src_y += src_stride_y;
592     src_u += src_stride_u;
593     src_v += src_stride_v;
594     dst_uyvy += dst_stride_uyvy;
595   }
596   return 0;
597 }
598 
599 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)600 int I420ToUYVY(const uint8_t* src_y,
601                int src_stride_y,
602                const uint8_t* src_u,
603                int src_stride_u,
604                const uint8_t* src_v,
605                int src_stride_v,
606                uint8_t* dst_uyvy,
607                int dst_stride_uyvy,
608                int width,
609                int height) {
610   int y;
611   void (*I422ToUYVYRow)(const uint8_t* src_y, const uint8_t* src_u,
612                         const uint8_t* src_v, uint8_t* dst_uyvy, int width) =
613       I422ToUYVYRow_C;
614   if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) {
615     return -1;
616   }
617   // Negative height means invert the image.
618   if (height < 0) {
619     height = -height;
620     dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
621     dst_stride_uyvy = -dst_stride_uyvy;
622   }
623 #if defined(HAS_I422TOUYVYROW_SSE2)
624   if (TestCpuFlag(kCpuHasSSE2)) {
625     I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
626     if (IS_ALIGNED(width, 16)) {
627       I422ToUYVYRow = I422ToUYVYRow_SSE2;
628     }
629   }
630 #endif
631 #if defined(HAS_I422TOUYVYROW_AVX2)
632   if (TestCpuFlag(kCpuHasAVX2)) {
633     I422ToUYVYRow = I422ToUYVYRow_Any_AVX2;
634     if (IS_ALIGNED(width, 32)) {
635       I422ToUYVYRow = I422ToUYVYRow_AVX2;
636     }
637   }
638 #endif
639 #if defined(HAS_I422TOUYVYROW_NEON)
640   if (TestCpuFlag(kCpuHasNEON)) {
641     I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
642     if (IS_ALIGNED(width, 16)) {
643       I422ToUYVYRow = I422ToUYVYRow_NEON;
644     }
645   }
646 #endif
647 #if defined(HAS_I422TOUYVYROW_MSA)
648   if (TestCpuFlag(kCpuHasMSA)) {
649     I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
650     if (IS_ALIGNED(width, 32)) {
651       I422ToUYVYRow = I422ToUYVYRow_MSA;
652     }
653   }
654 #endif
655 #if defined(HAS_I422TOUYVYROW_LSX)
656   if (TestCpuFlag(kCpuHasLSX)) {
657     I422ToUYVYRow = I422ToUYVYRow_Any_LSX;
658     if (IS_ALIGNED(width, 16)) {
659       I422ToUYVYRow = I422ToUYVYRow_LSX;
660     }
661   }
662 #endif
663 #if defined(HAS_I422TOUYVYROW_LASX)
664   if (TestCpuFlag(kCpuHasLASX)) {
665     I422ToUYVYRow = I422ToUYVYRow_Any_LASX;
666     if (IS_ALIGNED(width, 32)) {
667       I422ToUYVYRow = I422ToUYVYRow_LASX;
668     }
669   }
670 #endif
671 
672   for (y = 0; y < height - 1; y += 2) {
673     I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
674     I422ToUYVYRow(src_y + src_stride_y, src_u, src_v,
675                   dst_uyvy + dst_stride_uyvy, width);
676     src_y += src_stride_y * 2;
677     src_u += src_stride_u;
678     src_v += src_stride_v;
679     dst_uyvy += dst_stride_uyvy * 2;
680   }
681   if (height & 1) {
682     I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
683   }
684   return 0;
685 }
686 
687 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)688 int I420ToNV12(const uint8_t* src_y,
689                int src_stride_y,
690                const uint8_t* src_u,
691                int src_stride_u,
692                const uint8_t* src_v,
693                int src_stride_v,
694                uint8_t* dst_y,
695                int dst_stride_y,
696                uint8_t* dst_uv,
697                int dst_stride_uv,
698                int width,
699                int height) {
700   int halfwidth = (width + 1) / 2;
701   int halfheight = (height + 1) / 2;
702   if (!src_y || !src_u || !src_v || !dst_uv || width <= 0 || height == 0) {
703     return -1;
704   }
705   // Negative height means invert the image.
706   if (height < 0) {
707     height = -height;
708     halfheight = (height + 1) >> 1;
709     src_y = src_y + (height - 1) * src_stride_y;
710     src_u = src_u + (halfheight - 1) * src_stride_u;
711     src_v = src_v + (halfheight - 1) * src_stride_v;
712     src_stride_y = -src_stride_y;
713     src_stride_u = -src_stride_u;
714     src_stride_v = -src_stride_v;
715   }
716   if (dst_y) {
717     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
718   }
719   MergeUVPlane(src_u, src_stride_u, src_v, src_stride_v, dst_uv, dst_stride_uv,
720                halfwidth, halfheight);
721   return 0;
722 }
723 
724 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)725 int I420ToNV21(const uint8_t* src_y,
726                int src_stride_y,
727                const uint8_t* src_u,
728                int src_stride_u,
729                const uint8_t* src_v,
730                int src_stride_v,
731                uint8_t* dst_y,
732                int dst_stride_y,
733                uint8_t* dst_vu,
734                int dst_stride_vu,
735                int width,
736                int height) {
737   return I420ToNV12(src_y, src_stride_y, src_v, src_stride_v, src_u,
738                     src_stride_u, dst_y, dst_stride_y, dst_vu, dst_stride_vu,
739                     width, height);
740 }
741 
742 // Convert I420 to specified format
743 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)744 int ConvertFromI420(const uint8_t* y,
745                     int y_stride,
746                     const uint8_t* u,
747                     int u_stride,
748                     const uint8_t* v,
749                     int v_stride,
750                     uint8_t* dst_sample,
751                     int dst_sample_stride,
752                     int width,
753                     int height,
754                     uint32_t fourcc) {
755   uint32_t format = CanonicalFourCC(fourcc);
756   int r = 0;
757   if (!y || !u || !v || !dst_sample || width <= 0 || height == 0) {
758     return -1;
759   }
760   switch (format) {
761     // Single plane formats
762     case FOURCC_YUY2:
763       r = I420ToYUY2(y, y_stride, u, u_stride, v, v_stride, dst_sample,
764                      dst_sample_stride ? dst_sample_stride : width * 2, width,
765                      height);
766       break;
767     case FOURCC_UYVY:
768       r = I420ToUYVY(y, y_stride, u, u_stride, v, v_stride, dst_sample,
769                      dst_sample_stride ? dst_sample_stride : width * 2, width,
770                      height);
771       break;
772     case FOURCC_RGBP:
773       r = I420ToRGB565(y, y_stride, u, u_stride, v, v_stride, dst_sample,
774                        dst_sample_stride ? dst_sample_stride : width * 2, width,
775                        height);
776       break;
777     case FOURCC_RGBO:
778       r = I420ToARGB1555(y, y_stride, u, u_stride, v, v_stride, dst_sample,
779                          dst_sample_stride ? dst_sample_stride : width * 2,
780                          width, height);
781       break;
782     case FOURCC_R444:
783       r = I420ToARGB4444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
784                          dst_sample_stride ? dst_sample_stride : width * 2,
785                          width, height);
786       break;
787     case FOURCC_24BG:
788       r = I420ToRGB24(y, y_stride, u, u_stride, v, v_stride, dst_sample,
789                       dst_sample_stride ? dst_sample_stride : width * 3, width,
790                       height);
791       break;
792     case FOURCC_RAW:
793       r = I420ToRAW(y, y_stride, u, u_stride, v, v_stride, dst_sample,
794                     dst_sample_stride ? dst_sample_stride : width * 3, width,
795                     height);
796       break;
797     case FOURCC_ARGB:
798       r = I420ToARGB(y, y_stride, u, u_stride, v, v_stride, dst_sample,
799                      dst_sample_stride ? dst_sample_stride : width * 4, width,
800                      height);
801       break;
802     case FOURCC_BGRA:
803       r = I420ToBGRA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
804                      dst_sample_stride ? dst_sample_stride : width * 4, width,
805                      height);
806       break;
807     case FOURCC_ABGR:
808       r = I420ToABGR(y, y_stride, u, u_stride, v, v_stride, dst_sample,
809                      dst_sample_stride ? dst_sample_stride : width * 4, width,
810                      height);
811       break;
812     case FOURCC_RGBA:
813       r = I420ToRGBA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
814                      dst_sample_stride ? dst_sample_stride : width * 4, width,
815                      height);
816       break;
817     case FOURCC_AR30:
818       r = I420ToAR30(y, y_stride, u, u_stride, v, v_stride, dst_sample,
819                      dst_sample_stride ? dst_sample_stride : width * 4, width,
820                      height);
821       break;
822     case FOURCC_I400:
823       r = I400Copy(y, y_stride, dst_sample,
824                    dst_sample_stride ? dst_sample_stride : width, width,
825                    height);
826       break;
827     case FOURCC_NV12: {
828       int dst_y_stride = dst_sample_stride ? dst_sample_stride : width;
829       uint8_t* dst_uv = dst_sample + dst_y_stride * height;
830       r = I420ToNV12(y, y_stride, u, u_stride, v, v_stride, dst_sample,
831                      dst_sample_stride ? dst_sample_stride : width, dst_uv,
832                      dst_sample_stride ? dst_sample_stride : width, width,
833                      height);
834       break;
835     }
836     case FOURCC_NV21: {
837       int dst_y_stride = dst_sample_stride ? dst_sample_stride : width;
838       uint8_t* dst_vu = dst_sample + dst_y_stride * height;
839       r = I420ToNV21(y, y_stride, u, u_stride, v, v_stride, dst_sample,
840                      dst_sample_stride ? dst_sample_stride : width, dst_vu,
841                      dst_sample_stride ? dst_sample_stride : width, width,
842                      height);
843       break;
844     }
845     // Triplanar formats
846     case FOURCC_I420:
847     case FOURCC_YV12: {
848       dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
849       int halfstride = (dst_sample_stride + 1) / 2;
850       int halfheight = (height + 1) / 2;
851       uint8_t* dst_u;
852       uint8_t* dst_v;
853       if (format == FOURCC_YV12) {
854         dst_v = dst_sample + dst_sample_stride * height;
855         dst_u = dst_v + halfstride * halfheight;
856       } else {
857         dst_u = dst_sample + dst_sample_stride * height;
858         dst_v = dst_u + halfstride * halfheight;
859       }
860       r = I420Copy(y, y_stride, u, u_stride, v, v_stride, dst_sample,
861                    dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
862                    width, height);
863       break;
864     }
865     case FOURCC_I422:
866     case FOURCC_YV16: {
867       dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
868       int halfstride = (dst_sample_stride + 1) / 2;
869       uint8_t* dst_u;
870       uint8_t* dst_v;
871       if (format == FOURCC_YV16) {
872         dst_v = dst_sample + dst_sample_stride * height;
873         dst_u = dst_v + halfstride * height;
874       } else {
875         dst_u = dst_sample + dst_sample_stride * height;
876         dst_v = dst_u + halfstride * height;
877       }
878       r = I420ToI422(y, y_stride, u, u_stride, v, v_stride, dst_sample,
879                      dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
880                      width, height);
881       break;
882     }
883     case FOURCC_I444:
884     case FOURCC_YV24: {
885       dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
886       uint8_t* dst_u;
887       uint8_t* dst_v;
888       if (format == FOURCC_YV24) {
889         dst_v = dst_sample + dst_sample_stride * height;
890         dst_u = dst_v + dst_sample_stride * height;
891       } else {
892         dst_u = dst_sample + dst_sample_stride * height;
893         dst_v = dst_u + dst_sample_stride * height;
894       }
895       r = I420ToI444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
896                      dst_sample_stride, dst_u, dst_sample_stride, dst_v,
897                      dst_sample_stride, width, height);
898       break;
899     }
900     // Formats not supported - MJPG, biplanar, some rgb formats.
901     default:
902       return -1;  // unknown fourcc - return failure code.
903   }
904   return r;
905 }
906 
907 #ifdef __cplusplus
908 }  // extern "C"
909 }  // namespace libyuv
910 #endif
911