1 /*
2 * Copyright 2012 The LibYuv Project Authors. All rights reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "libyuv/convert_from.h"
12
13 #include "libyuv/basic_types.h"
14 #include "libyuv/convert.h" // For I420Copy
15 #include "libyuv/cpu_id.h"
16 #include "libyuv/planar_functions.h"
17 #include "libyuv/rotate.h"
18 #include "libyuv/row.h"
19 #include "libyuv/scale.h" // For ScalePlane()
20 #include "libyuv/video_common.h"
21
22 #ifdef __cplusplus
23 namespace libyuv {
24 extern "C" {
25 #endif
26
27 #define SUBSAMPLE(v, a, s) (v < 0) ? (-((-v + a) >> s)) : ((v + a) >> s)
Abs(int v)28 static __inline int Abs(int v) {
29 return v >= 0 ? v : -v;
30 }
31
32 // I420 To any I4xx YUV format with mirroring.
I420ToI4xx(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_u,int dst_stride_u,uint8_t * dst_v,int dst_stride_v,int src_y_width,int src_y_height,int dst_uv_width,int dst_uv_height)33 static int I420ToI4xx(const uint8_t* src_y,
34 int src_stride_y,
35 const uint8_t* src_u,
36 int src_stride_u,
37 const uint8_t* src_v,
38 int src_stride_v,
39 uint8_t* dst_y,
40 int dst_stride_y,
41 uint8_t* dst_u,
42 int dst_stride_u,
43 uint8_t* dst_v,
44 int dst_stride_v,
45 int src_y_width,
46 int src_y_height,
47 int dst_uv_width,
48 int dst_uv_height) {
49 const int dst_y_width = Abs(src_y_width);
50 const int dst_y_height = Abs(src_y_height);
51 const int src_uv_width = SUBSAMPLE(src_y_width, 1, 1);
52 const int src_uv_height = SUBSAMPLE(src_y_height, 1, 1);
53 if (src_y_width == 0 || src_y_height == 0 || dst_uv_width <= 0 ||
54 dst_uv_height <= 0) {
55 return -1;
56 }
57 if (dst_y) {
58 ScalePlane(src_y, src_stride_y, src_y_width, src_y_height, dst_y,
59 dst_stride_y, dst_y_width, dst_y_height, kFilterBilinear);
60 }
61 ScalePlane(src_u, src_stride_u, src_uv_width, src_uv_height, dst_u,
62 dst_stride_u, dst_uv_width, dst_uv_height, kFilterBilinear);
63 ScalePlane(src_v, src_stride_v, src_uv_width, src_uv_height, dst_v,
64 dst_stride_v, dst_uv_width, dst_uv_height, kFilterBilinear);
65 return 0;
66 }
67
68 // Convert 8 bit YUV to 10 bit.
69 LIBYUV_API
I420ToI010(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint16_t * dst_y,int dst_stride_y,uint16_t * dst_u,int dst_stride_u,uint16_t * dst_v,int dst_stride_v,int width,int height)70 int I420ToI010(const uint8_t* src_y,
71 int src_stride_y,
72 const uint8_t* src_u,
73 int src_stride_u,
74 const uint8_t* src_v,
75 int src_stride_v,
76 uint16_t* dst_y,
77 int dst_stride_y,
78 uint16_t* dst_u,
79 int dst_stride_u,
80 uint16_t* dst_v,
81 int dst_stride_v,
82 int width,
83 int height) {
84 int halfwidth = (width + 1) >> 1;
85 int halfheight = (height + 1) >> 1;
86 if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
87 return -1;
88 }
89 // Negative height means invert the image.
90 if (height < 0) {
91 height = -height;
92 halfheight = (height + 1) >> 1;
93 src_y = src_y + (height - 1) * src_stride_y;
94 src_u = src_u + (halfheight - 1) * src_stride_u;
95 src_v = src_v + (halfheight - 1) * src_stride_v;
96 src_stride_y = -src_stride_y;
97 src_stride_u = -src_stride_u;
98 src_stride_v = -src_stride_v;
99 }
100
101 // Convert Y plane.
102 Convert8To16Plane(src_y, src_stride_y, dst_y, dst_stride_y, 1024, width,
103 height);
104 // Convert UV planes.
105 Convert8To16Plane(src_u, src_stride_u, dst_u, dst_stride_u, 1024, halfwidth,
106 halfheight);
107 Convert8To16Plane(src_v, src_stride_v, dst_v, dst_stride_v, 1024, halfwidth,
108 halfheight);
109 return 0;
110 }
111
112 // 420 chroma is 1/2 width, 1/2 height
113 // 422 chroma is 1/2 width, 1x height
114 LIBYUV_API
I420ToI422(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_u,int dst_stride_u,uint8_t * dst_v,int dst_stride_v,int width,int height)115 int I420ToI422(const uint8_t* src_y,
116 int src_stride_y,
117 const uint8_t* src_u,
118 int src_stride_u,
119 const uint8_t* src_v,
120 int src_stride_v,
121 uint8_t* dst_y,
122 int dst_stride_y,
123 uint8_t* dst_u,
124 int dst_stride_u,
125 uint8_t* dst_v,
126 int dst_stride_v,
127 int width,
128 int height) {
129 const int dst_uv_width = (Abs(width) + 1) >> 1;
130 const int dst_uv_height = Abs(height);
131 return I420ToI4xx(src_y, src_stride_y, src_u, src_stride_u, src_v,
132 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
133 dst_v, dst_stride_v, width, height, dst_uv_width,
134 dst_uv_height);
135 }
136
137 // 420 chroma is 1/2 width, 1/2 height
138 // 444 chroma is 1x width, 1x height
139 LIBYUV_API
I420ToI444(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_u,int dst_stride_u,uint8_t * dst_v,int dst_stride_v,int width,int height)140 int I420ToI444(const uint8_t* src_y,
141 int src_stride_y,
142 const uint8_t* src_u,
143 int src_stride_u,
144 const uint8_t* src_v,
145 int src_stride_v,
146 uint8_t* dst_y,
147 int dst_stride_y,
148 uint8_t* dst_u,
149 int dst_stride_u,
150 uint8_t* dst_v,
151 int dst_stride_v,
152 int width,
153 int height) {
154 const int dst_uv_width = Abs(width);
155 const int dst_uv_height = Abs(height);
156 return I420ToI4xx(src_y, src_stride_y, src_u, src_stride_u, src_v,
157 src_stride_v, dst_y, dst_stride_y, dst_u, dst_stride_u,
158 dst_v, dst_stride_v, width, height, dst_uv_width,
159 dst_uv_height);
160 }
161
162 // Copy to I400. Source can be I420,422,444,400,NV12,NV21
163 LIBYUV_API
I400Copy(const uint8_t * src_y,int src_stride_y,uint8_t * dst_y,int dst_stride_y,int width,int height)164 int I400Copy(const uint8_t* src_y,
165 int src_stride_y,
166 uint8_t* dst_y,
167 int dst_stride_y,
168 int width,
169 int height) {
170 if (!src_y || !dst_y || width <= 0 || height == 0) {
171 return -1;
172 }
173 // Negative height means invert the image.
174 if (height < 0) {
175 height = -height;
176 src_y = src_y + (height - 1) * src_stride_y;
177 src_stride_y = -src_stride_y;
178 }
179 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
180 return 0;
181 }
182
183 LIBYUV_API
I422ToYUY2(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_yuy2,int dst_stride_yuy2,int width,int height)184 int I422ToYUY2(const uint8_t* src_y,
185 int src_stride_y,
186 const uint8_t* src_u,
187 int src_stride_u,
188 const uint8_t* src_v,
189 int src_stride_v,
190 uint8_t* dst_yuy2,
191 int dst_stride_yuy2,
192 int width,
193 int height) {
194 int y;
195 void (*I422ToYUY2Row)(const uint8_t* src_y, const uint8_t* src_u,
196 const uint8_t* src_v, uint8_t* dst_yuy2, int width) =
197 I422ToYUY2Row_C;
198 if (!src_y || !src_u || !src_v || !dst_yuy2 || width <= 0 || height == 0) {
199 return -1;
200 }
201 // Negative height means invert the image.
202 if (height < 0) {
203 height = -height;
204 dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
205 dst_stride_yuy2 = -dst_stride_yuy2;
206 }
207 // Coalesce rows.
208 if (src_stride_y == width && src_stride_u * 2 == width &&
209 src_stride_v * 2 == width && dst_stride_yuy2 == width * 2) {
210 width *= height;
211 height = 1;
212 src_stride_y = src_stride_u = src_stride_v = dst_stride_yuy2 = 0;
213 }
214 #if defined(HAS_I422TOYUY2ROW_SSE2)
215 if (TestCpuFlag(kCpuHasSSE2)) {
216 I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
217 if (IS_ALIGNED(width, 16)) {
218 I422ToYUY2Row = I422ToYUY2Row_SSE2;
219 }
220 }
221 #endif
222 #if defined(HAS_I422TOYUY2ROW_AVX2)
223 if (TestCpuFlag(kCpuHasAVX2)) {
224 I422ToYUY2Row = I422ToYUY2Row_Any_AVX2;
225 if (IS_ALIGNED(width, 32)) {
226 I422ToYUY2Row = I422ToYUY2Row_AVX2;
227 }
228 }
229 #endif
230 #if defined(HAS_I422TOYUY2ROW_NEON)
231 if (TestCpuFlag(kCpuHasNEON)) {
232 I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
233 if (IS_ALIGNED(width, 16)) {
234 I422ToYUY2Row = I422ToYUY2Row_NEON;
235 }
236 }
237 #endif
238
239 for (y = 0; y < height; ++y) {
240 I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
241 src_y += src_stride_y;
242 src_u += src_stride_u;
243 src_v += src_stride_v;
244 dst_yuy2 += dst_stride_yuy2;
245 }
246 return 0;
247 }
248
249 LIBYUV_API
I420ToYUY2(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_yuy2,int dst_stride_yuy2,int width,int height)250 int I420ToYUY2(const uint8_t* src_y,
251 int src_stride_y,
252 const uint8_t* src_u,
253 int src_stride_u,
254 const uint8_t* src_v,
255 int src_stride_v,
256 uint8_t* dst_yuy2,
257 int dst_stride_yuy2,
258 int width,
259 int height) {
260 int y;
261 void (*I422ToYUY2Row)(const uint8_t* src_y, const uint8_t* src_u,
262 const uint8_t* src_v, uint8_t* dst_yuy2, int width) =
263 I422ToYUY2Row_C;
264 if (!src_y || !src_u || !src_v || !dst_yuy2 || width <= 0 || height == 0) {
265 return -1;
266 }
267 // Negative height means invert the image.
268 if (height < 0) {
269 height = -height;
270 dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
271 dst_stride_yuy2 = -dst_stride_yuy2;
272 }
273 #if defined(HAS_I422TOYUY2ROW_SSE2)
274 if (TestCpuFlag(kCpuHasSSE2)) {
275 I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
276 if (IS_ALIGNED(width, 16)) {
277 I422ToYUY2Row = I422ToYUY2Row_SSE2;
278 }
279 }
280 #endif
281 #if defined(HAS_I422TOYUY2ROW_AVX2)
282 if (TestCpuFlag(kCpuHasAVX2)) {
283 I422ToYUY2Row = I422ToYUY2Row_Any_AVX2;
284 if (IS_ALIGNED(width, 32)) {
285 I422ToYUY2Row = I422ToYUY2Row_AVX2;
286 }
287 }
288 #endif
289 #if defined(HAS_I422TOYUY2ROW_NEON)
290 if (TestCpuFlag(kCpuHasNEON)) {
291 I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
292 if (IS_ALIGNED(width, 16)) {
293 I422ToYUY2Row = I422ToYUY2Row_NEON;
294 }
295 }
296 #endif
297 #if defined(HAS_I422TOYUY2ROW_MSA)
298 if (TestCpuFlag(kCpuHasMSA)) {
299 I422ToYUY2Row = I422ToYUY2Row_Any_MSA;
300 if (IS_ALIGNED(width, 32)) {
301 I422ToYUY2Row = I422ToYUY2Row_MSA;
302 }
303 }
304 #endif
305 #if defined(HAS_I422TOYUY2ROW_MMI)
306 if (TestCpuFlag(kCpuHasMMI)) {
307 I422ToYUY2Row = I422ToYUY2Row_Any_MMI;
308 if (IS_ALIGNED(width, 8)) {
309 I422ToYUY2Row = I422ToYUY2Row_MMI;
310 }
311 }
312 #endif
313
314 for (y = 0; y < height - 1; y += 2) {
315 I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
316 I422ToYUY2Row(src_y + src_stride_y, src_u, src_v,
317 dst_yuy2 + dst_stride_yuy2, width);
318 src_y += src_stride_y * 2;
319 src_u += src_stride_u;
320 src_v += src_stride_v;
321 dst_yuy2 += dst_stride_yuy2 * 2;
322 }
323 if (height & 1) {
324 I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
325 }
326 return 0;
327 }
328
329 LIBYUV_API
I422ToUYVY(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_uyvy,int dst_stride_uyvy,int width,int height)330 int I422ToUYVY(const uint8_t* src_y,
331 int src_stride_y,
332 const uint8_t* src_u,
333 int src_stride_u,
334 const uint8_t* src_v,
335 int src_stride_v,
336 uint8_t* dst_uyvy,
337 int dst_stride_uyvy,
338 int width,
339 int height) {
340 int y;
341 void (*I422ToUYVYRow)(const uint8_t* src_y, const uint8_t* src_u,
342 const uint8_t* src_v, uint8_t* dst_uyvy, int width) =
343 I422ToUYVYRow_C;
344 if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) {
345 return -1;
346 }
347 // Negative height means invert the image.
348 if (height < 0) {
349 height = -height;
350 dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
351 dst_stride_uyvy = -dst_stride_uyvy;
352 }
353 // Coalesce rows.
354 if (src_stride_y == width && src_stride_u * 2 == width &&
355 src_stride_v * 2 == width && dst_stride_uyvy == width * 2) {
356 width *= height;
357 height = 1;
358 src_stride_y = src_stride_u = src_stride_v = dst_stride_uyvy = 0;
359 }
360 #if defined(HAS_I422TOUYVYROW_SSE2)
361 if (TestCpuFlag(kCpuHasSSE2)) {
362 I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
363 if (IS_ALIGNED(width, 16)) {
364 I422ToUYVYRow = I422ToUYVYRow_SSE2;
365 }
366 }
367 #endif
368 #if defined(HAS_I422TOUYVYROW_AVX2)
369 if (TestCpuFlag(kCpuHasAVX2)) {
370 I422ToUYVYRow = I422ToUYVYRow_Any_AVX2;
371 if (IS_ALIGNED(width, 32)) {
372 I422ToUYVYRow = I422ToUYVYRow_AVX2;
373 }
374 }
375 #endif
376 #if defined(HAS_I422TOUYVYROW_NEON)
377 if (TestCpuFlag(kCpuHasNEON)) {
378 I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
379 if (IS_ALIGNED(width, 16)) {
380 I422ToUYVYRow = I422ToUYVYRow_NEON;
381 }
382 }
383 #endif
384 #if defined(HAS_I422TOUYVYROW_MSA)
385 if (TestCpuFlag(kCpuHasMSA)) {
386 I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
387 if (IS_ALIGNED(width, 32)) {
388 I422ToUYVYRow = I422ToUYVYRow_MSA;
389 }
390 }
391 #endif
392 #if defined(HAS_I422TOUYVYROW_MMI)
393 if (TestCpuFlag(kCpuHasMMI)) {
394 I422ToUYVYRow = I422ToUYVYRow_Any_MMI;
395 if (IS_ALIGNED(width, 8)) {
396 I422ToUYVYRow = I422ToUYVYRow_MMI;
397 }
398 }
399 #endif
400
401 for (y = 0; y < height; ++y) {
402 I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
403 src_y += src_stride_y;
404 src_u += src_stride_u;
405 src_v += src_stride_v;
406 dst_uyvy += dst_stride_uyvy;
407 }
408 return 0;
409 }
410
411 LIBYUV_API
I420ToUYVY(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_uyvy,int dst_stride_uyvy,int width,int height)412 int I420ToUYVY(const uint8_t* src_y,
413 int src_stride_y,
414 const uint8_t* src_u,
415 int src_stride_u,
416 const uint8_t* src_v,
417 int src_stride_v,
418 uint8_t* dst_uyvy,
419 int dst_stride_uyvy,
420 int width,
421 int height) {
422 int y;
423 void (*I422ToUYVYRow)(const uint8_t* src_y, const uint8_t* src_u,
424 const uint8_t* src_v, uint8_t* dst_uyvy, int width) =
425 I422ToUYVYRow_C;
426 if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) {
427 return -1;
428 }
429 // Negative height means invert the image.
430 if (height < 0) {
431 height = -height;
432 dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
433 dst_stride_uyvy = -dst_stride_uyvy;
434 }
435 #if defined(HAS_I422TOUYVYROW_SSE2)
436 if (TestCpuFlag(kCpuHasSSE2)) {
437 I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
438 if (IS_ALIGNED(width, 16)) {
439 I422ToUYVYRow = I422ToUYVYRow_SSE2;
440 }
441 }
442 #endif
443 #if defined(HAS_I422TOUYVYROW_AVX2)
444 if (TestCpuFlag(kCpuHasAVX2)) {
445 I422ToUYVYRow = I422ToUYVYRow_Any_AVX2;
446 if (IS_ALIGNED(width, 32)) {
447 I422ToUYVYRow = I422ToUYVYRow_AVX2;
448 }
449 }
450 #endif
451 #if defined(HAS_I422TOUYVYROW_NEON)
452 if (TestCpuFlag(kCpuHasNEON)) {
453 I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
454 if (IS_ALIGNED(width, 16)) {
455 I422ToUYVYRow = I422ToUYVYRow_NEON;
456 }
457 }
458 #endif
459 #if defined(HAS_I422TOUYVYROW_MSA)
460 if (TestCpuFlag(kCpuHasMSA)) {
461 I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
462 if (IS_ALIGNED(width, 32)) {
463 I422ToUYVYRow = I422ToUYVYRow_MSA;
464 }
465 }
466 #endif
467 #if defined(HAS_I422TOUYVYROW_MMI)
468 if (TestCpuFlag(kCpuHasMMI)) {
469 I422ToUYVYRow = I422ToUYVYRow_Any_MMI;
470 if (IS_ALIGNED(width, 8)) {
471 I422ToUYVYRow = I422ToUYVYRow_MMI;
472 }
473 }
474 #endif
475
476 for (y = 0; y < height - 1; y += 2) {
477 I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
478 I422ToUYVYRow(src_y + src_stride_y, src_u, src_v,
479 dst_uyvy + dst_stride_uyvy, width);
480 src_y += src_stride_y * 2;
481 src_u += src_stride_u;
482 src_v += src_stride_v;
483 dst_uyvy += dst_stride_uyvy * 2;
484 }
485 if (height & 1) {
486 I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
487 }
488 return 0;
489 }
490
491 // TODO(fbarchard): test negative height for invert.
492 LIBYUV_API
I420ToNV12(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_uv,int dst_stride_uv,int width,int height)493 int I420ToNV12(const uint8_t* src_y,
494 int src_stride_y,
495 const uint8_t* src_u,
496 int src_stride_u,
497 const uint8_t* src_v,
498 int src_stride_v,
499 uint8_t* dst_y,
500 int dst_stride_y,
501 uint8_t* dst_uv,
502 int dst_stride_uv,
503 int width,
504 int height) {
505 if (!src_y || !src_u || !src_v || !dst_y || !dst_uv || width <= 0 ||
506 height == 0) {
507 return -1;
508 }
509 int halfwidth = (width + 1) / 2;
510 int halfheight = height > 0 ? (height + 1) / 2 : (height - 1) / 2;
511 if (dst_y) {
512 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
513 }
514 MergeUVPlane(src_u, src_stride_u, src_v, src_stride_v, dst_uv, dst_stride_uv,
515 halfwidth, halfheight);
516 return 0;
517 }
518
519 LIBYUV_API
I420ToNV21(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint8_t * dst_y,int dst_stride_y,uint8_t * dst_vu,int dst_stride_vu,int width,int height)520 int I420ToNV21(const uint8_t* src_y,
521 int src_stride_y,
522 const uint8_t* src_u,
523 int src_stride_u,
524 const uint8_t* src_v,
525 int src_stride_v,
526 uint8_t* dst_y,
527 int dst_stride_y,
528 uint8_t* dst_vu,
529 int dst_stride_vu,
530 int width,
531 int height) {
532 return I420ToNV12(src_y, src_stride_y, src_v, src_stride_v, src_u,
533 src_stride_u, dst_y, dst_stride_y, dst_vu, dst_stride_vu,
534 width, height);
535 }
536
537 // Convert I422 to RGBA with matrix
I420ToRGBAMatrix(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_rgba,int dst_stride_rgba,const struct YuvConstants * yuvconstants,int width,int height)538 static int I420ToRGBAMatrix(const uint8_t* src_y,
539 int src_stride_y,
540 const uint8_t* src_u,
541 int src_stride_u,
542 const uint8_t* src_v,
543 int src_stride_v,
544 uint8_t* dst_rgba,
545 int dst_stride_rgba,
546 const struct YuvConstants* yuvconstants,
547 int width,
548 int height) {
549 int y;
550 void (*I422ToRGBARow)(const uint8_t* y_buf, const uint8_t* u_buf,
551 const uint8_t* v_buf, uint8_t* rgb_buf,
552 const struct YuvConstants* yuvconstants, int width) =
553 I422ToRGBARow_C;
554 if (!src_y || !src_u || !src_v || !dst_rgba || width <= 0 || height == 0) {
555 return -1;
556 }
557 // Negative height means invert the image.
558 if (height < 0) {
559 height = -height;
560 dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
561 dst_stride_rgba = -dst_stride_rgba;
562 }
563 #if defined(HAS_I422TORGBAROW_SSSE3)
564 if (TestCpuFlag(kCpuHasSSSE3)) {
565 I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
566 if (IS_ALIGNED(width, 8)) {
567 I422ToRGBARow = I422ToRGBARow_SSSE3;
568 }
569 }
570 #endif
571 #if defined(HAS_I422TORGBAROW_AVX2)
572 if (TestCpuFlag(kCpuHasAVX2)) {
573 I422ToRGBARow = I422ToRGBARow_Any_AVX2;
574 if (IS_ALIGNED(width, 16)) {
575 I422ToRGBARow = I422ToRGBARow_AVX2;
576 }
577 }
578 #endif
579 #if defined(HAS_I422TORGBAROW_NEON)
580 if (TestCpuFlag(kCpuHasNEON)) {
581 I422ToRGBARow = I422ToRGBARow_Any_NEON;
582 if (IS_ALIGNED(width, 8)) {
583 I422ToRGBARow = I422ToRGBARow_NEON;
584 }
585 }
586 #endif
587 #if defined(HAS_I422TORGBAROW_MSA)
588 if (TestCpuFlag(kCpuHasMSA)) {
589 I422ToRGBARow = I422ToRGBARow_Any_MSA;
590 if (IS_ALIGNED(width, 8)) {
591 I422ToRGBARow = I422ToRGBARow_MSA;
592 }
593 }
594 #endif
595
596 for (y = 0; y < height; ++y) {
597 I422ToRGBARow(src_y, src_u, src_v, dst_rgba, yuvconstants, width);
598 dst_rgba += dst_stride_rgba;
599 src_y += src_stride_y;
600 if (y & 1) {
601 src_u += src_stride_u;
602 src_v += src_stride_v;
603 }
604 }
605 return 0;
606 }
607
608 // Convert I420 to RGBA.
609 LIBYUV_API
I420ToRGBA(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_rgba,int dst_stride_rgba,int width,int height)610 int I420ToRGBA(const uint8_t* src_y,
611 int src_stride_y,
612 const uint8_t* src_u,
613 int src_stride_u,
614 const uint8_t* src_v,
615 int src_stride_v,
616 uint8_t* dst_rgba,
617 int dst_stride_rgba,
618 int width,
619 int height) {
620 return I420ToRGBAMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
621 src_stride_v, dst_rgba, dst_stride_rgba,
622 &kYuvI601Constants, width, height);
623 }
624
625 // Convert I420 to BGRA.
626 LIBYUV_API
I420ToBGRA(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_bgra,int dst_stride_bgra,int width,int height)627 int I420ToBGRA(const uint8_t* src_y,
628 int src_stride_y,
629 const uint8_t* src_u,
630 int src_stride_u,
631 const uint8_t* src_v,
632 int src_stride_v,
633 uint8_t* dst_bgra,
634 int dst_stride_bgra,
635 int width,
636 int height) {
637 return I420ToRGBAMatrix(src_y, src_stride_y, src_v,
638 src_stride_v, // Swap U and V
639 src_u, src_stride_u, dst_bgra, dst_stride_bgra,
640 &kYvuI601Constants, // Use Yvu matrix
641 width, height);
642 }
643
644 // Convert I420 to RGB24 with matrix
I420ToRGB24Matrix(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_rgb24,int dst_stride_rgb24,const struct YuvConstants * yuvconstants,int width,int height)645 static int I420ToRGB24Matrix(const uint8_t* src_y,
646 int src_stride_y,
647 const uint8_t* src_u,
648 int src_stride_u,
649 const uint8_t* src_v,
650 int src_stride_v,
651 uint8_t* dst_rgb24,
652 int dst_stride_rgb24,
653 const struct YuvConstants* yuvconstants,
654 int width,
655 int height) {
656 int y;
657 void (*I422ToRGB24Row)(const uint8_t* y_buf, const uint8_t* u_buf,
658 const uint8_t* v_buf, uint8_t* rgb_buf,
659 const struct YuvConstants* yuvconstants, int width) =
660 I422ToRGB24Row_C;
661 if (!src_y || !src_u || !src_v || !dst_rgb24 || width <= 0 || height == 0) {
662 return -1;
663 }
664 // Negative height means invert the image.
665 if (height < 0) {
666 height = -height;
667 dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
668 dst_stride_rgb24 = -dst_stride_rgb24;
669 }
670 #if defined(HAS_I422TORGB24ROW_SSSE3)
671 if (TestCpuFlag(kCpuHasSSSE3)) {
672 I422ToRGB24Row = I422ToRGB24Row_Any_SSSE3;
673 if (IS_ALIGNED(width, 16)) {
674 I422ToRGB24Row = I422ToRGB24Row_SSSE3;
675 }
676 }
677 #endif
678 #if defined(HAS_I422TORGB24ROW_AVX2)
679 if (TestCpuFlag(kCpuHasAVX2)) {
680 I422ToRGB24Row = I422ToRGB24Row_Any_AVX2;
681 if (IS_ALIGNED(width, 32)) {
682 I422ToRGB24Row = I422ToRGB24Row_AVX2;
683 }
684 }
685 #endif
686 #if defined(HAS_I422TORGB24ROW_NEON)
687 if (TestCpuFlag(kCpuHasNEON)) {
688 I422ToRGB24Row = I422ToRGB24Row_Any_NEON;
689 if (IS_ALIGNED(width, 8)) {
690 I422ToRGB24Row = I422ToRGB24Row_NEON;
691 }
692 }
693 #endif
694 #if defined(HAS_I422TORGB24ROW_MSA)
695 if (TestCpuFlag(kCpuHasMSA)) {
696 I422ToRGB24Row = I422ToRGB24Row_Any_MSA;
697 if (IS_ALIGNED(width, 16)) {
698 I422ToRGB24Row = I422ToRGB24Row_MSA;
699 }
700 }
701 #endif
702
703 for (y = 0; y < height; ++y) {
704 I422ToRGB24Row(src_y, src_u, src_v, dst_rgb24, yuvconstants, width);
705 dst_rgb24 += dst_stride_rgb24;
706 src_y += src_stride_y;
707 if (y & 1) {
708 src_u += src_stride_u;
709 src_v += src_stride_v;
710 }
711 }
712 return 0;
713 }
714
715 // Convert I420 to RGB24.
716 LIBYUV_API
I420ToRGB24(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_rgb24,int dst_stride_rgb24,int width,int height)717 int I420ToRGB24(const uint8_t* src_y,
718 int src_stride_y,
719 const uint8_t* src_u,
720 int src_stride_u,
721 const uint8_t* src_v,
722 int src_stride_v,
723 uint8_t* dst_rgb24,
724 int dst_stride_rgb24,
725 int width,
726 int height) {
727 return I420ToRGB24Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
728 src_stride_v, dst_rgb24, dst_stride_rgb24,
729 &kYuvI601Constants, width, height);
730 }
731
732 // Convert I420 to RAW.
733 LIBYUV_API
I420ToRAW(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_raw,int dst_stride_raw,int width,int height)734 int I420ToRAW(const uint8_t* src_y,
735 int src_stride_y,
736 const uint8_t* src_u,
737 int src_stride_u,
738 const uint8_t* src_v,
739 int src_stride_v,
740 uint8_t* dst_raw,
741 int dst_stride_raw,
742 int width,
743 int height) {
744 return I420ToRGB24Matrix(src_y, src_stride_y, src_v,
745 src_stride_v, // Swap U and V
746 src_u, src_stride_u, dst_raw, dst_stride_raw,
747 &kYvuI601Constants, // Use Yvu matrix
748 width, height);
749 }
750
751 // Convert H420 to RGB24.
752 LIBYUV_API
H420ToRGB24(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_rgb24,int dst_stride_rgb24,int width,int height)753 int H420ToRGB24(const uint8_t* src_y,
754 int src_stride_y,
755 const uint8_t* src_u,
756 int src_stride_u,
757 const uint8_t* src_v,
758 int src_stride_v,
759 uint8_t* dst_rgb24,
760 int dst_stride_rgb24,
761 int width,
762 int height) {
763 return I420ToRGB24Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
764 src_stride_v, dst_rgb24, dst_stride_rgb24,
765 &kYuvH709Constants, width, height);
766 }
767
768 // Convert H420 to RAW.
769 LIBYUV_API
H420ToRAW(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_raw,int dst_stride_raw,int width,int height)770 int H420ToRAW(const uint8_t* src_y,
771 int src_stride_y,
772 const uint8_t* src_u,
773 int src_stride_u,
774 const uint8_t* src_v,
775 int src_stride_v,
776 uint8_t* dst_raw,
777 int dst_stride_raw,
778 int width,
779 int height) {
780 return I420ToRGB24Matrix(src_y, src_stride_y, src_v,
781 src_stride_v, // Swap U and V
782 src_u, src_stride_u, dst_raw, dst_stride_raw,
783 &kYvuH709Constants, // Use Yvu matrix
784 width, height);
785 }
786
787 // Convert I420 to ARGB1555.
788 LIBYUV_API
I420ToARGB1555(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_argb1555,int dst_stride_argb1555,int width,int height)789 int I420ToARGB1555(const uint8_t* src_y,
790 int src_stride_y,
791 const uint8_t* src_u,
792 int src_stride_u,
793 const uint8_t* src_v,
794 int src_stride_v,
795 uint8_t* dst_argb1555,
796 int dst_stride_argb1555,
797 int width,
798 int height) {
799 int y;
800 void (*I422ToARGB1555Row)(const uint8_t* y_buf, const uint8_t* u_buf,
801 const uint8_t* v_buf, uint8_t* rgb_buf,
802 const struct YuvConstants* yuvconstants,
803 int width) = I422ToARGB1555Row_C;
804 if (!src_y || !src_u || !src_v || !dst_argb1555 || width <= 0 ||
805 height == 0) {
806 return -1;
807 }
808 // Negative height means invert the image.
809 if (height < 0) {
810 height = -height;
811 dst_argb1555 = dst_argb1555 + (height - 1) * dst_stride_argb1555;
812 dst_stride_argb1555 = -dst_stride_argb1555;
813 }
814 #if defined(HAS_I422TOARGB1555ROW_SSSE3)
815 if (TestCpuFlag(kCpuHasSSSE3)) {
816 I422ToARGB1555Row = I422ToARGB1555Row_Any_SSSE3;
817 if (IS_ALIGNED(width, 8)) {
818 I422ToARGB1555Row = I422ToARGB1555Row_SSSE3;
819 }
820 }
821 #endif
822 #if defined(HAS_I422TOARGB1555ROW_AVX2)
823 if (TestCpuFlag(kCpuHasAVX2)) {
824 I422ToARGB1555Row = I422ToARGB1555Row_Any_AVX2;
825 if (IS_ALIGNED(width, 16)) {
826 I422ToARGB1555Row = I422ToARGB1555Row_AVX2;
827 }
828 }
829 #endif
830 #if defined(HAS_I422TOARGB1555ROW_NEON)
831 if (TestCpuFlag(kCpuHasNEON)) {
832 I422ToARGB1555Row = I422ToARGB1555Row_Any_NEON;
833 if (IS_ALIGNED(width, 8)) {
834 I422ToARGB1555Row = I422ToARGB1555Row_NEON;
835 }
836 }
837 #endif
838 #if defined(HAS_I422TOARGB1555ROW_MSA)
839 if (TestCpuFlag(kCpuHasMSA)) {
840 I422ToARGB1555Row = I422ToARGB1555Row_Any_MSA;
841 if (IS_ALIGNED(width, 8)) {
842 I422ToARGB1555Row = I422ToARGB1555Row_MSA;
843 }
844 }
845 #endif
846
847 for (y = 0; y < height; ++y) {
848 I422ToARGB1555Row(src_y, src_u, src_v, dst_argb1555, &kYuvI601Constants,
849 width);
850 dst_argb1555 += dst_stride_argb1555;
851 src_y += src_stride_y;
852 if (y & 1) {
853 src_u += src_stride_u;
854 src_v += src_stride_v;
855 }
856 }
857 return 0;
858 }
859
860 // Convert I420 to ARGB4444.
861 LIBYUV_API
I420ToARGB4444(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_argb4444,int dst_stride_argb4444,int width,int height)862 int I420ToARGB4444(const uint8_t* src_y,
863 int src_stride_y,
864 const uint8_t* src_u,
865 int src_stride_u,
866 const uint8_t* src_v,
867 int src_stride_v,
868 uint8_t* dst_argb4444,
869 int dst_stride_argb4444,
870 int width,
871 int height) {
872 int y;
873 void (*I422ToARGB4444Row)(const uint8_t* y_buf, const uint8_t* u_buf,
874 const uint8_t* v_buf, uint8_t* rgb_buf,
875 const struct YuvConstants* yuvconstants,
876 int width) = I422ToARGB4444Row_C;
877 if (!src_y || !src_u || !src_v || !dst_argb4444 || width <= 0 ||
878 height == 0) {
879 return -1;
880 }
881 // Negative height means invert the image.
882 if (height < 0) {
883 height = -height;
884 dst_argb4444 = dst_argb4444 + (height - 1) * dst_stride_argb4444;
885 dst_stride_argb4444 = -dst_stride_argb4444;
886 }
887 #if defined(HAS_I422TOARGB4444ROW_SSSE3)
888 if (TestCpuFlag(kCpuHasSSSE3)) {
889 I422ToARGB4444Row = I422ToARGB4444Row_Any_SSSE3;
890 if (IS_ALIGNED(width, 8)) {
891 I422ToARGB4444Row = I422ToARGB4444Row_SSSE3;
892 }
893 }
894 #endif
895 #if defined(HAS_I422TOARGB4444ROW_AVX2)
896 if (TestCpuFlag(kCpuHasAVX2)) {
897 I422ToARGB4444Row = I422ToARGB4444Row_Any_AVX2;
898 if (IS_ALIGNED(width, 16)) {
899 I422ToARGB4444Row = I422ToARGB4444Row_AVX2;
900 }
901 }
902 #endif
903 #if defined(HAS_I422TOARGB4444ROW_NEON)
904 if (TestCpuFlag(kCpuHasNEON)) {
905 I422ToARGB4444Row = I422ToARGB4444Row_Any_NEON;
906 if (IS_ALIGNED(width, 8)) {
907 I422ToARGB4444Row = I422ToARGB4444Row_NEON;
908 }
909 }
910 #endif
911 #if defined(HAS_I422TOARGB4444ROW_MSA)
912 if (TestCpuFlag(kCpuHasMSA)) {
913 I422ToARGB4444Row = I422ToARGB4444Row_Any_MSA;
914 if (IS_ALIGNED(width, 8)) {
915 I422ToARGB4444Row = I422ToARGB4444Row_MSA;
916 }
917 }
918 #endif
919
920 for (y = 0; y < height; ++y) {
921 I422ToARGB4444Row(src_y, src_u, src_v, dst_argb4444, &kYuvI601Constants,
922 width);
923 dst_argb4444 += dst_stride_argb4444;
924 src_y += src_stride_y;
925 if (y & 1) {
926 src_u += src_stride_u;
927 src_v += src_stride_v;
928 }
929 }
930 return 0;
931 }
932
933 // Convert I420 to RGB565 with specified color matrix.
934 LIBYUV_API
I420ToRGB565Matrix(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_rgb565,int dst_stride_rgb565,const struct YuvConstants * yuvconstants,int width,int height)935 int I420ToRGB565Matrix(const uint8_t* src_y,
936 int src_stride_y,
937 const uint8_t* src_u,
938 int src_stride_u,
939 const uint8_t* src_v,
940 int src_stride_v,
941 uint8_t* dst_rgb565,
942 int dst_stride_rgb565,
943 const struct YuvConstants* yuvconstants,
944 int width,
945 int height) {
946 int y;
947 void (*I422ToRGB565Row)(const uint8_t* y_buf, const uint8_t* u_buf,
948 const uint8_t* v_buf, uint8_t* rgb_buf,
949 const struct YuvConstants* yuvconstants, int width) =
950 I422ToRGB565Row_C;
951 if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
952 return -1;
953 }
954 // Negative height means invert the image.
955 if (height < 0) {
956 height = -height;
957 dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
958 dst_stride_rgb565 = -dst_stride_rgb565;
959 }
960 #if defined(HAS_I422TORGB565ROW_SSSE3)
961 if (TestCpuFlag(kCpuHasSSSE3)) {
962 I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
963 if (IS_ALIGNED(width, 8)) {
964 I422ToRGB565Row = I422ToRGB565Row_SSSE3;
965 }
966 }
967 #endif
968 #if defined(HAS_I422TORGB565ROW_AVX2)
969 if (TestCpuFlag(kCpuHasAVX2)) {
970 I422ToRGB565Row = I422ToRGB565Row_Any_AVX2;
971 if (IS_ALIGNED(width, 16)) {
972 I422ToRGB565Row = I422ToRGB565Row_AVX2;
973 }
974 }
975 #endif
976 #if defined(HAS_I422TORGB565ROW_NEON)
977 if (TestCpuFlag(kCpuHasNEON)) {
978 I422ToRGB565Row = I422ToRGB565Row_Any_NEON;
979 if (IS_ALIGNED(width, 8)) {
980 I422ToRGB565Row = I422ToRGB565Row_NEON;
981 }
982 }
983 #endif
984 #if defined(HAS_I422TORGB565ROW_MSA)
985 if (TestCpuFlag(kCpuHasMSA)) {
986 I422ToRGB565Row = I422ToRGB565Row_Any_MSA;
987 if (IS_ALIGNED(width, 8)) {
988 I422ToRGB565Row = I422ToRGB565Row_MSA;
989 }
990 }
991 #endif
992
993 for (y = 0; y < height; ++y) {
994 I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, yuvconstants, width);
995 dst_rgb565 += dst_stride_rgb565;
996 src_y += src_stride_y;
997 if (y & 1) {
998 src_u += src_stride_u;
999 src_v += src_stride_v;
1000 }
1001 }
1002 return 0;
1003 }
1004
1005 // Convert I420 to RGB565.
1006 LIBYUV_API
I420ToRGB565(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_rgb565,int dst_stride_rgb565,int width,int height)1007 int I420ToRGB565(const uint8_t* src_y,
1008 int src_stride_y,
1009 const uint8_t* src_u,
1010 int src_stride_u,
1011 const uint8_t* src_v,
1012 int src_stride_v,
1013 uint8_t* dst_rgb565,
1014 int dst_stride_rgb565,
1015 int width,
1016 int height) {
1017 return I420ToRGB565Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1018 src_stride_v, dst_rgb565, dst_stride_rgb565,
1019 &kYuvI601Constants, width, height);
1020 }
1021
1022 // Convert J420 to RGB565.
1023 LIBYUV_API
J420ToRGB565(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_rgb565,int dst_stride_rgb565,int width,int height)1024 int J420ToRGB565(const uint8_t* src_y,
1025 int src_stride_y,
1026 const uint8_t* src_u,
1027 int src_stride_u,
1028 const uint8_t* src_v,
1029 int src_stride_v,
1030 uint8_t* dst_rgb565,
1031 int dst_stride_rgb565,
1032 int width,
1033 int height) {
1034 return I420ToRGB565Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1035 src_stride_v, dst_rgb565, dst_stride_rgb565,
1036 &kYuvJPEGConstants, width, height);
1037 }
1038
1039 // Convert H420 to RGB565.
1040 LIBYUV_API
H420ToRGB565(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_rgb565,int dst_stride_rgb565,int width,int height)1041 int H420ToRGB565(const uint8_t* src_y,
1042 int src_stride_y,
1043 const uint8_t* src_u,
1044 int src_stride_u,
1045 const uint8_t* src_v,
1046 int src_stride_v,
1047 uint8_t* dst_rgb565,
1048 int dst_stride_rgb565,
1049 int width,
1050 int height) {
1051 return I420ToRGB565Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1052 src_stride_v, dst_rgb565, dst_stride_rgb565,
1053 &kYuvH709Constants, width, height);
1054 }
1055
1056 // Convert I422 to RGB565.
1057 LIBYUV_API
I422ToRGB565(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_rgb565,int dst_stride_rgb565,int width,int height)1058 int I422ToRGB565(const uint8_t* src_y,
1059 int src_stride_y,
1060 const uint8_t* src_u,
1061 int src_stride_u,
1062 const uint8_t* src_v,
1063 int src_stride_v,
1064 uint8_t* dst_rgb565,
1065 int dst_stride_rgb565,
1066 int width,
1067 int height) {
1068 int y;
1069 void (*I422ToRGB565Row)(const uint8_t* y_buf, const uint8_t* u_buf,
1070 const uint8_t* v_buf, uint8_t* rgb_buf,
1071 const struct YuvConstants* yuvconstants, int width) =
1072 I422ToRGB565Row_C;
1073 if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
1074 return -1;
1075 }
1076 // Negative height means invert the image.
1077 if (height < 0) {
1078 height = -height;
1079 dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
1080 dst_stride_rgb565 = -dst_stride_rgb565;
1081 }
1082 #if defined(HAS_I422TORGB565ROW_SSSE3)
1083 if (TestCpuFlag(kCpuHasSSSE3)) {
1084 I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
1085 if (IS_ALIGNED(width, 8)) {
1086 I422ToRGB565Row = I422ToRGB565Row_SSSE3;
1087 }
1088 }
1089 #endif
1090 #if defined(HAS_I422TORGB565ROW_AVX2)
1091 if (TestCpuFlag(kCpuHasAVX2)) {
1092 I422ToRGB565Row = I422ToRGB565Row_Any_AVX2;
1093 if (IS_ALIGNED(width, 16)) {
1094 I422ToRGB565Row = I422ToRGB565Row_AVX2;
1095 }
1096 }
1097 #endif
1098 #if defined(HAS_I422TORGB565ROW_NEON)
1099 if (TestCpuFlag(kCpuHasNEON)) {
1100 I422ToRGB565Row = I422ToRGB565Row_Any_NEON;
1101 if (IS_ALIGNED(width, 8)) {
1102 I422ToRGB565Row = I422ToRGB565Row_NEON;
1103 }
1104 }
1105 #endif
1106 #if defined(HAS_I422TORGB565ROW_MSA)
1107 if (TestCpuFlag(kCpuHasMSA)) {
1108 I422ToRGB565Row = I422ToRGB565Row_Any_MSA;
1109 if (IS_ALIGNED(width, 8)) {
1110 I422ToRGB565Row = I422ToRGB565Row_MSA;
1111 }
1112 }
1113 #endif
1114
1115 for (y = 0; y < height; ++y) {
1116 I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, &kYuvI601Constants, width);
1117 dst_rgb565 += dst_stride_rgb565;
1118 src_y += src_stride_y;
1119 src_u += src_stride_u;
1120 src_v += src_stride_v;
1121 }
1122 return 0;
1123 }
1124
1125 // Ordered 8x8 dither for 888 to 565. Values from 0 to 7.
1126 static const uint8_t kDither565_4x4[16] = {
1127 0, 4, 1, 5, 6, 2, 7, 3, 1, 5, 0, 4, 7, 3, 6, 2,
1128 };
1129
1130 // Convert I420 to RGB565 with dithering.
1131 LIBYUV_API
I420ToRGB565Dither(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_rgb565,int dst_stride_rgb565,const uint8_t * dither4x4,int width,int height)1132 int I420ToRGB565Dither(const uint8_t* src_y,
1133 int src_stride_y,
1134 const uint8_t* src_u,
1135 int src_stride_u,
1136 const uint8_t* src_v,
1137 int src_stride_v,
1138 uint8_t* dst_rgb565,
1139 int dst_stride_rgb565,
1140 const uint8_t* dither4x4,
1141 int width,
1142 int height) {
1143 int y;
1144 void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
1145 const uint8_t* v_buf, uint8_t* rgb_buf,
1146 const struct YuvConstants* yuvconstants, int width) =
1147 I422ToARGBRow_C;
1148 void (*ARGBToRGB565DitherRow)(const uint8_t* src_argb, uint8_t* dst_rgb,
1149 const uint32_t dither4, int width) =
1150 ARGBToRGB565DitherRow_C;
1151 if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
1152 return -1;
1153 }
1154 // Negative height means invert the image.
1155 if (height < 0) {
1156 height = -height;
1157 dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
1158 dst_stride_rgb565 = -dst_stride_rgb565;
1159 }
1160 if (!dither4x4) {
1161 dither4x4 = kDither565_4x4;
1162 }
1163 #if defined(HAS_I422TOARGBROW_SSSE3)
1164 if (TestCpuFlag(kCpuHasSSSE3)) {
1165 I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
1166 if (IS_ALIGNED(width, 8)) {
1167 I422ToARGBRow = I422ToARGBRow_SSSE3;
1168 }
1169 }
1170 #endif
1171 #if defined(HAS_I422TOARGBROW_AVX2)
1172 if (TestCpuFlag(kCpuHasAVX2)) {
1173 I422ToARGBRow = I422ToARGBRow_Any_AVX2;
1174 if (IS_ALIGNED(width, 16)) {
1175 I422ToARGBRow = I422ToARGBRow_AVX2;
1176 }
1177 }
1178 #endif
1179 #if defined(HAS_I422TOARGBROW_NEON)
1180 if (TestCpuFlag(kCpuHasNEON)) {
1181 I422ToARGBRow = I422ToARGBRow_Any_NEON;
1182 if (IS_ALIGNED(width, 8)) {
1183 I422ToARGBRow = I422ToARGBRow_NEON;
1184 }
1185 }
1186 #endif
1187 #if defined(HAS_I422TOARGBROW_MSA)
1188 if (TestCpuFlag(kCpuHasMSA)) {
1189 I422ToARGBRow = I422ToARGBRow_Any_MSA;
1190 if (IS_ALIGNED(width, 8)) {
1191 I422ToARGBRow = I422ToARGBRow_MSA;
1192 }
1193 }
1194 #endif
1195 #if defined(HAS_ARGBTORGB565DITHERROW_SSE2)
1196 if (TestCpuFlag(kCpuHasSSE2)) {
1197 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_SSE2;
1198 if (IS_ALIGNED(width, 4)) {
1199 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_SSE2;
1200 }
1201 }
1202 #endif
1203 #if defined(HAS_ARGBTORGB565DITHERROW_AVX2)
1204 if (TestCpuFlag(kCpuHasAVX2)) {
1205 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_AVX2;
1206 if (IS_ALIGNED(width, 8)) {
1207 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_AVX2;
1208 }
1209 }
1210 #endif
1211 #if defined(HAS_ARGBTORGB565DITHERROW_NEON)
1212 if (TestCpuFlag(kCpuHasNEON)) {
1213 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_NEON;
1214 if (IS_ALIGNED(width, 8)) {
1215 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_NEON;
1216 }
1217 }
1218 #endif
1219 #if defined(HAS_ARGBTORGB565DITHERROW_MSA)
1220 if (TestCpuFlag(kCpuHasMSA)) {
1221 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_MSA;
1222 if (IS_ALIGNED(width, 8)) {
1223 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_MSA;
1224 }
1225 }
1226 #endif
1227 {
1228 // Allocate a row of argb.
1229 align_buffer_64(row_argb, width * 4);
1230 for (y = 0; y < height; ++y) {
1231 I422ToARGBRow(src_y, src_u, src_v, row_argb, &kYuvI601Constants, width);
1232 ARGBToRGB565DitherRow(row_argb, dst_rgb565,
1233 *(const uint32_t*)(dither4x4 + ((y & 3) << 2)),
1234 width);
1235 dst_rgb565 += dst_stride_rgb565;
1236 src_y += src_stride_y;
1237 if (y & 1) {
1238 src_u += src_stride_u;
1239 src_v += src_stride_v;
1240 }
1241 }
1242 free_aligned_buffer_64(row_argb);
1243 }
1244 return 0;
1245 }
1246
1247 // Convert I420 to AR30 with matrix
I420ToAR30Matrix(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_ar30,int dst_stride_ar30,const struct YuvConstants * yuvconstants,int width,int height)1248 static int I420ToAR30Matrix(const uint8_t* src_y,
1249 int src_stride_y,
1250 const uint8_t* src_u,
1251 int src_stride_u,
1252 const uint8_t* src_v,
1253 int src_stride_v,
1254 uint8_t* dst_ar30,
1255 int dst_stride_ar30,
1256 const struct YuvConstants* yuvconstants,
1257 int width,
1258 int height) {
1259 int y;
1260 void (*I422ToAR30Row)(const uint8_t* y_buf, const uint8_t* u_buf,
1261 const uint8_t* v_buf, uint8_t* rgb_buf,
1262 const struct YuvConstants* yuvconstants, int width) =
1263 I422ToAR30Row_C;
1264
1265 if (!src_y || !src_u || !src_v || !dst_ar30 || width <= 0 || height == 0) {
1266 return -1;
1267 }
1268 // Negative height means invert the image.
1269 if (height < 0) {
1270 height = -height;
1271 dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30;
1272 dst_stride_ar30 = -dst_stride_ar30;
1273 }
1274
1275 #if defined(HAS_I422TOAR30ROW_SSSE3)
1276 if (TestCpuFlag(kCpuHasSSSE3)) {
1277 I422ToAR30Row = I422ToAR30Row_Any_SSSE3;
1278 if (IS_ALIGNED(width, 8)) {
1279 I422ToAR30Row = I422ToAR30Row_SSSE3;
1280 }
1281 }
1282 #endif
1283 #if defined(HAS_I422TOAR30ROW_AVX2)
1284 if (TestCpuFlag(kCpuHasAVX2)) {
1285 I422ToAR30Row = I422ToAR30Row_Any_AVX2;
1286 if (IS_ALIGNED(width, 16)) {
1287 I422ToAR30Row = I422ToAR30Row_AVX2;
1288 }
1289 }
1290 #endif
1291
1292 for (y = 0; y < height; ++y) {
1293 I422ToAR30Row(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
1294 dst_ar30 += dst_stride_ar30;
1295 src_y += src_stride_y;
1296 if (y & 1) {
1297 src_u += src_stride_u;
1298 src_v += src_stride_v;
1299 }
1300 }
1301 return 0;
1302 }
1303
1304 // Convert I420 to AR30.
1305 LIBYUV_API
I420ToAR30(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_ar30,int dst_stride_ar30,int width,int height)1306 int I420ToAR30(const uint8_t* src_y,
1307 int src_stride_y,
1308 const uint8_t* src_u,
1309 int src_stride_u,
1310 const uint8_t* src_v,
1311 int src_stride_v,
1312 uint8_t* dst_ar30,
1313 int dst_stride_ar30,
1314 int width,
1315 int height) {
1316 return I420ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1317 src_stride_v, dst_ar30, dst_stride_ar30,
1318 &kYuvI601Constants, width, height);
1319 }
1320
1321 // Convert H420 to AR30.
1322 LIBYUV_API
H420ToAR30(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_ar30,int dst_stride_ar30,int width,int height)1323 int H420ToAR30(const uint8_t* src_y,
1324 int src_stride_y,
1325 const uint8_t* src_u,
1326 int src_stride_u,
1327 const uint8_t* src_v,
1328 int src_stride_v,
1329 uint8_t* dst_ar30,
1330 int dst_stride_ar30,
1331 int width,
1332 int height) {
1333 return I420ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1334 src_stride_v, dst_ar30, dst_stride_ar30,
1335 &kYvuH709Constants, width, height);
1336 }
1337
1338 // Convert I420 to specified format
1339 LIBYUV_API
ConvertFromI420(const uint8_t * y,int y_stride,const uint8_t * u,int u_stride,const uint8_t * v,int v_stride,uint8_t * dst_sample,int dst_sample_stride,int width,int height,uint32_t fourcc)1340 int ConvertFromI420(const uint8_t* y,
1341 int y_stride,
1342 const uint8_t* u,
1343 int u_stride,
1344 const uint8_t* v,
1345 int v_stride,
1346 uint8_t* dst_sample,
1347 int dst_sample_stride,
1348 int width,
1349 int height,
1350 uint32_t fourcc) {
1351 uint32_t format = CanonicalFourCC(fourcc);
1352 int r = 0;
1353 if (!y || !u || !v || !dst_sample || width <= 0 || height == 0) {
1354 return -1;
1355 }
1356 switch (format) {
1357 // Single plane formats
1358 case FOURCC_YUY2:
1359 r = I420ToYUY2(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1360 dst_sample_stride ? dst_sample_stride : width * 2, width,
1361 height);
1362 break;
1363 case FOURCC_UYVY:
1364 r = I420ToUYVY(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1365 dst_sample_stride ? dst_sample_stride : width * 2, width,
1366 height);
1367 break;
1368 case FOURCC_RGBP:
1369 r = I420ToRGB565(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1370 dst_sample_stride ? dst_sample_stride : width * 2, width,
1371 height);
1372 break;
1373 case FOURCC_RGBO:
1374 r = I420ToARGB1555(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1375 dst_sample_stride ? dst_sample_stride : width * 2,
1376 width, height);
1377 break;
1378 case FOURCC_R444:
1379 r = I420ToARGB4444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1380 dst_sample_stride ? dst_sample_stride : width * 2,
1381 width, height);
1382 break;
1383 case FOURCC_24BG:
1384 r = I420ToRGB24(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1385 dst_sample_stride ? dst_sample_stride : width * 3, width,
1386 height);
1387 break;
1388 case FOURCC_RAW:
1389 r = I420ToRAW(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1390 dst_sample_stride ? dst_sample_stride : width * 3, width,
1391 height);
1392 break;
1393 case FOURCC_ARGB:
1394 r = I420ToARGB(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1395 dst_sample_stride ? dst_sample_stride : width * 4, width,
1396 height);
1397 break;
1398 case FOURCC_BGRA:
1399 r = I420ToBGRA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1400 dst_sample_stride ? dst_sample_stride : width * 4, width,
1401 height);
1402 break;
1403 case FOURCC_ABGR:
1404 r = I420ToABGR(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1405 dst_sample_stride ? dst_sample_stride : width * 4, width,
1406 height);
1407 break;
1408 case FOURCC_RGBA:
1409 r = I420ToRGBA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1410 dst_sample_stride ? dst_sample_stride : width * 4, width,
1411 height);
1412 break;
1413 case FOURCC_AR30:
1414 r = I420ToAR30(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1415 dst_sample_stride ? dst_sample_stride : width * 4, width,
1416 height);
1417 break;
1418 case FOURCC_I400:
1419 r = I400Copy(y, y_stride, dst_sample,
1420 dst_sample_stride ? dst_sample_stride : width, width,
1421 height);
1422 break;
1423 case FOURCC_NV12: {
1424 uint8_t* dst_uv = dst_sample + width * height;
1425 r = I420ToNV12(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1426 dst_sample_stride ? dst_sample_stride : width, dst_uv,
1427 dst_sample_stride ? dst_sample_stride : width, width,
1428 height);
1429 break;
1430 }
1431 case FOURCC_NV21: {
1432 uint8_t* dst_vu = dst_sample + width * height;
1433 r = I420ToNV21(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1434 dst_sample_stride ? dst_sample_stride : width, dst_vu,
1435 dst_sample_stride ? dst_sample_stride : width, width,
1436 height);
1437 break;
1438 }
1439 // TODO(fbarchard): Add M420.
1440 // Triplanar formats
1441 case FOURCC_I420:
1442 case FOURCC_YV12: {
1443 dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1444 int halfstride = (dst_sample_stride + 1) / 2;
1445 int halfheight = (height + 1) / 2;
1446 uint8_t* dst_u;
1447 uint8_t* dst_v;
1448 if (format == FOURCC_YV12) {
1449 dst_v = dst_sample + dst_sample_stride * height;
1450 dst_u = dst_v + halfstride * halfheight;
1451 } else {
1452 dst_u = dst_sample + dst_sample_stride * height;
1453 dst_v = dst_u + halfstride * halfheight;
1454 }
1455 r = I420Copy(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1456 dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
1457 width, height);
1458 break;
1459 }
1460 case FOURCC_I422:
1461 case FOURCC_YV16: {
1462 dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1463 int halfstride = (dst_sample_stride + 1) / 2;
1464 uint8_t* dst_u;
1465 uint8_t* dst_v;
1466 if (format == FOURCC_YV16) {
1467 dst_v = dst_sample + dst_sample_stride * height;
1468 dst_u = dst_v + halfstride * height;
1469 } else {
1470 dst_u = dst_sample + dst_sample_stride * height;
1471 dst_v = dst_u + halfstride * height;
1472 }
1473 r = I420ToI422(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1474 dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
1475 width, height);
1476 break;
1477 }
1478 case FOURCC_I444:
1479 case FOURCC_YV24: {
1480 dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1481 uint8_t* dst_u;
1482 uint8_t* dst_v;
1483 if (format == FOURCC_YV24) {
1484 dst_v = dst_sample + dst_sample_stride * height;
1485 dst_u = dst_v + dst_sample_stride * height;
1486 } else {
1487 dst_u = dst_sample + dst_sample_stride * height;
1488 dst_v = dst_u + dst_sample_stride * height;
1489 }
1490 r = I420ToI444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1491 dst_sample_stride, dst_u, dst_sample_stride, dst_v,
1492 dst_sample_stride, width, height);
1493 break;
1494 }
1495 // Formats not supported - MJPG, biplanar, some rgb formats.
1496 default:
1497 return -1; // unknown fourcc - return failure code.
1498 }
1499 return r;
1500 }
1501
1502 #ifdef __cplusplus
1503 } // extern "C"
1504 } // namespace libyuv
1505 #endif
1506