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