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