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 
20 #ifdef __cplusplus
21 namespace libyuv {
22 extern "C" {
23 #endif
24 
25 #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
Abs(int v)26 static __inline int Abs(int v) {
27   return v >= 0 ? v : -v;
28 }
29 
30 // 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)31 static int I4xxToI420(const uint8_t* src_y,
32                       int src_stride_y,
33                       const uint8_t* src_u,
34                       int src_stride_u,
35                       const uint8_t* src_v,
36                       int src_stride_v,
37                       uint8_t* dst_y,
38                       int dst_stride_y,
39                       uint8_t* dst_u,
40                       int dst_stride_u,
41                       uint8_t* dst_v,
42                       int dst_stride_v,
43                       int src_y_width,
44                       int src_y_height,
45                       int src_uv_width,
46                       int src_uv_height) {
47   const int dst_y_width = Abs(src_y_width);
48   const int dst_y_height = Abs(src_y_height);
49   const int dst_uv_width = SUBSAMPLE(dst_y_width, 1, 1);
50   const int dst_uv_height = SUBSAMPLE(dst_y_height, 1, 1);
51   if (src_uv_width == 0 || src_uv_height == 0) {
52     return -1;
53   }
54   if (dst_y) {
55     ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, dst_y,
56                dst_stride_y, dst_y_width, dst_y_height, kFilterBilinear);
57   }
58   ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
59              dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
60   ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
61              dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
62   return 0;
63 }
64 
65 // Copy I420 with optional flipping.
66 // TODO(fbarchard): Use Scale plane which supports mirroring, but ensure
67 // is does row coalescing.
68 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)69 int I420Copy(const uint8_t* src_y,
70              int src_stride_y,
71              const uint8_t* src_u,
72              int src_stride_u,
73              const uint8_t* src_v,
74              int src_stride_v,
75              uint8_t* dst_y,
76              int dst_stride_y,
77              uint8_t* dst_u,
78              int dst_stride_u,
79              uint8_t* dst_v,
80              int dst_stride_v,
81              int width,
82              int height) {
83   int halfwidth = (width + 1) >> 1;
84   int halfheight = (height + 1) >> 1;
85   if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
86     return -1;
87   }
88   // Negative height means invert the image.
89   if (height < 0) {
90     height = -height;
91     halfheight = (height + 1) >> 1;
92     src_y = src_y + (height - 1) * src_stride_y;
93     src_u = src_u + (halfheight - 1) * src_stride_u;
94     src_v = src_v + (halfheight - 1) * src_stride_v;
95     src_stride_y = -src_stride_y;
96     src_stride_u = -src_stride_u;
97     src_stride_v = -src_stride_v;
98   }
99 
100   if (dst_y) {
101     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
102   }
103   // Copy UV planes.
104   CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
105   CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
106   return 0;
107 }
108 
109 // Copy I010 with optional flipping.
110 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)111 int I010Copy(const uint16_t* src_y,
112              int src_stride_y,
113              const uint16_t* src_u,
114              int src_stride_u,
115              const uint16_t* src_v,
116              int src_stride_v,
117              uint16_t* dst_y,
118              int dst_stride_y,
119              uint16_t* dst_u,
120              int dst_stride_u,
121              uint16_t* dst_v,
122              int dst_stride_v,
123              int width,
124              int height) {
125   int halfwidth = (width + 1) >> 1;
126   int halfheight = (height + 1) >> 1;
127   if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
128     return -1;
129   }
130   // Negative height means invert the image.
131   if (height < 0) {
132     height = -height;
133     halfheight = (height + 1) >> 1;
134     src_y = src_y + (height - 1) * src_stride_y;
135     src_u = src_u + (halfheight - 1) * src_stride_u;
136     src_v = src_v + (halfheight - 1) * src_stride_v;
137     src_stride_y = -src_stride_y;
138     src_stride_u = -src_stride_u;
139     src_stride_v = -src_stride_v;
140   }
141 
142   if (dst_y) {
143     CopyPlane_16(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
144   }
145   // Copy UV planes.
146   CopyPlane_16(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
147   CopyPlane_16(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
148   return 0;
149 }
150 
151 // Convert 10 bit YUV to 8 bit.
152 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)153 int I010ToI420(const uint16_t* src_y,
154                int src_stride_y,
155                const uint16_t* src_u,
156                int src_stride_u,
157                const uint16_t* src_v,
158                int src_stride_v,
159                uint8_t* dst_y,
160                int dst_stride_y,
161                uint8_t* dst_u,
162                int dst_stride_u,
163                uint8_t* dst_v,
164                int dst_stride_v,
165                int width,
166                int height) {
167   int halfwidth = (width + 1) >> 1;
168   int halfheight = (height + 1) >> 1;
169   if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
170     return -1;
171   }
172   // Negative height means invert the image.
173   if (height < 0) {
174     height = -height;
175     halfheight = (height + 1) >> 1;
176     src_y = src_y + (height - 1) * src_stride_y;
177     src_u = src_u + (halfheight - 1) * src_stride_u;
178     src_v = src_v + (halfheight - 1) * src_stride_v;
179     src_stride_y = -src_stride_y;
180     src_stride_u = -src_stride_u;
181     src_stride_v = -src_stride_v;
182   }
183 
184   // Convert Y plane.
185   Convert16To8Plane(src_y, src_stride_y, dst_y, dst_stride_y, 16384, width,
186                     height);
187   // Convert UV planes.
188   Convert16To8Plane(src_u, src_stride_u, dst_u, dst_stride_u, 16384, halfwidth,
189                     halfheight);
190   Convert16To8Plane(src_v, src_stride_v, dst_v, dst_stride_v, 16384, halfwidth,
191                     halfheight);
192   return 0;
193 }
194 
195 // 422 chroma is 1/2 width, 1x height
196 // 420 chroma is 1/2 width, 1/2 height
197 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)198 int I422ToI420(const uint8_t* src_y,
199                int src_stride_y,
200                const uint8_t* src_u,
201                int src_stride_u,
202                const uint8_t* src_v,
203                int src_stride_v,
204                uint8_t* dst_y,
205                int dst_stride_y,
206                uint8_t* dst_u,
207                int dst_stride_u,
208                uint8_t* dst_v,
209                int dst_stride_v,
210                int width,
211                int height) {
212   const int src_uv_width = SUBSAMPLE(width, 1, 1);
213   return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
214                     src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
215                     dst_v, dst_stride_v, width, height, src_uv_width, height);
216 }
217 
218 // TODO(fbarchard): Implement row conversion.
219 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)220 int I422ToNV21(const uint8_t* src_y,
221                int src_stride_y,
222                const uint8_t* src_u,
223                int src_stride_u,
224                const uint8_t* src_v,
225                int src_stride_v,
226                uint8_t* dst_y,
227                int dst_stride_y,
228                uint8_t* dst_vu,
229                int dst_stride_vu,
230                int width,
231                int height) {
232   int halfwidth = (width + 1) >> 1;
233   int halfheight = (height + 1) >> 1;
234   // Negative height means invert the image.
235   if (height < 0) {
236     height = -height;
237     halfheight = (height + 1) >> 1;
238     src_y = src_y + (height - 1) * src_stride_y;
239     src_u = src_u + (height - 1) * src_stride_u;
240     src_v = src_v + (height - 1) * src_stride_v;
241     src_stride_y = -src_stride_y;
242     src_stride_u = -src_stride_u;
243     src_stride_v = -src_stride_v;
244   }
245 
246   // Allocate u and v buffers
247   align_buffer_64(plane_u, halfwidth * halfheight * 2);
248   uint8_t* plane_v = plane_u + halfwidth * halfheight;
249 
250   I422ToI420(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
251              dst_y, dst_stride_y, plane_u, halfwidth, plane_v, halfwidth, width,
252              height);
253   MergeUVPlane(plane_v, halfwidth, plane_u, halfwidth, dst_vu, dst_stride_vu,
254                halfwidth, halfheight);
255   free_aligned_buffer_64(plane_u);
256   return 0;
257 }
258 
259 #ifdef I422TONV21_ROW_VERSION
260 // Unittest fails for this version.
261 // 422 chroma is 1/2 width, 1x height
262 // 420 chroma is 1/2 width, 1/2 height
263 // Swap src_u and src_v to implement I422ToNV12
264 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)265 int I422ToNV21(const uint8_t* src_y,
266                int src_stride_y,
267                const uint8_t* src_u,
268                int src_stride_u,
269                const uint8_t* src_v,
270                int src_stride_v,
271                uint8_t* dst_y,
272                int dst_stride_y,
273                uint8_t* dst_vu,
274                int dst_stride_vu,
275                int width,
276                int height) {
277   int y;
278   void (*MergeUVRow)(const uint8_t* src_u, const uint8_t* src_v,
279                      uint8_t* dst_uv, int width) = MergeUVRow_C;
280   void (*InterpolateRow)(uint8_t * dst_ptr, const uint8_t* src_ptr,
281                          ptrdiff_t src_stride, int dst_width,
282                          int source_y_fraction) = InterpolateRow_C;
283   int halfwidth = (width + 1) >> 1;
284   int halfheight = (height + 1) >> 1;
285   if (!src_u || !src_v || !dst_vu || width <= 0 || height == 0) {
286     return -1;
287   }
288   // Negative height means invert the image.
289   if (height < 0) {
290     height = -height;
291     halfheight = (height + 1) >> 1;
292     src_y = src_y + (height - 1) * src_stride_y;
293     src_u = src_u + (halfheight - 1) * src_stride_u;
294     src_v = src_v + (halfheight - 1) * src_stride_v;
295     src_stride_y = -src_stride_y;
296     src_stride_u = -src_stride_u;
297     src_stride_v = -src_stride_v;
298   }
299 #if defined(HAS_MERGEUVROW_SSE2)
300   if (TestCpuFlag(kCpuHasSSE2)) {
301     MergeUVRow = MergeUVRow_Any_SSE2;
302     if (IS_ALIGNED(halfwidth, 16)) {
303       MergeUVRow = MergeUVRow_SSE2;
304     }
305   }
306 #endif
307 #if defined(HAS_MERGEUVROW_AVX2)
308   if (TestCpuFlag(kCpuHasAVX2)) {
309     MergeUVRow = MergeUVRow_Any_AVX2;
310     if (IS_ALIGNED(halfwidth, 32)) {
311       MergeUVRow = MergeUVRow_AVX2;
312     }
313   }
314 #endif
315 #if defined(HAS_MERGEUVROW_NEON)
316   if (TestCpuFlag(kCpuHasNEON)) {
317     MergeUVRow = MergeUVRow_Any_NEON;
318     if (IS_ALIGNED(halfwidth, 16)) {
319       MergeUVRow = MergeUVRow_NEON;
320     }
321   }
322 #endif
323 #if defined(HAS_MERGEUVROW_MSA)
324   if (TestCpuFlag(kCpuHasMSA)) {
325     MergeUVRow = MergeUVRow_Any_MSA;
326     if (IS_ALIGNED(halfwidth, 16)) {
327       MergeUVRow = MergeUVRow_MSA;
328     }
329   }
330 #endif
331 #if defined(HAS_MERGEUVROW_MMI)
332   if (TestCpuFlag(kCpuHasMMI)) {
333     MergeUVRow = MergeUVRow_Any_MMI;
334     if (IS_ALIGNED(halfwidth, 8)) {
335       MergeUVRow = MergeUVRow_MMI;
336     }
337   }
338 #endif
339 #if defined(HAS_INTERPOLATEROW_SSSE3)
340   if (TestCpuFlag(kCpuHasSSSE3)) {
341     InterpolateRow = InterpolateRow_Any_SSSE3;
342     if (IS_ALIGNED(width, 16)) {
343       InterpolateRow = InterpolateRow_SSSE3;
344     }
345   }
346 #endif
347 #if defined(HAS_INTERPOLATEROW_AVX2)
348   if (TestCpuFlag(kCpuHasAVX2)) {
349     InterpolateRow = InterpolateRow_Any_AVX2;
350     if (IS_ALIGNED(width, 32)) {
351       InterpolateRow = InterpolateRow_AVX2;
352     }
353   }
354 #endif
355 #if defined(HAS_INTERPOLATEROW_NEON)
356   if (TestCpuFlag(kCpuHasNEON)) {
357     InterpolateRow = InterpolateRow_Any_NEON;
358     if (IS_ALIGNED(width, 16)) {
359       InterpolateRow = InterpolateRow_NEON;
360     }
361   }
362 #endif
363 #if defined(HAS_INTERPOLATEROW_MSA)
364   if (TestCpuFlag(kCpuHasMSA)) {
365     InterpolateRow = InterpolateRow_Any_MSA;
366     if (IS_ALIGNED(width, 32)) {
367       InterpolateRow = InterpolateRow_MSA;
368     }
369   }
370 #endif
371 #if defined(HAS_INTERPOLATEROW_MMI)
372   if (TestCpuFlag(kCpuHasMMI)) {
373     InterpolateRow = InterpolateRow_Any_MMI;
374     if (IS_ALIGNED(width, 8)) {
375       InterpolateRow = InterpolateRow_MMI;
376     }
377   }
378 #endif
379 
380   if (dst_y) {
381     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, halfwidth, height);
382   }
383   {
384     // Allocate 2 rows of vu.
385     int awidth = halfwidth * 2;
386     align_buffer_64(row_vu_0, awidth * 2);
387     uint8_t* row_vu_1 = row_vu_0 + awidth;
388 
389     for (y = 0; y < height - 1; y += 2) {
390       MergeUVRow(src_v, src_u, row_vu_0, halfwidth);
391       MergeUVRow(src_v + src_stride_v, src_u + src_stride_u, row_vu_1,
392                  halfwidth);
393       InterpolateRow(dst_vu, row_vu_0, awidth, awidth, 128);
394       src_u += src_stride_u * 2;
395       src_v += src_stride_v * 2;
396       dst_vu += dst_stride_vu;
397     }
398     if (height & 1) {
399       MergeUVRow(src_v, src_u, dst_vu, halfwidth);
400     }
401     free_aligned_buffer_64(row_vu_0);
402   }
403   return 0;
404 }
405 #endif  // I422TONV21_ROW_VERSION
406 
407 // 444 chroma is 1x width, 1x height
408 // 420 chroma is 1/2 width, 1/2 height
409 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)410 int I444ToI420(const uint8_t* src_y,
411                int src_stride_y,
412                const uint8_t* src_u,
413                int src_stride_u,
414                const uint8_t* src_v,
415                int src_stride_v,
416                uint8_t* dst_y,
417                int dst_stride_y,
418                uint8_t* dst_u,
419                int dst_stride_u,
420                uint8_t* dst_v,
421                int dst_stride_v,
422                int width,
423                int height) {
424   return I4xxToI420(src_y, src_stride_y, src_u, src_stride_u, src_v,
425                     src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
426                     dst_v, dst_stride_v, width, height, width, height);
427 }
428 
429 // TODO(fbarchard): Implement row conversion.
430 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)431 int I444ToNV21(const uint8_t* src_y,
432                int src_stride_y,
433                const uint8_t* src_u,
434                int src_stride_u,
435                const uint8_t* src_v,
436                int src_stride_v,
437                uint8_t* dst_y,
438                int dst_stride_y,
439                uint8_t* dst_vu,
440                int dst_stride_vu,
441                int width,
442                int height) {
443   int halfwidth = (width + 1) >> 1;
444   int halfheight = (height + 1) >> 1;
445   // Negative height means invert the image.
446   if (height < 0) {
447     height = -height;
448     halfheight = (height + 1) >> 1;
449     src_y = src_y + (height - 1) * src_stride_y;
450     src_u = src_u + (height - 1) * src_stride_u;
451     src_v = src_v + (height - 1) * src_stride_v;
452     src_stride_y = -src_stride_y;
453     src_stride_u = -src_stride_u;
454     src_stride_v = -src_stride_v;
455   }
456   // Allocate u and v buffers
457   align_buffer_64(plane_u, halfwidth * halfheight * 2);
458   uint8_t* plane_v = plane_u + halfwidth * halfheight;
459 
460   I444ToI420(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
461              dst_y, dst_stride_y, plane_u, halfwidth, plane_v, halfwidth, width,
462              height);
463   MergeUVPlane(plane_v, halfwidth, plane_u, halfwidth, dst_vu, dst_stride_vu,
464                halfwidth, halfheight);
465   free_aligned_buffer_64(plane_u);
466   return 0;
467 }
468 
469 // I400 is greyscale typically used in MJPG
470 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)471 int I400ToI420(const uint8_t* src_y,
472                int src_stride_y,
473                uint8_t* dst_y,
474                int dst_stride_y,
475                uint8_t* dst_u,
476                int dst_stride_u,
477                uint8_t* dst_v,
478                int dst_stride_v,
479                int width,
480                int height) {
481   int halfwidth = (width + 1) >> 1;
482   int halfheight = (height + 1) >> 1;
483   if (!dst_u || !dst_v || width <= 0 || height == 0) {
484     return -1;
485   }
486   // Negative height means invert the image.
487   if (height < 0) {
488     height = -height;
489     halfheight = (height + 1) >> 1;
490     src_y = src_y + (height - 1) * src_stride_y;
491     src_stride_y = -src_stride_y;
492   }
493   if (dst_y) {
494     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
495   }
496   SetPlane(dst_u, dst_stride_u, halfwidth, halfheight, 128);
497   SetPlane(dst_v, dst_stride_v, halfwidth, halfheight, 128);
498   return 0;
499 }
500 
501 // I400 is greyscale typically used in MJPG
502 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)503 int I400ToNV21(const uint8_t* src_y,
504                int src_stride_y,
505                uint8_t* dst_y,
506                int dst_stride_y,
507                uint8_t* dst_vu,
508                int dst_stride_vu,
509                int width,
510                int height) {
511   int halfwidth = (width + 1) >> 1;
512   int halfheight = (height + 1) >> 1;
513   if (!dst_vu || width <= 0 || height == 0) {
514     return -1;
515   }
516   // Negative height means invert the image.
517   if (height < 0) {
518     height = -height;
519     halfheight = (height + 1) >> 1;
520     src_y = src_y + (height - 1) * src_stride_y;
521     src_stride_y = -src_stride_y;
522   }
523   if (dst_y) {
524     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
525   }
526   SetPlane(dst_vu, dst_stride_vu, halfwidth * 2, halfheight, 128);
527   return 0;
528 }
529 
CopyPlane2(const uint8_t * src,int src_stride_0,int src_stride_1,uint8_t * dst,int dst_stride,int width,int height)530 static void CopyPlane2(const uint8_t* src,
531                        int src_stride_0,
532                        int src_stride_1,
533                        uint8_t* dst,
534                        int dst_stride,
535                        int width,
536                        int height) {
537   int y;
538   void (*CopyRow)(const uint8_t* src, uint8_t* dst, int width) = CopyRow_C;
539 #if defined(HAS_COPYROW_SSE2)
540   if (TestCpuFlag(kCpuHasSSE2)) {
541     CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2;
542   }
543 #endif
544 #if defined(HAS_COPYROW_AVX)
545   if (TestCpuFlag(kCpuHasAVX)) {
546     CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
547   }
548 #endif
549 #if defined(HAS_COPYROW_ERMS)
550   if (TestCpuFlag(kCpuHasERMS)) {
551     CopyRow = CopyRow_ERMS;
552   }
553 #endif
554 #if defined(HAS_COPYROW_NEON)
555   if (TestCpuFlag(kCpuHasNEON)) {
556     CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
557   }
558 #endif
559 
560   // Copy plane
561   for (y = 0; y < height - 1; y += 2) {
562     CopyRow(src, dst, width);
563     CopyRow(src + src_stride_0, dst + dst_stride, width);
564     src += src_stride_0 + src_stride_1;
565     dst += dst_stride * 2;
566   }
567   if (height & 1) {
568     CopyRow(src, dst, width);
569   }
570 }
571 
572 // Support converting from FOURCC_M420
573 // Useful for bandwidth constrained transports like USB 1.0 and 2.0 and for
574 // easy conversion to I420.
575 // M420 format description:
576 // M420 is row biplanar 420: 2 rows of Y and 1 row of UV.
577 // Chroma is half width / half height. (420)
578 // src_stride_m420 is row planar. Normally this will be the width in pixels.
579 //   The UV plane is half width, but 2 values, so src_stride_m420 applies to
580 //   this as well as the two Y planes.
X420ToI420(const uint8_t * src_y,int src_stride_y0,int src_stride_y1,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)581 static int X420ToI420(const uint8_t* src_y,
582                       int src_stride_y0,
583                       int src_stride_y1,
584                       const uint8_t* src_uv,
585                       int src_stride_uv,
586                       uint8_t* dst_y,
587                       int dst_stride_y,
588                       uint8_t* dst_u,
589                       int dst_stride_u,
590                       uint8_t* dst_v,
591                       int dst_stride_v,
592                       int width,
593                       int height) {
594   int halfwidth = (width + 1) >> 1;
595   int halfheight = (height + 1) >> 1;
596   if (!src_uv || !dst_u || !dst_v || width <= 0 || height == 0) {
597     return -1;
598   }
599   // Negative height means invert the image.
600   if (height < 0) {
601     height = -height;
602     halfheight = (height + 1) >> 1;
603     if (dst_y) {
604       dst_y = dst_y + (height - 1) * dst_stride_y;
605     }
606     dst_u = dst_u + (halfheight - 1) * dst_stride_u;
607     dst_v = dst_v + (halfheight - 1) * dst_stride_v;
608     dst_stride_y = -dst_stride_y;
609     dst_stride_u = -dst_stride_u;
610     dst_stride_v = -dst_stride_v;
611   }
612   // Coalesce rows.
613   if (src_stride_y0 == width && src_stride_y1 == width &&
614       dst_stride_y == width) {
615     width *= height;
616     height = 1;
617     src_stride_y0 = src_stride_y1 = dst_stride_y = 0;
618   }
619   // Coalesce rows.
620   if (src_stride_uv == halfwidth * 2 && dst_stride_u == halfwidth &&
621       dst_stride_v == halfwidth) {
622     halfwidth *= halfheight;
623     halfheight = 1;
624     src_stride_uv = dst_stride_u = dst_stride_v = 0;
625   }
626 
627   if (dst_y) {
628     if (src_stride_y0 == src_stride_y1) {
629       CopyPlane(src_y, src_stride_y0, dst_y, dst_stride_y, width, height);
630     } else {
631       CopyPlane2(src_y, src_stride_y0, src_stride_y1, dst_y, dst_stride_y,
632                  width, height);
633     }
634   }
635 
636   // Split UV plane - NV12 / NV21
637   SplitUVPlane(src_uv, src_stride_uv, dst_u, dst_stride_u, dst_v, dst_stride_v,
638                halfwidth, halfheight);
639 
640   return 0;
641 }
642 
643 // Convert NV12 to I420.
644 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)645 int NV12ToI420(const uint8_t* src_y,
646                int src_stride_y,
647                const uint8_t* src_uv,
648                int src_stride_uv,
649                uint8_t* dst_y,
650                int dst_stride_y,
651                uint8_t* dst_u,
652                int dst_stride_u,
653                uint8_t* dst_v,
654                int dst_stride_v,
655                int width,
656                int height) {
657   return X420ToI420(src_y, src_stride_y, src_stride_y, src_uv, src_stride_uv,
658                     dst_y, dst_stride_y, dst_u, dst_stride_u, dst_v,
659                     dst_stride_v, width, height);
660 }
661 
662 // Convert NV21 to I420.  Same as NV12 but u and v pointers swapped.
663 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)664 int NV21ToI420(const uint8_t* src_y,
665                int src_stride_y,
666                const uint8_t* src_vu,
667                int src_stride_vu,
668                uint8_t* dst_y,
669                int dst_stride_y,
670                uint8_t* dst_u,
671                int dst_stride_u,
672                uint8_t* dst_v,
673                int dst_stride_v,
674                int width,
675                int height) {
676   return X420ToI420(src_y, src_stride_y, src_stride_y, src_vu, src_stride_vu,
677                     dst_y, dst_stride_y, dst_v, dst_stride_v, dst_u,
678                     dst_stride_u, width, height);
679 }
680 
681 // Convert M420 to I420.
682 LIBYUV_API
M420ToI420(const uint8_t * src_m420,int src_stride_m420,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)683 int M420ToI420(const uint8_t* src_m420,
684                int src_stride_m420,
685                uint8_t* dst_y,
686                int dst_stride_y,
687                uint8_t* dst_u,
688                int dst_stride_u,
689                uint8_t* dst_v,
690                int dst_stride_v,
691                int width,
692                int height) {
693   return X420ToI420(src_m420, src_stride_m420, src_stride_m420 * 2,
694                     src_m420 + src_stride_m420 * 2, src_stride_m420 * 3, dst_y,
695                     dst_stride_y, dst_u, dst_stride_u, dst_v, dst_stride_v,
696                     width, height);
697 }
698 
699 // Convert YUY2 to I420.
700 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)701 int YUY2ToI420(const uint8_t* src_yuy2,
702                int src_stride_yuy2,
703                uint8_t* dst_y,
704                int dst_stride_y,
705                uint8_t* dst_u,
706                int dst_stride_u,
707                uint8_t* dst_v,
708                int dst_stride_v,
709                int width,
710                int height) {
711   int y;
712   void (*YUY2ToUVRow)(const uint8_t* src_yuy2, int src_stride_yuy2,
713                       uint8_t* dst_u, uint8_t* dst_v, int width) =
714       YUY2ToUVRow_C;
715   void (*YUY2ToYRow)(const uint8_t* src_yuy2, uint8_t* dst_y, int width) =
716       YUY2ToYRow_C;
717   // Negative height means invert the image.
718   if (height < 0) {
719     height = -height;
720     src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
721     src_stride_yuy2 = -src_stride_yuy2;
722   }
723 #if defined(HAS_YUY2TOYROW_SSE2)
724   if (TestCpuFlag(kCpuHasSSE2)) {
725     YUY2ToUVRow = YUY2ToUVRow_Any_SSE2;
726     YUY2ToYRow = YUY2ToYRow_Any_SSE2;
727     if (IS_ALIGNED(width, 16)) {
728       YUY2ToUVRow = YUY2ToUVRow_SSE2;
729       YUY2ToYRow = YUY2ToYRow_SSE2;
730     }
731   }
732 #endif
733 #if defined(HAS_YUY2TOYROW_AVX2)
734   if (TestCpuFlag(kCpuHasAVX2)) {
735     YUY2ToUVRow = YUY2ToUVRow_Any_AVX2;
736     YUY2ToYRow = YUY2ToYRow_Any_AVX2;
737     if (IS_ALIGNED(width, 32)) {
738       YUY2ToUVRow = YUY2ToUVRow_AVX2;
739       YUY2ToYRow = YUY2ToYRow_AVX2;
740     }
741   }
742 #endif
743 #if defined(HAS_YUY2TOYROW_NEON)
744   if (TestCpuFlag(kCpuHasNEON)) {
745     YUY2ToYRow = YUY2ToYRow_Any_NEON;
746     YUY2ToUVRow = YUY2ToUVRow_Any_NEON;
747     if (IS_ALIGNED(width, 16)) {
748       YUY2ToYRow = YUY2ToYRow_NEON;
749       YUY2ToUVRow = YUY2ToUVRow_NEON;
750     }
751   }
752 #endif
753 #if defined(HAS_YUY2TOYROW_MSA)
754   if (TestCpuFlag(kCpuHasMSA)) {
755     YUY2ToYRow = YUY2ToYRow_Any_MSA;
756     YUY2ToUVRow = YUY2ToUVRow_Any_MSA;
757     if (IS_ALIGNED(width, 32)) {
758       YUY2ToYRow = YUY2ToYRow_MSA;
759       YUY2ToUVRow = YUY2ToUVRow_MSA;
760     }
761   }
762 #endif
763 #if defined(HAS_YUY2TOYROW_MMI)
764   if (TestCpuFlag(kCpuHasMMI)) {
765     YUY2ToYRow = YUY2ToYRow_Any_MMI;
766     YUY2ToUVRow = YUY2ToUVRow_Any_MMI;
767     if (IS_ALIGNED(width, 8)) {
768       YUY2ToYRow = YUY2ToYRow_MMI;
769       if (IS_ALIGNED(width, 16)) {
770         YUY2ToUVRow = YUY2ToUVRow_MMI;
771       }
772     }
773   }
774 #endif
775 
776   for (y = 0; y < height - 1; y += 2) {
777     YUY2ToUVRow(src_yuy2, src_stride_yuy2, dst_u, dst_v, width);
778     YUY2ToYRow(src_yuy2, dst_y, width);
779     YUY2ToYRow(src_yuy2 + src_stride_yuy2, dst_y + dst_stride_y, width);
780     src_yuy2 += src_stride_yuy2 * 2;
781     dst_y += dst_stride_y * 2;
782     dst_u += dst_stride_u;
783     dst_v += dst_stride_v;
784   }
785   if (height & 1) {
786     YUY2ToUVRow(src_yuy2, 0, dst_u, dst_v, width);
787     YUY2ToYRow(src_yuy2, dst_y, width);
788   }
789   return 0;
790 }
791 
792 // Convert UYVY to I420.
793 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)794 int UYVYToI420(const uint8_t* src_uyvy,
795                int src_stride_uyvy,
796                uint8_t* dst_y,
797                int dst_stride_y,
798                uint8_t* dst_u,
799                int dst_stride_u,
800                uint8_t* dst_v,
801                int dst_stride_v,
802                int width,
803                int height) {
804   int y;
805   void (*UYVYToUVRow)(const uint8_t* src_uyvy, int src_stride_uyvy,
806                       uint8_t* dst_u, uint8_t* dst_v, int width) =
807       UYVYToUVRow_C;
808   void (*UYVYToYRow)(const uint8_t* src_uyvy, uint8_t* dst_y, int width) =
809       UYVYToYRow_C;
810   // Negative height means invert the image.
811   if (height < 0) {
812     height = -height;
813     src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
814     src_stride_uyvy = -src_stride_uyvy;
815   }
816 #if defined(HAS_UYVYTOYROW_SSE2)
817   if (TestCpuFlag(kCpuHasSSE2)) {
818     UYVYToUVRow = UYVYToUVRow_Any_SSE2;
819     UYVYToYRow = UYVYToYRow_Any_SSE2;
820     if (IS_ALIGNED(width, 16)) {
821       UYVYToUVRow = UYVYToUVRow_SSE2;
822       UYVYToYRow = UYVYToYRow_SSE2;
823     }
824   }
825 #endif
826 #if defined(HAS_UYVYTOYROW_AVX2)
827   if (TestCpuFlag(kCpuHasAVX2)) {
828     UYVYToUVRow = UYVYToUVRow_Any_AVX2;
829     UYVYToYRow = UYVYToYRow_Any_AVX2;
830     if (IS_ALIGNED(width, 32)) {
831       UYVYToUVRow = UYVYToUVRow_AVX2;
832       UYVYToYRow = UYVYToYRow_AVX2;
833     }
834   }
835 #endif
836 #if defined(HAS_UYVYTOYROW_NEON)
837   if (TestCpuFlag(kCpuHasNEON)) {
838     UYVYToYRow = UYVYToYRow_Any_NEON;
839     UYVYToUVRow = UYVYToUVRow_Any_NEON;
840     if (IS_ALIGNED(width, 16)) {
841       UYVYToYRow = UYVYToYRow_NEON;
842       UYVYToUVRow = UYVYToUVRow_NEON;
843     }
844   }
845 #endif
846 #if defined(HAS_UYVYTOYROW_MSA)
847   if (TestCpuFlag(kCpuHasMSA)) {
848     UYVYToYRow = UYVYToYRow_Any_MSA;
849     UYVYToUVRow = UYVYToUVRow_Any_MSA;
850     if (IS_ALIGNED(width, 32)) {
851       UYVYToYRow = UYVYToYRow_MSA;
852       UYVYToUVRow = UYVYToUVRow_MSA;
853     }
854   }
855 #endif
856 #if defined(HAS_UYVYTOYROW_MMI)
857   if (TestCpuFlag(kCpuHasMMI)) {
858     UYVYToYRow = UYVYToYRow_Any_MMI;
859     UYVYToUVRow = UYVYToUVRow_Any_MMI;
860     if (IS_ALIGNED(width, 16)) {
861       UYVYToYRow = UYVYToYRow_MMI;
862       UYVYToUVRow = UYVYToUVRow_MMI;
863     }
864   }
865 #endif
866 
867   for (y = 0; y < height - 1; y += 2) {
868     UYVYToUVRow(src_uyvy, src_stride_uyvy, dst_u, dst_v, width);
869     UYVYToYRow(src_uyvy, dst_y, width);
870     UYVYToYRow(src_uyvy + src_stride_uyvy, dst_y + dst_stride_y, width);
871     src_uyvy += src_stride_uyvy * 2;
872     dst_y += dst_stride_y * 2;
873     dst_u += dst_stride_u;
874     dst_v += dst_stride_v;
875   }
876   if (height & 1) {
877     UYVYToUVRow(src_uyvy, 0, dst_u, dst_v, width);
878     UYVYToYRow(src_uyvy, dst_y, width);
879   }
880   return 0;
881 }
882 
883 // Convert AYUV to NV12.
884 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)885 int AYUVToNV12(const uint8_t* src_ayuv,
886                int src_stride_ayuv,
887                uint8_t* dst_y,
888                int dst_stride_y,
889                uint8_t* dst_uv,
890                int dst_stride_uv,
891                int width,
892                int height) {
893   int y;
894   void (*AYUVToUVRow)(const uint8_t* src_ayuv, int src_stride_ayuv,
895                       uint8_t* dst_uv, int width) = AYUVToUVRow_C;
896   void (*AYUVToYRow)(const uint8_t* src_ayuv, uint8_t* dst_y, int width) =
897       AYUVToYRow_C;
898   // Negative height means invert the image.
899   if (height < 0) {
900     height = -height;
901     src_ayuv = src_ayuv + (height - 1) * src_stride_ayuv;
902     src_stride_ayuv = -src_stride_ayuv;
903   }
904 // place holders for future intel code
905 #if defined(HAS_AYUVTOYROW_SSE2)
906   if (TestCpuFlag(kCpuHasSSE2)) {
907     AYUVToUVRow = AYUVToUVRow_Any_SSE2;
908     AYUVToYRow = AYUVToYRow_Any_SSE2;
909     if (IS_ALIGNED(width, 16)) {
910       AYUVToUVRow = AYUVToUVRow_SSE2;
911       AYUVToYRow = AYUVToYRow_SSE2;
912     }
913   }
914 #endif
915 #if defined(HAS_AYUVTOYROW_AVX2)
916   if (TestCpuFlag(kCpuHasAVX2)) {
917     AYUVToUVRow = AYUVToUVRow_Any_AVX2;
918     AYUVToYRow = AYUVToYRow_Any_AVX2;
919     if (IS_ALIGNED(width, 32)) {
920       AYUVToUVRow = AYUVToUVRow_AVX2;
921       AYUVToYRow = AYUVToYRow_AVX2;
922     }
923   }
924 #endif
925 
926 #if defined(HAS_AYUVTOYROW_NEON)
927   if (TestCpuFlag(kCpuHasNEON)) {
928     AYUVToYRow = AYUVToYRow_Any_NEON;
929     AYUVToUVRow = AYUVToUVRow_Any_NEON;
930     if (IS_ALIGNED(width, 16)) {
931       AYUVToYRow = AYUVToYRow_NEON;
932       AYUVToUVRow = AYUVToUVRow_NEON;
933     }
934   }
935 #endif
936 
937   for (y = 0; y < height - 1; y += 2) {
938     AYUVToUVRow(src_ayuv, src_stride_ayuv, dst_uv, width);
939     AYUVToYRow(src_ayuv, dst_y, width);
940     AYUVToYRow(src_ayuv + src_stride_ayuv, dst_y + dst_stride_y, width);
941     src_ayuv += src_stride_ayuv * 2;
942     dst_y += dst_stride_y * 2;
943     dst_uv += dst_stride_uv;
944   }
945   if (height & 1) {
946     AYUVToUVRow(src_ayuv, 0, dst_uv, width);
947     AYUVToYRow(src_ayuv, dst_y, width);
948   }
949   return 0;
950 }
951 
952 // Convert AYUV to NV21.
953 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)954 int AYUVToNV21(const uint8_t* src_ayuv,
955                int src_stride_ayuv,
956                uint8_t* dst_y,
957                int dst_stride_y,
958                uint8_t* dst_vu,
959                int dst_stride_vu,
960                int width,
961                int height) {
962   int y;
963   void (*AYUVToVURow)(const uint8_t* src_ayuv, int src_stride_ayuv,
964                       uint8_t* dst_vu, int width) = AYUVToVURow_C;
965   void (*AYUVToYRow)(const uint8_t* src_ayuv, uint8_t* dst_y, int width) =
966       AYUVToYRow_C;
967   // Negative height means invert the image.
968   if (height < 0) {
969     height = -height;
970     src_ayuv = src_ayuv + (height - 1) * src_stride_ayuv;
971     src_stride_ayuv = -src_stride_ayuv;
972   }
973 // place holders for future intel code
974 #if defined(HAS_AYUVTOYROW_SSE2)
975   if (TestCpuFlag(kCpuHasSSE2)) {
976     AYUVToVURow = AYUVToVURow_Any_SSE2;
977     AYUVToYRow = AYUVToYRow_Any_SSE2;
978     if (IS_ALIGNED(width, 16)) {
979       AYUVToVURow = AYUVToVURow_SSE2;
980       AYUVToYRow = AYUVToYRow_SSE2;
981     }
982   }
983 #endif
984 #if defined(HAS_AYUVTOYROW_AVX2)
985   if (TestCpuFlag(kCpuHasAVX2)) {
986     AYUVToVURow = AYUVToVURow_Any_AVX2;
987     AYUVToYRow = AYUVToYRow_Any_AVX2;
988     if (IS_ALIGNED(width, 32)) {
989       AYUVToVURow = AYUVToVURow_AVX2;
990       AYUVToYRow = AYUVToYRow_AVX2;
991     }
992   }
993 #endif
994 
995 #if defined(HAS_AYUVTOYROW_NEON)
996   if (TestCpuFlag(kCpuHasNEON)) {
997     AYUVToYRow = AYUVToYRow_Any_NEON;
998     AYUVToVURow = AYUVToVURow_Any_NEON;
999     if (IS_ALIGNED(width, 16)) {
1000       AYUVToYRow = AYUVToYRow_NEON;
1001       AYUVToVURow = AYUVToVURow_NEON;
1002     }
1003   }
1004 #endif
1005 
1006   for (y = 0; y < height - 1; y += 2) {
1007     AYUVToVURow(src_ayuv, src_stride_ayuv, dst_vu, width);
1008     AYUVToYRow(src_ayuv, dst_y, width);
1009     AYUVToYRow(src_ayuv + src_stride_ayuv, dst_y + dst_stride_y, width);
1010     src_ayuv += src_stride_ayuv * 2;
1011     dst_y += dst_stride_y * 2;
1012     dst_vu += dst_stride_vu;
1013   }
1014   if (height & 1) {
1015     AYUVToVURow(src_ayuv, 0, dst_vu, width);
1016     AYUVToYRow(src_ayuv, dst_y, width);
1017   }
1018   return 0;
1019 }
1020 
1021 // Convert ARGB to I420.
1022 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)1023 int ARGBToI420(const uint8_t* src_argb,
1024                int src_stride_argb,
1025                uint8_t* dst_y,
1026                int dst_stride_y,
1027                uint8_t* dst_u,
1028                int dst_stride_u,
1029                uint8_t* dst_v,
1030                int dst_stride_v,
1031                int width,
1032                int height) {
1033   int y;
1034   void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
1035                       uint8_t* dst_u, uint8_t* dst_v, int width) =
1036       ARGBToUVRow_C;
1037   void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
1038       ARGBToYRow_C;
1039   if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1040     return -1;
1041   }
1042   // Negative height means invert the image.
1043   if (height < 0) {
1044     height = -height;
1045     src_argb = src_argb + (height - 1) * src_stride_argb;
1046     src_stride_argb = -src_stride_argb;
1047   }
1048 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1049   if (TestCpuFlag(kCpuHasSSSE3)) {
1050     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1051     ARGBToYRow = ARGBToYRow_Any_SSSE3;
1052     if (IS_ALIGNED(width, 16)) {
1053       ARGBToUVRow = ARGBToUVRow_SSSE3;
1054       ARGBToYRow = ARGBToYRow_SSSE3;
1055     }
1056   }
1057 #endif
1058 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1059   if (TestCpuFlag(kCpuHasAVX2)) {
1060     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1061     ARGBToYRow = ARGBToYRow_Any_AVX2;
1062     if (IS_ALIGNED(width, 32)) {
1063       ARGBToUVRow = ARGBToUVRow_AVX2;
1064       ARGBToYRow = ARGBToYRow_AVX2;
1065     }
1066   }
1067 #endif
1068 #if defined(HAS_ARGBTOYROW_NEON)
1069   if (TestCpuFlag(kCpuHasNEON)) {
1070     ARGBToYRow = ARGBToYRow_Any_NEON;
1071     if (IS_ALIGNED(width, 8)) {
1072       ARGBToYRow = ARGBToYRow_NEON;
1073     }
1074   }
1075 #endif
1076 #if defined(HAS_ARGBTOUVROW_NEON)
1077   if (TestCpuFlag(kCpuHasNEON)) {
1078     ARGBToUVRow = ARGBToUVRow_Any_NEON;
1079     if (IS_ALIGNED(width, 16)) {
1080       ARGBToUVRow = ARGBToUVRow_NEON;
1081     }
1082   }
1083 #endif
1084 #if defined(HAS_ARGBTOYROW_MSA)
1085   if (TestCpuFlag(kCpuHasMSA)) {
1086     ARGBToYRow = ARGBToYRow_Any_MSA;
1087     if (IS_ALIGNED(width, 16)) {
1088       ARGBToYRow = ARGBToYRow_MSA;
1089     }
1090   }
1091 #endif
1092 #if defined(HAS_ARGBTOUVROW_MSA)
1093   if (TestCpuFlag(kCpuHasMSA)) {
1094     ARGBToUVRow = ARGBToUVRow_Any_MSA;
1095     if (IS_ALIGNED(width, 32)) {
1096       ARGBToUVRow = ARGBToUVRow_MSA;
1097     }
1098   }
1099 #endif
1100 #if defined(HAS_ARGBTOYROW_MMI)
1101   if (TestCpuFlag(kCpuHasMMI)) {
1102     ARGBToYRow = ARGBToYRow_Any_MMI;
1103     if (IS_ALIGNED(width, 8)) {
1104       ARGBToYRow = ARGBToYRow_MMI;
1105     }
1106   }
1107 #endif
1108 #if defined(HAS_ARGBTOUVROW_MMI)
1109   if (TestCpuFlag(kCpuHasMMI)) {
1110     ARGBToUVRow = ARGBToUVRow_Any_MMI;
1111     if (IS_ALIGNED(width, 16)) {
1112       ARGBToUVRow = ARGBToUVRow_MMI;
1113     }
1114   }
1115 #endif
1116 
1117   for (y = 0; y < height - 1; y += 2) {
1118     ARGBToUVRow(src_argb, src_stride_argb, dst_u, dst_v, width);
1119     ARGBToYRow(src_argb, dst_y, width);
1120     ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
1121     src_argb += src_stride_argb * 2;
1122     dst_y += dst_stride_y * 2;
1123     dst_u += dst_stride_u;
1124     dst_v += dst_stride_v;
1125   }
1126   if (height & 1) {
1127     ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
1128     ARGBToYRow(src_argb, dst_y, width);
1129   }
1130   return 0;
1131 }
1132 
1133 // Convert BGRA to I420.
1134 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)1135 int BGRAToI420(const uint8_t* src_bgra,
1136                int src_stride_bgra,
1137                uint8_t* dst_y,
1138                int dst_stride_y,
1139                uint8_t* dst_u,
1140                int dst_stride_u,
1141                uint8_t* dst_v,
1142                int dst_stride_v,
1143                int width,
1144                int height) {
1145   int y;
1146   void (*BGRAToUVRow)(const uint8_t* src_bgra0, int src_stride_bgra,
1147                       uint8_t* dst_u, uint8_t* dst_v, int width) =
1148       BGRAToUVRow_C;
1149   void (*BGRAToYRow)(const uint8_t* src_bgra, uint8_t* dst_y, int width) =
1150       BGRAToYRow_C;
1151   if (!src_bgra || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1152     return -1;
1153   }
1154   // Negative height means invert the image.
1155   if (height < 0) {
1156     height = -height;
1157     src_bgra = src_bgra + (height - 1) * src_stride_bgra;
1158     src_stride_bgra = -src_stride_bgra;
1159   }
1160 #if defined(HAS_BGRATOYROW_SSSE3) && defined(HAS_BGRATOUVROW_SSSE3)
1161   if (TestCpuFlag(kCpuHasSSSE3)) {
1162     BGRAToUVRow = BGRAToUVRow_Any_SSSE3;
1163     BGRAToYRow = BGRAToYRow_Any_SSSE3;
1164     if (IS_ALIGNED(width, 16)) {
1165       BGRAToUVRow = BGRAToUVRow_SSSE3;
1166       BGRAToYRow = BGRAToYRow_SSSE3;
1167     }
1168   }
1169 #endif
1170 #if defined(HAS_BGRATOYROW_NEON)
1171   if (TestCpuFlag(kCpuHasNEON)) {
1172     BGRAToYRow = BGRAToYRow_Any_NEON;
1173     if (IS_ALIGNED(width, 8)) {
1174       BGRAToYRow = BGRAToYRow_NEON;
1175     }
1176   }
1177 #endif
1178 #if defined(HAS_BGRATOUVROW_NEON)
1179   if (TestCpuFlag(kCpuHasNEON)) {
1180     BGRAToUVRow = BGRAToUVRow_Any_NEON;
1181     if (IS_ALIGNED(width, 16)) {
1182       BGRAToUVRow = BGRAToUVRow_NEON;
1183     }
1184   }
1185 #endif
1186 #if defined(HAS_BGRATOYROW_MSA)
1187   if (TestCpuFlag(kCpuHasMSA)) {
1188     BGRAToYRow = BGRAToYRow_Any_MSA;
1189     if (IS_ALIGNED(width, 16)) {
1190       BGRAToYRow = BGRAToYRow_MSA;
1191     }
1192   }
1193 #endif
1194 #if defined(HAS_BGRATOUVROW_MSA)
1195   if (TestCpuFlag(kCpuHasMSA)) {
1196     BGRAToUVRow = BGRAToUVRow_Any_MSA;
1197     if (IS_ALIGNED(width, 16)) {
1198       BGRAToUVRow = BGRAToUVRow_MSA;
1199     }
1200   }
1201 #endif
1202 #if defined(HAS_BGRATOYROW_MMI)
1203   if (TestCpuFlag(kCpuHasMMI)) {
1204     BGRAToYRow = BGRAToYRow_Any_MMI;
1205     if (IS_ALIGNED(width, 8)) {
1206       BGRAToYRow = BGRAToYRow_MMI;
1207     }
1208   }
1209 #endif
1210 #if defined(HAS_BGRATOUVROW_MMI)
1211   if (TestCpuFlag(kCpuHasMMI)) {
1212     BGRAToUVRow = BGRAToUVRow_Any_MMI;
1213     if (IS_ALIGNED(width, 16)) {
1214       BGRAToUVRow = BGRAToUVRow_MMI;
1215     }
1216   }
1217 #endif
1218 
1219   for (y = 0; y < height - 1; y += 2) {
1220     BGRAToUVRow(src_bgra, src_stride_bgra, dst_u, dst_v, width);
1221     BGRAToYRow(src_bgra, dst_y, width);
1222     BGRAToYRow(src_bgra + src_stride_bgra, dst_y + dst_stride_y, width);
1223     src_bgra += src_stride_bgra * 2;
1224     dst_y += dst_stride_y * 2;
1225     dst_u += dst_stride_u;
1226     dst_v += dst_stride_v;
1227   }
1228   if (height & 1) {
1229     BGRAToUVRow(src_bgra, 0, dst_u, dst_v, width);
1230     BGRAToYRow(src_bgra, dst_y, width);
1231   }
1232   return 0;
1233 }
1234 
1235 // Convert ABGR to I420.
1236 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)1237 int ABGRToI420(const uint8_t* src_abgr,
1238                int src_stride_abgr,
1239                uint8_t* dst_y,
1240                int dst_stride_y,
1241                uint8_t* dst_u,
1242                int dst_stride_u,
1243                uint8_t* dst_v,
1244                int dst_stride_v,
1245                int width,
1246                int height) {
1247   int y;
1248   void (*ABGRToUVRow)(const uint8_t* src_abgr0, int src_stride_abgr,
1249                       uint8_t* dst_u, uint8_t* dst_v, int width) =
1250       ABGRToUVRow_C;
1251   void (*ABGRToYRow)(const uint8_t* src_abgr, uint8_t* dst_y, int width) =
1252       ABGRToYRow_C;
1253   if (!src_abgr || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1254     return -1;
1255   }
1256   // Negative height means invert the image.
1257   if (height < 0) {
1258     height = -height;
1259     src_abgr = src_abgr + (height - 1) * src_stride_abgr;
1260     src_stride_abgr = -src_stride_abgr;
1261   }
1262 #if defined(HAS_ABGRTOYROW_SSSE3) && defined(HAS_ABGRTOUVROW_SSSE3)
1263   if (TestCpuFlag(kCpuHasSSSE3)) {
1264     ABGRToUVRow = ABGRToUVRow_Any_SSSE3;
1265     ABGRToYRow = ABGRToYRow_Any_SSSE3;
1266     if (IS_ALIGNED(width, 16)) {
1267       ABGRToUVRow = ABGRToUVRow_SSSE3;
1268       ABGRToYRow = ABGRToYRow_SSSE3;
1269     }
1270   }
1271 #endif
1272 #if defined(HAS_ABGRTOYROW_NEON)
1273   if (TestCpuFlag(kCpuHasNEON)) {
1274     ABGRToYRow = ABGRToYRow_Any_NEON;
1275     if (IS_ALIGNED(width, 8)) {
1276       ABGRToYRow = ABGRToYRow_NEON;
1277     }
1278   }
1279 #endif
1280 #if defined(HAS_ABGRTOUVROW_NEON)
1281   if (TestCpuFlag(kCpuHasNEON)) {
1282     ABGRToUVRow = ABGRToUVRow_Any_NEON;
1283     if (IS_ALIGNED(width, 16)) {
1284       ABGRToUVRow = ABGRToUVRow_NEON;
1285     }
1286   }
1287 #endif
1288 #if defined(HAS_ABGRTOYROW_MSA)
1289   if (TestCpuFlag(kCpuHasMSA)) {
1290     ABGRToYRow = ABGRToYRow_Any_MSA;
1291     if (IS_ALIGNED(width, 16)) {
1292       ABGRToYRow = ABGRToYRow_MSA;
1293     }
1294   }
1295 #endif
1296 #if defined(HAS_ABGRTOUVROW_MSA)
1297   if (TestCpuFlag(kCpuHasMSA)) {
1298     ABGRToUVRow = ABGRToUVRow_Any_MSA;
1299     if (IS_ALIGNED(width, 16)) {
1300       ABGRToUVRow = ABGRToUVRow_MSA;
1301     }
1302   }
1303 #endif
1304 #if defined(HAS_ABGRTOYROW_MMI)
1305   if (TestCpuFlag(kCpuHasMMI)) {
1306     ABGRToYRow = ABGRToYRow_Any_MMI;
1307     if (IS_ALIGNED(width, 8)) {
1308       ABGRToYRow = ABGRToYRow_MMI;
1309     }
1310   }
1311 #endif
1312 #if defined(HAS_ABGRTOUVROW_MMI)
1313   if (TestCpuFlag(kCpuHasMMI)) {
1314     ABGRToUVRow = ABGRToUVRow_Any_MMI;
1315     if (IS_ALIGNED(width, 16)) {
1316       ABGRToUVRow = ABGRToUVRow_MMI;
1317     }
1318   }
1319 #endif
1320 
1321   for (y = 0; y < height - 1; y += 2) {
1322     ABGRToUVRow(src_abgr, src_stride_abgr, dst_u, dst_v, width);
1323     ABGRToYRow(src_abgr, dst_y, width);
1324     ABGRToYRow(src_abgr + src_stride_abgr, dst_y + dst_stride_y, width);
1325     src_abgr += src_stride_abgr * 2;
1326     dst_y += dst_stride_y * 2;
1327     dst_u += dst_stride_u;
1328     dst_v += dst_stride_v;
1329   }
1330   if (height & 1) {
1331     ABGRToUVRow(src_abgr, 0, dst_u, dst_v, width);
1332     ABGRToYRow(src_abgr, dst_y, width);
1333   }
1334   return 0;
1335 }
1336 
1337 // Convert RGBA to I420.
1338 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)1339 int RGBAToI420(const uint8_t* src_rgba,
1340                int src_stride_rgba,
1341                uint8_t* dst_y,
1342                int dst_stride_y,
1343                uint8_t* dst_u,
1344                int dst_stride_u,
1345                uint8_t* dst_v,
1346                int dst_stride_v,
1347                int width,
1348                int height) {
1349   int y;
1350   void (*RGBAToUVRow)(const uint8_t* src_rgba0, int src_stride_rgba,
1351                       uint8_t* dst_u, uint8_t* dst_v, int width) =
1352       RGBAToUVRow_C;
1353   void (*RGBAToYRow)(const uint8_t* src_rgba, uint8_t* dst_y, int width) =
1354       RGBAToYRow_C;
1355   if (!src_rgba || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1356     return -1;
1357   }
1358   // Negative height means invert the image.
1359   if (height < 0) {
1360     height = -height;
1361     src_rgba = src_rgba + (height - 1) * src_stride_rgba;
1362     src_stride_rgba = -src_stride_rgba;
1363   }
1364 #if defined(HAS_RGBATOYROW_SSSE3) && defined(HAS_RGBATOUVROW_SSSE3)
1365   if (TestCpuFlag(kCpuHasSSSE3)) {
1366     RGBAToUVRow = RGBAToUVRow_Any_SSSE3;
1367     RGBAToYRow = RGBAToYRow_Any_SSSE3;
1368     if (IS_ALIGNED(width, 16)) {
1369       RGBAToUVRow = RGBAToUVRow_SSSE3;
1370       RGBAToYRow = RGBAToYRow_SSSE3;
1371     }
1372   }
1373 #endif
1374 #if defined(HAS_RGBATOYROW_NEON)
1375   if (TestCpuFlag(kCpuHasNEON)) {
1376     RGBAToYRow = RGBAToYRow_Any_NEON;
1377     if (IS_ALIGNED(width, 8)) {
1378       RGBAToYRow = RGBAToYRow_NEON;
1379     }
1380   }
1381 #endif
1382 #if defined(HAS_RGBATOUVROW_NEON)
1383   if (TestCpuFlag(kCpuHasNEON)) {
1384     RGBAToUVRow = RGBAToUVRow_Any_NEON;
1385     if (IS_ALIGNED(width, 16)) {
1386       RGBAToUVRow = RGBAToUVRow_NEON;
1387     }
1388   }
1389 #endif
1390 #if defined(HAS_RGBATOYROW_MSA)
1391   if (TestCpuFlag(kCpuHasMSA)) {
1392     RGBAToYRow = RGBAToYRow_Any_MSA;
1393     if (IS_ALIGNED(width, 16)) {
1394       RGBAToYRow = RGBAToYRow_MSA;
1395     }
1396   }
1397 #endif
1398 #if defined(HAS_RGBATOUVROW_MSA)
1399   if (TestCpuFlag(kCpuHasMSA)) {
1400     RGBAToUVRow = RGBAToUVRow_Any_MSA;
1401     if (IS_ALIGNED(width, 16)) {
1402       RGBAToUVRow = RGBAToUVRow_MSA;
1403     }
1404   }
1405 #endif
1406 #if defined(HAS_RGBATOYROW_MMI)
1407   if (TestCpuFlag(kCpuHasMMI)) {
1408     RGBAToYRow = RGBAToYRow_Any_MMI;
1409     if (IS_ALIGNED(width, 8)) {
1410       RGBAToYRow = RGBAToYRow_MMI;
1411     }
1412   }
1413 #endif
1414 #if defined(HAS_RGBATOUVROW_MMI)
1415   if (TestCpuFlag(kCpuHasMMI)) {
1416     RGBAToUVRow = RGBAToUVRow_Any_MMI;
1417     if (IS_ALIGNED(width, 16)) {
1418       RGBAToUVRow = RGBAToUVRow_MMI;
1419     }
1420   }
1421 #endif
1422 
1423   for (y = 0; y < height - 1; y += 2) {
1424     RGBAToUVRow(src_rgba, src_stride_rgba, dst_u, dst_v, width);
1425     RGBAToYRow(src_rgba, dst_y, width);
1426     RGBAToYRow(src_rgba + src_stride_rgba, dst_y + dst_stride_y, width);
1427     src_rgba += src_stride_rgba * 2;
1428     dst_y += dst_stride_y * 2;
1429     dst_u += dst_stride_u;
1430     dst_v += dst_stride_v;
1431   }
1432   if (height & 1) {
1433     RGBAToUVRow(src_rgba, 0, dst_u, dst_v, width);
1434     RGBAToYRow(src_rgba, dst_y, width);
1435   }
1436   return 0;
1437 }
1438 
1439 // Convert RGB24 to I420.
1440 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)1441 int RGB24ToI420(const uint8_t* src_rgb24,
1442                 int src_stride_rgb24,
1443                 uint8_t* dst_y,
1444                 int dst_stride_y,
1445                 uint8_t* dst_u,
1446                 int dst_stride_u,
1447                 uint8_t* dst_v,
1448                 int dst_stride_v,
1449                 int width,
1450                 int height) {
1451   int y;
1452 #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA) || \
1453      defined(HAS_RGB24TOYROW_MMI))
1454   void (*RGB24ToUVRow)(const uint8_t* src_rgb24, int src_stride_rgb24,
1455                        uint8_t* dst_u, uint8_t* dst_v, int width) =
1456       RGB24ToUVRow_C;
1457   void (*RGB24ToYRow)(const uint8_t* src_rgb24, uint8_t* dst_y, int width) =
1458       RGB24ToYRow_C;
1459 #else
1460   void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
1461       RGB24ToARGBRow_C;
1462   void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
1463                       uint8_t* dst_u, uint8_t* dst_v, int width) =
1464       ARGBToUVRow_C;
1465   void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
1466       ARGBToYRow_C;
1467 #endif
1468   if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1469     return -1;
1470   }
1471   // Negative height means invert the image.
1472   if (height < 0) {
1473     height = -height;
1474     src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
1475     src_stride_rgb24 = -src_stride_rgb24;
1476   }
1477 
1478 // Neon version does direct RGB24 to YUV.
1479 #if defined(HAS_RGB24TOYROW_NEON)
1480   if (TestCpuFlag(kCpuHasNEON)) {
1481     RGB24ToUVRow = RGB24ToUVRow_Any_NEON;
1482     RGB24ToYRow = RGB24ToYRow_Any_NEON;
1483     if (IS_ALIGNED(width, 8)) {
1484       RGB24ToYRow = RGB24ToYRow_NEON;
1485       if (IS_ALIGNED(width, 16)) {
1486         RGB24ToUVRow = RGB24ToUVRow_NEON;
1487       }
1488     }
1489   }
1490 #elif defined(HAS_RGB24TOYROW_MSA)
1491   if (TestCpuFlag(kCpuHasMSA)) {
1492     RGB24ToUVRow = RGB24ToUVRow_Any_MSA;
1493     RGB24ToYRow = RGB24ToYRow_Any_MSA;
1494     if (IS_ALIGNED(width, 16)) {
1495       RGB24ToYRow = RGB24ToYRow_MSA;
1496       RGB24ToUVRow = RGB24ToUVRow_MSA;
1497     }
1498   }
1499 #elif defined(HAS_RGB24TOYROW_MMI)
1500   if (TestCpuFlag(kCpuHasMMI)) {
1501     RGB24ToUVRow = RGB24ToUVRow_Any_MMI;
1502     RGB24ToYRow = RGB24ToYRow_Any_MMI;
1503     if (IS_ALIGNED(width, 8)) {
1504       RGB24ToYRow = RGB24ToYRow_MMI;
1505       if (IS_ALIGNED(width, 16)) {
1506         RGB24ToUVRow = RGB24ToUVRow_MMI;
1507       }
1508     }
1509   }
1510 // Other platforms do intermediate conversion from RGB24 to ARGB.
1511 #else
1512 #if defined(HAS_RGB24TOARGBROW_SSSE3)
1513   if (TestCpuFlag(kCpuHasSSSE3)) {
1514     RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
1515     if (IS_ALIGNED(width, 16)) {
1516       RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
1517     }
1518   }
1519 #endif
1520 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1521   if (TestCpuFlag(kCpuHasSSSE3)) {
1522     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1523     ARGBToYRow = ARGBToYRow_Any_SSSE3;
1524     if (IS_ALIGNED(width, 16)) {
1525       ARGBToUVRow = ARGBToUVRow_SSSE3;
1526       ARGBToYRow = ARGBToYRow_SSSE3;
1527     }
1528   }
1529 #endif
1530 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1531   if (TestCpuFlag(kCpuHasAVX2)) {
1532     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1533     ARGBToYRow = ARGBToYRow_Any_AVX2;
1534     if (IS_ALIGNED(width, 32)) {
1535       ARGBToUVRow = ARGBToUVRow_AVX2;
1536       ARGBToYRow = ARGBToYRow_AVX2;
1537     }
1538   }
1539 #endif
1540 #endif
1541 
1542   {
1543 #if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA) || \
1544       defined(HAS_RGB24TOYROW_MMI))
1545     // Allocate 2 rows of ARGB.
1546     const int kRowSize = (width * 4 + 31) & ~31;
1547     align_buffer_64(row, kRowSize * 2);
1548 #endif
1549 
1550     for (y = 0; y < height - 1; y += 2) {
1551 #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA) || \
1552      defined(HAS_RGB24TOYROW_MMI))
1553       RGB24ToUVRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
1554       RGB24ToYRow(src_rgb24, dst_y, width);
1555       RGB24ToYRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
1556 #else
1557       RGB24ToARGBRow(src_rgb24, row, width);
1558       RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
1559       ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1560       ARGBToYRow(row, dst_y, width);
1561       ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1562 #endif
1563       src_rgb24 += src_stride_rgb24 * 2;
1564       dst_y += dst_stride_y * 2;
1565       dst_u += dst_stride_u;
1566       dst_v += dst_stride_v;
1567     }
1568     if (height & 1) {
1569 #if (defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA) || \
1570      defined(HAS_RGB24TOYROW_MMI))
1571       RGB24ToUVRow(src_rgb24, 0, dst_u, dst_v, width);
1572       RGB24ToYRow(src_rgb24, dst_y, width);
1573 #else
1574       RGB24ToARGBRow(src_rgb24, row, width);
1575       ARGBToUVRow(row, 0, dst_u, dst_v, width);
1576       ARGBToYRow(row, dst_y, width);
1577 #endif
1578     }
1579 #if !(defined(HAS_RGB24TOYROW_NEON) || defined(HAS_RGB24TOYROW_MSA) || \
1580       defined(HAS_RGB24TOYROW_MMI))
1581     free_aligned_buffer_64(row);
1582 #endif
1583   }
1584   return 0;
1585 }
1586 
1587 // TODO(fbarchard): Use Matrix version to implement I420 and J420.
1588 // Convert RGB24 to J420.
1589 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)1590 int RGB24ToJ420(const uint8_t* src_rgb24,
1591                 int src_stride_rgb24,
1592                 uint8_t* dst_y,
1593                 int dst_stride_y,
1594                 uint8_t* dst_u,
1595                 int dst_stride_u,
1596                 uint8_t* dst_v,
1597                 int dst_stride_v,
1598                 int width,
1599                 int height) {
1600   int y;
1601 #if (defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
1602      defined(HAS_RGB24TOYJROW_MMI))
1603   void (*RGB24ToUVJRow)(const uint8_t* src_rgb24, int src_stride_rgb24,
1604                         uint8_t* dst_u, uint8_t* dst_v, int width) =
1605       RGB24ToUVJRow_C;
1606   void (*RGB24ToYJRow)(const uint8_t* src_rgb24, uint8_t* dst_y, int width) =
1607       RGB24ToYJRow_C;
1608 #else
1609   void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
1610       RGB24ToARGBRow_C;
1611   void (*ARGBToUVJRow)(const uint8_t* src_argb0, int src_stride_argb,
1612                        uint8_t* dst_u, uint8_t* dst_v, int width) =
1613       ARGBToUVJRow_C;
1614   void (*ARGBToYJRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
1615       ARGBToYJRow_C;
1616 #endif
1617   if (!src_rgb24 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1618     return -1;
1619   }
1620   // Negative height means invert the image.
1621   if (height < 0) {
1622     height = -height;
1623     src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
1624     src_stride_rgb24 = -src_stride_rgb24;
1625   }
1626 
1627 // Neon version does direct RGB24 to YUV.
1628 #if defined(HAS_RGB24TOYJROW_NEON)
1629   if (TestCpuFlag(kCpuHasNEON)) {
1630     RGB24ToUVJRow = RGB24ToUVJRow_Any_NEON;
1631     RGB24ToYJRow = RGB24ToYJRow_Any_NEON;
1632     if (IS_ALIGNED(width, 8)) {
1633       RGB24ToYJRow = RGB24ToYJRow_NEON;
1634       if (IS_ALIGNED(width, 16)) {
1635         RGB24ToUVJRow = RGB24ToUVJRow_NEON;
1636       }
1637     }
1638   }
1639 #elif defined(HAS_RGB24TOYJROW_MSA)
1640   if (TestCpuFlag(kCpuHasMSA)) {
1641     RGB24ToUVJRow = RGB24ToUVJRow_Any_MSA;
1642     RGB24ToYJRow = RGB24ToYJRow_Any_MSA;
1643     if (IS_ALIGNED(width, 16)) {
1644       RGB24ToYJRow = RGB24ToYJRow_MSA;
1645       RGB24ToUVJRow = RGB24ToUVJRow_MSA;
1646     }
1647   }
1648 #elif defined(HAS_RGB24TOYJROW_MMI)
1649   if (TestCpuFlag(kCpuHasMMI)) {
1650     RGB24ToUVJRow = RGB24ToUVJRow_Any_MMI;
1651     RGB24ToYJRow = RGB24ToYJRow_Any_MMI;
1652     if (IS_ALIGNED(width, 8)) {
1653       RGB24ToYJRow = RGB24ToYJRow_MMI;
1654       if (IS_ALIGNED(width, 16)) {
1655         RGB24ToUVJRow = RGB24ToUVJRow_MMI;
1656       }
1657     }
1658   }
1659 // Other platforms do intermediate conversion from RGB24 to ARGB.
1660 #else
1661 #if defined(HAS_RGB24TOARGBROW_SSSE3)
1662   if (TestCpuFlag(kCpuHasSSSE3)) {
1663     RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
1664     if (IS_ALIGNED(width, 16)) {
1665       RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
1666     }
1667   }
1668 #endif
1669 #if defined(HAS_ARGBTOYJROW_SSSE3) && defined(HAS_ARGBTOUVJROW_SSSE3)
1670   if (TestCpuFlag(kCpuHasSSSE3)) {
1671     ARGBToUVJRow = ARGBToUVJRow_Any_SSSE3;
1672     ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
1673     if (IS_ALIGNED(width, 16)) {
1674       ARGBToUVJRow = ARGBToUVJRow_SSSE3;
1675       ARGBToYJRow = ARGBToYJRow_SSSE3;
1676     }
1677   }
1678 #endif
1679 #if defined(HAS_ARGBTOYJROW_AVX2) && defined(HAS_ARGBTOUVJROW_AVX2)
1680   if (TestCpuFlag(kCpuHasAVX2)) {
1681     ARGBToUVJRow = ARGBToUVJRow_Any_AVX2;
1682     ARGBToYJRow = ARGBToYJRow_Any_AVX2;
1683     if (IS_ALIGNED(width, 32)) {
1684       ARGBToUVJRow = ARGBToUVJRow_AVX2;
1685       ARGBToYJRow = ARGBToYJRow_AVX2;
1686     }
1687   }
1688 #endif
1689 #endif
1690 
1691   {
1692 #if !(defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
1693       defined(HAS_RGB24TOYJROW_MMI))
1694     // Allocate 2 rows of ARGB.
1695     const int kRowSize = (width * 4 + 31) & ~31;
1696     align_buffer_64(row, kRowSize * 2);
1697 #endif
1698 
1699     for (y = 0; y < height - 1; y += 2) {
1700 #if (defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
1701      defined(HAS_RGB24TOYJROW_MMI))
1702       RGB24ToUVJRow(src_rgb24, src_stride_rgb24, dst_u, dst_v, width);
1703       RGB24ToYJRow(src_rgb24, dst_y, width);
1704       RGB24ToYJRow(src_rgb24 + src_stride_rgb24, dst_y + dst_stride_y, width);
1705 #else
1706       RGB24ToARGBRow(src_rgb24, row, width);
1707       RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
1708       ARGBToUVJRow(row, kRowSize, dst_u, dst_v, width);
1709       ARGBToYJRow(row, dst_y, width);
1710       ARGBToYJRow(row + kRowSize, dst_y + dst_stride_y, width);
1711 #endif
1712       src_rgb24 += src_stride_rgb24 * 2;
1713       dst_y += dst_stride_y * 2;
1714       dst_u += dst_stride_u;
1715       dst_v += dst_stride_v;
1716     }
1717     if (height & 1) {
1718 #if (defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
1719      defined(HAS_RGB24TOYJROW_MMI))
1720       RGB24ToUVJRow(src_rgb24, 0, dst_u, dst_v, width);
1721       RGB24ToYJRow(src_rgb24, dst_y, width);
1722 #else
1723       RGB24ToARGBRow(src_rgb24, row, width);
1724       ARGBToUVJRow(row, 0, dst_u, dst_v, width);
1725       ARGBToYJRow(row, dst_y, width);
1726 #endif
1727     }
1728 #if !(defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
1729       defined(HAS_RGB24TOYJROW_MMI))
1730     free_aligned_buffer_64(row);
1731 #endif
1732   }
1733   return 0;
1734 }
1735 
1736 // Convert RAW to I420.
1737 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)1738 int RAWToI420(const uint8_t* src_raw,
1739               int src_stride_raw,
1740               uint8_t* dst_y,
1741               int dst_stride_y,
1742               uint8_t* dst_u,
1743               int dst_stride_u,
1744               uint8_t* dst_v,
1745               int dst_stride_v,
1746               int width,
1747               int height) {
1748   int y;
1749 #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA) || \
1750      defined(HAS_RAWTOYROW_MMI))
1751   void (*RAWToUVRow)(const uint8_t* src_raw, int src_stride_raw, uint8_t* dst_u,
1752                      uint8_t* dst_v, int width) = RAWToUVRow_C;
1753   void (*RAWToYRow)(const uint8_t* src_raw, uint8_t* dst_y, int width) =
1754       RAWToYRow_C;
1755 #else
1756   void (*RAWToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
1757       RAWToARGBRow_C;
1758   void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
1759                       uint8_t* dst_u, uint8_t* dst_v, int width) =
1760       ARGBToUVRow_C;
1761   void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
1762       ARGBToYRow_C;
1763 #endif
1764   if (!src_raw || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1765     return -1;
1766   }
1767   // Negative height means invert the image.
1768   if (height < 0) {
1769     height = -height;
1770     src_raw = src_raw + (height - 1) * src_stride_raw;
1771     src_stride_raw = -src_stride_raw;
1772   }
1773 
1774 // Neon version does direct RAW to YUV.
1775 #if defined(HAS_RAWTOYROW_NEON)
1776   if (TestCpuFlag(kCpuHasNEON)) {
1777     RAWToUVRow = RAWToUVRow_Any_NEON;
1778     RAWToYRow = RAWToYRow_Any_NEON;
1779     if (IS_ALIGNED(width, 8)) {
1780       RAWToYRow = RAWToYRow_NEON;
1781       if (IS_ALIGNED(width, 16)) {
1782         RAWToUVRow = RAWToUVRow_NEON;
1783       }
1784     }
1785   }
1786 #elif defined(HAS_RAWTOYROW_MSA)
1787   if (TestCpuFlag(kCpuHasMSA)) {
1788     RAWToUVRow = RAWToUVRow_Any_MSA;
1789     RAWToYRow = RAWToYRow_Any_MSA;
1790     if (IS_ALIGNED(width, 16)) {
1791       RAWToYRow = RAWToYRow_MSA;
1792       RAWToUVRow = RAWToUVRow_MSA;
1793     }
1794   }
1795 #elif defined(HAS_RAWTOYROW_MMI)
1796   if (TestCpuFlag(kCpuHasMMI)) {
1797     RAWToUVRow = RAWToUVRow_Any_MMI;
1798     RAWToYRow = RAWToYRow_Any_MMI;
1799     if (IS_ALIGNED(width, 8)) {
1800       RAWToYRow = RAWToYRow_MMI;
1801       if (IS_ALIGNED(width, 16)) {
1802         RAWToUVRow = RAWToUVRow_MMI;
1803       }
1804     }
1805   }
1806 // Other platforms do intermediate conversion from RAW to ARGB.
1807 #else
1808 #if defined(HAS_RAWTOARGBROW_SSSE3)
1809   if (TestCpuFlag(kCpuHasSSSE3)) {
1810     RAWToARGBRow = RAWToARGBRow_Any_SSSE3;
1811     if (IS_ALIGNED(width, 16)) {
1812       RAWToARGBRow = RAWToARGBRow_SSSE3;
1813     }
1814   }
1815 #endif
1816 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1817   if (TestCpuFlag(kCpuHasSSSE3)) {
1818     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1819     ARGBToYRow = ARGBToYRow_Any_SSSE3;
1820     if (IS_ALIGNED(width, 16)) {
1821       ARGBToUVRow = ARGBToUVRow_SSSE3;
1822       ARGBToYRow = ARGBToYRow_SSSE3;
1823     }
1824   }
1825 #endif
1826 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1827   if (TestCpuFlag(kCpuHasAVX2)) {
1828     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1829     ARGBToYRow = ARGBToYRow_Any_AVX2;
1830     if (IS_ALIGNED(width, 32)) {
1831       ARGBToUVRow = ARGBToUVRow_AVX2;
1832       ARGBToYRow = ARGBToYRow_AVX2;
1833     }
1834   }
1835 #endif
1836 #endif
1837 
1838   {
1839 #if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA) || \
1840       defined(HAS_RAWTOYROW_MMI))
1841     // Allocate 2 rows of ARGB.
1842     const int kRowSize = (width * 4 + 31) & ~31;
1843     align_buffer_64(row, kRowSize * 2);
1844 #endif
1845 
1846     for (y = 0; y < height - 1; y += 2) {
1847 #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA) || \
1848      defined(HAS_RAWTOYROW_MMI))
1849       RAWToUVRow(src_raw, src_stride_raw, dst_u, dst_v, width);
1850       RAWToYRow(src_raw, dst_y, width);
1851       RAWToYRow(src_raw + src_stride_raw, dst_y + dst_stride_y, width);
1852 #else
1853       RAWToARGBRow(src_raw, row, width);
1854       RAWToARGBRow(src_raw + src_stride_raw, row + kRowSize, width);
1855       ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
1856       ARGBToYRow(row, dst_y, width);
1857       ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
1858 #endif
1859       src_raw += src_stride_raw * 2;
1860       dst_y += dst_stride_y * 2;
1861       dst_u += dst_stride_u;
1862       dst_v += dst_stride_v;
1863     }
1864     if (height & 1) {
1865 #if (defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA) || \
1866      defined(HAS_RAWTOYROW_MMI))
1867       RAWToUVRow(src_raw, 0, dst_u, dst_v, width);
1868       RAWToYRow(src_raw, dst_y, width);
1869 #else
1870       RAWToARGBRow(src_raw, row, width);
1871       ARGBToUVRow(row, 0, dst_u, dst_v, width);
1872       ARGBToYRow(row, dst_y, width);
1873 #endif
1874     }
1875 #if !(defined(HAS_RAWTOYROW_NEON) || defined(HAS_RAWTOYROW_MSA) || \
1876       defined(HAS_RAWTOYROW_MMI))
1877     free_aligned_buffer_64(row);
1878 #endif
1879   }
1880   return 0;
1881 }
1882 
1883 // Convert RGB565 to I420.
1884 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)1885 int RGB565ToI420(const uint8_t* src_rgb565,
1886                  int src_stride_rgb565,
1887                  uint8_t* dst_y,
1888                  int dst_stride_y,
1889                  uint8_t* dst_u,
1890                  int dst_stride_u,
1891                  uint8_t* dst_v,
1892                  int dst_stride_v,
1893                  int width,
1894                  int height) {
1895   int y;
1896 #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
1897      defined(HAS_RGB565TOYROW_MMI))
1898   void (*RGB565ToUVRow)(const uint8_t* src_rgb565, int src_stride_rgb565,
1899                         uint8_t* dst_u, uint8_t* dst_v, int width) =
1900       RGB565ToUVRow_C;
1901   void (*RGB565ToYRow)(const uint8_t* src_rgb565, uint8_t* dst_y, int width) =
1902       RGB565ToYRow_C;
1903 #else
1904   void (*RGB565ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
1905                           int width) = RGB565ToARGBRow_C;
1906   void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
1907                       uint8_t* dst_u, uint8_t* dst_v, int width) =
1908       ARGBToUVRow_C;
1909   void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
1910       ARGBToYRow_C;
1911 #endif
1912   if (!src_rgb565 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
1913     return -1;
1914   }
1915   // Negative height means invert the image.
1916   if (height < 0) {
1917     height = -height;
1918     src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565;
1919     src_stride_rgb565 = -src_stride_rgb565;
1920   }
1921 
1922 // Neon version does direct RGB565 to YUV.
1923 #if defined(HAS_RGB565TOYROW_NEON)
1924   if (TestCpuFlag(kCpuHasNEON)) {
1925     RGB565ToUVRow = RGB565ToUVRow_Any_NEON;
1926     RGB565ToYRow = RGB565ToYRow_Any_NEON;
1927     if (IS_ALIGNED(width, 8)) {
1928       RGB565ToYRow = RGB565ToYRow_NEON;
1929       if (IS_ALIGNED(width, 16)) {
1930         RGB565ToUVRow = RGB565ToUVRow_NEON;
1931       }
1932     }
1933   }
1934 #elif defined(HAS_RGB565TOYROW_MSA)
1935   if (TestCpuFlag(kCpuHasMSA)) {
1936     RGB565ToUVRow = RGB565ToUVRow_Any_MSA;
1937     RGB565ToYRow = RGB565ToYRow_Any_MSA;
1938     if (IS_ALIGNED(width, 16)) {
1939       RGB565ToYRow = RGB565ToYRow_MSA;
1940       RGB565ToUVRow = RGB565ToUVRow_MSA;
1941     }
1942   }
1943 #elif defined(HAS_RGB565TOYROW_MMI)
1944   if (TestCpuFlag(kCpuHasMMI)) {
1945     RGB565ToUVRow = RGB565ToUVRow_Any_MMI;
1946     RGB565ToYRow = RGB565ToYRow_Any_MMI;
1947     if (IS_ALIGNED(width, 8)) {
1948       RGB565ToYRow = RGB565ToYRow_MMI;
1949       if (IS_ALIGNED(width, 16)) {
1950         RGB565ToUVRow = RGB565ToUVRow_MMI;
1951       }
1952     }
1953   }
1954 // Other platforms do intermediate conversion from RGB565 to ARGB.
1955 #else
1956 #if defined(HAS_RGB565TOARGBROW_SSE2)
1957   if (TestCpuFlag(kCpuHasSSE2)) {
1958     RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2;
1959     if (IS_ALIGNED(width, 8)) {
1960       RGB565ToARGBRow = RGB565ToARGBRow_SSE2;
1961     }
1962   }
1963 #endif
1964 #if defined(HAS_RGB565TOARGBROW_AVX2)
1965   if (TestCpuFlag(kCpuHasAVX2)) {
1966     RGB565ToARGBRow = RGB565ToARGBRow_Any_AVX2;
1967     if (IS_ALIGNED(width, 16)) {
1968       RGB565ToARGBRow = RGB565ToARGBRow_AVX2;
1969     }
1970   }
1971 #endif
1972 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
1973   if (TestCpuFlag(kCpuHasSSSE3)) {
1974     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
1975     ARGBToYRow = ARGBToYRow_Any_SSSE3;
1976     if (IS_ALIGNED(width, 16)) {
1977       ARGBToUVRow = ARGBToUVRow_SSSE3;
1978       ARGBToYRow = ARGBToYRow_SSSE3;
1979     }
1980   }
1981 #endif
1982 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
1983   if (TestCpuFlag(kCpuHasAVX2)) {
1984     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
1985     ARGBToYRow = ARGBToYRow_Any_AVX2;
1986     if (IS_ALIGNED(width, 32)) {
1987       ARGBToUVRow = ARGBToUVRow_AVX2;
1988       ARGBToYRow = ARGBToYRow_AVX2;
1989     }
1990   }
1991 #endif
1992 #endif
1993   {
1994 #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
1995       defined(HAS_RGB565TOYROW_MMI))
1996     // Allocate 2 rows of ARGB.
1997     const int kRowSize = (width * 4 + 31) & ~31;
1998     align_buffer_64(row, kRowSize * 2);
1999 #endif
2000     for (y = 0; y < height - 1; y += 2) {
2001 #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
2002      defined(HAS_RGB565TOYROW_MMI))
2003       RGB565ToUVRow(src_rgb565, src_stride_rgb565, dst_u, dst_v, width);
2004       RGB565ToYRow(src_rgb565, dst_y, width);
2005       RGB565ToYRow(src_rgb565 + src_stride_rgb565, dst_y + dst_stride_y, width);
2006 #else
2007       RGB565ToARGBRow(src_rgb565, row, width);
2008       RGB565ToARGBRow(src_rgb565 + src_stride_rgb565, row + kRowSize, width);
2009       ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
2010       ARGBToYRow(row, dst_y, width);
2011       ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
2012 #endif
2013       src_rgb565 += src_stride_rgb565 * 2;
2014       dst_y += dst_stride_y * 2;
2015       dst_u += dst_stride_u;
2016       dst_v += dst_stride_v;
2017     }
2018     if (height & 1) {
2019 #if (defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
2020      defined(HAS_RGB565TOYROW_MMI))
2021       RGB565ToUVRow(src_rgb565, 0, dst_u, dst_v, width);
2022       RGB565ToYRow(src_rgb565, dst_y, width);
2023 #else
2024       RGB565ToARGBRow(src_rgb565, row, width);
2025       ARGBToUVRow(row, 0, dst_u, dst_v, width);
2026       ARGBToYRow(row, dst_y, width);
2027 #endif
2028     }
2029 #if !(defined(HAS_RGB565TOYROW_NEON) || defined(HAS_RGB565TOYROW_MSA) || \
2030       defined(HAS_RGB565TOYROW_MMI))
2031     free_aligned_buffer_64(row);
2032 #endif
2033   }
2034   return 0;
2035 }
2036 
2037 // Convert ARGB1555 to I420.
2038 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)2039 int ARGB1555ToI420(const uint8_t* src_argb1555,
2040                    int src_stride_argb1555,
2041                    uint8_t* dst_y,
2042                    int dst_stride_y,
2043                    uint8_t* dst_u,
2044                    int dst_stride_u,
2045                    uint8_t* dst_v,
2046                    int dst_stride_v,
2047                    int width,
2048                    int height) {
2049   int y;
2050 #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
2051      defined(HAS_ARGB1555TOYROW_MMI))
2052   void (*ARGB1555ToUVRow)(const uint8_t* src_argb1555, int src_stride_argb1555,
2053                           uint8_t* dst_u, uint8_t* dst_v, int width) =
2054       ARGB1555ToUVRow_C;
2055   void (*ARGB1555ToYRow)(const uint8_t* src_argb1555, uint8_t* dst_y,
2056                          int width) = ARGB1555ToYRow_C;
2057 #else
2058   void (*ARGB1555ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
2059                             int width) = ARGB1555ToARGBRow_C;
2060   void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
2061                       uint8_t* dst_u, uint8_t* dst_v, int width) =
2062       ARGBToUVRow_C;
2063   void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
2064       ARGBToYRow_C;
2065 #endif
2066   if (!src_argb1555 || !dst_y || !dst_u || !dst_v || width <= 0 ||
2067       height == 0) {
2068     return -1;
2069   }
2070   // Negative height means invert the image.
2071   if (height < 0) {
2072     height = -height;
2073     src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555;
2074     src_stride_argb1555 = -src_stride_argb1555;
2075   }
2076 
2077 // Neon version does direct ARGB1555 to YUV.
2078 #if defined(HAS_ARGB1555TOYROW_NEON)
2079   if (TestCpuFlag(kCpuHasNEON)) {
2080     ARGB1555ToUVRow = ARGB1555ToUVRow_Any_NEON;
2081     ARGB1555ToYRow = ARGB1555ToYRow_Any_NEON;
2082     if (IS_ALIGNED(width, 8)) {
2083       ARGB1555ToYRow = ARGB1555ToYRow_NEON;
2084       if (IS_ALIGNED(width, 16)) {
2085         ARGB1555ToUVRow = ARGB1555ToUVRow_NEON;
2086       }
2087     }
2088   }
2089 #elif defined(HAS_ARGB1555TOYROW_MSA)
2090   if (TestCpuFlag(kCpuHasMSA)) {
2091     ARGB1555ToUVRow = ARGB1555ToUVRow_Any_MSA;
2092     ARGB1555ToYRow = ARGB1555ToYRow_Any_MSA;
2093     if (IS_ALIGNED(width, 16)) {
2094       ARGB1555ToYRow = ARGB1555ToYRow_MSA;
2095       ARGB1555ToUVRow = ARGB1555ToUVRow_MSA;
2096     }
2097   }
2098 #elif defined(HAS_ARGB1555TOYROW_MMI)
2099   if (TestCpuFlag(kCpuHasMMI)) {
2100     ARGB1555ToUVRow = ARGB1555ToUVRow_Any_MMI;
2101     ARGB1555ToYRow = ARGB1555ToYRow_Any_MMI;
2102     if (IS_ALIGNED(width, 8)) {
2103       ARGB1555ToYRow = ARGB1555ToYRow_MMI;
2104       if (IS_ALIGNED(width, 16)) {
2105         ARGB1555ToUVRow = ARGB1555ToUVRow_MMI;
2106       }
2107     }
2108   }
2109 // Other platforms do intermediate conversion from ARGB1555 to ARGB.
2110 #else
2111 #if defined(HAS_ARGB1555TOARGBROW_SSE2)
2112   if (TestCpuFlag(kCpuHasSSE2)) {
2113     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2;
2114     if (IS_ALIGNED(width, 8)) {
2115       ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2;
2116     }
2117   }
2118 #endif
2119 #if defined(HAS_ARGB1555TOARGBROW_AVX2)
2120   if (TestCpuFlag(kCpuHasAVX2)) {
2121     ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_AVX2;
2122     if (IS_ALIGNED(width, 16)) {
2123       ARGB1555ToARGBRow = ARGB1555ToARGBRow_AVX2;
2124     }
2125   }
2126 #endif
2127 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
2128   if (TestCpuFlag(kCpuHasSSSE3)) {
2129     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
2130     ARGBToYRow = ARGBToYRow_Any_SSSE3;
2131     if (IS_ALIGNED(width, 16)) {
2132       ARGBToUVRow = ARGBToUVRow_SSSE3;
2133       ARGBToYRow = ARGBToYRow_SSSE3;
2134     }
2135   }
2136 #endif
2137 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
2138   if (TestCpuFlag(kCpuHasAVX2)) {
2139     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
2140     ARGBToYRow = ARGBToYRow_Any_AVX2;
2141     if (IS_ALIGNED(width, 32)) {
2142       ARGBToUVRow = ARGBToUVRow_AVX2;
2143       ARGBToYRow = ARGBToYRow_AVX2;
2144     }
2145   }
2146 #endif
2147 #endif
2148   {
2149 #if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
2150       defined(HAS_ARGB1555TOYROW_MMI))
2151     // Allocate 2 rows of ARGB.
2152     const int kRowSize = (width * 4 + 31) & ~31;
2153     align_buffer_64(row, kRowSize * 2);
2154 #endif
2155 
2156     for (y = 0; y < height - 1; y += 2) {
2157 #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
2158      defined(HAS_ARGB1555TOYROW_MMI))
2159       ARGB1555ToUVRow(src_argb1555, src_stride_argb1555, dst_u, dst_v, width);
2160       ARGB1555ToYRow(src_argb1555, dst_y, width);
2161       ARGB1555ToYRow(src_argb1555 + src_stride_argb1555, dst_y + dst_stride_y,
2162                      width);
2163 #else
2164       ARGB1555ToARGBRow(src_argb1555, row, width);
2165       ARGB1555ToARGBRow(src_argb1555 + src_stride_argb1555, row + kRowSize,
2166                         width);
2167       ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
2168       ARGBToYRow(row, dst_y, width);
2169       ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
2170 #endif
2171       src_argb1555 += src_stride_argb1555 * 2;
2172       dst_y += dst_stride_y * 2;
2173       dst_u += dst_stride_u;
2174       dst_v += dst_stride_v;
2175     }
2176     if (height & 1) {
2177 #if (defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
2178      defined(HAS_ARGB1555TOYROW_MMI))
2179       ARGB1555ToUVRow(src_argb1555, 0, dst_u, dst_v, width);
2180       ARGB1555ToYRow(src_argb1555, dst_y, width);
2181 #else
2182       ARGB1555ToARGBRow(src_argb1555, row, width);
2183       ARGBToUVRow(row, 0, dst_u, dst_v, width);
2184       ARGBToYRow(row, dst_y, width);
2185 #endif
2186     }
2187 #if !(defined(HAS_ARGB1555TOYROW_NEON) || defined(HAS_ARGB1555TOYROW_MSA) || \
2188       defined(HAS_ARGB1555TOYROW_MMI))
2189     free_aligned_buffer_64(row);
2190 #endif
2191   }
2192   return 0;
2193 }
2194 
2195 // Convert ARGB4444 to I420.
2196 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)2197 int ARGB4444ToI420(const uint8_t* src_argb4444,
2198                    int src_stride_argb4444,
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 #if (defined(HAS_ARGB4444TOYROW_NEON) || defined(HAS_ARGB4444TOYROW_MMI))
2209   void (*ARGB4444ToUVRow)(const uint8_t* src_argb4444, int src_stride_argb4444,
2210                           uint8_t* dst_u, uint8_t* dst_v, int width) =
2211       ARGB4444ToUVRow_C;
2212   void (*ARGB4444ToYRow)(const uint8_t* src_argb4444, uint8_t* dst_y,
2213                          int width) = ARGB4444ToYRow_C;
2214 #else
2215   void (*ARGB4444ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb,
2216                             int width) = ARGB4444ToARGBRow_C;
2217   void (*ARGBToUVRow)(const uint8_t* src_argb0, int src_stride_argb,
2218                       uint8_t* dst_u, uint8_t* dst_v, int width) =
2219       ARGBToUVRow_C;
2220   void (*ARGBToYRow)(const uint8_t* src_argb, uint8_t* dst_y, int width) =
2221       ARGBToYRow_C;
2222 #endif
2223   if (!src_argb4444 || !dst_y || !dst_u || !dst_v || width <= 0 ||
2224       height == 0) {
2225     return -1;
2226   }
2227   // Negative height means invert the image.
2228   if (height < 0) {
2229     height = -height;
2230     src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444;
2231     src_stride_argb4444 = -src_stride_argb4444;
2232   }
2233 
2234 // Neon version does direct ARGB4444 to YUV.
2235 #if defined(HAS_ARGB4444TOYROW_NEON)
2236   if (TestCpuFlag(kCpuHasNEON)) {
2237     ARGB4444ToUVRow = ARGB4444ToUVRow_Any_NEON;
2238     ARGB4444ToYRow = ARGB4444ToYRow_Any_NEON;
2239     if (IS_ALIGNED(width, 8)) {
2240       ARGB4444ToYRow = ARGB4444ToYRow_NEON;
2241       if (IS_ALIGNED(width, 16)) {
2242         ARGB4444ToUVRow = ARGB4444ToUVRow_NEON;
2243       }
2244     }
2245   }
2246 #elif defined(HAS_ARGB4444TOYROW_MMI)
2247   if (TestCpuFlag(kCpuHasMMI)) {
2248     ARGB4444ToUVRow = ARGB4444ToUVRow_Any_MMI;
2249     ARGB4444ToYRow = ARGB4444ToYRow_Any_MMI;
2250     if (IS_ALIGNED(width, 8)) {
2251       ARGB4444ToYRow = ARGB4444ToYRow_MMI;
2252       if (IS_ALIGNED(width, 16)) {
2253         ARGB4444ToUVRow = ARGB4444ToUVRow_MMI;
2254       }
2255     }
2256   }
2257 // Other platforms do intermediate conversion from ARGB4444 to ARGB.
2258 #else
2259 #if defined(HAS_ARGB4444TOARGBROW_SSE2)
2260   if (TestCpuFlag(kCpuHasSSE2)) {
2261     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2;
2262     if (IS_ALIGNED(width, 8)) {
2263       ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2;
2264     }
2265   }
2266 #endif
2267 #if defined(HAS_ARGB4444TOARGBROW_AVX2)
2268   if (TestCpuFlag(kCpuHasAVX2)) {
2269     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_AVX2;
2270     if (IS_ALIGNED(width, 16)) {
2271       ARGB4444ToARGBRow = ARGB4444ToARGBRow_AVX2;
2272     }
2273   }
2274 #endif
2275 #if defined(HAS_ARGB4444TOARGBROW_MSA)
2276   if (TestCpuFlag(kCpuHasMSA)) {
2277     ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_MSA;
2278     if (IS_ALIGNED(width, 16)) {
2279       ARGB4444ToARGBRow = ARGB4444ToARGBRow_MSA;
2280     }
2281   }
2282 #endif
2283 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
2284   if (TestCpuFlag(kCpuHasSSSE3)) {
2285     ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
2286     ARGBToYRow = ARGBToYRow_Any_SSSE3;
2287     if (IS_ALIGNED(width, 16)) {
2288       ARGBToUVRow = ARGBToUVRow_SSSE3;
2289       ARGBToYRow = ARGBToYRow_SSSE3;
2290     }
2291   }
2292 #endif
2293 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
2294   if (TestCpuFlag(kCpuHasAVX2)) {
2295     ARGBToUVRow = ARGBToUVRow_Any_AVX2;
2296     ARGBToYRow = ARGBToYRow_Any_AVX2;
2297     if (IS_ALIGNED(width, 32)) {
2298       ARGBToUVRow = ARGBToUVRow_AVX2;
2299       ARGBToYRow = ARGBToYRow_AVX2;
2300     }
2301   }
2302 #endif
2303 #if defined(HAS_ARGBTOYROW_MSA)
2304   if (TestCpuFlag(kCpuHasMSA)) {
2305     ARGBToUVRow = ARGBToUVRow_Any_MSA;
2306     ARGBToYRow = ARGBToYRow_Any_MSA;
2307     if (IS_ALIGNED(width, 16)) {
2308       ARGBToYRow = ARGBToYRow_MSA;
2309       if (IS_ALIGNED(width, 32)) {
2310         ARGBToUVRow = ARGBToUVRow_MSA;
2311       }
2312     }
2313   }
2314 #endif
2315 #if defined(HAS_ARGBTOYROW_MMI)
2316   if (TestCpuFlag(kCpuHasMMI)) {
2317     ARGBToUVRow = ARGBToUVRow_Any_MMI;
2318     ARGBToYRow = ARGBToYRow_Any_MMI;
2319     if (IS_ALIGNED(width, 8)) {
2320       ARGBToYRow = ARGBToYRow_MMI;
2321       if (IS_ALIGNED(width, 16)) {
2322         ARGBToUVRow = ARGBToUVRow_MMI;
2323       }
2324     }
2325   }
2326 #endif
2327 #endif
2328 
2329   {
2330 #if !(defined(HAS_ARGB4444TOYROW_NEON) || defined(HAS_ARGB4444TOYROW_MMI))
2331     // Allocate 2 rows of ARGB.
2332     const int kRowSize = (width * 4 + 31) & ~31;
2333     align_buffer_64(row, kRowSize * 2);
2334 #endif
2335 
2336     for (y = 0; y < height - 1; y += 2) {
2337 #if (defined(HAS_ARGB4444TOYROW_NEON) || defined(HAS_ARGB4444TOYROW_MMI))
2338       ARGB4444ToUVRow(src_argb4444, src_stride_argb4444, dst_u, dst_v, width);
2339       ARGB4444ToYRow(src_argb4444, dst_y, width);
2340       ARGB4444ToYRow(src_argb4444 + src_stride_argb4444, dst_y + dst_stride_y,
2341                      width);
2342 #else
2343       ARGB4444ToARGBRow(src_argb4444, row, width);
2344       ARGB4444ToARGBRow(src_argb4444 + src_stride_argb4444, row + kRowSize,
2345                         width);
2346       ARGBToUVRow(row, kRowSize, dst_u, dst_v, width);
2347       ARGBToYRow(row, dst_y, width);
2348       ARGBToYRow(row + kRowSize, dst_y + dst_stride_y, width);
2349 #endif
2350       src_argb4444 += src_stride_argb4444 * 2;
2351       dst_y += dst_stride_y * 2;
2352       dst_u += dst_stride_u;
2353       dst_v += dst_stride_v;
2354     }
2355     if (height & 1) {
2356 #if (defined(HAS_ARGB4444TOYROW_NEON) || defined(HAS_ARGB4444TOYROW_MMI))
2357       ARGB4444ToUVRow(src_argb4444, 0, dst_u, dst_v, width);
2358       ARGB4444ToYRow(src_argb4444, dst_y, width);
2359 #else
2360       ARGB4444ToARGBRow(src_argb4444, row, width);
2361       ARGBToUVRow(row, 0, dst_u, dst_v, width);
2362       ARGBToYRow(row, dst_y, width);
2363 #endif
2364     }
2365 #if !(defined(HAS_ARGB4444TOYROW_NEON) || defined(HAS_ARGB4444TOYROW_MMI))
2366     free_aligned_buffer_64(row);
2367 #endif
2368   }
2369   return 0;
2370 }
2371 
2372 // Convert RGB24 to J400.
2373 LIBYUV_API
RGB24ToJ400(const uint8_t * src_rgb24,int src_stride_rgb24,uint8_t * dst_yj,int dst_stride_yj,int width,int height)2374 int RGB24ToJ400(const uint8_t* src_rgb24,
2375                 int src_stride_rgb24,
2376                 uint8_t* dst_yj,
2377                 int dst_stride_yj,
2378                 int width,
2379                 int height) {
2380   int y;
2381 #if (defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
2382      defined(HAS_RGB24TOYJROW_MMI))
2383   void (*RGB24ToYJRow)(const uint8_t* src_rgb24, uint8_t* dst_yj, int width) =
2384       RGB24ToYJRow_C;
2385 #else
2386   void (*RGB24ToARGBRow)(const uint8_t* src_rgb, uint8_t* dst_argb, int width) =
2387       RGB24ToARGBRow_C;
2388   void (*ARGBToYJRow)(const uint8_t* src_argb, uint8_t* dst_yj, int width) =
2389       ARGBToYJRow_C;
2390 #endif
2391   if (!src_rgb24 || !dst_yj || width <= 0 || height == 0) {
2392     return -1;
2393   }
2394   // Negative height means invert the image.
2395   if (height < 0) {
2396     height = -height;
2397     src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24;
2398     src_stride_rgb24 = -src_stride_rgb24;
2399   }
2400 
2401 // Neon version does direct RGB24 to YUV.
2402 #if defined(HAS_RGB24TOYJROW_NEON)
2403   if (TestCpuFlag(kCpuHasNEON)) {
2404     RGB24ToYJRow = RGB24ToYJRow_Any_NEON;
2405     if (IS_ALIGNED(width, 8)) {
2406       RGB24ToYJRow = RGB24ToYJRow_NEON;
2407     }
2408   }
2409 #elif defined(HAS_RGB24TOYJROW_MSA)
2410   if (TestCpuFlag(kCpuHasMSA)) {
2411     RGB24ToYJRow = RGB24ToYJRow_Any_MSA;
2412     if (IS_ALIGNED(width, 16)) {
2413       RGB24ToYJRow = RGB24ToYJRow_MSA;
2414     }
2415   }
2416 #elif defined(HAS_RGB24TOYJROW_MMI)
2417   if (TestCpuFlag(kCpuHasMMI)) {
2418     RGB24ToYJRow = RGB24ToYJRow_Any_MMI;
2419     if (IS_ALIGNED(width, 8)) {
2420       RGB24ToYJRow = RGB24ToYJRow_MMI;
2421     }
2422   }
2423 // Other platforms do intermediate conversion from RGB24 to ARGB.
2424 #else
2425 #if defined(HAS_RGB24TOARGBROW_SSSE3)
2426   if (TestCpuFlag(kCpuHasSSSE3)) {
2427     RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3;
2428     if (IS_ALIGNED(width, 16)) {
2429       RGB24ToARGBRow = RGB24ToARGBRow_SSSE3;
2430     }
2431   }
2432 #endif
2433 #if defined(HAS_ARGBTOYJROW_SSSE3)
2434   if (TestCpuFlag(kCpuHasSSSE3)) {
2435     ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
2436     if (IS_ALIGNED(width, 16)) {
2437       ARGBToYJRow = ARGBToYJRow_SSSE3;
2438     }
2439   }
2440 #endif
2441 #if defined(HAS_ARGBTOYJROW_AVX2)
2442   if (TestCpuFlag(kCpuHasAVX2)) {
2443     ARGBToYJRow = ARGBToYJRow_Any_AVX2;
2444     if (IS_ALIGNED(width, 32)) {
2445       ARGBToYJRow = ARGBToYJRow_AVX2;
2446     }
2447   }
2448 #endif
2449 #endif
2450 
2451   {
2452 #if !(defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
2453       defined(HAS_RGB24TOYJROW_MMI))
2454     // Allocate 2 rows of ARGB.
2455     const int kRowSize = (width * 4 + 31) & ~31;
2456     align_buffer_64(row, kRowSize * 2);
2457 #endif
2458 
2459     for (y = 0; y < height - 1; y += 2) {
2460 #if (defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
2461      defined(HAS_RGB24TOYJROW_MMI))
2462       RGB24ToYJRow(src_rgb24, dst_yj, width);
2463       RGB24ToYJRow(src_rgb24 + src_stride_rgb24, dst_yj + dst_stride_yj, width);
2464 #else
2465       RGB24ToARGBRow(src_rgb24, row, width);
2466       RGB24ToARGBRow(src_rgb24 + src_stride_rgb24, row + kRowSize, width);
2467       ARGBToYJRow(row, dst_yj, width);
2468       ARGBToYJRow(row + kRowSize, dst_yj + dst_stride_yj, width);
2469 #endif
2470       src_rgb24 += src_stride_rgb24 * 2;
2471       dst_yj += dst_stride_yj * 2;
2472     }
2473     if (height & 1) {
2474 #if (defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
2475      defined(HAS_RGB24TOYJROW_MMI))
2476       RGB24ToYJRow(src_rgb24, dst_yj, width);
2477 #else
2478       RGB24ToARGBRow(src_rgb24, row, width);
2479       ARGBToYJRow(row, dst_yj, width);
2480 #endif
2481     }
2482 #if !(defined(HAS_RGB24TOYJROW_NEON) || defined(HAS_RGB24TOYJROW_MSA) || \
2483       defined(HAS_RGB24TOYJROW_MMI))
2484     free_aligned_buffer_64(row);
2485 #endif
2486   }
2487   return 0;
2488 }
2489 
SplitPixels(const uint8_t * src_u,int src_pixel_stride_uv,uint8_t * dst_u,int width)2490 static void SplitPixels(const uint8_t* src_u,
2491                         int src_pixel_stride_uv,
2492                         uint8_t* dst_u,
2493                         int width) {
2494   int i;
2495   for (i = 0; i < width; ++i) {
2496     *dst_u = *src_u;
2497     ++dst_u;
2498     src_u += src_pixel_stride_uv;
2499   }
2500 }
2501 
2502 // Convert Android420 to I420.
2503 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)2504 int Android420ToI420(const uint8_t* src_y,
2505                      int src_stride_y,
2506                      const uint8_t* src_u,
2507                      int src_stride_u,
2508                      const uint8_t* src_v,
2509                      int src_stride_v,
2510                      int src_pixel_stride_uv,
2511                      uint8_t* dst_y,
2512                      int dst_stride_y,
2513                      uint8_t* dst_u,
2514                      int dst_stride_u,
2515                      uint8_t* dst_v,
2516                      int dst_stride_v,
2517                      int width,
2518                      int height) {
2519   int y;
2520   const ptrdiff_t vu_off = src_v - src_u;
2521   int halfwidth = (width + 1) >> 1;
2522   int halfheight = (height + 1) >> 1;
2523   if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
2524     return -1;
2525   }
2526   // Negative height means invert the image.
2527   if (height < 0) {
2528     height = -height;
2529     halfheight = (height + 1) >> 1;
2530     src_y = src_y + (height - 1) * src_stride_y;
2531     src_u = src_u + (halfheight - 1) * src_stride_u;
2532     src_v = src_v + (halfheight - 1) * src_stride_v;
2533     src_stride_y = -src_stride_y;
2534     src_stride_u = -src_stride_u;
2535     src_stride_v = -src_stride_v;
2536   }
2537 
2538   if (dst_y) {
2539     CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
2540   }
2541 
2542   // Copy UV planes as is - I420
2543   if (src_pixel_stride_uv == 1) {
2544     CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
2545     CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
2546     return 0;
2547     // Split UV planes - NV21
2548   }
2549   if (src_pixel_stride_uv == 2 && vu_off == -1 &&
2550       src_stride_u == src_stride_v) {
2551     SplitUVPlane(src_v, src_stride_v, dst_v, dst_stride_v, dst_u, dst_stride_u,
2552                  halfwidth, halfheight);
2553     return 0;
2554     // Split UV planes - NV12
2555   }
2556   if (src_pixel_stride_uv == 2 && vu_off == 1 && src_stride_u == src_stride_v) {
2557     SplitUVPlane(src_u, src_stride_u, dst_u, dst_stride_u, dst_v, dst_stride_v,
2558                  halfwidth, halfheight);
2559     return 0;
2560   }
2561 
2562   for (y = 0; y < halfheight; ++y) {
2563     SplitPixels(src_u, src_pixel_stride_uv, dst_u, halfwidth);
2564     SplitPixels(src_v, src_pixel_stride_uv, dst_v, halfwidth);
2565     src_u += src_stride_u;
2566     src_v += src_stride_v;
2567     dst_u += dst_stride_u;
2568     dst_v += dst_stride_v;
2569   }
2570   return 0;
2571 }
2572 
2573 #ifdef __cplusplus
2574 }  // extern "C"
2575 }  // namespace libyuv
2576 #endif
2577