• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *  Copyright 2011 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.h"
12 
13 #include "libyuv/basic_types.h"
14 #include "libyuv/cpu_id.h"
15 #include "libyuv/planar_functions.h"
16 #include "libyuv/rotate.h"
17 #include "libyuv/row.h"
18 #include "libyuv/scale.h"      // For ScalePlane()
19 #include "libyuv/scale_row.h"  // For FixedDiv
20 #include "libyuv/scale_uv.h"   // For UVScale()
21 
22 #ifdef __cplusplus
23 namespace libyuv {
24 extern "C" {
25 #endif
26 
27 // Subsample amount uses a shift.
28 //   v is value
29 //   a is amount to add to round up
30 //   s is shift to subsample down
31 #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
Abs(int v)32 static __inline int Abs(int v) {
33   return v >= 0 ? v : -v;
34 }
35 
36 // Any I4xx To I420 format with mirroring.
I4xxToI420(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 src_uv_width,int src_uv_height)37 static int I4xxToI420(const uint8_t* src_y,
38                       int src_stride_y,
39                       const uint8_t* src_u,
40                       int src_stride_u,
41                       const uint8_t* src_v,
42                       int src_stride_v,
43                       uint8_t* dst_y,
44                       int dst_stride_y,
45                       uint8_t* dst_u,
46                       int dst_stride_u,
47                       uint8_t* dst_v,
48                       int dst_stride_v,
49                       int src_y_width,
50                       int src_y_height,
51                       int src_uv_width,
52                       int src_uv_height) {
53   const int dst_y_width = Abs(src_y_width);
54   const int dst_y_height = Abs(src_y_height);
55   const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
56   const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
57   int r;
58   if (src_uv_width <= 0 || src_uv_height == 0) {
59     return -1;
60   }
61   if (dst_y) {
62     r = ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, dst_y,
63                    dst_stride_y, dst_y_width, dst_y_height, kFilterBilinear);
64     if (r != 0) {
65       return r;
66     }
67   }
68   r = ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
69                  dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
70   if (r != 0) {
71     return r;
72   }
73   r = ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
74                  dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
75   return r;
76 }
77 
78 // Copy I420 with optional flipping.
79 // TODO(fbarchard): Use Scale plane which supports mirroring, but ensure
80 // is does row coalescing.
81 LIBYUV_API
I420Copy(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)82 int I420Copy(const uint8_t* src_y,
83              int src_stride_y,
84              const uint8_t* src_u,
85              int src_stride_u,
86              const uint8_t* src_v,
87              int src_stride_v,
88              uint8_t* dst_y,
89              int dst_stride_y,
90              uint8_t* dst_u,
91              int dst_stride_u,
92              uint8_t* dst_v,
93              int dst_stride_v,
94              int width,
95              int height) {
96   int halfwidth = (width + 1) >> 1;
97   int halfheight = (height + 1) >> 1;
98   if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
99       height == 0) {
100     return -1;
101   }
102   // Negative height means invert the image.
103   if (height < 0) {
104     height = -height;
105     halfheight = (height + 1) >> 1;
106     src_y = src_y + (height - 1) * src_stride_y;
107     src_u = src_u + (halfheight - 1) * src_stride_u;
108     src_v = src_v + (halfheight - 1) * src_stride_v;
109     src_stride_y = -src_stride_y;
110     src_stride_u = -src_stride_u;
111     src_stride_v = -src_stride_v;
112   }
113 
114   if (dst_y) {
115     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
116   }
117   // Copy UV planes.
118   CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
119   CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
120   return 0;
121 }
122 
123 // Copy I010 with optional flipping.
124 LIBYUV_API
I010Copy(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)125 int I010Copy(const uint16_t* src_y,
126              int src_stride_y,
127              const uint16_t* src_u,
128              int src_stride_u,
129              const uint16_t* src_v,
130              int src_stride_v,
131              uint16_t* dst_y,
132              int dst_stride_y,
133              uint16_t* dst_u,
134              int dst_stride_u,
135              uint16_t* dst_v,
136              int dst_stride_v,
137              int width,
138              int height) {
139   int halfwidth = (width + 1) >> 1;
140   int halfheight = (height + 1) >> 1;
141   if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
142       height == 0) {
143     return -1;
144   }
145   // Negative height means invert the image.
146   if (height < 0) {
147     height = -height;
148     halfheight = (height + 1) >> 1;
149     src_y = src_y + (height - 1) * src_stride_y;
150     src_u = src_u + (halfheight - 1) * src_stride_u;
151     src_v = src_v + (halfheight - 1) * src_stride_v;
152     src_stride_y = -src_stride_y;
153     src_stride_u = -src_stride_u;
154     src_stride_v = -src_stride_v;
155   }
156 
157   if (dst_y) {
158     CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
159   }
160   // Copy UV planes.
161   CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
162   CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
163   return 0;
164 }
165 
Planar16bitTo8bit(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,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,int subsample_x,int subsample_y,int depth)166 static int Planar16bitTo8bit(const uint16_t* src_y,
167                              int src_stride_y,
168                              const uint16_t* src_u,
169                              int src_stride_u,
170                              const uint16_t* src_v,
171                              int src_stride_v,
172                              uint8_t* dst_y,
173                              int dst_stride_y,
174                              uint8_t* dst_u,
175                              int dst_stride_u,
176                              uint8_t* dst_v,
177                              int dst_stride_v,
178                              int width,
179                              int height,
180                              int subsample_x,
181                              int subsample_y,
182                              int depth) {
183   int uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
184   int uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
185   int scale = 1 << (24 - depth);
186   if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
187       height == 0) {
188     return -1;
189   }
190   // Negative height means invert the image.
191   if (height < 0) {
192     height = -height;
193     uv_height = -uv_height;
194     src_y = src_y + (height - 1) * src_stride_y;
195     src_u = src_u + (uv_height - 1) * src_stride_u;
196     src_v = src_v + (uv_height - 1) * src_stride_v;
197     src_stride_y = -src_stride_y;
198     src_stride_u = -src_stride_u;
199     src_stride_v = -src_stride_v;
200   }
201 
202   // Convert Y plane.
203   Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
204                     height);
205   // Convert UV planes.
206   Convert16To8Plane(src_u, src_stride_u, dst_u, dst_stride_u, scale, uv_width,
207                     uv_height);
208   Convert16To8Plane(src_v, src_stride_v, dst_v, dst_stride_v, scale, uv_width,
209                     uv_height);
210   return 0;
211 }
212 
I41xToI420(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,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,int depth)213 static int I41xToI420(const uint16_t* src_y,
214                       int src_stride_y,
215                       const uint16_t* src_u,
216                       int src_stride_u,
217                       const uint16_t* src_v,
218                       int src_stride_v,
219                       uint8_t* dst_y,
220                       int dst_stride_y,
221                       uint8_t* dst_u,
222                       int dst_stride_u,
223                       uint8_t* dst_v,
224                       int dst_stride_v,
225                       int width,
226                       int height,
227                       int depth) {
228   const int scale = 1 << (24 - depth);
229 
230   if (width <= 0 || height == 0) {
231     return -1;
232   }
233   // Negative height means invert the image.
234   if (height < 0) {
235     height = -height;
236     src_y = src_y + (height - 1) * src_stride_y;
237     src_u = src_u + (height - 1) * src_stride_u;
238     src_v = src_v + (height - 1) * src_stride_v;
239     src_stride_y = -src_stride_y;
240     src_stride_u = -src_stride_u;
241     src_stride_v = -src_stride_v;
242   }
243 
244   {
245     const int uv_width = SUBSAMPLE(width, 1, 1);
246     const int uv_height = SUBSAMPLE(height, 1, 1);
247 
248     Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
249                       height);
250     ScalePlaneDown2_16To8(width, height, uv_width, uv_height, src_stride_u,
251                           dst_stride_u, src_u, dst_u, scale, kFilterBilinear);
252     ScalePlaneDown2_16To8(width, height, uv_width, uv_height, src_stride_v,
253                           dst_stride_v, src_v, dst_v, scale, kFilterBilinear);
254   }
255   return 0;
256 }
257 
I21xToI420(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,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,int depth)258 static int I21xToI420(const uint16_t* src_y,
259                       int src_stride_y,
260                       const uint16_t* src_u,
261                       int src_stride_u,
262                       const uint16_t* src_v,
263                       int src_stride_v,
264                       uint8_t* dst_y,
265                       int dst_stride_y,
266                       uint8_t* dst_u,
267                       int dst_stride_u,
268                       uint8_t* dst_v,
269                       int dst_stride_v,
270                       int width,
271                       int height,
272                       int depth) {
273   const int scale = 1 << (24 - depth);
274 
275   if (width <= 0 || height == 0) {
276     return -1;
277   }
278   // Negative height means invert the image.
279   if (height < 0) {
280     height = -height;
281     src_y = src_y + (height - 1) * src_stride_y;
282     src_u = src_u + (height - 1) * src_stride_u;
283     src_v = src_v + (height - 1) * src_stride_v;
284     src_stride_y = -src_stride_y;
285     src_stride_u = -src_stride_u;
286     src_stride_v = -src_stride_v;
287   }
288 
289   {
290     const int uv_width = SUBSAMPLE(width, 1, 1);
291     const int uv_height = SUBSAMPLE(height, 1, 1);
292     const int dy = FixedDiv(height, uv_height);
293 
294     Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, scale, width,
295                       height);
296     ScalePlaneVertical_16To8(height, uv_width, uv_height, src_stride_u,
297                              dst_stride_u, src_u, dst_u, 0, 32768, dy,
298                              /*bpp=*/1, scale, kFilterBilinear);
299     ScalePlaneVertical_16To8(height, uv_width, uv_height, src_stride_v,
300                              dst_stride_v, src_v, dst_v, 0, 32768, dy,
301                              /*bpp=*/1, scale, kFilterBilinear);
302   }
303   return 0;
304 }
305 
306 // Convert 10 bit YUV to 8 bit.
307 LIBYUV_API
I010ToI420(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,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)308 int I010ToI420(const uint16_t* src_y,
309                int src_stride_y,
310                const uint16_t* src_u,
311                int src_stride_u,
312                const uint16_t* src_v,
313                int src_stride_v,
314                uint8_t* dst_y,
315                int dst_stride_y,
316                uint8_t* dst_u,
317                int dst_stride_u,
318                uint8_t* dst_v,
319                int dst_stride_v,
320                int width,
321                int height) {
322   return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
323                            src_stride_v, dst_y, dst_stride_y, dst_u,
324                            dst_stride_u, dst_v, dst_stride_v, width, height, 1,
325                            1, 10);
326 }
327 
328 LIBYUV_API
I210ToI420(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,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)329 int I210ToI420(const uint16_t* src_y,
330                int src_stride_y,
331                const uint16_t* src_u,
332                int src_stride_u,
333                const uint16_t* src_v,
334                int src_stride_v,
335                uint8_t* dst_y,
336                int dst_stride_y,
337                uint8_t* dst_u,
338                int dst_stride_u,
339                uint8_t* dst_v,
340                int dst_stride_v,
341                int width,
342                int height) {
343   return I21xToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
344                     src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
345                     dst_v, dst_stride_v, width, height, 10);
346 }
347 
348 LIBYUV_API
I210ToI422(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,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)349 int I210ToI422(const uint16_t* src_y,
350                int src_stride_y,
351                const uint16_t* src_u,
352                int src_stride_u,
353                const uint16_t* src_v,
354                int src_stride_v,
355                uint8_t* dst_y,
356                int dst_stride_y,
357                uint8_t* dst_u,
358                int dst_stride_u,
359                uint8_t* dst_v,
360                int dst_stride_v,
361                int width,
362                int height) {
363   return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
364                            src_stride_v, dst_y, dst_stride_y, dst_u,
365                            dst_stride_u, dst_v, dst_stride_v, width, height, 1,
366                            0, 10);
367 }
368 
369 LIBYUV_API
I410ToI420(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,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)370 int I410ToI420(const uint16_t* src_y,
371                int src_stride_y,
372                const uint16_t* src_u,
373                int src_stride_u,
374                const uint16_t* src_v,
375                int src_stride_v,
376                uint8_t* dst_y,
377                int dst_stride_y,
378                uint8_t* dst_u,
379                int dst_stride_u,
380                uint8_t* dst_v,
381                int dst_stride_v,
382                int width,
383                int height) {
384   return I41xToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
385                     src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
386                     dst_v, dst_stride_v, width, height, 10);
387 }
388 
389 LIBYUV_API
I410ToI444(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,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)390 int I410ToI444(const uint16_t* src_y,
391                int src_stride_y,
392                const uint16_t* src_u,
393                int src_stride_u,
394                const uint16_t* src_v,
395                int src_stride_v,
396                uint8_t* dst_y,
397                int dst_stride_y,
398                uint8_t* dst_u,
399                int dst_stride_u,
400                uint8_t* dst_v,
401                int dst_stride_v,
402                int width,
403                int height) {
404   return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
405                            src_stride_v, dst_y, dst_stride_y, dst_u,
406                            dst_stride_u, dst_v, dst_stride_v, width, height, 0,
407                            0, 10);
408 }
409 
410 LIBYUV_API
I012ToI420(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,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)411 int I012ToI420(const uint16_t* src_y,
412                int src_stride_y,
413                const uint16_t* src_u,
414                int src_stride_u,
415                const uint16_t* src_v,
416                int src_stride_v,
417                uint8_t* dst_y,
418                int dst_stride_y,
419                uint8_t* dst_u,
420                int dst_stride_u,
421                uint8_t* dst_v,
422                int dst_stride_v,
423                int width,
424                int height) {
425   return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
426                            src_stride_v, dst_y, dst_stride_y, dst_u,
427                            dst_stride_u, dst_v, dst_stride_v, width, height, 1,
428                            1, 12);
429 }
430 
431 LIBYUV_API
I212ToI422(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,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)432 int I212ToI422(const uint16_t* src_y,
433                int src_stride_y,
434                const uint16_t* src_u,
435                int src_stride_u,
436                const uint16_t* src_v,
437                int src_stride_v,
438                uint8_t* dst_y,
439                int dst_stride_y,
440                uint8_t* dst_u,
441                int dst_stride_u,
442                uint8_t* dst_v,
443                int dst_stride_v,
444                int width,
445                int height) {
446   return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
447                            src_stride_v, dst_y, dst_stride_y, dst_u,
448                            dst_stride_u, dst_v, dst_stride_v, width, height, 1,
449                            0, 12);
450 }
451 
452 LIBYUV_API
I212ToI420(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,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)453 int I212ToI420(const uint16_t* src_y,
454                int src_stride_y,
455                const uint16_t* src_u,
456                int src_stride_u,
457                const uint16_t* src_v,
458                int src_stride_v,
459                uint8_t* dst_y,
460                int dst_stride_y,
461                uint8_t* dst_u,
462                int dst_stride_u,
463                uint8_t* dst_v,
464                int dst_stride_v,
465                int width,
466                int height) {
467   return I21xToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
468                     src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
469                     dst_v, dst_stride_v, width, height, 12);
470 }
471 
472 LIBYUV_API
I412ToI444(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,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)473 int I412ToI444(const uint16_t* src_y,
474                int src_stride_y,
475                const uint16_t* src_u,
476                int src_stride_u,
477                const uint16_t* src_v,
478                int src_stride_v,
479                uint8_t* dst_y,
480                int dst_stride_y,
481                uint8_t* dst_u,
482                int dst_stride_u,
483                uint8_t* dst_v,
484                int dst_stride_v,
485                int width,
486                int height) {
487   return Planar16bitTo8bit(src_y, src_stride_y, src_u, src_stride_u, src_v,
488                            src_stride_v, dst_y, dst_stride_y, dst_u,
489                            dst_stride_u, dst_v, dst_stride_v, width, height, 0,
490                            0, 12);
491 }
492 
493 LIBYUV_API
I412ToI420(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,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)494 int I412ToI420(const uint16_t* src_y,
495                int src_stride_y,
496                const uint16_t* src_u,
497                int src_stride_u,
498                const uint16_t* src_v,
499                int src_stride_v,
500                uint8_t* dst_y,
501                int dst_stride_y,
502                uint8_t* dst_u,
503                int dst_stride_u,
504                uint8_t* dst_v,
505                int dst_stride_v,
506                int width,
507                int height) {
508   return I41xToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
509                     src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
510                     dst_v, dst_stride_v, width, height, 12);
511 }
512 
513 // Any Ix10 To I010 format with mirroring.
Ix10ToI010(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,int subsample_x,int subsample_y)514 static int Ix10ToI010(const uint16_t* src_y,
515                       int src_stride_y,
516                       const uint16_t* src_u,
517                       int src_stride_u,
518                       const uint16_t* src_v,
519                       int src_stride_v,
520                       uint16_t* dst_y,
521                       int dst_stride_y,
522                       uint16_t* dst_u,
523                       int dst_stride_u,
524                       uint16_t* dst_v,
525                       int dst_stride_v,
526                       int width,
527                       int height,
528                       int subsample_x,
529                       int subsample_y) {
530   const int dst_y_width = Abs(width);
531   const int dst_y_height = Abs(height);
532   const int src_uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
533   const int src_uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
534   const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
535   const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
536   int r;
537   if (width <= 0 || height == 0) {
538     return -1;
539   }
540   if (dst_y) {
541     r = ScalePlane_12(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
542                       dst_y_width, dst_y_height, kFilterBilinear);
543     if (r != 0) {
544       return r;
545     }
546   }
547   r = ScalePlane_12(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
548                     dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
549   if (r != 0) {
550     return r;
551   }
552   r = ScalePlane_12(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
553                     dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
554   return r;
555 }
556 
557 LIBYUV_API
I410ToI010(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)558 int I410ToI010(const uint16_t* src_y,
559                int src_stride_y,
560                const uint16_t* src_u,
561                int src_stride_u,
562                const uint16_t* src_v,
563                int src_stride_v,
564                uint16_t* dst_y,
565                int dst_stride_y,
566                uint16_t* dst_u,
567                int dst_stride_u,
568                uint16_t* dst_v,
569                int dst_stride_v,
570                int width,
571                int height) {
572   return Ix10ToI010(src_y, src_stride_y, src_u, src_stride_u, src_v,
573                     src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
574                     dst_v, dst_stride_v, width, height, 0, 0);
575 }
576 
577 LIBYUV_API
I210ToI010(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)578 int I210ToI010(const uint16_t* src_y,
579                int src_stride_y,
580                const uint16_t* src_u,
581                int src_stride_u,
582                const uint16_t* src_v,
583                int src_stride_v,
584                uint16_t* dst_y,
585                int dst_stride_y,
586                uint16_t* dst_u,
587                int dst_stride_u,
588                uint16_t* dst_v,
589                int dst_stride_v,
590                int width,
591                int height) {
592   return Ix10ToI010(src_y, src_stride_y, src_u, src_stride_u, src_v,
593                     src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
594                     dst_v, dst_stride_v, width, height, 1, 0);
595 }
596 
597 // Any I[420]1[02] to P[420]1[02] format with mirroring.
IxxxToPxxx(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_uv,int dst_stride_uv,int width,int height,int subsample_x,int subsample_y,int depth)598 static int IxxxToPxxx(const uint16_t* src_y,
599                       int src_stride_y,
600                       const uint16_t* src_u,
601                       int src_stride_u,
602                       const uint16_t* src_v,
603                       int src_stride_v,
604                       uint16_t* dst_y,
605                       int dst_stride_y,
606                       uint16_t* dst_uv,
607                       int dst_stride_uv,
608                       int width,
609                       int height,
610                       int subsample_x,
611                       int subsample_y,
612                       int depth) {
613   const int uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
614   const int uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
615   if (width <= 0 || height == 0) {
616     return -1;
617   }
618 
619   ConvertToMSBPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height,
620                        depth);
621   MergeUVPlane_16(src_u, src_stride_u, src_v, src_stride_v, dst_uv,
622                   dst_stride_uv, uv_width, uv_height, depth);
623   return 0;
624 }
625 
626 LIBYUV_API
I010ToP010(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_uv,int dst_stride_uv,int width,int height)627 int I010ToP010(const uint16_t* src_y,
628                int src_stride_y,
629                const uint16_t* src_u,
630                int src_stride_u,
631                const uint16_t* src_v,
632                int src_stride_v,
633                uint16_t* dst_y,
634                int dst_stride_y,
635                uint16_t* dst_uv,
636                int dst_stride_uv,
637                int width,
638                int height) {
639   return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
640                     src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
641                     width, height, 1, 1, 10);
642 }
643 
644 LIBYUV_API
I210ToP210(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_uv,int dst_stride_uv,int width,int height)645 int I210ToP210(const uint16_t* src_y,
646                int src_stride_y,
647                const uint16_t* src_u,
648                int src_stride_u,
649                const uint16_t* src_v,
650                int src_stride_v,
651                uint16_t* dst_y,
652                int dst_stride_y,
653                uint16_t* dst_uv,
654                int dst_stride_uv,
655                int width,
656                int height) {
657   return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
658                     src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
659                     width, height, 1, 0, 10);
660 }
661 
662 LIBYUV_API
I012ToP012(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_uv,int dst_stride_uv,int width,int height)663 int I012ToP012(const uint16_t* src_y,
664                int src_stride_y,
665                const uint16_t* src_u,
666                int src_stride_u,
667                const uint16_t* src_v,
668                int src_stride_v,
669                uint16_t* dst_y,
670                int dst_stride_y,
671                uint16_t* dst_uv,
672                int dst_stride_uv,
673                int width,
674                int height) {
675   return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
676                     src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
677                     width, height, 1, 1, 12);
678 }
679 
680 LIBYUV_API
I212ToP212(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_uv,int dst_stride_uv,int width,int height)681 int I212ToP212(const uint16_t* src_y,
682                int src_stride_y,
683                const uint16_t* src_u,
684                int src_stride_u,
685                const uint16_t* src_v,
686                int src_stride_v,
687                uint16_t* dst_y,
688                int dst_stride_y,
689                uint16_t* dst_uv,
690                int dst_stride_uv,
691                int width,
692                int height) {
693   return IxxxToPxxx(src_y, src_stride_y, src_u, src_stride_u, src_v,
694                     src_stride_v, dst_y, dst_stride_y, dst_uv, dst_stride_uv,
695                     width, height, 1, 0, 12);
696 }
697 
698 // 422 chroma is 1/2 width, 1x height
699 // 420 chroma is 1/2 width, 1/2 height
700 LIBYUV_API
I422ToI420(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)701 int I422ToI420(const uint8_t* src_y,
702                int src_stride_y,
703                const uint8_t* src_u,
704                int src_stride_u,
705                const uint8_t* src_v,
706                int src_stride_v,
707                uint8_t* dst_y,
708                int dst_stride_y,
709                uint8_t* dst_u,
710                int dst_stride_u,
711                uint8_t* dst_v,
712                int dst_stride_v,
713                int width,
714                int height) {
715   const int src_uv_width = SUBSAMPLE(width, 1, 1);
716   return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
717                     src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
718                     dst_v, dst_stride_v, width, height, src_uv_width, height);
719 }
720 
721 LIBYUV_API
I422ToI210(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)722 int I422ToI210(const uint8_t* src_y,
723                int src_stride_y,
724                const uint8_t* src_u,
725                int src_stride_u,
726                const uint8_t* src_v,
727                int src_stride_v,
728                uint16_t* dst_y,
729                int dst_stride_y,
730                uint16_t* dst_u,
731                int dst_stride_u,
732                uint16_t* dst_v,
733                int dst_stride_v,
734                int width,
735                int height) {
736   int halfwidth = (width + 1) >> 1;
737   if ((!src_y && dst_y) || !src_u || !src_v || !dst_u || !dst_v || width <= 0 ||
738       height == 0) {
739     return -1;
740   }
741   // Negative height means invert the image.
742   if (height < 0) {
743     height = -height;
744     src_y = src_y + (height - 1) * src_stride_y;
745     src_u = src_u + (height - 1) * src_stride_u;
746     src_v = src_v + (height - 1) * src_stride_v;
747     src_stride_y = -src_stride_y;
748     src_stride_u = -src_stride_u;
749     src_stride_v = -src_stride_v;
750   }
751 
752   // Convert Y plane.
753   Convert8To16Plane(src_y, src_stride_y, dst_y, dst_stride_y, 1024, width,
754                     height);
755   // Convert UV planes.
756   Convert8To16Plane(src_u, src_stride_u, dst_u, dst_stride_u, 1024, halfwidth,
757                     height);
758   Convert8To16Plane(src_v, src_stride_v, dst_v, dst_stride_v, 1024, halfwidth,
759                     height);
760   return 0;
761 }
762 
763 // TODO(fbarchard): Implement row conversion.
764 LIBYUV_API
I422ToNV21(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)765 int I422ToNV21(const uint8_t* src_y,
766                int src_stride_y,
767                const uint8_t* src_u,
768                int src_stride_u,
769                const uint8_t* src_v,
770                int src_stride_v,
771                uint8_t* dst_y,
772                int dst_stride_y,
773                uint8_t* dst_vu,
774                int dst_stride_vu,
775                int width,
776                int height) {
777   int halfwidth = (width + 1) >> 1;
778   int halfheight = (height + 1) >> 1;
779   // Negative height means invert the image.
780   if (height < 0) {
781     height = -height;
782     halfheight = (height + 1) >> 1;
783     src_y = src_y + (height - 1) * src_stride_y;
784     src_u = src_u + (height - 1) * src_stride_u;
785     src_v = src_v + (height - 1) * src_stride_v;
786     src_stride_y = -src_stride_y;
787     src_stride_u = -src_stride_u;
788     src_stride_v = -src_stride_v;
789   }
790 
791   // Allocate u and v buffers
792   align_buffer_64(plane_u, halfwidth * halfheight * 2);
793   uint8_t* plane_v = plane_u + halfwidth * halfheight;
794   if (!plane_u)
795     return 1;
796 
797   I422ToI420(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
798              dst_y, dst_stride_y, plane_u, halfwidth, plane_v, halfwidth, width,
799              height);
800   MergeUVPlane(plane_v, halfwidth, plane_u, halfwidth, dst_vu, dst_stride_vu,
801                halfwidth, halfheight);
802   free_aligned_buffer_64(plane_u);
803   return 0;
804 }
805 
806 LIBYUV_API
MM21ToNV12(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_uv,int dst_stride_uv,int width,int height)807 int MM21ToNV12(const uint8_t* src_y,
808                int src_stride_y,
809                const uint8_t* src_uv,
810                int src_stride_uv,
811                uint8_t* dst_y,
812                int dst_stride_y,
813                uint8_t* dst_uv,
814                int dst_stride_uv,
815                int width,
816                int height) {
817   if (!src_uv || !dst_uv || width <= 0) {
818     return -1;
819   }
820 
821   int sign = height < 0 ? -1 : 1;
822 
823   if (dst_y) {
824     DetilePlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height, 32);
825   }
826   DetilePlane(src_uv, src_stride_uv, dst_uv, dst_stride_uv, (width + 1) & ~1,
827               (height + sign) / 2, 16);
828 
829   return 0;
830 }
831 
832 LIBYUV_API
MM21ToI420(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,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)833 int MM21ToI420(const uint8_t* src_y,
834                int src_stride_y,
835                const uint8_t* src_uv,
836                int src_stride_uv,
837                uint8_t* dst_y,
838                int dst_stride_y,
839                uint8_t* dst_u,
840                int dst_stride_u,
841                uint8_t* dst_v,
842                int dst_stride_v,
843                int width,
844                int height) {
845   int sign = height < 0 ? -1 : 1;
846 
847   if (!src_uv || !dst_u || !dst_v || width <= 0) {
848     return -1;
849   }
850 
851   if (dst_y) {
852     DetilePlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height, 32);
853   }
854   DetileSplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
855                      dst_stride_v, (width + 1) & ~1, (height + sign) / 2, 16);
856 
857   return 0;
858 }
859 
860 LIBYUV_API
MM21ToYUY2(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,uint8_t * dst_yuy2,int dst_stride_yuy2,int width,int height)861 int MM21ToYUY2(const uint8_t* src_y,
862                int src_stride_y,
863                const uint8_t* src_uv,
864                int src_stride_uv,
865                uint8_t* dst_yuy2,
866                int dst_stride_yuy2,
867                int width,
868                int height) {
869   if (!src_y || !src_uv || !dst_yuy2 || width <= 0) {
870     return -1;
871   }
872 
873   DetileToYUY2(src_y, src_stride_y, src_uv, src_stride_uv, dst_yuy2,
874                dst_stride_yuy2, width, height, 32);
875 
876   return 0;
877 }
878 
879 // Convert MT2T into P010. See tinyurl.com/mtk-10bit-video-format for format
880 // documentation.
881 // TODO(greenjustin): Add an MT2T to I420 conversion.
882 LIBYUV_API
MT2TToP010(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,uint16_t * dst_y,int dst_stride_y,uint16_t * dst_uv,int dst_stride_uv,int width,int height)883 int MT2TToP010(const uint8_t* src_y,
884                int src_stride_y,
885                const uint8_t* src_uv,
886                int src_stride_uv,
887                uint16_t* dst_y,
888                int dst_stride_y,
889                uint16_t* dst_uv,
890                int dst_stride_uv,
891                int width,
892                int height) {
893   if (width <= 0 || !height || !src_uv || !dst_uv) {
894     return -1;
895   }
896 
897   {
898     int uv_width = (width + 1) & ~1;
899     int uv_height = (height + 1) / 2;
900     int y = 0;
901     const int tile_width = 16;
902     const int y_tile_height = 32;
903     const int uv_tile_height = 16;
904     int padded_width = (width + tile_width - 1) & ~(tile_width - 1);
905     int y_tile_row_size = padded_width * y_tile_height * 10 / 8;
906     int uv_tile_row_size = padded_width * uv_tile_height * 10 / 8;
907     size_t row_buf_size = padded_width * y_tile_height * sizeof(uint16_t);
908     void (*UnpackMT2T)(const uint8_t* src, uint16_t* dst, size_t size) =
909         UnpackMT2T_C;
910     align_buffer_64(row_buf, row_buf_size);
911     if (!row_buf)
912       return 1;
913 
914 #if defined(HAS_UNPACKMT2T_NEON)
915     if (TestCpuFlag(kCpuHasNEON)) {
916       UnpackMT2T = UnpackMT2T_NEON;
917     }
918 #endif
919     // Negative height means invert the image.
920     if (height < 0) {
921       height = -height;
922       uv_height = (height + 1) / 2;
923       if (dst_y) {
924         dst_y = dst_y + (height - 1) * dst_stride_y;
925         dst_stride_y = -dst_stride_y;
926       }
927       dst_uv = dst_uv + (uv_height - 1) * dst_stride_uv;
928       dst_stride_uv = -dst_stride_uv;
929     }
930 
931     // Unpack and detile Y in rows of tiles
932     if (src_y && dst_y) {
933       for (y = 0; y < (height & ~(y_tile_height - 1)); y += y_tile_height) {
934         UnpackMT2T(src_y, (uint16_t*)row_buf, y_tile_row_size);
935         DetilePlane_16((uint16_t*)row_buf, padded_width, dst_y, dst_stride_y,
936                        width, y_tile_height, y_tile_height);
937         src_y += src_stride_y * y_tile_height;
938         dst_y += dst_stride_y * y_tile_height;
939       }
940       if (height & (y_tile_height - 1)) {
941         UnpackMT2T(src_y, (uint16_t*)row_buf, y_tile_row_size);
942         DetilePlane_16((uint16_t*)row_buf, padded_width, dst_y, dst_stride_y,
943                        width, height & (y_tile_height - 1), y_tile_height);
944       }
945     }
946 
947     // Unpack and detile UV plane
948     for (y = 0; y < (uv_height & ~(uv_tile_height - 1)); y += uv_tile_height) {
949       UnpackMT2T(src_uv, (uint16_t*)row_buf, uv_tile_row_size);
950       DetilePlane_16((uint16_t*)row_buf, padded_width, dst_uv, dst_stride_uv,
951                      uv_width, uv_tile_height, uv_tile_height);
952       src_uv += src_stride_uv * uv_tile_height;
953       dst_uv += dst_stride_uv * uv_tile_height;
954     }
955     if (uv_height & (uv_tile_height - 1)) {
956       UnpackMT2T(src_uv, (uint16_t*)row_buf, uv_tile_row_size);
957       DetilePlane_16((uint16_t*)row_buf, padded_width, dst_uv, dst_stride_uv,
958                      uv_width, uv_height & (uv_tile_height - 1),
959                      uv_tile_height);
960     }
961     free_aligned_buffer_64(row_buf);
962   }
963   return 0;
964 }
965 
966 #ifdef I422TONV21_ROW_VERSION
967 // Unittest fails for this version.
968 // 422 chroma is 1/2 width, 1x height
969 // 420 chroma is 1/2 width, 1/2 height
970 // Swap src_u and src_v to implement I422ToNV12
971 LIBYUV_API
I422ToNV21(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)972 int I422ToNV21(const uint8_t* src_y,
973                int src_stride_y,
974                const uint8_t* src_u,
975                int src_stride_u,
976                const uint8_t* src_v,
977                int src_stride_v,
978                uint8_t* dst_y,
979                int dst_stride_y,
980                uint8_t* dst_vu,
981                int dst_stride_vu,
982                int width,
983                int height) {
984   int y;
985   void (*MergeUVRow)(const uint8_t* src_u, const uint8_t* src_v,
986                      uint8_t* dst_uv, int width) = MergeUVRow_C;
987   void (*InterpolateRow)(uint8_t* dst_ptr, const uint8_t* src_ptr,
988                          ptrdiff_t src_stride, int dst_width,
989                          int source_y_fraction) = InterpolateRow_C;
990   int halfwidth = (width + 1) >> 1;
991   int halfheight = (height + 1) >> 1;
992   if (!src_u || !src_v || !dst_vu || width <= 0 || height == 0) {
993     return -1;
994   }
995   // Negative height means invert the image.
996   if (height < 0) {
997     height = -height;
998     halfheight = (height + 1) >> 1;
999     src_y = src_y + (height - 1) * src_stride_y;
1000     src_u = src_u + (halfheight - 1) * src_stride_u;
1001     src_v = src_v + (halfheight - 1) * src_stride_v;
1002     src_stride_y = -src_stride_y;
1003     src_stride_u = -src_stride_u;
1004     src_stride_v = -src_stride_v;
1005   }
1006 #if defined(HAS_MERGEUVROW_SSE2)
1007   if (TestCpuFlag(kCpuHasSSE2)) {
1008     MergeUVRow = MergeUVRow_Any_SSE2;
1009     if (IS_ALIGNED(halfwidth, 16)) {
1010       MergeUVRow = MergeUVRow_SSE2;
1011     }
1012   }
1013 #endif
1014 #if defined(HAS_MERGEUVROW_AVX2)
1015   if (TestCpuFlag(kCpuHasAVX2)) {
1016     MergeUVRow = MergeUVRow_Any_AVX2;
1017     if (IS_ALIGNED(halfwidth, 16)) {
1018       MergeUVRow = MergeUVRow_AVX2;
1019     }
1020   }
1021 #endif
1022 #if defined(HAS_MERGEUVROW_AVX512BW)
1023   if (TestCpuFlag(kCpuHasAVX512BW)) {
1024     MergeUVRow = MergeUVRow_Any_AVX512BW;
1025     if (IS_ALIGNED(halfwidth, 32)) {
1026       MergeUVRow = MergeUVRow_AVX512BW;
1027     }
1028   }
1029 #endif
1030 #if defined(HAS_MERGEUVROW_NEON)
1031   if (TestCpuFlag(kCpuHasNEON)) {
1032     MergeUVRow = MergeUVRow_Any_NEON;
1033     if (IS_ALIGNED(halfwidth, 16)) {
1034       MergeUVRow = MergeUVRow_NEON;
1035     }
1036   }
1037 #endif
1038 #if defined(HAS_MERGEUVROW_MSA)
1039   if (TestCpuFlag(kCpuHasMSA)) {
1040     MergeUVRow = MergeUVRow_Any_MSA;
1041     if (IS_ALIGNED(halfwidth, 16)) {
1042       MergeUVRow = MergeUVRow_MSA;
1043     }
1044   }
1045 #endif
1046 #if defined(HAS_MERGEUVROW_LSX)
1047   if (TestCpuFlag(kCpuHasLSX)) {
1048     MergeUVRow = MergeUVRow_Any_LSX;
1049     if (IS_ALIGNED(halfwidth, 16)) {
1050       MergeUVRow = MergeUVRow_LSX;
1051     }
1052   }
1053 #endif
1054 #if defined(HAS_MERGEUVROW_RVV)
1055   if (TestCpuFlag(kCpuHasRVV)) {
1056     MergeUVRow = MergeUVRow_RVV;
1057   }
1058 #endif
1059 #if defined(HAS_INTERPOLATEROW_SSSE3)
1060   if (TestCpuFlag(kCpuHasSSSE3)) {
1061     InterpolateRow = InterpolateRow_Any_SSSE3;
1062     if (IS_ALIGNED(width, 16)) {
1063       InterpolateRow = InterpolateRow_SSSE3;
1064     }
1065   }
1066 #endif
1067 #if defined(HAS_INTERPOLATEROW_AVX2)
1068   if (TestCpuFlag(kCpuHasAVX2)) {
1069     InterpolateRow = InterpolateRow_Any_AVX2;
1070     if (IS_ALIGNED(width, 32)) {
1071       InterpolateRow = InterpolateRow_AVX2;
1072     }
1073   }
1074 #endif
1075 #if defined(HAS_INTERPOLATEROW_NEON)
1076   if (TestCpuFlag(kCpuHasNEON)) {
1077     InterpolateRow = InterpolateRow_Any_NEON;
1078     if (IS_ALIGNED(width, 16)) {
1079       InterpolateRow = InterpolateRow_NEON;
1080     }
1081   }
1082 #endif
1083 #if defined(HAS_INTERPOLATEROW_MSA)
1084   if (TestCpuFlag(kCpuHasMSA)) {
1085     InterpolateRow = InterpolateRow_Any_MSA;
1086     if (IS_ALIGNED(width, 32)) {
1087       InterpolateRow = InterpolateRow_MSA;
1088     }
1089   }
1090 #endif
1091 #if defined(HAS_INTERPOLATEROW_LSX)
1092   if (TestCpuFlag(kCpuHasLSX)) {
1093     InterpolateRow = InterpolateRow_Any_LSX;
1094     if (IS_ALIGNED(width, 32)) {
1095       InterpolateRow = InterpolateRow_LSX;
1096     }
1097   }
1098 #endif
1099 #if defined(HAS_INTERPOLATEROW_RVV)
1100   if (TestCpuFlag(kCpuHasRVV)) {
1101     InterpolateRow = InterpolateRow_RVV;
1102   }
1103 #endif
1104 
1105   if (dst_y) {
1106     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, halfwidth, height);
1107   }
1108   {
1109     // Allocate 2 rows of vu.
1110     int awidth = halfwidth * 2;
1111     align_buffer_64(row_vu_0, awidth * 2);
1112     uint8_t* row_vu_1 = row_vu_0 + awidth;
1113     if (!row_vu_0)
1114       return 1;
1115 
1116     for (y = 0; y < height - 1; y += 2) {
1117       MergeUVRow(src_v, src_u, row_vu_0, halfwidth);
1118       MergeUVRow(src_v + src_stride_v, src_u + src_stride_u, row_vu_1,
1119                  halfwidth);
1120       InterpolateRow(dst_vu, row_vu_0, awidth, awidth, 128);
1121       src_u += src_stride_u * 2;
1122       src_v += src_stride_v * 2;
1123       dst_vu += dst_stride_vu;
1124     }
1125     if (height & 1) {
1126       MergeUVRow(src_v, src_u, dst_vu, halfwidth);
1127     }
1128     free_aligned_buffer_64(row_vu_0);
1129   }
1130   return 0;
1131 }
1132 #endif  // I422TONV21_ROW_VERSION
1133 
1134 // 444 chroma is 1x width, 1x height
1135 // 420 chroma is 1/2 width, 1/2 height
1136 LIBYUV_API
I444ToI420(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)1137 int I444ToI420(const uint8_t* src_y,
1138                int src_stride_y,
1139                const uint8_t* src_u,
1140                int src_stride_u,
1141                const uint8_t* src_v,
1142                int src_stride_v,
1143                uint8_t* dst_y,
1144                int dst_stride_y,
1145                uint8_t* dst_u,
1146                int dst_stride_u,
1147                uint8_t* dst_v,
1148                int dst_stride_v,
1149                int width,
1150                int height) {
1151   return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
1152                     src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
1153                     dst_v, dst_stride_v, width, height, width, height);
1154 }
1155 
1156 LIBYUV_API
I444ToNV12(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)1157 int I444ToNV12(const uint8_t* src_y,
1158                int src_stride_y,
1159                const uint8_t* src_u,
1160                int src_stride_u,
1161                const uint8_t* src_v,
1162                int src_stride_v,
1163                uint8_t* dst_y,
1164                int dst_stride_y,
1165                uint8_t* dst_uv,
1166                int dst_stride_uv,
1167                int width,
1168                int height) {
1169   if (!src_y || !src_u || !src_v || !dst_uv || width <= 0 || height == 0) {
1170     return -1;
1171   }
1172   // Negative height means invert the image.
1173   if (height < 0) {
1174     height = -height;
1175     src_y = src_y + (height - 1) * src_stride_y;
1176     src_u = src_u + (height - 1) * src_stride_u;
1177     src_v = src_v + (height - 1) * src_stride_v;
1178     src_stride_y = -src_stride_y;
1179     src_stride_u = -src_stride_u;
1180     src_stride_v = -src_stride_v;
1181   }
1182   if (dst_y) {
1183     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1184   }
1185   HalfMergeUVPlane(src_u, src_stride_u, src_v, src_stride_v, dst_uv,
1186                    dst_stride_uv, width, height);
1187   return 0;
1188 }
1189 
1190 LIBYUV_API
I444ToNV21(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)1191 int I444ToNV21(const uint8_t* src_y,
1192                int src_stride_y,
1193                const uint8_t* src_u,
1194                int src_stride_u,
1195                const uint8_t* src_v,
1196                int src_stride_v,
1197                uint8_t* dst_y,
1198                int dst_stride_y,
1199                uint8_t* dst_vu,
1200                int dst_stride_vu,
1201                int width,
1202                int height) {
1203   return I444ToNV12(src_y, src_stride_y, src_v, src_stride_v, src_u,
1204                     src_stride_u, dst_y, dst_stride_y, dst_vu, dst_stride_vu,
1205                     width, height);
1206 }
1207 
1208 // I400 is greyscale typically used in MJPG
1209 LIBYUV_API
I400ToI420(const uint8_t * src_y,int src_stride_y,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)1210 int I400ToI420(const uint8_t* src_y,
1211                int src_stride_y,
1212                uint8_t* dst_y,
1213                int dst_stride_y,
1214                uint8_t* dst_u,
1215                int dst_stride_u,
1216                uint8_t* dst_v,
1217                int dst_stride_v,
1218                int width,
1219                int height) {
1220   int halfwidth = (width + 1) >> 1;
1221   int halfheight = (height + 1) >> 1;
1222   if (!dst_u || !dst_v || width <= 0 || height == 0) {
1223     return -1;
1224   }
1225   // Negative height means invert the image.
1226   if (height < 0) {
1227     height = -height;
1228     halfheight = (height + 1) >> 1;
1229     src_y = src_y + (height - 1) * src_stride_y;
1230     src_stride_y = -src_stride_y;
1231   }
1232   if (dst_y) {
1233     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1234   }
1235   SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128);
1236   SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128);
1237   return 0;
1238 }
1239 
1240 // I400 is greyscale typically used in MJPG
1241 LIBYUV_API
I400ToNV21(const uint8_t * src_y,int src_stride_y,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_vu,int dst_stride_vu,int width,int height)1242 int I400ToNV21(const uint8_t* src_y,
1243                int src_stride_y,
1244                uint8_t* dst_y,
1245                int dst_stride_y,
1246                uint8_t* dst_vu,
1247                int dst_stride_vu,
1248                int width,
1249                int height) {
1250   int halfwidth = (width + 1) >> 1;
1251   int halfheight = (height + 1) >> 1;
1252   if (!dst_vu || width <= 0 || height == 0) {
1253     return -1;
1254   }
1255   // Negative height means invert the image.
1256   if (height < 0) {
1257     height = -height;
1258     halfheight = (height + 1) >> 1;
1259     src_y = src_y + (height - 1) * src_stride_y;
1260     src_stride_y = -src_stride_y;
1261   }
1262   if (dst_y) {
1263     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1264   }
1265   SetPlane(dst_vu, dst_stride_vu, halfwidth * 2, halfheight, 128);
1266   return 0;
1267 }
1268 
1269 // Convert NV12 to I420.
1270 // TODO(fbarchard): Consider inverting destination. Faster on ARM with prfm.
1271 LIBYUV_API
NV12ToI420(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,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)1272 int NV12ToI420(const uint8_t* src_y,
1273                int src_stride_y,
1274                const uint8_t* src_uv,
1275                int src_stride_uv,
1276                uint8_t* dst_y,
1277                int dst_stride_y,
1278                uint8_t* dst_u,
1279                int dst_stride_u,
1280                uint8_t* dst_v,
1281                int dst_stride_v,
1282                int width,
1283                int height) {
1284   int halfwidth = (width + 1) >> 1;
1285   int halfheight = (height + 1) >> 1;
1286   if (!src_uv || !dst_u || !dst_v || width <= 0 || height == 0) {
1287     return -1;
1288   }
1289   // Negative height means invert the image.
1290   if (height < 0) {
1291     height = -height;
1292     halfheight = (height + 1) >> 1;
1293     src_y = src_y + (height - 1) * src_stride_y;
1294     src_uv = src_uv + (halfheight - 1) * src_stride_uv;
1295     src_stride_y = -src_stride_y;
1296     src_stride_uv = -src_stride_uv;
1297   }
1298   // Coalesce rows.
1299   if (src_stride_y == width && dst_stride_y == width) {
1300     width *= height;
1301     height = 1;
1302     src_stride_y = dst_stride_y = 0;
1303   }
1304   // Coalesce rows.
1305   if (src_stride_uv == halfwidth * 2 && dst_stride_u == halfwidth &&
1306       dst_stride_v == halfwidth) {
1307     halfwidth *= halfheight;
1308     halfheight = 1;
1309     src_stride_uv = dst_stride_u = dst_stride_v = 0;
1310   }
1311 
1312   if (dst_y) {
1313     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
1314   }
1315 
1316   // Split UV plane - NV12 / NV21
1317   SplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v, dst_stride_v,
1318                halfwidth, halfheight);
1319 
1320   return 0;
1321 }
1322 
1323 // Convert NV21 to I420.  Same as NV12 but u and v pointers swapped.
1324 LIBYUV_API
NV21ToI420(const uint8_t * src_y,int src_stride_y,const uint8_t * src_vu,int src_stride_vu,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)1325 int NV21ToI420(const uint8_t* src_y,
1326                int src_stride_y,
1327                const uint8_t* src_vu,
1328                int src_stride_vu,
1329                uint8_t* dst_y,
1330                int dst_stride_y,
1331                uint8_t* dst_u,
1332                int dst_stride_u,
1333                uint8_t* dst_v,
1334                int dst_stride_v,
1335                int width,
1336                int height) {
1337   return NV12ToI420(src_y, src_stride_y, src_vu, src_stride_vu, dst_y,
1338                     dst_stride_y, dst_v, dst_stride_v, dst_u, dst_stride_u,
1339                     width, height);
1340 }
1341 
1342 LIBYUV_API
NV12ToNV24(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_uv,int dst_stride_uv,int width,int height)1343 int NV12ToNV24(const uint8_t* src_y,
1344                int src_stride_y,
1345                const uint8_t* src_uv,
1346                int src_stride_uv,
1347                uint8_t* dst_y,
1348                int dst_stride_y,
1349                uint8_t* dst_uv,
1350                int dst_stride_uv,
1351                int width,
1352                int height) {
1353   int r;
1354   if (width <= 0 || height == 0) {
1355     return -1;
1356   }
1357 
1358   if (dst_y) {
1359     r = ScalePlane(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
1360                    Abs(width), Abs(height), kFilterBilinear);
1361     if (r != 0) {
1362       return r;
1363     }
1364   }
1365   r = UVScale(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1),
1366               SUBSAMPLE(height, 1, 1), dst_uv, dst_stride_uv, Abs(width),
1367               Abs(height), kFilterBilinear);
1368   return r;
1369 }
1370 
1371 LIBYUV_API
NV16ToNV24(const uint8_t * src_y,int src_stride_y,const uint8_t * src_uv,int src_stride_uv,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_uv,int dst_stride_uv,int width,int height)1372 int NV16ToNV24(const uint8_t* src_y,
1373                int src_stride_y,
1374                const uint8_t* src_uv,
1375                int src_stride_uv,
1376                uint8_t* dst_y,
1377                int dst_stride_y,
1378                uint8_t* dst_uv,
1379                int dst_stride_uv,
1380                int width,
1381                int height) {
1382   int r;
1383   if (width <= 0 || height == 0) {
1384     return -1;
1385   }
1386 
1387   if (dst_y) {
1388     r = ScalePlane(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
1389                    Abs(width), Abs(height), kFilterBilinear);
1390     if (r != 0) {
1391       return r;
1392     }
1393   }
1394   r = UVScale(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1), height, dst_uv,
1395               dst_stride_uv, Abs(width), Abs(height), kFilterBilinear);
1396   return r;
1397 }
1398 
1399 // Any P[420]1[02] to I[420]1[02] format with mirroring.
PxxxToIxxx(const uint16_t * src_y,int src_stride_y,const uint16_t * src_uv,int src_stride_uv,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,int subsample_x,int subsample_y,int depth)1400 static int PxxxToIxxx(const uint16_t* src_y,
1401                       int src_stride_y,
1402                       const uint16_t* src_uv,
1403                       int src_stride_uv,
1404                       uint16_t* dst_y,
1405                       int dst_stride_y,
1406                       uint16_t* dst_u,
1407                       int dst_stride_u,
1408                       uint16_t* dst_v,
1409                       int dst_stride_v,
1410                       int width,
1411                       int height,
1412                       int subsample_x,
1413                       int subsample_y,
1414                       int depth) {
1415   const int uv_width = SUBSAMPLE(width, subsample_x, subsample_x);
1416   const int uv_height = SUBSAMPLE(height, subsample_y, subsample_y);
1417   if (width <= 0 || height == 0) {
1418     return -1;
1419   }
1420   ConvertToLSBPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height,
1421                        depth);
1422   SplitUVPlane_16(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v,
1423                   dst_stride_v, uv_width, uv_height, depth);
1424   return 0;
1425 }
1426 
1427 LIBYUV_API
P010ToI010(const uint16_t * src_y,int src_stride_y,const uint16_t * src_uv,int src_stride_uv,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)1428 int P010ToI010(const uint16_t* src_y,
1429                int src_stride_y,
1430                const uint16_t* src_uv,
1431                int src_stride_uv,
1432                uint16_t* dst_y,
1433                int dst_stride_y,
1434                uint16_t* dst_u,
1435                int dst_stride_u,
1436                uint16_t* dst_v,
1437                int dst_stride_v,
1438                int width,
1439                int height) {
1440   return PxxxToIxxx(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
1441                     dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
1442                     width, height, 1, 1, 10);
1443 }
1444 
1445 LIBYUV_API
P012ToI012(const uint16_t * src_y,int src_stride_y,const uint16_t * src_uv,int src_stride_uv,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)1446 int P012ToI012(const uint16_t* src_y,
1447                int src_stride_y,
1448                const uint16_t* src_uv,
1449                int src_stride_uv,
1450                uint16_t* dst_y,
1451                int dst_stride_y,
1452                uint16_t* dst_u,
1453                int dst_stride_u,
1454                uint16_t* dst_v,
1455                int dst_stride_v,
1456                int width,
1457                int height) {
1458   return PxxxToIxxx(src_y, src_stride_y, src_uv, src_stride_uv, dst_y,
1459                     dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
1460                     width, height, 1, 1, 12);
1461 }
1462 
1463 LIBYUV_API
P010ToP410(const uint16_t * src_y,int src_stride_y,const uint16_t * src_uv,int src_stride_uv,uint16_t * dst_y,int dst_stride_y,uint16_t * dst_uv,int dst_stride_uv,int width,int height)1464 int P010ToP410(const uint16_t* src_y,
1465                int src_stride_y,
1466                const uint16_t* src_uv,
1467                int src_stride_uv,
1468                uint16_t* dst_y,
1469                int dst_stride_y,
1470                uint16_t* dst_uv,
1471                int dst_stride_uv,
1472                int width,
1473                int height) {
1474   int r;
1475   if (width <= 0 || height == 0) {
1476     return -1;
1477   }
1478 
1479   if (dst_y) {
1480     r = ScalePlane_16(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
1481                       Abs(width), Abs(height), kFilterBilinear);
1482     if (r != 0) {
1483       return r;
1484     }
1485   }
1486   r = UVScale_16(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1),
1487                  SUBSAMPLE(height, 1, 1), dst_uv, dst_stride_uv, Abs(width),
1488                  Abs(height), kFilterBilinear);
1489   return r;
1490 }
1491 
1492 LIBYUV_API
P210ToP410(const uint16_t * src_y,int src_stride_y,const uint16_t * src_uv,int src_stride_uv,uint16_t * dst_y,int dst_stride_y,uint16_t * dst_uv,int dst_stride_uv,int width,int height)1493 int P210ToP410(const uint16_t* src_y,
1494                int src_stride_y,
1495                const uint16_t* src_uv,
1496                int src_stride_uv,
1497                uint16_t* dst_y,
1498                int dst_stride_y,
1499                uint16_t* dst_uv,
1500                int dst_stride_uv,
1501                int width,
1502                int height) {
1503   int r;
1504   if (width <= 0 || height == 0) {
1505     return -1;
1506   }
1507 
1508   if (dst_y) {
1509     r = ScalePlane_16(src_y, src_stride_y, width, height, dst_y, dst_stride_y,
1510                       Abs(width), Abs(height), kFilterBilinear);
1511     if (r != 0) {
1512       return r;
1513     }
1514   }
1515   r = UVScale_16(src_uv, src_stride_uv, SUBSAMPLE(width, 1, 1), height, dst_uv,
1516                  dst_stride_uv, Abs(width), Abs(height), kFilterBilinear);
1517   return r;
1518 }
1519 
1520 // Convert YUY2 to I420.
1521 LIBYUV_API
YUY2ToI420(const uint8_t * src_yuy2,int src_stride_yuy2,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)1522 int YUY2ToI420(const uint8_t* src_yuy2,
1523                int src_stride_yuy2,
1524                uint8_t* dst_y,
1525                int dst_stride_y,
1526                uint8_t* dst_u,
1527                int dst_stride_u,
1528                uint8_t* dst_v,
1529                int dst_stride_v,
1530                int width,
1531                int height) {
1532   int y;
1533   void (*YUY2ToUVRow)(const uint8_t* src_yuy2, int src_stride_yuy2,
1534                       uint8_t* dst_u, uint8_t* dst_v, int width) =
1535       YUY2ToUVRow_C;
1536   void (*YUY2ToYRow)(const uint8_t* src_yuy2, uint8_t* dst_y, int width) =
1537       YUY2ToYRow_C;
1538   // Negative height means invert the image.
1539   if (height < 0) {
1540     height = -height;
1541     src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
1542     src_stride_yuy2 = -src_stride_yuy2;
1543   }
1544 #if defined(HAS_YUY2TOYROW_SSE2)
1545   if (TestCpuFlag(kCpuHasSSE2)) {
1546     YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
1547     YUY2ToYRow = YUY2ToYRow_Any_SSE2;
1548     if (IS_ALIGNED(width, 16)) {
1549       YUY2ToUVRow = YUY2ToUVRow_SSE2;
1550       YUY2ToYRow = YUY2ToYRow_SSE2;
1551     }
1552   }
1553 #endif
1554 #if defined(HAS_YUY2TOYROW_AVX2)
1555   if (TestCpuFlag(kCpuHasAVX2)) {
1556     YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
1557     YUY2ToYRow = YUY2ToYRow_Any_AVX2;
1558     if (IS_ALIGNED(width, 32)) {
1559       YUY2ToUVRow = YUY2ToUVRow_AVX2;
1560       YUY2ToYRow = YUY2ToYRow_AVX2;
1561     }
1562   }
1563 #endif
1564 #if defined(HAS_YUY2TOYROW_NEON)
1565   if (TestCpuFlag(kCpuHasNEON)) {
1566     YUY2ToYRow = YUY2ToYRow_Any_NEON;
1567     YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
1568     if (IS_ALIGNED(width, 16)) {
1569       YUY2ToYRow = YUY2ToYRow_NEON;
1570       YUY2ToUVRow = YUY2ToUVRow_NEON;
1571     }
1572   }
1573 #endif
1574 #if defined(HAS_YUY2TOYROW_MSA) && defined(HAS_YUY2TOUVROW_MSA)
1575   if (TestCpuFlag(kCpuHasMSA)) {
1576     YUY2ToYRow = YUY2ToYRow_Any_MSA;
1577     YUY2ToUVRow = YUY2ToUVRow_Any_MSA;
1578     if (IS_ALIGNED(width, 32)) {
1579       YUY2ToYRow = YUY2ToYRow_MSA;
1580       YUY2ToUVRow = YUY2ToUVRow_MSA;
1581     }
1582   }
1583 #endif
1584 #if defined(HAS_YUY2TOYROW_LSX) && defined(HAS_YUY2TOUVROW_LSX)
1585   if (TestCpuFlag(kCpuHasLSX)) {
1586     YUY2ToYRow = YUY2ToYRow_Any_LSX;
1587     YUY2ToUVRow = YUY2ToUVRow_Any_LSX;
1588     if (IS_ALIGNED(width, 16)) {
1589       YUY2ToYRow = YUY2ToYRow_LSX;
1590       YUY2ToUVRow = YUY2ToUVRow_LSX;
1591     }
1592   }
1593 #endif
1594 #if defined(HAS_YUY2TOYROW_LASX) && defined(HAS_YUY2TOUVROW_LASX)
1595   if (TestCpuFlag(kCpuHasLASX)) {
1596     YUY2ToYRow = YUY2ToYRow_Any_LASX;
1597     YUY2ToUVRow = YUY2ToUVRow_Any_LASX;
1598     if (IS_ALIGNED(width, 32)) {
1599       YUY2ToYRow = YUY2ToYRow_LASX;
1600       YUY2ToUVRow = YUY2ToUVRow_LASX;
1601     }
1602   }
1603 #endif
1604 
1605   for (y = 0; y < height - 1; y += 2) {
1606     YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
1607     YUY2ToYRow(src_yuy2, dst_y, width);
1608     YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
1609     src_yuy2 += src_stride_yuy2 * 2;
1610     dst_y += dst_stride_y * 2;
1611     dst_u += dst_stride_u;
1612     dst_v += dst_stride_v;
1613   }
1614   if (height & 1) {
1615     YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
1616     YUY2ToYRow(src_yuy2, dst_y, width);
1617   }
1618   return 0;
1619 }
1620 
1621 // Convert UYVY to I420.
1622 LIBYUV_API
UYVYToI420(const uint8_t * src_uyvy,int src_stride_uyvy,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)1623 int UYVYToI420(const uint8_t* src_uyvy,
1624                int src_stride_uyvy,
1625                uint8_t* dst_y,
1626                int dst_stride_y,
1627                uint8_t* dst_u,
1628                int dst_stride_u,
1629                uint8_t* dst_v,
1630                int dst_stride_v,
1631                int width,
1632                int height) {
1633   int y;
1634   void (*UYVYToUVRow)(const uint8_t* src_uyvy, int src_stride_uyvy,
1635                       uint8_t* dst_u, uint8_t* dst_v, int width) =
1636       UYVYToUVRow_C;
1637   void (*UYVYToYRow)(const uint8_t* src_uyvy, uint8_t* dst_y, int width) =
1638       UYVYToYRow_C;
1639   // Negative height means invert the image.
1640   if (height < 0) {
1641     height = -height;
1642     src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
1643     src_stride_uyvy = -src_stride_uyvy;
1644   }
1645 #if defined(HAS_UYVYTOYROW_SSE2)
1646   if (TestCpuFlag(kCpuHasSSE2)) {
1647     UYVYToUVRow = UYVYToUVRow_Any_SSE2;
1648     UYVYToYRow = UYVYToYRow_Any_SSE2;
1649     if (IS_ALIGNED(width, 16)) {
1650       UYVYToUVRow = UYVYToUVRow_SSE2;
1651       UYVYToYRow = UYVYToYRow_SSE2;
1652     }
1653   }
1654 #endif
1655 #if defined(HAS_UYVYTOYROW_AVX2)
1656   if (TestCpuFlag(kCpuHasAVX2)) {
1657     UYVYToUVRow = UYVYToUVRow_Any_AVX2;
1658     UYVYToYRow = UYVYToYRow_Any_AVX2;
1659     if (IS_ALIGNED(width, 32)) {
1660       UYVYToUVRow = UYVYToUVRow_AVX2;
1661       UYVYToYRow = UYVYToYRow_AVX2;
1662     }
1663   }
1664 #endif
1665 #if defined(HAS_UYVYTOYROW_NEON)
1666   if (TestCpuFlag(kCpuHasNEON)) {
1667     UYVYToYRow = UYVYToYRow_Any_NEON;
1668     UYVYToUVRow = UYVYToUVRow_Any_NEON;
1669     if (IS_ALIGNED(width, 16)) {
1670       UYVYToYRow = UYVYToYRow_NEON;
1671       UYVYToUVRow = UYVYToUVRow_NEON;
1672     }
1673   }
1674 #endif
1675 #if defined(HAS_UYVYTOYROW_MSA)
1676   if (TestCpuFlag(kCpuHasMSA)) {
1677     UYVYToYRow = UYVYToYRow_Any_MSA;
1678     UYVYToUVRow = UYVYToUVRow_Any_MSA;
1679     if (IS_ALIGNED(width, 32)) {
1680       UYVYToYRow = UYVYToYRow_MSA;
1681       UYVYToUVRow = UYVYToUVRow_MSA;
1682     }
1683   }
1684 #endif
1685 #if defined(HAS_UYVYTOYROW_LSX)
1686   if (TestCpuFlag(kCpuHasLSX)) {
1687     UYVYToYRow = UYVYToYRow_Any_LSX;
1688     UYVYToUVRow = UYVYToUVRow_Any_LSX;
1689     if (IS_ALIGNED(width, 16)) {
1690       UYVYToYRow = UYVYToYRow_LSX;
1691       UYVYToUVRow = UYVYToUVRow_LSX;
1692     }
1693   }
1694 #endif
1695 #if defined(HAS_UYVYTOYROW_LSX)
1696   if (TestCpuFlag(kCpuHasLSX)) {
1697     UYVYToYRow = UYVYToYRow_Any_LSX;
1698     UYVYToUVRow = UYVYToUVRow_Any_LSX;
1699     if (IS_ALIGNED(width, 16)) {
1700       UYVYToYRow = UYVYToYRow_LSX;
1701       UYVYToUVRow = UYVYToUVRow_LSX;
1702     }
1703   }
1704 #endif
1705 #if defined(HAS_UYVYTOYROW_LASX)
1706   if (TestCpuFlag(kCpuHasLASX)) {
1707     UYVYToYRow = UYVYToYRow_Any_LASX;
1708     UYVYToUVRow = UYVYToUVRow_Any_LASX;
1709     if (IS_ALIGNED(width, 32)) {
1710       UYVYToYRow = UYVYToYRow_LASX;
1711       UYVYToUVRow = UYVYToUVRow_LASX;
1712     }
1713   }
1714 #endif
1715 
1716   for (y = 0; y < height - 1; y += 2) {
1717     UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
1718     UYVYToYRow(src_uyvy, dst_y, width);
1719     UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
1720     src_uyvy += src_stride_uyvy * 2;
1721     dst_y += dst_stride_y * 2;
1722     dst_u += dst_stride_u;
1723     dst_v += dst_stride_v;
1724   }
1725   if (height & 1) {
1726     UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
1727     UYVYToYRow(src_uyvy, dst_y, width);
1728   }
1729   return 0;
1730 }
1731 
1732 // Convert AYUV to NV12.
1733 LIBYUV_API
AYUVToNV12(const uint8_t * src_ayuv,int src_stride_ayuv,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_uv,int dst_stride_uv,int width,int height)1734 int AYUVToNV12(const uint8_t* src_ayuv,
1735                int src_stride_ayuv,
1736                uint8_t* dst_y,
1737                int dst_stride_y,
1738                uint8_t* dst_uv,
1739                int dst_stride_uv,
1740                int width,
1741                int height) {
1742   int y;
1743   void (*AYUVToUVRow)(const uint8_t* src_ayuv, int src_stride_ayuv,
1744                       uint8_t* dst_uv, int width) = AYUVToUVRow_C;
1745   void (*AYUVToYRow)(const uint8_t* src_ayuv, uint8_t* dst_y, int width) =
1746       AYUVToYRow_C;
1747   // Negative height means invert the image.
1748   if (height < 0) {
1749     height = -height;
1750     src_ayuv = src_ayuv + (height - 1) * src_stride_ayuv;
1751     src_stride_ayuv = -src_stride_ayuv;
1752   }
1753 // place holders for future intel code
1754 #if defined(HAS_AYUVTOYROW_SSE2)
1755   if (TestCpuFlag(kCpuHasSSE2)) {
1756     AYUVToUVRow = AYUVToUVRow_Any_SSE2;
1757     AYUVToYRow = AYUVToYRow_Any_SSE2;
1758     if (IS_ALIGNED(width, 16)) {
1759       AYUVToUVRow = AYUVToUVRow_SSE2;
1760       AYUVToYRow = AYUVToYRow_SSE2;
1761     }
1762   }
1763 #endif
1764 #if defined(HAS_AYUVTOYROW_AVX2)
1765   if (TestCpuFlag(kCpuHasAVX2)) {
1766     AYUVToUVRow = AYUVToUVRow_Any_AVX2;
1767     AYUVToYRow = AYUVToYRow_Any_AVX2;
1768     if (IS_ALIGNED(width, 32)) {
1769       AYUVToUVRow = AYUVToUVRow_AVX2;
1770       AYUVToYRow = AYUVToYRow_AVX2;
1771     }
1772   }
1773 #endif
1774 
1775 #if defined(HAS_AYUVTOYROW_NEON)
1776   if (TestCpuFlag(kCpuHasNEON)) {
1777     AYUVToYRow = AYUVToYRow_Any_NEON;
1778     AYUVToUVRow = AYUVToUVRow_Any_NEON;
1779     if (IS_ALIGNED(width, 16)) {
1780       AYUVToYRow = AYUVToYRow_NEON;
1781       AYUVToUVRow = AYUVToUVRow_NEON;
1782     }
1783   }
1784 #endif
1785 
1786   for (y = 0; y < height - 1; y += 2) {
1787     AYUVToUVRow(src_ayuv, src_stride_ayuv, dst_uv, width);
1788     AYUVToYRow(src_ayuv, dst_y, width);
1789     AYUVToYRow(src_ayuv + src_stride_ayuv, dst_y + dst_stride_y, width);
1790     src_ayuv += src_stride_ayuv * 2;
1791     dst_y += dst_stride_y * 2;
1792     dst_uv += dst_stride_uv;
1793   }
1794   if (height & 1) {
1795     AYUVToUVRow(src_ayuv, 0, dst_uv, width);
1796     AYUVToYRow(src_ayuv, dst_y, width);
1797   }
1798   return 0;
1799 }
1800 
1801 // Convert AYUV to NV21.
1802 LIBYUV_API
AYUVToNV21(const uint8_t * src_ayuv,int src_stride_ayuv,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_vu,int dst_stride_vu,int width,int height)1803 int AYUVToNV21(const uint8_t* src_ayuv,
1804                int src_stride_ayuv,
1805                uint8_t* dst_y,
1806                int dst_stride_y,
1807                uint8_t* dst_vu,
1808                int dst_stride_vu,
1809                int width,
1810                int height) {
1811   int y;
1812   void (*AYUVToVURow)(const uint8_t* src_ayuv, int src_stride_ayuv,
1813                       uint8_t* dst_vu, int width) = AYUVToVURow_C;
1814   void (*AYUVToYRow)(const uint8_t* src_ayuv, uint8_t* dst_y, int width) =
1815       AYUVToYRow_C;
1816   // Negative height means invert the image.
1817   if (height < 0) {
1818     height = -height;
1819     src_ayuv = src_ayuv + (height - 1) * src_stride_ayuv;
1820     src_stride_ayuv = -src_stride_ayuv;
1821   }
1822 // place holders for future intel code
1823 #if defined(HAS_AYUVTOYROW_SSE2)
1824   if (TestCpuFlag(kCpuHasSSE2)) {
1825     AYUVToVURow = AYUVToVURow_Any_SSE2;
1826     AYUVToYRow = AYUVToYRow_Any_SSE2;
1827     if (IS_ALIGNED(width, 16)) {
1828       AYUVToVURow = AYUVToVURow_SSE2;
1829       AYUVToYRow = AYUVToYRow_SSE2;
1830     }
1831   }
1832 #endif
1833 #if defined(HAS_AYUVTOYROW_AVX2)
1834   if (TestCpuFlag(kCpuHasAVX2)) {
1835     AYUVToVURow = AYUVToVURow_Any_AVX2;
1836     AYUVToYRow = AYUVToYRow_Any_AVX2;
1837     if (IS_ALIGNED(width, 32)) {
1838       AYUVToVURow = AYUVToVURow_AVX2;
1839       AYUVToYRow = AYUVToYRow_AVX2;
1840     }
1841   }
1842 #endif
1843 
1844 #if defined(HAS_AYUVTOYROW_NEON)
1845   if (TestCpuFlag(kCpuHasNEON)) {
1846     AYUVToYRow = AYUVToYRow_Any_NEON;
1847     AYUVToVURow = AYUVToVURow_Any_NEON;
1848     if (IS_ALIGNED(width, 16)) {
1849       AYUVToYRow = AYUVToYRow_NEON;
1850       AYUVToVURow = AYUVToVURow_NEON;
1851     }
1852   }
1853 #endif
1854 
1855   for (y = 0; y < height - 1; y += 2) {
1856     AYUVToVURow(src_ayuv, src_stride_ayuv, dst_vu, width);
1857     AYUVToYRow(src_ayuv, dst_y, width);
1858     AYUVToYRow(src_ayuv + src_stride_ayuv, dst_y + dst_stride_y, width);
1859     src_ayuv += src_stride_ayuv * 2;
1860     dst_y += dst_stride_y * 2;
1861     dst_vu += dst_stride_vu;
1862   }
1863   if (height & 1) {
1864     AYUVToVURow(src_ayuv, 0, dst_vu, width);
1865     AYUVToYRow(src_ayuv, dst_y, width);
1866   }
1867   return 0;
1868 }
1869 
1870 // Convert ARGB to I420.
1871 LIBYUV_API
ARGBToI420(const uint8_t * src_argb,int src_stride_argb,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)1872 int ARGBToI420(const uint8_t* src_argb,
1873                int src_stride_argb,
1874                uint8_t* dst_y,
1875                int dst_stride_y,
1876                uint8_t* dst_u,
1877                int dst_stride_u,
1878                uint8_t* dst_v,
1879                int dst_stride_v,
1880                int width,
1881                int height) {
1882   int y;
1883   void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
1884                       uint8_t* dst_u, uint8_t* dst_v, int width) =
1885       ARGBToUVRow_C;
1886   void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
1887       ARGBToYRow_C;
1888   if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1889     return -1;
1890   }
1891   // Negative height means invert the image.
1892   if (height < 0) {
1893     height = -height;
1894     src_argb = src_argb + (height - 1) * src_stride_argb;
1895     src_stride_argb = -src_stride_argb;
1896   }
1897 #if defined(HAS_ARGBTOYROW_NEON)
1898   if (TestCpuFlag(kCpuHasNEON)) {
1899     ARGBToYRow = ARGBToYRow_Any_NEON;
1900     if (IS_ALIGNED(width, 16)) {
1901       ARGBToYRow = ARGBToYRow_NEON;
1902     }
1903   }
1904 #endif
1905 #if defined(HAS_ARGBTOUVROW_NEON)
1906   if (TestCpuFlag(kCpuHasNEON)) {
1907     ARGBToUVRow = ARGBToUVRow_Any_NEON;
1908     if (IS_ALIGNED(width, 16)) {
1909       ARGBToUVRow = ARGBToUVRow_NEON;
1910     }
1911   }
1912 #endif
1913 #if defined(HAS_ARGBTOYROW_SSSE3)
1914   if (TestCpuFlag(kCpuHasSSSE3)) {
1915     ARGBToYRow = ARGBToYRow_Any_SSSE3;
1916     if (IS_ALIGNED(width, 16)) {
1917       ARGBToYRow = ARGBToYRow_SSSE3;
1918     }
1919   }
1920 #endif
1921 #if defined(HAS_ARGBTOUVROW_SSSE3)
1922   if (TestCpuFlag(kCpuHasSSSE3)) {
1923     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1924     if (IS_ALIGNED(width, 16)) {
1925       ARGBToUVRow = ARGBToUVRow_SSSE3;
1926     }
1927   }
1928 #endif
1929 #if defined(HAS_ARGBTOYROW_AVX2)
1930   if (TestCpuFlag(kCpuHasAVX2)) {
1931     ARGBToYRow = ARGBToYRow_Any_AVX2;
1932     if (IS_ALIGNED(width, 32)) {
1933       ARGBToYRow = ARGBToYRow_AVX2;
1934     }
1935   }
1936 #endif
1937 #if defined(HAS_ARGBTOUVROW_AVX2)
1938   if (TestCpuFlag(kCpuHasAVX2)) {
1939     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1940     if (IS_ALIGNED(width, 32)) {
1941       ARGBToUVRow = ARGBToUVRow_AVX2;
1942     }
1943   }
1944 #endif
1945 #if defined(HAS_ARGBTOYROW_MSA) && defined(HAS_ARGBTOUVROW_MSA)
1946   if (TestCpuFlag(kCpuHasMSA)) {
1947     ARGBToYRow = ARGBToYRow_Any_MSA;
1948     ARGBToUVRow = ARGBToUVRow_Any_MSA;
1949     if (IS_ALIGNED(width, 16)) {
1950       ARGBToYRow = ARGBToYRow_MSA;
1951     }
1952     if (IS_ALIGNED(width, 32)) {
1953       ARGBToUVRow = ARGBToUVRow_MSA;
1954     }
1955   }
1956 #endif
1957 #if defined(HAS_ARGBTOYROW_LSX)
1958   if (TestCpuFlag(kCpuHasLSX)) {
1959     ARGBToYRow = ARGBToYRow_Any_LSX;
1960     if (IS_ALIGNED(width, 16)) {
1961       ARGBToYRow = ARGBToYRow_LSX;
1962     }
1963   }
1964 #endif
1965 #if defined(HAS_ARGBTOYROW_LSX) && defined(HAS_ARGBTOUVROW_LSX)
1966   if (TestCpuFlag(kCpuHasLSX)) {
1967     ARGBToYRow = ARGBToYRow_Any_LSX;
1968     ARGBToUVRow = ARGBToUVRow_Any_LSX;
1969     if (IS_ALIGNED(width, 16)) {
1970       ARGBToYRow = ARGBToYRow_LSX;
1971       ARGBToUVRow = ARGBToUVRow_LSX;
1972     }
1973   }
1974 #endif
1975 #if defined(HAS_ARGBTOYROW_LASX) && defined(HAS_ARGBTOUVROW_LASX)
1976   if (TestCpuFlag(kCpuHasLASX)) {
1977     ARGBToYRow = ARGBToYRow_Any_LASX;
1978     ARGBToUVRow = ARGBToUVRow_Any_LASX;
1979     if (IS_ALIGNED(width, 32)) {
1980       ARGBToYRow = ARGBToYRow_LASX;
1981       ARGBToUVRow = ARGBToUVRow_LASX;
1982     }
1983   }
1984 #endif
1985 
1986   for (y = 0; y < height - 1; y += 2) {
1987     ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
1988     ARGBToYRow(src_argb, dst_y, width);
1989     ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
1990     src_argb += src_stride_argb * 2;
1991     dst_y += dst_stride_y * 2;
1992     dst_u += dst_stride_u;
1993     dst_v += dst_stride_v;
1994   }
1995   if (height & 1) {
1996     ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
1997     ARGBToYRow(src_argb, dst_y, width);
1998   }
1999   return 0;
2000 }
2001 
2002 #ifdef USE_EXTRACTALPHA
2003 // Convert ARGB to I420 with Alpha
2004 // The following version calls ARGBExtractAlpha on the full image.
2005 LIBYUV_API
ARGBToI420Alpha(const uint8_t * src_argb,int src_stride_argb,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_u,int dst_stride_u,uint8_t * dst_v,int dst_stride_v,uint8_t * dst_a,int dst_stride_a,int width,int height)2006 int ARGBToI420Alpha(const uint8_t* src_argb,
2007                     int src_stride_argb,
2008                     uint8_t* dst_y,
2009                     int dst_stride_y,
2010                     uint8_t* dst_u,
2011                     int dst_stride_u,
2012                     uint8_t* dst_v,
2013                     int dst_stride_v,
2014                     uint8_t* dst_a,
2015                     int dst_stride_a,
2016                     int width,
2017                     int height) {
2018   int r = ARGBToI420(src_argb, src_stride_argb, dst_y, dst_stride_y, dst_u,
2019                      dst_stride_u, dst_v, dst_stride_v, width, height);
2020   if (r == 0) {
2021     r = ARGBExtractAlpha(src_argb, src_stride_argb, dst_a, dst_stride_a, width,
2022                          height);
2023   }
2024   return r;
2025 }
2026 #else  // USE_EXTRACTALPHA
2027 // Convert ARGB to I420 with Alpha
2028 LIBYUV_API
ARGBToI420Alpha(const uint8_t * src_argb,int src_stride_argb,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_u,int dst_stride_u,uint8_t * dst_v,int dst_stride_v,uint8_t * dst_a,int dst_stride_a,int width,int height)2029 int ARGBToI420Alpha(const uint8_t* src_argb,
2030                     int src_stride_argb,
2031                     uint8_t* dst_y,
2032                     int dst_stride_y,
2033                     uint8_t* dst_u,
2034                     int dst_stride_u,
2035                     uint8_t* dst_v,
2036                     int dst_stride_v,
2037                     uint8_t* dst_a,
2038                     int dst_stride_a,
2039                     int width,
2040                     int height) {
2041   int y;
2042   void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
2043                       uint8_t* dst_u, uint8_t* dst_v, int width) =
2044       ARGBToUVRow_C;
2045   void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
2046       ARGBToYRow_C;
2047   void (*ARGBExtractAlphaRow)(const uint8_t* src_argb, uint8_t* dst_a,
2048                               int width) = ARGBExtractAlphaRow_C;
2049   if (!src_argb || !dst_y || !dst_u || !dst_v || !dst_a || width <= 0 ||
2050       height == 0) {
2051     return -1;
2052   }
2053   // Negative height means invert the image.
2054   if (height < 0) {
2055     height = -height;
2056     src_argb = src_argb + (height - 1) * src_stride_argb;
2057     src_stride_argb = -src_stride_argb;
2058   }
2059 #if defined(HAS_ARGBTOYROW_NEON)
2060   if (TestCpuFlag(kCpuHasNEON)) {
2061     ARGBToYRow = ARGBToYRow_Any_NEON;
2062     if (IS_ALIGNED(width, 16)) {
2063       ARGBToYRow = ARGBToYRow_NEON;
2064     }
2065   }
2066 #endif
2067 #if defined(HAS_ARGBTOUVROW_NEON)
2068   if (TestCpuFlag(kCpuHasNEON)) {
2069     ARGBToUVRow = ARGBToUVRow_Any_NEON;
2070     if (IS_ALIGNED(width, 16)) {
2071       ARGBToUVRow = ARGBToUVRow_NEON;
2072     }
2073   }
2074 #endif
2075 #if defined(HAS_ARGBTOYROW_SSSE3)
2076   if (TestCpuFlag(kCpuHasSSSE3)) {
2077     ARGBToYRow = ARGBToYRow_Any_SSSE3;
2078     if (IS_ALIGNED(width, 16)) {
2079       ARGBToYRow = ARGBToYRow_SSSE3;
2080     }
2081   }
2082 #endif
2083 #if defined(HAS_ARGBTOUVROW_SSSE3)
2084   if (TestCpuFlag(kCpuHasSSSE3)) {
2085     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
2086     if (IS_ALIGNED(width, 16)) {
2087       ARGBToUVRow = ARGBToUVRow_SSSE3;
2088     }
2089   }
2090 #endif
2091 #if defined(HAS_ARGBTOYROW_AVX2)
2092   if (TestCpuFlag(kCpuHasAVX2)) {
2093     ARGBToYRow = ARGBToYRow_Any_AVX2;
2094     if (IS_ALIGNED(width, 32)) {
2095       ARGBToYRow = ARGBToYRow_AVX2;
2096     }
2097   }
2098 #endif
2099 #if defined(HAS_ARGBTOUVROW_AVX2)
2100   if (TestCpuFlag(kCpuHasAVX2)) {
2101     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
2102     if (IS_ALIGNED(width, 32)) {
2103       ARGBToUVRow = ARGBToUVRow_AVX2;
2104     }
2105   }
2106 #endif
2107 #if defined(HAS_ARGBTOYROW_MSA) && defined(HAS_ARGBTOUVROW_MSA)
2108   if (TestCpuFlag(kCpuHasMSA)) {
2109     ARGBToYRow = ARGBToYRow_Any_MSA;
2110     ARGBToUVRow = ARGBToUVRow_Any_MSA;
2111     if (IS_ALIGNED(width, 16)) {
2112       ARGBToYRow = ARGBToYRow_MSA;
2113     }
2114     if (IS_ALIGNED(width, 32)) {
2115       ARGBToUVRow = ARGBToUVRow_MSA;
2116     }
2117   }
2118 #endif
2119 #if defined(HAS_ARGBTOYROW_LSX)
2120   if (TestCpuFlag(kCpuHasLSX)) {
2121     ARGBToYRow = ARGBToYRow_Any_LSX;
2122     if (IS_ALIGNED(width, 16)) {
2123       ARGBToYRow = ARGBToYRow_LSX;
2124     }
2125   }
2126 #endif
2127 #if defined(HAS_ARGBTOYROW_LASX) && defined(HAS_ARGBTOUVROW_LASX)
2128   if (TestCpuFlag(kCpuHasLASX)) {
2129     ARGBToYRow = ARGBToYRow_Any_LASX;
2130     ARGBToUVRow = ARGBToUVRow_Any_LASX;
2131     if (IS_ALIGNED(width, 32)) {
2132       ARGBToYRow = ARGBToYRow_LASX;
2133       ARGBToUVRow = ARGBToUVRow_LASX;
2134     }
2135   }
2136 #endif
2137 #if defined(HAS_ARGBEXTRACTALPHAROW_SSE2)
2138   if (TestCpuFlag(kCpuHasSSE2)) {
2139     ARGBExtractAlphaRow = IS_ALIGNED(width, 8) ? ARGBExtractAlphaRow_SSE2
2140                                                : ARGBExtractAlphaRow_Any_SSE2;
2141   }
2142 #endif
2143 #if defined(HAS_ARGBEXTRACTALPHAROW_AVX2)
2144   if (TestCpuFlag(kCpuHasAVX2)) {
2145     ARGBExtractAlphaRow = IS_ALIGNED(width, 32) ? ARGBExtractAlphaRow_AVX2
2146                                                 : ARGBExtractAlphaRow_Any_AVX2;
2147   }
2148 #endif
2149 #if defined(HAS_ARGBEXTRACTALPHAROW_NEON)
2150   if (TestCpuFlag(kCpuHasNEON)) {
2151     ARGBExtractAlphaRow = IS_ALIGNED(width, 16) ? ARGBExtractAlphaRow_NEON
2152                                                 : ARGBExtractAlphaRow_Any_NEON;
2153   }
2154 #endif
2155 #if defined(HAS_ARGBEXTRACTALPHAROW_MSA)
2156   if (TestCpuFlag(kCpuHasMSA)) {
2157     ARGBExtractAlphaRow = IS_ALIGNED(width, 16) ? ARGBExtractAlphaRow_MSA
2158                                                 : ARGBExtractAlphaRow_Any_MSA;
2159   }
2160 #endif
2161 #if defined(HAS_ARGBEXTRACTALPHAROW_LSX)
2162   if (TestCpuFlag(kCpuHasLSX)) {
2163     ARGBExtractAlphaRow = IS_ALIGNED(width, 16) ? ARGBExtractAlphaRow_LSX
2164                                                 : ARGBExtractAlphaRow_Any_LSX;
2165   }
2166 #endif
2167 #if defined(HAS_ARGBEXTRACTALPHAROW_RVV)
2168   if (TestCpuFlag(kCpuHasRVV)) {
2169     ARGBExtractAlphaRow = ARGBExtractAlphaRow_RVV;
2170   }
2171 #endif
2172 
2173   for (y = 0; y < height - 1; y += 2) {
2174     ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
2175     ARGBToYRow(src_argb, dst_y, width);
2176     ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
2177     ARGBExtractAlphaRow(src_argb, dst_a, width);
2178     ARGBExtractAlphaRow(src_argb + src_stride_argb, dst_a + dst_stride_a,
2179                         width);
2180     src_argb += src_stride_argb * 2;
2181     dst_y += dst_stride_y * 2;
2182     dst_u += dst_stride_u;
2183     dst_v += dst_stride_v;
2184     dst_a += dst_stride_a * 2;
2185   }
2186   if (height & 1) {
2187     ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
2188     ARGBToYRow(src_argb, dst_y, width);
2189     ARGBExtractAlphaRow(src_argb, dst_a, width);
2190   }
2191   return 0;
2192 }
2193 #endif  // USE_EXTRACTALPHA
2194 
2195 // Convert BGRA to I420.
2196 LIBYUV_API
BGRAToI420(const uint8_t * src_bgra,int src_stride_bgra,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)2197 int BGRAToI420(const uint8_t* src_bgra,
2198                int src_stride_bgra,
2199                uint8_t* dst_y,
2200                int dst_stride_y,
2201                uint8_t* dst_u,
2202                int dst_stride_u,
2203                uint8_t* dst_v,
2204                int dst_stride_v,
2205                int width,
2206                int height) {
2207   int y;
2208   void (*BGRAToUVRow)(const uint8_t* src_bgra0, int src_stride_bgra,
2209                       uint8_t* dst_u, uint8_t* dst_v, int width) =
2210       BGRAToUVRow_C;
2211   void (*BGRAToYRow)(const uint8_t* src_bgra, uint8_t* dst_y, int width) =
2212       BGRAToYRow_C;
2213   if (!src_bgra || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
2214     return -1;
2215   }
2216   // Negative height means invert the image.
2217   if (height < 0) {
2218     height = -height;
2219     src_bgra = src_bgra + (height - 1) * src_stride_bgra;
2220     src_stride_bgra = -src_stride_bgra;
2221   }
2222 #if defined(HAS_BGRATOYROW_NEON)
2223   if (TestCpuFlag(kCpuHasNEON)) {
2224     BGRAToYRow = BGRAToYRow_Any_NEON;
2225     if (IS_ALIGNED(width, 16)) {
2226       BGRAToYRow = BGRAToYRow_NEON;
2227     }
2228   }
2229 #endif
2230 #if defined(HAS_BGRATOUVROW_NEON)
2231   if (TestCpuFlag(kCpuHasNEON)) {
2232     BGRAToUVRow = BGRAToUVRow_Any_NEON;
2233     if (IS_ALIGNED(width, 16)) {
2234       BGRAToUVRow = BGRAToUVRow_NEON;
2235     }
2236   }
2237 #endif
2238 #if defined(HAS_BGRATOYROW_SSSE3)
2239   if (TestCpuFlag(kCpuHasSSSE3)) {
2240     BGRAToYRow = BGRAToYRow_Any_SSSE3;
2241     if (IS_ALIGNED(width, 16)) {
2242       BGRAToYRow = BGRAToYRow_SSSE3;
2243     }
2244   }
2245 #endif
2246 #if defined(HAS_BGRATOUVROW_SSSE3)
2247   if (TestCpuFlag(kCpuHasSSSE3)) {
2248     BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
2249     if (IS_ALIGNED(width, 16)) {
2250       BGRAToUVRow = BGRAToUVRow_SSSE3;
2251     }
2252   }
2253 #endif
2254 #if defined(HAS_BGRATOYROW_AVX2)
2255   if (TestCpuFlag(kCpuHasAVX2)) {
2256     BGRAToYRow = BGRAToYRow_Any_AVX2;
2257     if (IS_ALIGNED(width, 32)) {
2258       BGRAToYRow = BGRAToYRow_AVX2;
2259     }
2260   }
2261 #endif
2262 #if defined(HAS_BGRATOUVROW_AVX2)
2263   if (TestCpuFlag(kCpuHasAVX2)) {
2264     BGRAToUVRow = BGRAToUVRow_Any_AVX2;
2265     if (IS_ALIGNED(width, 32)) {
2266       BGRAToUVRow = BGRAToUVRow_AVX2;
2267     }
2268   }
2269 #endif
2270 #if defined(HAS_BGRATOYROW_MSA) && defined(HAS_BGRATOUVROW_MSA)
2271   if (TestCpuFlag(kCpuHasMSA)) {
2272     BGRAToYRow = BGRAToYRow_Any_MSA;
2273     BGRAToUVRow = BGRAToUVRow_Any_MSA;
2274     if (IS_ALIGNED(width, 16)) {
2275       BGRAToYRow = BGRAToYRow_MSA;
2276     }
2277     if (IS_ALIGNED(width, 32)) {
2278       BGRAToUVRow = BGRAToUVRow_MSA;
2279     }
2280   }
2281 #endif
2282 #if defined(HAS_BGRATOYROW_LSX) && defined(HAS_BGRATOUVROW_LSX)
2283   if (TestCpuFlag(kCpuHasLSX)) {
2284     BGRAToYRow = BGRAToYRow_Any_LSX;
2285     BGRAToUVRow = BGRAToUVRow_Any_LSX;
2286     if (IS_ALIGNED(width, 16)) {
2287       BGRAToYRow = BGRAToYRow_LSX;
2288       BGRAToUVRow = BGRAToUVRow_LSX;
2289     }
2290   }
2291 #endif
2292 #if defined(HAS_BGRATOYROW_LASX)
2293   if (TestCpuFlag(kCpuHasLASX)) {
2294     BGRAToYRow = BGRAToYRow_Any_LASX;
2295     if (IS_ALIGNED(width, 32)) {
2296       BGRAToYRow = BGRAToYRow_LASX;
2297     }
2298   }
2299 #endif
2300 #if defined(HAS_BGRATOYROW_RVV)
2301   if (TestCpuFlag(kCpuHasRVV)) {
2302     BGRAToYRow = BGRAToYRow_RVV;
2303   }
2304 #endif
2305 
2306   for (y = 0; y < height - 1; y += 2) {
2307     BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
2308     BGRAToYRow(src_bgra, dst_y, width);
2309     BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
2310     src_bgra += src_stride_bgra * 2;
2311     dst_y += dst_stride_y * 2;
2312     dst_u += dst_stride_u;
2313     dst_v += dst_stride_v;
2314   }
2315   if (height & 1) {
2316     BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
2317     BGRAToYRow(src_bgra, dst_y, width);
2318   }
2319   return 0;
2320 }
2321 
2322 // Convert ABGR to I420.
2323 LIBYUV_API
ABGRToI420(const uint8_t * src_abgr,int src_stride_abgr,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)2324 int ABGRToI420(const uint8_t* src_abgr,
2325                int src_stride_abgr,
2326                uint8_t* dst_y,
2327                int dst_stride_y,
2328                uint8_t* dst_u,
2329                int dst_stride_u,
2330                uint8_t* dst_v,
2331                int dst_stride_v,
2332                int width,
2333                int height) {
2334   int y;
2335   void (*ABGRToUVRow)(const uint8_t* src_abgr0, int src_stride_abgr,
2336                       uint8_t* dst_u, uint8_t* dst_v, int width) =
2337       ABGRToUVRow_C;
2338   void (*ABGRToYRow)(const uint8_t* src_abgr, uint8_t* dst_y, int width) =
2339       ABGRToYRow_C;
2340   if (!src_abgr || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
2341     return -1;
2342   }
2343   // Negative height means invert the image.
2344   if (height < 0) {
2345     height = -height;
2346     src_abgr = src_abgr + (height - 1) * src_stride_abgr;
2347     src_stride_abgr = -src_stride_abgr;
2348   }
2349 #if defined(HAS_ABGRTOYROW_SSSE3)
2350   if (TestCpuFlag(kCpuHasSSSE3)) {
2351     ABGRToYRow = ABGRToYRow_Any_SSSE3;
2352     if (IS_ALIGNED(width, 16)) {
2353       ABGRToYRow = ABGRToYRow_SSSE3;
2354     }
2355   }
2356 #endif
2357 #if defined(HAS_ABGRTOUVROW_SSSE3)
2358   if (TestCpuFlag(kCpuHasSSSE3)) {
2359     ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
2360     if (IS_ALIGNED(width, 16)) {
2361       ABGRToUVRow = ABGRToUVRow_SSSE3;
2362     }
2363   }
2364 #endif
2365 #if defined(HAS_ABGRTOYROW_AVX2)
2366   if (TestCpuFlag(kCpuHasAVX2)) {
2367     ABGRToYRow = ABGRToYRow_Any_AVX2;
2368     if (IS_ALIGNED(width, 32)) {
2369       ABGRToYRow = ABGRToYRow_AVX2;
2370     }
2371   }
2372 #endif
2373 #if defined(HAS_ABGRTOUVROW_AVX2)
2374   if (TestCpuFlag(kCpuHasAVX2)) {
2375     ABGRToUVRow = ABGRToUVRow_Any_AVX2;
2376     if (IS_ALIGNED(width, 32)) {
2377       ABGRToUVRow = ABGRToUVRow_AVX2;
2378     }
2379   }
2380 #endif
2381 #if defined(HAS_ABGRTOYROW_NEON)
2382   if (TestCpuFlag(kCpuHasNEON)) {
2383     ABGRToYRow = ABGRToYRow_Any_NEON;
2384     if (IS_ALIGNED(width, 16)) {
2385       ABGRToYRow = ABGRToYRow_NEON;
2386     }
2387   }
2388 #endif
2389 #if defined(HAS_ABGRTOUVROW_NEON)
2390   if (TestCpuFlag(kCpuHasNEON)) {
2391     ABGRToUVRow = ABGRToUVRow_Any_NEON;
2392     if (IS_ALIGNED(width, 16)) {
2393       ABGRToUVRow = ABGRToUVRow_NEON;
2394     }
2395   }
2396 #endif
2397 #if defined(HAS_ABGRTOYROW_MSA) && defined(HAS_ABGRTOUVROW_MSA)
2398   if (TestCpuFlag(kCpuHasMSA)) {
2399     ABGRToYRow = ABGRToYRow_Any_MSA;
2400     ABGRToUVRow = ABGRToUVRow_Any_MSA;
2401     if (IS_ALIGNED(width, 16)) {
2402       ABGRToYRow = ABGRToYRow_MSA;
2403       ABGRToUVRow = ABGRToUVRow_MSA;
2404     }
2405   }
2406 #endif
2407 #if defined(HAS_ABGRTOYROW_LSX) && defined(HAS_ABGRTOUVROW_LSX)
2408   if (TestCpuFlag(kCpuHasLSX)) {
2409     ABGRToYRow = ABGRToYRow_Any_LSX;
2410     ABGRToUVRow = ABGRToUVRow_Any_LSX;
2411     if (IS_ALIGNED(width, 16)) {
2412       ABGRToYRow = ABGRToYRow_LSX;
2413       ABGRToUVRow = ABGRToUVRow_LSX;
2414     }
2415   }
2416 #endif
2417 #if defined(HAS_ABGRTOYROW_LASX)
2418   if (TestCpuFlag(kCpuHasLASX)) {
2419     ABGRToYRow = ABGRToYRow_Any_LASX;
2420     if (IS_ALIGNED(width, 32)) {
2421       ABGRToYRow = ABGRToYRow_LASX;
2422     }
2423   }
2424 #endif
2425 #if defined(HAS_ABGRTOYROW_RVV)
2426   if (TestCpuFlag(kCpuHasRVV)) {
2427     ABGRToYRow = ABGRToYRow_RVV;
2428   }
2429 #endif
2430 
2431   for (y = 0; y < height - 1; y += 2) {
2432     ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
2433     ABGRToYRow(src_abgr, dst_y, width);
2434     ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
2435     src_abgr += src_stride_abgr * 2;
2436     dst_y += dst_stride_y * 2;
2437     dst_u += dst_stride_u;
2438     dst_v += dst_stride_v;
2439   }
2440   if (height & 1) {
2441     ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
2442     ABGRToYRow(src_abgr, dst_y, width);
2443   }
2444   return 0;
2445 }
2446 
2447 // Convert RGBA to I420.
2448 LIBYUV_API
RGBAToI420(const uint8_t * src_rgba,int src_stride_rgba,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)2449 int RGBAToI420(const uint8_t* src_rgba,
2450                int src_stride_rgba,
2451                uint8_t* dst_y,
2452                int dst_stride_y,
2453                uint8_t* dst_u,
2454                int dst_stride_u,
2455                uint8_t* dst_v,
2456                int dst_stride_v,
2457                int width,
2458                int height) {
2459   int y;
2460   void (*RGBAToUVRow)(const uint8_t* src_rgba0, int src_stride_rgba,
2461                       uint8_t* dst_u, uint8_t* dst_v, int width) =
2462       RGBAToUVRow_C;
2463   void (*RGBAToYRow)(const uint8_t* src_rgba, uint8_t* dst_y, int width) =
2464       RGBAToYRow_C;
2465   if (!src_rgba || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
2466     return -1;
2467   }
2468   // Negative height means invert the image.
2469   if (height < 0) {
2470     height = -height;
2471     src_rgba = src_rgba + (height - 1) * src_stride_rgba;
2472     src_stride_rgba = -src_stride_rgba;
2473   }
2474 #if defined(HAS_RGBATOYROW_SSSE3)
2475   if (TestCpuFlag(kCpuHasSSSE3)) {
2476     RGBAToYRow = RGBAToYRow_Any_SSSE3;
2477     if (IS_ALIGNED(width, 16)) {
2478       RGBAToYRow = RGBAToYRow_SSSE3;
2479     }
2480   }
2481 #endif
2482 #if defined(HAS_RGBATOUVROW_SSSE3)
2483   if (TestCpuFlag(kCpuHasSSSE3)) {
2484     RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
2485     if (IS_ALIGNED(width, 16)) {
2486       RGBAToUVRow = RGBAToUVRow_SSSE3;
2487     }
2488   }
2489 #endif
2490 #if defined(HAS_RGBATOYROW_NEON)
2491   if (TestCpuFlag(kCpuHasNEON)) {
2492     RGBAToYRow = RGBAToYRow_Any_NEON;
2493     if (IS_ALIGNED(width, 16)) {
2494       RGBAToYRow = RGBAToYRow_NEON;
2495     }
2496   }
2497 #endif
2498 #if defined(HAS_RGBATOUVROW_NEON)
2499   if (TestCpuFlag(kCpuHasNEON)) {
2500     RGBAToUVRow = RGBAToUVRow_Any_NEON;
2501     if (IS_ALIGNED(width, 16)) {
2502       RGBAToUVRow = RGBAToUVRow_NEON;
2503     }
2504   }
2505 #endif
2506 #if defined(HAS_RGBATOYROW_MSA) && defined(HAS_RGBATOUVROW_MSA)
2507   if (TestCpuFlag(kCpuHasMSA)) {
2508     RGBAToYRow = RGBAToYRow_Any_MSA;
2509     RGBAToUVRow = RGBAToUVRow_Any_MSA;
2510     if (IS_ALIGNED(width, 16)) {
2511       RGBAToYRow = RGBAToYRow_MSA;
2512       RGBAToUVRow = RGBAToUVRow_MSA;
2513     }
2514   }
2515 #endif
2516 #if defined(HAS_RGBATOYROW_LSX) && defined(HAS_RGBATOUVROW_LSX)
2517   if (TestCpuFlag(kCpuHasLSX)) {
2518     RGBAToYRow = RGBAToYRow_Any_LSX;
2519     RGBAToUVRow = RGBAToUVRow_Any_LSX;
2520     if (IS_ALIGNED(width, 16)) {
2521       RGBAToYRow = RGBAToYRow_LSX;
2522       RGBAToUVRow = RGBAToUVRow_LSX;
2523     }
2524   }
2525 #endif
2526 #if defined(HAS_RGBATOYROW_LASX)
2527   if (TestCpuFlag(kCpuHasNEON)) {
2528     RGBAToYRow = RGBAToYRow_Any_LASX;
2529     if (IS_ALIGNED(width, 32)) {
2530       RGBAToYRow = RGBAToYRow_LASX;
2531     }
2532   }
2533 #endif
2534 #if defined(HAS_RGBATOYROW_RVV)
2535   if (TestCpuFlag(kCpuHasRVV)) {
2536     RGBAToYRow = RGBAToYRow_RVV;
2537   }
2538 #endif
2539 
2540   for (y = 0; y < height - 1; y += 2) {
2541     RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
2542     RGBAToYRow(src_rgba, dst_y, width);
2543     RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
2544     src_rgba += src_stride_rgba * 2;
2545     dst_y += dst_stride_y * 2;
2546     dst_u += dst_stride_u;
2547     dst_v += dst_stride_v;
2548   }
2549   if (height & 1) {
2550     RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
2551     RGBAToYRow(src_rgba, dst_y, width);
2552   }
2553   return 0;
2554 }
2555 
2556 // Enabled if 1 pass is available
2557 #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA) || \
2558      defined(HAS_RGB24TOYROW_LSX) || defined(HAS_RGB24TOYROW_RVV))
2559 #define HAS_RGB24TOYROW
2560 #endif
2561 
2562 // Convert RGB24 to I420.
2563 LIBYUV_API
RGB24ToI420(const uint8_t * src_rgb24,int src_stride_rgb24,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)2564 int RGB24ToI420(const uint8_t* src_rgb24,
2565                 int src_stride_rgb24,
2566                 uint8_t* dst_y,
2567                 int dst_stride_y,
2568                 uint8_t* dst_u,
2569                 int dst_stride_u,
2570                 uint8_t* dst_v,
2571                 int dst_stride_v,
2572                 int width,
2573                 int height) {
2574   int y;
2575 #if defined(HAS_RGB24TOYROW)
2576   void (*RGB24ToUVRow)(const uint8_t* src_rgb24, int src_stride_rgb24,
2577                        uint8_t* dst_u, uint8_t* dst_v, int width) =
2578       RGB24ToUVRow_C;
2579   void (*RGB24ToYRow)(const uint8_t* src_rgb24, uint8_t* dst_y, int width) =
2580       RGB24ToYRow_C;
2581 #else
2582   void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
2583       RGB24ToARGBRow_C;
2584   void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
2585                       uint8_t* dst_u, uint8_t* dst_v, int width) =
2586       ARGBToUVRow_C;
2587   void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
2588       ARGBToYRow_C;
2589 #endif
2590   if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
2591     return -1;
2592   }
2593   // Negative height means invert the image.
2594   if (height < 0) {
2595     height = -height;
2596     src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
2597     src_stride_rgb24 = -src_stride_rgb24;
2598   }
2599 
2600 #if defined(HAS_RGB24TOYROW)
2601 
2602 // Neon version does direct RGB24 to YUV.
2603 #if defined(HAS_RGB24TOYROW_NEON) && defined(HAS_RGB24TOUVROW_NEON)
2604   if (TestCpuFlag(kCpuHasNEON)) {
2605     RGB24ToUVRow = RGB24ToUVRow_Any_NEON;
2606     RGB24ToYRow = RGB24ToYRow_Any_NEON;
2607     if (IS_ALIGNED(width, 16)) {
2608       RGB24ToYRow = RGB24ToYRow_NEON;
2609       RGB24ToUVRow = RGB24ToUVRow_NEON;
2610     }
2611   }
2612 #endif
2613 #if defined(HAS_RGB24TOYROW_MSA) && defined(HAS_RGB24TOUVROW_MSA)
2614   if (TestCpuFlag(kCpuHasMSA)) {
2615     RGB24ToUVRow = RGB24ToUVRow_Any_MSA;
2616     RGB24ToYRow = RGB24ToYRow_Any_MSA;
2617     if (IS_ALIGNED(width, 16)) {
2618       RGB24ToYRow = RGB24ToYRow_MSA;
2619       RGB24ToUVRow = RGB24ToUVRow_MSA;
2620     }
2621   }
2622 #endif
2623 #if defined(HAS_RGB24TOYROW_LSX) && defined(HAS_RGB24TOUVROW_LSX)
2624   if (TestCpuFlag(kCpuHasLSX)) {
2625     RGB24ToUVRow = RGB24ToUVRow_Any_LSX;
2626     RGB24ToYRow = RGB24ToYRow_Any_LSX;
2627     if (IS_ALIGNED(width, 16)) {
2628       RGB24ToYRow = RGB24ToYRow_LSX;
2629       RGB24ToUVRow = RGB24ToUVRow_LSX;
2630     }
2631   }
2632 #endif
2633 #if defined(HAS_RGB24TOYROW_LASX) && defined(HAS_RGB24TOUVROW_LASX)
2634   if (TestCpuFlag(kCpuHasLASX)) {
2635     RGB24ToUVRow = RGB24ToUVRow_Any_LASX;
2636     RGB24ToYRow = RGB24ToYRow_Any_LASX;
2637     if (IS_ALIGNED(width, 32)) {
2638       RGB24ToYRow = RGB24ToYRow_LASX;
2639       RGB24ToUVRow = RGB24ToUVRow_LASX;
2640     }
2641   }
2642 #endif
2643 #if defined(HAS_RGB24TOYROW_RVV)
2644   if (TestCpuFlag(kCpuHasRVV)) {
2645     RGB24ToYRow = RGB24ToYRow_RVV;
2646   }
2647 #endif
2648 
2649 // Other platforms do intermediate conversion from RGB24 to ARGB.
2650 #else  // HAS_RGB24TOYROW
2651 
2652 #if defined(HAS_RGB24TOARGBROW_SSSE3)
2653   if (TestCpuFlag(kCpuHasSSSE3)) {
2654     RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
2655     if (IS_ALIGNED(width, 16)) {
2656       RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
2657     }
2658   }
2659 #endif
2660 #if defined(HAS_ARGBTOYROW_SSSE3)
2661   if (TestCpuFlag(kCpuHasSSSE3)) {
2662     ARGBToYRow = ARGBToYRow_Any_SSSE3;
2663     if (IS_ALIGNED(width, 16)) {
2664       ARGBToYRow = ARGBToYRow_SSSE3;
2665     }
2666   }
2667 #endif
2668 #if defined(HAS_ARGBTOYROW_AVX2)
2669   if (TestCpuFlag(kCpuHasAVX2)) {
2670     ARGBToYRow = ARGBToYRow_Any_AVX2;
2671     if (IS_ALIGNED(width, 32)) {
2672       ARGBToYRow = ARGBToYRow_AVX2;
2673     }
2674   }
2675 #endif
2676 #if defined(HAS_ARGBTOUVROW_SSSE3)
2677   if (TestCpuFlag(kCpuHasSSSE3)) {
2678     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
2679     if (IS_ALIGNED(width, 16)) {
2680       ARGBToUVRow = ARGBToUVRow_SSSE3;
2681     }
2682   }
2683 #endif
2684 #if defined(HAS_ARGBTOUVROW_AVX2)
2685   if (TestCpuFlag(kCpuHasAVX2)) {
2686     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
2687     if (IS_ALIGNED(width, 32)) {
2688       ARGBToUVRow = ARGBToUVRow_AVX2;
2689     }
2690   }
2691 #endif
2692 #endif  // HAS_RGB24TOYROW
2693 
2694   {
2695 #if !defined(HAS_RGB24TOYROW)
2696     // Allocate 2 rows of ARGB.
2697     const int row_size = (width * 4 + 31) & ~31;
2698     align_buffer_64(row, row_size * 2);
2699     if (!row)
2700       return 1;
2701 #endif
2702 
2703     for (y = 0; y < height - 1; y += 2) {
2704 #if defined(HAS_RGB24TOYROW)
2705       RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
2706       RGB24ToYRow(src_rgb24, dst_y, width);
2707       RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
2708 #else
2709       RGB24ToARGBRow(src_rgb24, row, width);
2710       RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + row_size, width);
2711       ARGBToUVRow(row, row_size, dst_u, dst_v, width);
2712       ARGBToYRow(row, dst_y, width);
2713       ARGBToYRow(row + row_size, dst_y + dst_stride_y, width);
2714 #endif
2715       src_rgb24 += src_stride_rgb24 * 2;
2716       dst_y += dst_stride_y * 2;
2717       dst_u += dst_stride_u;
2718       dst_v += dst_stride_v;
2719     }
2720     if (height & 1) {
2721 #if defined(HAS_RGB24TOYROW)
2722       RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
2723       RGB24ToYRow(src_rgb24, dst_y, width);
2724 #else
2725       RGB24ToARGBRow(src_rgb24, row, width);
2726       ARGBToUVRow(row, 0, dst_u, dst_v, width);
2727       ARGBToYRow(row, dst_y, width);
2728 #endif
2729     }
2730 #if !defined(HAS_RGB24TOYROW)
2731     free_aligned_buffer_64(row);
2732 #endif
2733   }
2734   return 0;
2735 }
2736 #undef HAS_RGB24TOYROW
2737 
2738 // Enabled if 1 pass is available
2739 #if defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
2740     defined(HAS_RGB24TOYJROW_RVV)
2741 #define HAS_RGB24TOYJROW
2742 #endif
2743 
2744 // Convert RGB24 to J420.
2745 LIBYUV_API
RGB24ToJ420(const uint8_t * src_rgb24,int src_stride_rgb24,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)2746 int RGB24ToJ420(const uint8_t* src_rgb24,
2747                 int src_stride_rgb24,
2748                 uint8_t* dst_y,
2749                 int dst_stride_y,
2750                 uint8_t* dst_u,
2751                 int dst_stride_u,
2752                 uint8_t* dst_v,
2753                 int dst_stride_v,
2754                 int width,
2755                 int height) {
2756   int y;
2757 #if defined(HAS_RGB24TOYJROW)
2758   void (*RGB24ToUVJRow)(const uint8_t* src_rgb24, int src_stride_rgb24,
2759                         uint8_t* dst_u, uint8_t* dst_v, int width) =
2760       RGB24ToUVJRow_C;
2761   void (*RGB24ToYJRow)(const uint8_t* src_rgb24, uint8_t* dst_y, int width) =
2762       RGB24ToYJRow_C;
2763 #else
2764   void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
2765       RGB24ToARGBRow_C;
2766   void (*ARGBToUVJRow)(const uint8_t* src_argb0, int src_stride_argb,
2767                        uint8_t* dst_u, uint8_t* dst_v, int width) =
2768       ARGBToUVJRow_C;
2769   void (*ARGBToYJRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
2770       ARGBToYJRow_C;
2771 #endif
2772   if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
2773     return -1;
2774   }
2775   // Negative height means invert the image.
2776   if (height < 0) {
2777     height = -height;
2778     src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
2779     src_stride_rgb24 = -src_stride_rgb24;
2780   }
2781 
2782 #if defined(HAS_RGB24TOYJROW)
2783 
2784 // Neon version does direct RGB24 to YUV.
2785 #if defined(HAS_RGB24TOYJROW_NEON) && defined(HAS_RGB24TOUVJROW_NEON)
2786   if (TestCpuFlag(kCpuHasNEON)) {
2787     RGB24ToUVJRow = RGB24ToUVJRow_Any_NEON;
2788     RGB24ToYJRow = RGB24ToYJRow_Any_NEON;
2789     if (IS_ALIGNED(width, 16)) {
2790       RGB24ToYJRow = RGB24ToYJRow_NEON;
2791       RGB24ToUVJRow = RGB24ToUVJRow_NEON;
2792     }
2793   }
2794 #endif
2795 #if defined(HAS_RGB24TOYJROW_MSA) && defined(HAS_RGB24TOUVJROW_MSA)
2796   if (TestCpuFlag(kCpuHasMSA)) {
2797     RGB24ToUVJRow = RGB24ToUVJRow_Any_MSA;
2798     RGB24ToYJRow = RGB24ToYJRow_Any_MSA;
2799     if (IS_ALIGNED(width, 16)) {
2800       RGB24ToYJRow = RGB24ToYJRow_MSA;
2801       RGB24ToUVJRow = RGB24ToUVJRow_MSA;
2802     }
2803   }
2804 #endif
2805 #if defined(HAS_RGB24TOYJROW_LSX)
2806   if (TestCpuFlag(kCpuHasLSX)) {
2807     RGB24ToYJRow = RGB24ToYJRow_Any_LSX;
2808     if (IS_ALIGNED(width, 16)) {
2809       RGB24ToYJRow = RGB24ToYJRow_LSX;
2810     }
2811   }
2812 #endif
2813 #if defined(HAS_RGB24TOYJROW_LASX)
2814   if (TestCpuFlag(kCpuHasLASX)) {
2815     RGB24ToYJRow = RGB24ToYJRow_Any_LASX;
2816     if (IS_ALIGNED(width, 32)) {
2817       RGB24ToYJRow = RGB24ToYJRow_LASX;
2818     }
2819   }
2820 #endif
2821 #if defined(HAS_RGB24TOYJROW_RVV)
2822   if (TestCpuFlag(kCpuHasRVV)) {
2823     RGB24ToYJRow = RGB24ToYJRow_RVV;
2824   }
2825 #endif
2826 
2827 // Other platforms do intermediate conversion from RGB24 to ARGB.
2828 #else  // HAS_RGB24TOYJROW
2829 
2830 #if defined(HAS_RGB24TOARGBROW_SSSE3)
2831   if (TestCpuFlag(kCpuHasSSSE3)) {
2832     RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
2833     if (IS_ALIGNED(width, 16)) {
2834       RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
2835     }
2836   }
2837 #endif
2838 #if defined(HAS_ARGBTOYJROW_SSSE3)
2839   if (TestCpuFlag(kCpuHasSSSE3)) {
2840     ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
2841     if (IS_ALIGNED(width, 16)) {
2842       ARGBToYJRow = ARGBToYJRow_SSSE3;
2843     }
2844   }
2845 #endif
2846 #if defined(HAS_ARGBTOYJROW_AVX2)
2847   if (TestCpuFlag(kCpuHasAVX2)) {
2848     ARGBToYJRow = ARGBToYJRow_Any_AVX2;
2849     if (IS_ALIGNED(width, 32)) {
2850       ARGBToYJRow = ARGBToYJRow_AVX2;
2851     }
2852   }
2853 #endif
2854 #if defined(HAS_ARGBTOUVJROW_SSSE3)
2855   if (TestCpuFlag(kCpuHasSSSE3)) {
2856     ARGBToUVJRow = ARGBToUVJRow_Any_SSSE3;
2857     if (IS_ALIGNED(width, 16)) {
2858       ARGBToUVJRow = ARGBToUVJRow_SSSE3;
2859     }
2860   }
2861 #endif
2862 #if defined(HAS_ARGBTOUVJROW_AVX2)
2863   if (TestCpuFlag(kCpuHasAVX2)) {
2864     ARGBToUVJRow = ARGBToUVJRow_Any_AVX2;
2865     if (IS_ALIGNED(width, 32)) {
2866       ARGBToUVJRow = ARGBToUVJRow_AVX2;
2867     }
2868   }
2869 #endif
2870 #endif  // HAS_RGB24TOYJROW
2871 
2872   {
2873 #if !defined(HAS_RGB24TOYJROW)
2874     // Allocate 2 rows of ARGB.
2875     const int row_size = (width * 4 + 31) & ~31;
2876     align_buffer_64(row, row_size * 2);
2877     if (!row)
2878       return 1;
2879 #endif
2880 
2881     for (y = 0; y < height - 1; y += 2) {
2882 #if defined(HAS_RGB24TOYJROW)
2883       RGB24ToUVJRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
2884       RGB24ToYJRow(src_rgb24, dst_y, width);
2885       RGB24ToYJRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
2886 #else
2887       RGB24ToARGBRow(src_rgb24, row, width);
2888       RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + row_size, width);
2889       ARGBToUVJRow(row, row_size, dst_u, dst_v, width);
2890       ARGBToYJRow(row, dst_y, width);
2891       ARGBToYJRow(row + row_size, dst_y + dst_stride_y, width);
2892 #endif
2893       src_rgb24 += src_stride_rgb24 * 2;
2894       dst_y += dst_stride_y * 2;
2895       dst_u += dst_stride_u;
2896       dst_v += dst_stride_v;
2897     }
2898     if (height & 1) {
2899 #if defined(HAS_RGB24TOYJROW)
2900       RGB24ToUVJRow(src_rgb24, 0, dst_u, dst_v, width);
2901       RGB24ToYJRow(src_rgb24, dst_y, width);
2902 #else
2903       RGB24ToARGBRow(src_rgb24, row, width);
2904       ARGBToUVJRow(row, 0, dst_u, dst_v, width);
2905       ARGBToYJRow(row, dst_y, width);
2906 #endif
2907     }
2908 #if !defined(HAS_RGB24TOYJROW)
2909     free_aligned_buffer_64(row);
2910 #endif
2911   }
2912   return 0;
2913 }
2914 #undef HAS_RGB24TOYJROW
2915 
2916 // Enabled if 1 pass is available
2917 #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA) || \
2918      defined(HAS_RAWTOYROW_LSX) || defined(HAS_RAWTOYROW_RVV))
2919 #define HAS_RAWTOYROW
2920 #endif
2921 
2922 // Convert RAW to I420.
2923 LIBYUV_API
RAWToI420(const uint8_t * src_raw,int src_stride_raw,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)2924 int RAWToI420(const uint8_t* src_raw,
2925               int src_stride_raw,
2926               uint8_t* dst_y,
2927               int dst_stride_y,
2928               uint8_t* dst_u,
2929               int dst_stride_u,
2930               uint8_t* dst_v,
2931               int dst_stride_v,
2932               int width,
2933               int height) {
2934   int y;
2935 #if defined(HAS_RAWTOYROW)
2936   void (*RAWToUVRow)(const uint8_t* src_raw, int src_stride_raw, uint8_t* dst_u,
2937                      uint8_t* dst_v, int width) = RAWToUVRow_C;
2938   void (*RAWToYRow)(const uint8_t* src_raw, uint8_t* dst_y, int width) =
2939       RAWToYRow_C;
2940 #else
2941   void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
2942       RAWToARGBRow_C;
2943   void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
2944                       uint8_t* dst_u, uint8_t* dst_v, int width) =
2945       ARGBToUVRow_C;
2946   void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
2947       ARGBToYRow_C;
2948 #endif
2949   if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
2950     return -1;
2951   }
2952   // Negative height means invert the image.
2953   if (height < 0) {
2954     height = -height;
2955     src_raw = src_raw + (height - 1) * src_stride_raw;
2956     src_stride_raw = -src_stride_raw;
2957   }
2958 
2959 #if defined(HAS_RAWTOYROW)
2960 
2961 // Neon version does direct RAW to YUV.
2962 #if defined(HAS_RAWTOYROW_NEON) && defined(HAS_RAWTOUVROW_NEON)
2963   if (TestCpuFlag(kCpuHasNEON)) {
2964     RAWToUVRow = RAWToUVRow_Any_NEON;
2965     RAWToYRow = RAWToYRow_Any_NEON;
2966     if (IS_ALIGNED(width, 16)) {
2967       RAWToYRow = RAWToYRow_NEON;
2968       RAWToUVRow = RAWToUVRow_NEON;
2969     }
2970   }
2971 #endif
2972 #if defined(HAS_RAWTOYROW_MSA) && defined(HAS_RAWTOUVROW_MSA)
2973   if (TestCpuFlag(kCpuHasMSA)) {
2974     RAWToUVRow = RAWToUVRow_Any_MSA;
2975     RAWToYRow = RAWToYRow_Any_MSA;
2976     if (IS_ALIGNED(width, 16)) {
2977       RAWToYRow = RAWToYRow_MSA;
2978       RAWToUVRow = RAWToUVRow_MSA;
2979     }
2980   }
2981 #endif
2982 #if defined(HAS_RAWTOYROW_LSX) && defined(HAS_RAWTOUVROW_LSX)
2983   if (TestCpuFlag(kCpuHasLSX)) {
2984     RAWToUVRow = RAWToUVRow_Any_LSX;
2985     RAWToYRow = RAWToYRow_Any_LSX;
2986     if (IS_ALIGNED(width, 16)) {
2987       RAWToYRow = RAWToYRow_LSX;
2988       RAWToUVRow = RAWToUVRow_LSX;
2989     }
2990   }
2991 #endif
2992 #if defined(HAS_RAWTOYROW_LASX) && defined(HAS_RAWTOUVROW_LASX)
2993   if (TestCpuFlag(kCpuHasLASX)) {
2994     RAWToUVRow = RAWToUVRow_Any_LASX;
2995     RAWToYRow = RAWToYRow_Any_LASX;
2996     if (IS_ALIGNED(width, 32)) {
2997       RAWToYRow = RAWToYRow_LASX;
2998       RAWToUVRow = RAWToUVRow_LASX;
2999     }
3000   }
3001 #endif
3002 #if defined(HAS_RAWTOYROW_RVV)
3003   if (TestCpuFlag(kCpuHasRVV)) {
3004     RAWToYRow = RAWToYRow_RVV;
3005   }
3006 #endif
3007 
3008 // Other platforms do intermediate conversion from RAW to ARGB.
3009 #else  // HAS_RAWTOYROW
3010 
3011 #if defined(HAS_RAWTOARGBROW_SSSE3)
3012   if (TestCpuFlag(kCpuHasSSSE3)) {
3013     RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
3014     if (IS_ALIGNED(width, 16)) {
3015       RAWToARGBRow = RAWToARGBRow_SSSE3;
3016     }
3017   }
3018 #endif
3019 #if defined(HAS_ARGBTOYROW_SSSE3)
3020   if (TestCpuFlag(kCpuHasSSSE3)) {
3021     ARGBToYRow = ARGBToYRow_Any_SSSE3;
3022     if (IS_ALIGNED(width, 16)) {
3023       ARGBToYRow = ARGBToYRow_SSSE3;
3024     }
3025   }
3026 #endif
3027 #if defined(HAS_ARGBTOYROW_AVX2)
3028   if (TestCpuFlag(kCpuHasAVX2)) {
3029     ARGBToYRow = ARGBToYRow_Any_AVX2;
3030     if (IS_ALIGNED(width, 32)) {
3031       ARGBToYRow = ARGBToYRow_AVX2;
3032     }
3033   }
3034 #endif
3035 #if defined(HAS_ARGBTOUVROW_SSSE3)
3036   if (TestCpuFlag(kCpuHasSSSE3)) {
3037     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
3038     if (IS_ALIGNED(width, 16)) {
3039       ARGBToUVRow = ARGBToUVRow_SSSE3;
3040     }
3041   }
3042 #endif
3043 #if defined(HAS_ARGBTOUVROW_AVX2)
3044   if (TestCpuFlag(kCpuHasAVX2)) {
3045     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
3046     if (IS_ALIGNED(width, 32)) {
3047       ARGBToUVRow = ARGBToUVRow_AVX2;
3048     }
3049   }
3050 #endif
3051 #endif  // HAS_RAWTOYROW
3052 
3053   {
3054 #if !defined(HAS_RAWTOYROW)
3055     // Allocate 2 rows of ARGB.
3056     const int row_size = (width * 4 + 31) & ~31;
3057     align_buffer_64(row, row_size * 2);
3058     if (!row)
3059       return 1;
3060 #endif
3061 
3062     for (y = 0; y < height - 1; y += 2) {
3063 #if defined(HAS_RAWTOYROW)
3064       RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width);
3065       RAWToYRow(src_raw, dst_y, width);
3066       RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
3067 #else
3068       RAWToARGBRow(src_raw, row, width);
3069       RAWToARGBRow(src_raw + src_stride_raw, row + row_size, width);
3070       ARGBToUVRow(row, row_size, dst_u, dst_v, width);
3071       ARGBToYRow(row, dst_y, width);
3072       ARGBToYRow(row + row_size, dst_y + dst_stride_y, width);
3073 #endif
3074       src_raw += src_stride_raw * 2;
3075       dst_y += dst_stride_y * 2;
3076       dst_u += dst_stride_u;
3077       dst_v += dst_stride_v;
3078     }
3079     if (height & 1) {
3080 #if defined(HAS_RAWTOYROW)
3081       RAWToUVRow(src_raw, 0, dst_u, dst_v, width);
3082       RAWToYRow(src_raw, dst_y, width);
3083 #else
3084       RAWToARGBRow(src_raw, row, width);
3085       ARGBToUVRow(row, 0, dst_u, dst_v, width);
3086       ARGBToYRow(row, dst_y, width);
3087 #endif
3088     }
3089 #if !defined(HAS_RAWTOYROW)
3090     free_aligned_buffer_64(row);
3091 #endif
3092   }
3093   return 0;
3094 }
3095 #undef HAS_RAWTOYROW
3096 
3097 // Enabled if 1 pass is available
3098 #if defined(HAS_RAWTOYJROW_NEON) || defined(HAS_RAWTOYJROW_MSA) || \
3099     defined(HAS_RAWTOYJROW_RVV)
3100 #define HAS_RAWTOYJROW
3101 #endif
3102 
3103 // Convert RAW to J420.
3104 LIBYUV_API
RAWToJ420(const uint8_t * src_raw,int src_stride_raw,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)3105 int RAWToJ420(const uint8_t* src_raw,
3106               int src_stride_raw,
3107               uint8_t* dst_y,
3108               int dst_stride_y,
3109               uint8_t* dst_u,
3110               int dst_stride_u,
3111               uint8_t* dst_v,
3112               int dst_stride_v,
3113               int width,
3114               int height) {
3115   int y;
3116 #if defined(HAS_RAWTOYJROW)
3117   void (*RAWToUVJRow)(const uint8_t* src_raw, int src_stride_raw,
3118                       uint8_t* dst_u, uint8_t* dst_v, int width) =
3119       RAWToUVJRow_C;
3120   void (*RAWToYJRow)(const uint8_t* src_raw, uint8_t* dst_y, int width) =
3121       RAWToYJRow_C;
3122 #else
3123   void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
3124       RAWToARGBRow_C;
3125   void (*ARGBToUVJRow)(const uint8_t* src_argb0, int src_stride_argb,
3126                        uint8_t* dst_u, uint8_t* dst_v, int width) =
3127       ARGBToUVJRow_C;
3128   void (*ARGBToYJRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
3129       ARGBToYJRow_C;
3130 #endif
3131   if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
3132     return -1;
3133   }
3134   // Negative height means invert the image.
3135   if (height < 0) {
3136     height = -height;
3137     src_raw = src_raw + (height - 1) * src_stride_raw;
3138     src_stride_raw = -src_stride_raw;
3139   }
3140 
3141 #if defined(HAS_RAWTOYJROW)
3142 
3143 // Neon version does direct RAW to YUV.
3144 #if defined(HAS_RAWTOYJROW_NEON) && defined(HAS_RAWTOUVJROW_NEON)
3145   if (TestCpuFlag(kCpuHasNEON)) {
3146     RAWToUVJRow = RAWToUVJRow_Any_NEON;
3147     RAWToYJRow = RAWToYJRow_Any_NEON;
3148     if (IS_ALIGNED(width, 16)) {
3149       RAWToYJRow = RAWToYJRow_NEON;
3150       RAWToUVJRow = RAWToUVJRow_NEON;
3151     }
3152   }
3153 #endif
3154 #if defined(HAS_RAWTOYJROW_MSA) && defined(HAS_RAWTOUVJROW_MSA)
3155   if (TestCpuFlag(kCpuHasMSA)) {
3156     RAWToUVJRow = RAWToUVJRow_Any_MSA;
3157     RAWToYJRow = RAWToYJRow_Any_MSA;
3158     if (IS_ALIGNED(width, 16)) {
3159       RAWToYJRow = RAWToYJRow_MSA;
3160       RAWToUVJRow = RAWToUVJRow_MSA;
3161     }
3162   }
3163 #endif
3164 #if defined(HAS_RAWTOYJROW_LSX)
3165   if (TestCpuFlag(kCpuHasLSX)) {
3166     RAWToYJRow = RAWToYJRow_Any_LSX;
3167     if (IS_ALIGNED(width, 16)) {
3168       RAWToYJRow = RAWToYJRow_LSX;
3169     }
3170   }
3171 #endif
3172 #if defined(HAS_RAWTOYJROW_LASX)
3173   if (TestCpuFlag(kCpuHasLASX)) {
3174     RAWToYJRow = RAWToYJRow_Any_LASX;
3175     if (IS_ALIGNED(width, 32)) {
3176       RAWToYJRow = RAWToYJRow_LASX;
3177     }
3178   }
3179 #endif
3180 #if defined(HAS_RAWTOYJROW_RVV)
3181   if (TestCpuFlag(kCpuHasRVV)) {
3182     RAWToYJRow = RAWToYJRow_RVV;
3183   }
3184 #endif
3185 
3186 // Other platforms do intermediate conversion from RAW to ARGB.
3187 #else  // HAS_RAWTOYJROW
3188 
3189 #if defined(HAS_RAWTOARGBROW_SSSE3)
3190   if (TestCpuFlag(kCpuHasSSSE3)) {
3191     RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
3192     if (IS_ALIGNED(width, 16)) {
3193       RAWToARGBRow = RAWToARGBRow_SSSE3;
3194     }
3195   }
3196 #endif
3197 #if defined(HAS_ARGBTOYJROW_SSSE3)
3198   if (TestCpuFlag(kCpuHasSSSE3)) {
3199     ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
3200     if (IS_ALIGNED(width, 16)) {
3201       ARGBToYJRow = ARGBToYJRow_SSSE3;
3202     }
3203   }
3204 #endif
3205 #if defined(HAS_ARGBTOYJROW_AVX2)
3206   if (TestCpuFlag(kCpuHasAVX2)) {
3207     ARGBToYJRow = ARGBToYJRow_Any_AVX2;
3208     if (IS_ALIGNED(width, 32)) {
3209       ARGBToYJRow = ARGBToYJRow_AVX2;
3210     }
3211   }
3212 #endif
3213 #if defined(HAS_ARGBTOUVJROW_SSSE3)
3214   if (TestCpuFlag(kCpuHasSSSE3)) {
3215     ARGBToUVJRow = ARGBToUVJRow_Any_SSSE3;
3216     if (IS_ALIGNED(width, 16)) {
3217       ARGBToUVJRow = ARGBToUVJRow_SSSE3;
3218     }
3219   }
3220 #endif
3221 #if defined(HAS_ARGBTOUVJROW_AVX2)
3222   if (TestCpuFlag(kCpuHasAVX2)) {
3223     ARGBToUVJRow = ARGBToUVJRow_Any_AVX2;
3224     if (IS_ALIGNED(width, 32)) {
3225       ARGBToUVJRow = ARGBToUVJRow_AVX2;
3226     }
3227   }
3228 #endif
3229 #endif  // HAS_RAWTOYJROW
3230 
3231   {
3232 #if !defined(HAS_RAWTOYJROW)
3233     // Allocate 2 rows of ARGB.
3234     const int row_size = (width * 4 + 31) & ~31;
3235     align_buffer_64(row, row_size * 2);
3236     if (!row)
3237       return 1;
3238 #endif
3239 
3240     for (y = 0; y < height - 1; y += 2) {
3241 #if defined(HAS_RAWTOYJROW)
3242       RAWToUVJRow(src_raw, src_stride_raw, dst_u, dst_v, width);
3243       RAWToYJRow(src_raw, dst_y, width);
3244       RAWToYJRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
3245 #else
3246       RAWToARGBRow(src_raw, row, width);
3247       RAWToARGBRow(src_raw + src_stride_raw, row + row_size, width);
3248       ARGBToUVJRow(row, row_size, dst_u, dst_v, width);
3249       ARGBToYJRow(row, dst_y, width);
3250       ARGBToYJRow(row + row_size, dst_y + dst_stride_y, width);
3251 #endif
3252       src_raw += src_stride_raw * 2;
3253       dst_y += dst_stride_y * 2;
3254       dst_u += dst_stride_u;
3255       dst_v += dst_stride_v;
3256     }
3257     if (height & 1) {
3258 #if defined(HAS_RAWTOYJROW)
3259       RAWToUVJRow(src_raw, 0, dst_u, dst_v, width);
3260       RAWToYJRow(src_raw, dst_y, width);
3261 #else
3262       RAWToARGBRow(src_raw, row, width);
3263       ARGBToUVJRow(row, 0, dst_u, dst_v, width);
3264       ARGBToYJRow(row, dst_y, width);
3265 #endif
3266     }
3267 #if !defined(HAS_RAWTOYJROW)
3268     free_aligned_buffer_64(row);
3269 #endif
3270   }
3271   return 0;
3272 }
3273 #undef HAS_RAWTOYJROW
3274 
3275 // Convert RGB565 to I420.
3276 LIBYUV_API
RGB565ToI420(const uint8_t * src_rgb565,int src_stride_rgb565,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)3277 int RGB565ToI420(const uint8_t* src_rgb565,
3278                  int src_stride_rgb565,
3279                  uint8_t* dst_y,
3280                  int dst_stride_y,
3281                  uint8_t* dst_u,
3282                  int dst_stride_u,
3283                  uint8_t* dst_v,
3284                  int dst_stride_v,
3285                  int width,
3286                  int height) {
3287   int y;
3288 #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
3289      defined(HAS_RGB565TOYROW_LSX) || defined(HAS_RGB565TOYROW_LASX))
3290   void (*RGB565ToUVRow)(const uint8_t* src_rgb565, int src_stride_rgb565,
3291                         uint8_t* dst_u, uint8_t* dst_v, int width) =
3292       RGB565ToUVRow_C;
3293   void (*RGB565ToYRow)(const uint8_t* src_rgb565, uint8_t* dst_y, int width) =
3294       RGB565ToYRow_C;
3295 #else
3296   void (*RGB565ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
3297                           int width) = RGB565ToARGBRow_C;
3298   void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
3299                       uint8_t* dst_u, uint8_t* dst_v, int width) =
3300       ARGBToUVRow_C;
3301   void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
3302       ARGBToYRow_C;
3303 #endif
3304   if (!src_rgb565 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
3305     return -1;
3306   }
3307   // Negative height means invert the image.
3308   if (height < 0) {
3309     height = -height;
3310     src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
3311     src_stride_rgb565 = -src_stride_rgb565;
3312   }
3313 
3314 // Neon version does direct RGB565 to YUV.
3315 #if defined(HAS_RGB565TOYROW_NEON)
3316   if (TestCpuFlag(kCpuHasNEON)) {
3317     RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
3318     RGB565ToYRow = RGB565ToYRow_Any_NEON;
3319     if (IS_ALIGNED(width, 8)) {
3320       RGB565ToYRow = RGB565ToYRow_NEON;
3321       if (IS_ALIGNED(width, 16)) {
3322         RGB565ToUVRow = RGB565ToUVRow_NEON;
3323       }
3324     }
3325   }
3326 // MSA version does direct RGB565 to YUV.
3327 #elif (defined(HAS_RGB565TOYROW_MSA) || defined(HAS_RGB565TOYROW_LSX) || \
3328        defined(HAS_RGB565TOYROW_LASX))
3329 #if defined(HAS_RGB565TOYROW_MSA) && defined(HAS_RGB565TOUVROW_MSA)
3330   if (TestCpuFlag(kCpuHasMSA)) {
3331     RGB565ToUVRow = RGB565ToUVRow_Any_MSA;
3332     RGB565ToYRow = RGB565ToYRow_Any_MSA;
3333     if (IS_ALIGNED(width, 16)) {
3334       RGB565ToYRow = RGB565ToYRow_MSA;
3335       RGB565ToUVRow = RGB565ToUVRow_MSA;
3336     }
3337   }
3338 #endif
3339 #if defined(HAS_RGB565TOYROW_LSX) && defined(HAS_RGB565TOUVROW_LSX)
3340   if (TestCpuFlag(kCpuHasLSX)) {
3341     RGB565ToUVRow = RGB565ToUVRow_Any_LSX;
3342     RGB565ToYRow = RGB565ToYRow_Any_LSX;
3343     if (IS_ALIGNED(width, 16)) {
3344       RGB565ToYRow = RGB565ToYRow_LSX;
3345       RGB565ToUVRow = RGB565ToUVRow_LSX;
3346     }
3347   }
3348 #endif
3349 #if defined(HAS_RGB565TOYROW_LASX) && defined(HAS_RGB565TOUVROW_LASX)
3350   if (TestCpuFlag(kCpuHasLASX)) {
3351     RGB565ToUVRow = RGB565ToUVRow_Any_LASX;
3352     RGB565ToYRow = RGB565ToYRow_Any_LASX;
3353     if (IS_ALIGNED(width, 32)) {
3354       RGB565ToYRow = RGB565ToYRow_LASX;
3355       RGB565ToUVRow = RGB565ToUVRow_LASX;
3356     }
3357   }
3358 #endif
3359 // Other platforms do intermediate conversion from RGB565 to ARGB.
3360 #else
3361 #if defined(HAS_RGB565TOARGBROW_SSE2)
3362   if (TestCpuFlag(kCpuHasSSE2)) {
3363     RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
3364     if (IS_ALIGNED(width, 8)) {
3365       RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
3366     }
3367   }
3368 #endif
3369 #if defined(HAS_RGB565TOARGBROW_AVX2)
3370   if (TestCpuFlag(kCpuHasAVX2)) {
3371     RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
3372     if (IS_ALIGNED(width, 16)) {
3373       RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
3374     }
3375   }
3376 #endif
3377 #if defined(HAS_ARGBTOYROW_SSSE3)
3378   if (TestCpuFlag(kCpuHasSSSE3)) {
3379     ARGBToYRow = ARGBToYRow_Any_SSSE3;
3380     if (IS_ALIGNED(width, 16)) {
3381       ARGBToYRow = ARGBToYRow_SSSE3;
3382     }
3383   }
3384 #endif
3385 #if defined(HAS_ARGBTOUVROW_SSSE3)
3386   if (TestCpuFlag(kCpuHasSSSE3)) {
3387     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
3388     if (IS_ALIGNED(width, 16)) {
3389       ARGBToUVRow = ARGBToUVRow_SSSE3;
3390     }
3391   }
3392 #endif
3393 #if defined(HAS_ARGBTOYROW_AVX2)
3394   if (TestCpuFlag(kCpuHasAVX2)) {
3395     ARGBToYRow = ARGBToYRow_Any_AVX2;
3396     if (IS_ALIGNED(width, 32)) {
3397       ARGBToYRow = ARGBToYRow_AVX2;
3398     }
3399   }
3400 #endif
3401 #if defined(HAS_ARGBTOUVROW_AVX2)
3402   if (TestCpuFlag(kCpuHasAVX2)) {
3403     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
3404     if (IS_ALIGNED(width, 32)) {
3405       ARGBToUVRow = ARGBToUVRow_AVX2;
3406     }
3407   }
3408 #endif
3409 #endif
3410   {
3411 #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
3412       defined(HAS_RGB565TOYROW_LSX) || defined(HAS_RGB565TOYROW_LASX))
3413     // Allocate 2 rows of ARGB.
3414     const int row_size = (width * 4 + 31) & ~31;
3415     align_buffer_64(row, row_size * 2);
3416     if (!row)
3417       return 1;
3418 #endif
3419     for (y = 0; y < height - 1; y += 2) {
3420 #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
3421      defined(HAS_RGB565TOYROW_LSX) || defined(HAS_RGB565TOYROW_LASX))
3422       RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width);
3423       RGB565ToYRow(src_rgb565, dst_y, width);
3424       RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
3425 #else
3426       RGB565ToARGBRow(src_rgb565, row, width);
3427       RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + row_size, width);
3428       ARGBToUVRow(row, row_size, dst_u, dst_v, width);
3429       ARGBToYRow(row, dst_y, width);
3430       ARGBToYRow(row + row_size, dst_y + dst_stride_y, width);
3431 #endif
3432       src_rgb565 += src_stride_rgb565 * 2;
3433       dst_y += dst_stride_y * 2;
3434       dst_u += dst_stride_u;
3435       dst_v += dst_stride_v;
3436     }
3437     if (height & 1) {
3438 #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
3439      defined(HAS_RGB565TOYROW_LSX) || defined(HAS_RGB565TOYROW_LASX))
3440       RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width);
3441       RGB565ToYRow(src_rgb565, dst_y, width);
3442 #else
3443       RGB565ToARGBRow(src_rgb565, row, width);
3444       ARGBToUVRow(row, 0, dst_u, dst_v, width);
3445       ARGBToYRow(row, dst_y, width);
3446 #endif
3447     }
3448 #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
3449       defined(HAS_RGB565TOYROW_LSX) || defined(HAS_RGB565TOYROW_LASX))
3450     free_aligned_buffer_64(row);
3451 #endif
3452   }
3453   return 0;
3454 }
3455 
3456 // Convert ARGB1555 to I420.
3457 LIBYUV_API
ARGB1555ToI420(const uint8_t * src_argb1555,int src_stride_argb1555,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)3458 int ARGB1555ToI420(const uint8_t* src_argb1555,
3459                    int src_stride_argb1555,
3460                    uint8_t* dst_y,
3461                    int dst_stride_y,
3462                    uint8_t* dst_u,
3463                    int dst_stride_u,
3464                    uint8_t* dst_v,
3465                    int dst_stride_v,
3466                    int width,
3467                    int height) {
3468   int y;
3469 #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
3470      defined(HAS_ARGB1555TOYROW_LSX) || defined(HAS_ARGB1555TOYROW_LASX))
3471   void (*ARGB1555ToUVRow)(const uint8_t* src_argb1555, int src_stride_argb1555,
3472                           uint8_t* dst_u, uint8_t* dst_v, int width) =
3473       ARGB1555ToUVRow_C;
3474   void (*ARGB1555ToYRow)(const uint8_t* src_argb1555, uint8_t* dst_y,
3475                          int width) = ARGB1555ToYRow_C;
3476 #else
3477   void (*ARGB1555ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
3478                             int width) = ARGB1555ToARGBRow_C;
3479   void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
3480                       uint8_t* dst_u, uint8_t* dst_v, int width) =
3481       ARGBToUVRow_C;
3482   void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
3483       ARGBToYRow_C;
3484 #endif
3485   if (!src_argb1555 || !dst_y || !dst_u || !dst_v || width <= 0 ||
3486       height == 0) {
3487     return -1;
3488   }
3489   // Negative height means invert the image.
3490   if (height < 0) {
3491     height = -height;
3492     src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
3493     src_stride_argb1555 = -src_stride_argb1555;
3494   }
3495 
3496 // Neon version does direct ARGB1555 to YUV.
3497 #if defined(HAS_ARGB1555TOYROW_NEON)
3498   if (TestCpuFlag(kCpuHasNEON)) {
3499     ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
3500     ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
3501     if (IS_ALIGNED(width, 8)) {
3502       ARGB1555ToYRow = ARGB1555ToYRow_NEON;
3503       if (IS_ALIGNED(width, 16)) {
3504         ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
3505       }
3506     }
3507   }
3508 // MSA version does direct ARGB1555 to YUV.
3509 #elif (defined(HAS_ARGB1555TOYROW_MSA) || defined(HAS_ARGB1555TOYROW_LSX) || \
3510        defined(HAS_ARGB1555TOYROW_LASX))
3511 #if defined(HAS_ARGB1555TOYROW_MSA) && defined(HAS_ARGB1555TOUVROW_MSA)
3512   if (TestCpuFlag(kCpuHasMSA)) {
3513     ARGB1555ToUVRow = ARGB1555ToUVRow_Any_MSA;
3514     ARGB1555ToYRow = ARGB1555ToYRow_Any_MSA;
3515     if (IS_ALIGNED(width, 16)) {
3516       ARGB1555ToYRow = ARGB1555ToYRow_MSA;
3517       ARGB1555ToUVRow = ARGB1555ToUVRow_MSA;
3518     }
3519   }
3520 #endif
3521 #if defined(HAS_ARGB1555TOYROW_LSX) && defined(HAS_ARGB1555TOUVROW_LSX)
3522   if (TestCpuFlag(kCpuHasLSX)) {
3523     ARGB1555ToUVRow = ARGB1555ToUVRow_Any_LSX;
3524     ARGB1555ToYRow = ARGB1555ToYRow_Any_LSX;
3525     if (IS_ALIGNED(width, 16)) {
3526       ARGB1555ToYRow = ARGB1555ToYRow_LSX;
3527       ARGB1555ToUVRow = ARGB1555ToUVRow_LSX;
3528     }
3529   }
3530 #endif
3531 #if defined(HAS_ARGB1555TOYROW_LASX) && defined(HAS_ARGB1555TOUVROW_LASX)
3532   if (TestCpuFlag(kCpuHasLASX)) {
3533     ARGB1555ToUVRow = ARGB1555ToUVRow_Any_LASX;
3534     ARGB1555ToYRow = ARGB1555ToYRow_Any_LASX;
3535     if (IS_ALIGNED(width, 32)) {
3536       ARGB1555ToYRow = ARGB1555ToYRow_LASX;
3537       ARGB1555ToUVRow = ARGB1555ToUVRow_LASX;
3538     }
3539   }
3540 #endif
3541 // Other platforms do intermediate conversion from ARGB1555 to ARGB.
3542 #else
3543 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
3544   if (TestCpuFlag(kCpuHasSSE2)) {
3545     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
3546     if (IS_ALIGNED(width, 8)) {
3547       ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
3548     }
3549   }
3550 #endif
3551 #if defined(HAS_ARGB1555TOARGBROW_AVX2)
3552   if (TestCpuFlag(kCpuHasAVX2)) {
3553     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
3554     if (IS_ALIGNED(width, 16)) {
3555       ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
3556     }
3557   }
3558 #endif
3559 #if defined(HAS_ARGBTOYROW_SSSE3)
3560   if (TestCpuFlag(kCpuHasSSSE3)) {
3561     ARGBToYRow = ARGBToYRow_Any_SSSE3;
3562     if (IS_ALIGNED(width, 16)) {
3563       ARGBToYRow = ARGBToYRow_SSSE3;
3564     }
3565   }
3566 #endif
3567 #if defined(HAS_ARGBTOUVROW_SSSE3)
3568   if (TestCpuFlag(kCpuHasSSSE3)) {
3569     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
3570     if (IS_ALIGNED(width, 16)) {
3571       ARGBToUVRow = ARGBToUVRow_SSSE3;
3572     }
3573   }
3574 #endif
3575 #if defined(HAS_ARGBTOYROW_AVX2)
3576   if (TestCpuFlag(kCpuHasAVX2)) {
3577     ARGBToYRow = ARGBToYRow_Any_AVX2;
3578     if (IS_ALIGNED(width, 32)) {
3579       ARGBToYRow = ARGBToYRow_AVX2;
3580     }
3581   }
3582 #endif
3583 #if defined(HAS_ARGBTOUVROW_AVX2)
3584   if (TestCpuFlag(kCpuHasAVX2)) {
3585     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
3586     if (IS_ALIGNED(width, 32)) {
3587       ARGBToUVRow = ARGBToUVRow_AVX2;
3588     }
3589   }
3590 #endif
3591 #endif
3592   {
3593 #if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
3594       defined(HAS_ARGB1555TOYROW_LSX) || defined(HAS_ARGB1555TOYROW_LASX))
3595     // Allocate 2 rows of ARGB.
3596     const int row_size = (width * 4 + 31) & ~31;
3597     align_buffer_64(row, row_size * 2);
3598     if (!row)
3599       return 1;
3600 #endif
3601 
3602     for (y = 0; y < height - 1; y += 2) {
3603 #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
3604      defined(HAS_ARGB1555TOYROW_LSX) || defined(HAS_ARGB1555TOYROW_LASX))
3605       ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width);
3606       ARGB1555ToYRow(src_argb1555, dst_y, width);
3607       ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y,
3608                      width);
3609 #else
3610       ARGB1555ToARGBRow(src_argb1555, row, width);
3611       ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + row_size,
3612                         width);
3613       ARGBToUVRow(row, row_size, dst_u, dst_v, width);
3614       ARGBToYRow(row, dst_y, width);
3615       ARGBToYRow(row + row_size, dst_y + dst_stride_y, width);
3616 #endif
3617       src_argb1555 += src_stride_argb1555 * 2;
3618       dst_y += dst_stride_y * 2;
3619       dst_u += dst_stride_u;
3620       dst_v += dst_stride_v;
3621     }
3622     if (height & 1) {
3623 #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
3624      defined(HAS_ARGB1555TOYROW_LSX) || defined(HAS_ARGB1555TOYROW_LASX))
3625       ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width);
3626       ARGB1555ToYRow(src_argb1555, dst_y, width);
3627 #else
3628       ARGB1555ToARGBRow(src_argb1555, row, width);
3629       ARGBToUVRow(row, 0, dst_u, dst_v, width);
3630       ARGBToYRow(row, dst_y, width);
3631 #endif
3632     }
3633 #if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
3634       defined(HAS_ARGB1555TOYROW_LSX) || defined(HAS_ARGB1555TOYROW_LASX))
3635     free_aligned_buffer_64(row);
3636 #endif
3637   }
3638   return 0;
3639 }
3640 
3641 // Convert ARGB4444 to I420.
3642 LIBYUV_API
ARGB4444ToI420(const uint8_t * src_argb4444,int src_stride_argb4444,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)3643 int ARGB4444ToI420(const uint8_t* src_argb4444,
3644                    int src_stride_argb4444,
3645                    uint8_t* dst_y,
3646                    int dst_stride_y,
3647                    uint8_t* dst_u,
3648                    int dst_stride_u,
3649                    uint8_t* dst_v,
3650                    int dst_stride_v,
3651                    int width,
3652                    int height) {
3653   int y;
3654 #if defined(HAS_ARGB4444TOYROW_NEON)
3655   void (*ARGB4444ToUVRow)(const uint8_t* src_argb4444, int src_stride_argb4444,
3656                           uint8_t* dst_u, uint8_t* dst_v, int width) =
3657       ARGB4444ToUVRow_C;
3658   void (*ARGB4444ToYRow)(const uint8_t* src_argb4444, uint8_t* dst_y,
3659                          int width) = ARGB4444ToYRow_C;
3660 #else
3661   void (*ARGB4444ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
3662                             int width) = ARGB4444ToARGBRow_C;
3663   void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
3664                       uint8_t* dst_u, uint8_t* dst_v, int width) =
3665       ARGBToUVRow_C;
3666   void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
3667       ARGBToYRow_C;
3668 #endif
3669   if (!src_argb4444 || !dst_y || !dst_u || !dst_v || width <= 0 ||
3670       height == 0) {
3671     return -1;
3672   }
3673   // Negative height means invert the image.
3674   if (height < 0) {
3675     height = -height;
3676     src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
3677     src_stride_argb4444 = -src_stride_argb4444;
3678   }
3679 
3680 // Neon version does direct ARGB4444 to YUV.
3681 #if defined(HAS_ARGB4444TOYROW_NEON)
3682   if (TestCpuFlag(kCpuHasNEON)) {
3683     ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
3684     ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
3685     if (IS_ALIGNED(width, 8)) {
3686       ARGB4444ToYRow = ARGB4444ToYRow_NEON;
3687       if (IS_ALIGNED(width, 16)) {
3688         ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
3689       }
3690     }
3691   }
3692 // Other platforms do intermediate conversion from ARGB4444 to ARGB.
3693 #else
3694 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
3695   if (TestCpuFlag(kCpuHasSSE2)) {
3696     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
3697     if (IS_ALIGNED(width, 8)) {
3698       ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
3699     }
3700   }
3701 #endif
3702 #if defined(HAS_ARGB4444TOARGBROW_AVX2)
3703   if (TestCpuFlag(kCpuHasAVX2)) {
3704     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
3705     if (IS_ALIGNED(width, 16)) {
3706       ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
3707     }
3708   }
3709 #endif
3710 #if defined(HAS_ARGB4444TOARGBROW_MSA)
3711   if (TestCpuFlag(kCpuHasMSA)) {
3712     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA;
3713     if (IS_ALIGNED(width, 16)) {
3714       ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA;
3715     }
3716   }
3717 #endif
3718 #if defined(HAS_ARGB4444TOARGBROW_LSX)
3719   if (TestCpuFlag(kCpuHasLSX)) {
3720     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_LSX;
3721     if (IS_ALIGNED(width, 16)) {
3722       ARGB4444ToARGBRow = ARGB4444ToARGBRow_LSX;
3723     }
3724   }
3725 #endif
3726 #if defined(HAS_ARGB4444TOARGBROW_LASX)
3727   if (TestCpuFlag(kCpuHasLASX)) {
3728     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_LASX;
3729     if (IS_ALIGNED(width, 32)) {
3730       ARGB4444ToARGBRow = ARGB4444ToARGBRow_LASX;
3731     }
3732   }
3733 #endif
3734 #if defined(HAS_ARGBTOYROW_SSSE3)
3735   if (TestCpuFlag(kCpuHasSSSE3)) {
3736     ARGBToYRow = ARGBToYRow_Any_SSSE3;
3737     if (IS_ALIGNED(width, 16)) {
3738       ARGBToYRow = ARGBToYRow_SSSE3;
3739     }
3740   }
3741 #endif
3742 #if defined(HAS_ARGBTOUVROW_SSSE3)
3743   if (TestCpuFlag(kCpuHasSSSE3)) {
3744     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
3745     if (IS_ALIGNED(width, 16)) {
3746       ARGBToUVRow = ARGBToUVRow_SSSE3;
3747     }
3748   }
3749 #endif
3750 #if defined(HAS_ARGBTOYROW_AVX2)
3751   if (TestCpuFlag(kCpuHasAVX2)) {
3752     ARGBToYRow = ARGBToYRow_Any_AVX2;
3753     if (IS_ALIGNED(width, 32)) {
3754       ARGBToYRow = ARGBToYRow_AVX2;
3755     }
3756   }
3757 #endif
3758 #if defined(HAS_ARGBTOUVROW_AVX2)
3759   if (TestCpuFlag(kCpuHasAVX2)) {
3760     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
3761     if (IS_ALIGNED(width, 32)) {
3762       ARGBToUVRow = ARGBToUVRow_AVX2;
3763     }
3764   }
3765 #endif
3766 #if defined(HAS_ARGBTOYROW_MSA) && defined(HAS_ARGBTOUVROW_MSA)
3767   if (TestCpuFlag(kCpuHasMSA)) {
3768     ARGBToUVRow = ARGBToUVRow_Any_MSA;
3769     ARGBToYRow = ARGBToYRow_Any_MSA;
3770     if (IS_ALIGNED(width, 16)) {
3771       ARGBToYRow = ARGBToYRow_MSA;
3772       if (IS_ALIGNED(width, 32)) {
3773         ARGBToUVRow = ARGBToUVRow_MSA;
3774       }
3775     }
3776   }
3777 #endif
3778 #if defined(HAS_ARGBTOYROW_LSX)
3779   if (TestCpuFlag(kCpuHasLSX)) {
3780     ARGBToYRow = ARGBToYRow_Any_LSX;
3781     if (IS_ALIGNED(width, 16)) {
3782       ARGBToYRow = ARGBToYRow_LSX;
3783     }
3784   }
3785 #endif
3786 #if defined(HAS_ARGBTOYROW_LSX) && defined(HAS_ARGBTOUVROW_LSX)
3787   if (TestCpuFlag(kCpuHasLSX)) {
3788     ARGBToYRow = ARGBToYRow_Any_LSX;
3789     ARGBToUVRow = ARGBToUVRow_Any_LSX;
3790     if (IS_ALIGNED(width, 16)) {
3791       ARGBToYRow = ARGBToYRow_LSX;
3792       ARGBToUVRow = ARGBToUVRow_LSX;
3793     }
3794   }
3795 #endif
3796 #if defined(HAS_ARGBTOYROW_LASX) && defined(HAS_ARGBTOUVROW_LASX)
3797   if (TestCpuFlag(kCpuHasLASX)) {
3798     ARGBToYRow = ARGBToYRow_Any_LASX;
3799     ARGBToUVRow = ARGBToUVRow_Any_LASX;
3800     if (IS_ALIGNED(width, 32)) {
3801       ARGBToYRow = ARGBToYRow_LASX;
3802       ARGBToUVRow = ARGBToUVRow_LASX;
3803     }
3804   }
3805 #endif
3806 #endif
3807 
3808   {
3809 #if !(defined(HAS_ARGB4444TOYROW_NEON))
3810     // Allocate 2 rows of ARGB.
3811     const int row_size = (width * 4 + 31) & ~31;
3812     align_buffer_64(row, row_size * 2);
3813     if (!row)
3814       return 1;
3815 #endif
3816 
3817     for (y = 0; y < height - 1; y += 2) {
3818 #if defined(HAS_ARGB4444TOYROW_NEON)
3819       ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width);
3820       ARGB4444ToYRow(src_argb4444, dst_y, width);
3821       ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y,
3822                      width);
3823 #else
3824       ARGB4444ToARGBRow(src_argb4444, row, width);
3825       ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + row_size,
3826                         width);
3827       ARGBToUVRow(row, row_size, dst_u, dst_v, width);
3828       ARGBToYRow(row, dst_y, width);
3829       ARGBToYRow(row + row_size, dst_y + dst_stride_y, width);
3830 #endif
3831       src_argb4444 += src_stride_argb4444 * 2;
3832       dst_y += dst_stride_y * 2;
3833       dst_u += dst_stride_u;
3834       dst_v += dst_stride_v;
3835     }
3836     if (height & 1) {
3837 #if defined(HAS_ARGB4444TOYROW_NEON)
3838       ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width);
3839       ARGB4444ToYRow(src_argb4444, dst_y, width);
3840 #else
3841       ARGB4444ToARGBRow(src_argb4444, row, width);
3842       ARGBToUVRow(row, 0, dst_u, dst_v, width);
3843       ARGBToYRow(row, dst_y, width);
3844 #endif
3845     }
3846 #if !(defined(HAS_ARGB4444TOYROW_NEON))
3847     free_aligned_buffer_64(row);
3848 #endif
3849   }
3850   return 0;
3851 }
3852 
3853 // Convert RGB24 to J400.
3854 LIBYUV_API
RGB24ToJ400(const uint8_t * src_rgb24,int src_stride_rgb24,uint8_t * dst_yj,int dst_stride_yj,int width,int height)3855 int RGB24ToJ400(const uint8_t* src_rgb24,
3856                 int src_stride_rgb24,
3857                 uint8_t* dst_yj,
3858                 int dst_stride_yj,
3859                 int width,
3860                 int height) {
3861   int y;
3862   void (*RGB24ToYJRow)(const uint8_t* src_rgb24, uint8_t* dst_yj, int width) =
3863       RGB24ToYJRow_C;
3864   if (!src_rgb24 || !dst_yj || width <= 0 || height == 0) {
3865     return -1;
3866   }
3867   if (height < 0) {
3868     height = -height;
3869     src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
3870     src_stride_rgb24 = -src_stride_rgb24;
3871   }
3872   // Coalesce rows.
3873   if (src_stride_rgb24 == width * 3 && dst_stride_yj == width) {
3874     width *= height;
3875     height = 1;
3876     src_stride_rgb24 = dst_stride_yj = 0;
3877   }
3878 #if defined(HAS_RGB24TOYJROW_SSSE3)
3879   if (TestCpuFlag(kCpuHasSSSE3)) {
3880     RGB24ToYJRow = RGB24ToYJRow_Any_SSSE3;
3881     if (IS_ALIGNED(width, 16)) {
3882       RGB24ToYJRow = RGB24ToYJRow_SSSE3;
3883     }
3884   }
3885 #endif
3886 #if defined(HAS_RGB24TOYJROW_AVX2)
3887   if (TestCpuFlag(kCpuHasAVX2)) {
3888     RGB24ToYJRow = RGB24ToYJRow_Any_AVX2;
3889     if (IS_ALIGNED(width, 32)) {
3890       RGB24ToYJRow = RGB24ToYJRow_AVX2;
3891     }
3892   }
3893 #endif
3894 #if defined(HAS_RGB24TOYJROW_NEON)
3895   if (TestCpuFlag(kCpuHasNEON)) {
3896     RGB24ToYJRow = RGB24ToYJRow_Any_NEON;
3897     if (IS_ALIGNED(width, 16)) {
3898       RGB24ToYJRow = RGB24ToYJRow_NEON;
3899     }
3900   }
3901 #endif
3902 #if defined(HAS_RGB24TOYJROW_MSA)
3903   if (TestCpuFlag(kCpuHasMSA)) {
3904     RGB24ToYJRow = RGB24ToYJRow_Any_MSA;
3905     if (IS_ALIGNED(width, 16)) {
3906       RGB24ToYJRow = RGB24ToYJRow_MSA;
3907     }
3908   }
3909 #endif
3910 #if defined(HAS_RGB24TOYJROW_LSX)
3911   if (TestCpuFlag(kCpuHasLSX)) {
3912     RGB24ToYJRow = RGB24ToYJRow_Any_LSX;
3913     if (IS_ALIGNED(width, 16)) {
3914       RGB24ToYJRow = RGB24ToYJRow_LSX;
3915     }
3916   }
3917 #endif
3918 #if defined(HAS_RGB24TOYJROW_LASX)
3919   if (TestCpuFlag(kCpuHasLASX)) {
3920     RGB24ToYJRow = RGB24ToYJRow_Any_LASX;
3921     if (IS_ALIGNED(width, 32)) {
3922       RGB24ToYJRow = RGB24ToYJRow_LASX;
3923     }
3924   }
3925 #endif
3926 #if defined(HAS_RGB24TOYJROW_RVV)
3927   if (TestCpuFlag(kCpuHasRVV)) {
3928     RGB24ToYJRow = RGB24ToYJRow_RVV;
3929   }
3930 #endif
3931 
3932   for (y = 0; y < height; ++y) {
3933     RGB24ToYJRow(src_rgb24, dst_yj, width);
3934     src_rgb24 += src_stride_rgb24;
3935     dst_yj += dst_stride_yj;
3936   }
3937   return 0;
3938 }
3939 
3940 // Convert RAW to J400.
3941 LIBYUV_API
RAWToJ400(const uint8_t * src_raw,int src_stride_raw,uint8_t * dst_yj,int dst_stride_yj,int width,int height)3942 int RAWToJ400(const uint8_t* src_raw,
3943               int src_stride_raw,
3944               uint8_t* dst_yj,
3945               int dst_stride_yj,
3946               int width,
3947               int height) {
3948   int y;
3949   void (*RAWToYJRow)(const uint8_t* src_raw, uint8_t* dst_yj, int width) =
3950       RAWToYJRow_C;
3951   if (!src_raw || !dst_yj || width <= 0 || height == 0) {
3952     return -1;
3953   }
3954 
3955   if (height < 0) {
3956     height = -height;
3957     src_raw = src_raw + (height - 1) * src_stride_raw;
3958     src_stride_raw = -src_stride_raw;
3959   }
3960   // Coalesce rows.
3961   if (src_stride_raw == width * 3 && dst_stride_yj == width) {
3962     width *= height;
3963     height = 1;
3964     src_stride_raw = dst_stride_yj = 0;
3965   }
3966 
3967 #if defined(HAS_RAWTOYJROW_SSSE3)
3968   if (TestCpuFlag(kCpuHasSSSE3)) {
3969     RAWToYJRow = RAWToYJRow_Any_SSSE3;
3970     if (IS_ALIGNED(width, 16)) {
3971       RAWToYJRow = RAWToYJRow_SSSE3;
3972     }
3973   }
3974 #endif
3975 #if defined(HAS_RAWTOYJROW_AVX2)
3976   if (TestCpuFlag(kCpuHasAVX2)) {
3977     RAWToYJRow = RAWToYJRow_Any_AVX2;
3978     if (IS_ALIGNED(width, 32)) {
3979       RAWToYJRow = RAWToYJRow_AVX2;
3980     }
3981   }
3982 #endif
3983 #if defined(HAS_RAWTOYJROW_NEON)
3984   if (TestCpuFlag(kCpuHasNEON)) {
3985     RAWToYJRow = RAWToYJRow_Any_NEON;
3986     if (IS_ALIGNED(width, 16)) {
3987       RAWToYJRow = RAWToYJRow_NEON;
3988     }
3989   }
3990 #endif
3991 #if defined(HAS_RAWTOYJROW_MSA)
3992   if (TestCpuFlag(kCpuHasMSA)) {
3993     RAWToYJRow = RAWToYJRow_Any_MSA;
3994     if (IS_ALIGNED(width, 16)) {
3995       RAWToYJRow = RAWToYJRow_MSA;
3996     }
3997   }
3998 #endif
3999 #if defined(HAS_RAWTOYJROW_LSX)
4000   if (TestCpuFlag(kCpuHasLSX)) {
4001     RAWToYJRow = RAWToYJRow_Any_LSX;
4002     if (IS_ALIGNED(width, 16)) {
4003       RAWToYJRow = RAWToYJRow_LSX;
4004     }
4005   }
4006 #endif
4007 #if defined(HAS_RAWTOYJROW_LASX)
4008   if (TestCpuFlag(kCpuHasLASX)) {
4009     RAWToYJRow = RAWToYJRow_Any_LASX;
4010     if (IS_ALIGNED(width, 32)) {
4011       RAWToYJRow = RAWToYJRow_LASX;
4012     }
4013   }
4014 #endif
4015 #if defined(HAS_RAWTOYJROW_RVV)
4016   if (TestCpuFlag(kCpuHasRVV)) {
4017     RAWToYJRow = RAWToYJRow_RVV;
4018   }
4019 #endif
4020 
4021   for (y = 0; y < height; ++y) {
4022     RAWToYJRow(src_raw, dst_yj, width);
4023     src_raw += src_stride_raw;
4024     dst_yj += dst_stride_yj;
4025   }
4026   return 0;
4027 }
4028 
4029 // Convert Android420 to I420.
4030 LIBYUV_API
Android420ToI420(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,int src_pixel_stride_uv,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)4031 int Android420ToI420(const uint8_t* src_y,
4032                      int src_stride_y,
4033                      const uint8_t* src_u,
4034                      int src_stride_u,
4035                      const uint8_t* src_v,
4036                      int src_stride_v,
4037                      int src_pixel_stride_uv,
4038                      uint8_t* dst_y,
4039                      int dst_stride_y,
4040                      uint8_t* dst_u,
4041                      int dst_stride_u,
4042                      uint8_t* dst_v,
4043                      int dst_stride_v,
4044                      int width,
4045                      int height) {
4046   return Android420ToI420Rotate(src_y, src_stride_y, src_u, src_stride_u, src_v,
4047                                 src_stride_v, src_pixel_stride_uv, dst_y,
4048                                 dst_stride_y, dst_u, dst_stride_u, dst_v,
4049                                 dst_stride_v, width, height, kRotate0);
4050 }
4051 
4052 #ifdef __cplusplus
4053 }  // extern "C"
4054 }  // namespace libyuv
4055 #endif
4056