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