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
306 for (y = 0; y < height - 1; y += 2) {
307 I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
308 I422ToYUY2Row(src_y + src_stride_y, src_u, src_v,
309 dst_yuy2 + dst_stride_yuy2, width);
310 src_y += src_stride_y * 2;
311 src_u += src_stride_u;
312 src_v += src_stride_v;
313 dst_yuy2 += dst_stride_yuy2 * 2;
314 }
315 if (height & 1) {
316 I422ToYUY2Row(src_y, src_u, src_v, dst_yuy2, width);
317 }
318 return 0;
319 }
320
321 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)322 int I422ToUYVY(const uint8_t* src_y,
323 int src_stride_y,
324 const uint8_t* src_u,
325 int src_stride_u,
326 const uint8_t* src_v,
327 int src_stride_v,
328 uint8_t* dst_uyvy,
329 int dst_stride_uyvy,
330 int width,
331 int height) {
332 int y;
333 void (*I422ToUYVYRow)(const uint8_t* src_y, const uint8_t* src_u,
334 const uint8_t* src_v, uint8_t* dst_uyvy, int width) =
335 I422ToUYVYRow_C;
336 if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) {
337 return -1;
338 }
339 // Negative height means invert the image.
340 if (height < 0) {
341 height = -height;
342 dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
343 dst_stride_uyvy = -dst_stride_uyvy;
344 }
345 // Coalesce rows.
346 if (src_stride_y == width && src_stride_u * 2 == width &&
347 src_stride_v * 2 == width && dst_stride_uyvy == width * 2) {
348 width *= height;
349 height = 1;
350 src_stride_y = src_stride_u = src_stride_v = dst_stride_uyvy = 0;
351 }
352 #if defined(HAS_I422TOUYVYROW_SSE2)
353 if (TestCpuFlag(kCpuHasSSE2)) {
354 I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
355 if (IS_ALIGNED(width, 16)) {
356 I422ToUYVYRow = I422ToUYVYRow_SSE2;
357 }
358 }
359 #endif
360 #if defined(HAS_I422TOUYVYROW_AVX2)
361 if (TestCpuFlag(kCpuHasAVX2)) {
362 I422ToUYVYRow = I422ToUYVYRow_Any_AVX2;
363 if (IS_ALIGNED(width, 32)) {
364 I422ToUYVYRow = I422ToUYVYRow_AVX2;
365 }
366 }
367 #endif
368 #if defined(HAS_I422TOUYVYROW_NEON)
369 if (TestCpuFlag(kCpuHasNEON)) {
370 I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
371 if (IS_ALIGNED(width, 16)) {
372 I422ToUYVYRow = I422ToUYVYRow_NEON;
373 }
374 }
375 #endif
376 #if defined(HAS_I422TOUYVYROW_MSA)
377 if (TestCpuFlag(kCpuHasMSA)) {
378 I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
379 if (IS_ALIGNED(width, 32)) {
380 I422ToUYVYRow = I422ToUYVYRow_MSA;
381 }
382 }
383 #endif
384
385 for (y = 0; y < height; ++y) {
386 I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
387 src_y += src_stride_y;
388 src_u += src_stride_u;
389 src_v += src_stride_v;
390 dst_uyvy += dst_stride_uyvy;
391 }
392 return 0;
393 }
394
395 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)396 int I420ToUYVY(const uint8_t* src_y,
397 int src_stride_y,
398 const uint8_t* src_u,
399 int src_stride_u,
400 const uint8_t* src_v,
401 int src_stride_v,
402 uint8_t* dst_uyvy,
403 int dst_stride_uyvy,
404 int width,
405 int height) {
406 int y;
407 void (*I422ToUYVYRow)(const uint8_t* src_y, const uint8_t* src_u,
408 const uint8_t* src_v, uint8_t* dst_uyvy, int width) =
409 I422ToUYVYRow_C;
410 if (!src_y || !src_u || !src_v || !dst_uyvy || width <= 0 || height == 0) {
411 return -1;
412 }
413 // Negative height means invert the image.
414 if (height < 0) {
415 height = -height;
416 dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
417 dst_stride_uyvy = -dst_stride_uyvy;
418 }
419 #if defined(HAS_I422TOUYVYROW_SSE2)
420 if (TestCpuFlag(kCpuHasSSE2)) {
421 I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
422 if (IS_ALIGNED(width, 16)) {
423 I422ToUYVYRow = I422ToUYVYRow_SSE2;
424 }
425 }
426 #endif
427 #if defined(HAS_I422TOUYVYROW_AVX2)
428 if (TestCpuFlag(kCpuHasAVX2)) {
429 I422ToUYVYRow = I422ToUYVYRow_Any_AVX2;
430 if (IS_ALIGNED(width, 32)) {
431 I422ToUYVYRow = I422ToUYVYRow_AVX2;
432 }
433 }
434 #endif
435 #if defined(HAS_I422TOUYVYROW_NEON)
436 if (TestCpuFlag(kCpuHasNEON)) {
437 I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
438 if (IS_ALIGNED(width, 16)) {
439 I422ToUYVYRow = I422ToUYVYRow_NEON;
440 }
441 }
442 #endif
443 #if defined(HAS_I422TOUYVYROW_MSA)
444 if (TestCpuFlag(kCpuHasMSA)) {
445 I422ToUYVYRow = I422ToUYVYRow_Any_MSA;
446 if (IS_ALIGNED(width, 32)) {
447 I422ToUYVYRow = I422ToUYVYRow_MSA;
448 }
449 }
450 #endif
451
452 for (y = 0; y < height - 1; y += 2) {
453 I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
454 I422ToUYVYRow(src_y + src_stride_y, src_u, src_v,
455 dst_uyvy + dst_stride_uyvy, width);
456 src_y += src_stride_y * 2;
457 src_u += src_stride_u;
458 src_v += src_stride_v;
459 dst_uyvy += dst_stride_uyvy * 2;
460 }
461 if (height & 1) {
462 I422ToUYVYRow(src_y, src_u, src_v, dst_uyvy, width);
463 }
464 return 0;
465 }
466
467 // TODO(fbarchard): test negative height for invert.
468 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)469 int I420ToNV12(const uint8_t* src_y,
470 int src_stride_y,
471 const uint8_t* src_u,
472 int src_stride_u,
473 const uint8_t* src_v,
474 int src_stride_v,
475 uint8_t* dst_y,
476 int dst_stride_y,
477 uint8_t* dst_uv,
478 int dst_stride_uv,
479 int width,
480 int height) {
481 if (!src_y || !src_u || !src_v || !dst_y || !dst_uv || width <= 0 ||
482 height == 0) {
483 return -1;
484 }
485 int halfwidth = (width + 1) / 2;
486 int halfheight = height > 0 ? (height + 1) / 2 : (height - 1) / 2;
487 if (dst_y) {
488 CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
489 }
490 MergeUVPlane(src_u, src_stride_u, src_v, src_stride_v, dst_uv, dst_stride_uv,
491 halfwidth, halfheight);
492 return 0;
493 }
494
495 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)496 int I420ToNV21(const uint8_t* src_y,
497 int src_stride_y,
498 const uint8_t* src_u,
499 int src_stride_u,
500 const uint8_t* src_v,
501 int src_stride_v,
502 uint8_t* dst_y,
503 int dst_stride_y,
504 uint8_t* dst_vu,
505 int dst_stride_vu,
506 int width,
507 int height) {
508 return I420ToNV12(src_y, src_stride_y, src_v, src_stride_v, src_u,
509 src_stride_u, dst_y, dst_stride_y, dst_vu, dst_stride_vu,
510 width, height);
511 }
512
513 // 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)514 static int I420ToRGBAMatrix(const uint8_t* src_y,
515 int src_stride_y,
516 const uint8_t* src_u,
517 int src_stride_u,
518 const uint8_t* src_v,
519 int src_stride_v,
520 uint8_t* dst_rgba,
521 int dst_stride_rgba,
522 const struct YuvConstants* yuvconstants,
523 int width,
524 int height) {
525 int y;
526 void (*I422ToRGBARow)(const uint8_t* y_buf, const uint8_t* u_buf,
527 const uint8_t* v_buf, uint8_t* rgb_buf,
528 const struct YuvConstants* yuvconstants, int width) =
529 I422ToRGBARow_C;
530 if (!src_y || !src_u || !src_v || !dst_rgba || width <= 0 || height == 0) {
531 return -1;
532 }
533 // Negative height means invert the image.
534 if (height < 0) {
535 height = -height;
536 dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
537 dst_stride_rgba = -dst_stride_rgba;
538 }
539 #if defined(HAS_I422TORGBAROW_SSSE3)
540 if (TestCpuFlag(kCpuHasSSSE3)) {
541 I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
542 if (IS_ALIGNED(width, 8)) {
543 I422ToRGBARow = I422ToRGBARow_SSSE3;
544 }
545 }
546 #endif
547 #if defined(HAS_I422TORGBAROW_AVX2)
548 if (TestCpuFlag(kCpuHasAVX2)) {
549 I422ToRGBARow = I422ToRGBARow_Any_AVX2;
550 if (IS_ALIGNED(width, 16)) {
551 I422ToRGBARow = I422ToRGBARow_AVX2;
552 }
553 }
554 #endif
555 #if defined(HAS_I422TORGBAROW_NEON)
556 if (TestCpuFlag(kCpuHasNEON)) {
557 I422ToRGBARow = I422ToRGBARow_Any_NEON;
558 if (IS_ALIGNED(width, 8)) {
559 I422ToRGBARow = I422ToRGBARow_NEON;
560 }
561 }
562 #endif
563 #if defined(HAS_I422TORGBAROW_MSA)
564 if (TestCpuFlag(kCpuHasMSA)) {
565 I422ToRGBARow = I422ToRGBARow_Any_MSA;
566 if (IS_ALIGNED(width, 8)) {
567 I422ToRGBARow = I422ToRGBARow_MSA;
568 }
569 }
570 #endif
571
572 for (y = 0; y < height; ++y) {
573 I422ToRGBARow(src_y, src_u, src_v, dst_rgba, yuvconstants, width);
574 dst_rgba += dst_stride_rgba;
575 src_y += src_stride_y;
576 if (y & 1) {
577 src_u += src_stride_u;
578 src_v += src_stride_v;
579 }
580 }
581 return 0;
582 }
583
584 // Convert I420 to RGBA.
585 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)586 int I420ToRGBA(const uint8_t* src_y,
587 int src_stride_y,
588 const uint8_t* src_u,
589 int src_stride_u,
590 const uint8_t* src_v,
591 int src_stride_v,
592 uint8_t* dst_rgba,
593 int dst_stride_rgba,
594 int width,
595 int height) {
596 return I420ToRGBAMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
597 src_stride_v, dst_rgba, dst_stride_rgba,
598 &kYuvI601Constants, width, height);
599 }
600
601 // Convert I420 to BGRA.
602 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)603 int I420ToBGRA(const uint8_t* src_y,
604 int src_stride_y,
605 const uint8_t* src_u,
606 int src_stride_u,
607 const uint8_t* src_v,
608 int src_stride_v,
609 uint8_t* dst_bgra,
610 int dst_stride_bgra,
611 int width,
612 int height) {
613 return I420ToRGBAMatrix(src_y, src_stride_y, src_v,
614 src_stride_v, // Swap U and V
615 src_u, src_stride_u, dst_bgra, dst_stride_bgra,
616 &kYvuI601Constants, // Use Yvu matrix
617 width, height);
618 }
619
620 // 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)621 static int I420ToRGB24Matrix(const uint8_t* src_y,
622 int src_stride_y,
623 const uint8_t* src_u,
624 int src_stride_u,
625 const uint8_t* src_v,
626 int src_stride_v,
627 uint8_t* dst_rgb24,
628 int dst_stride_rgb24,
629 const struct YuvConstants* yuvconstants,
630 int width,
631 int height) {
632 int y;
633 void (*I422ToRGB24Row)(const uint8_t* y_buf, const uint8_t* u_buf,
634 const uint8_t* v_buf, uint8_t* rgb_buf,
635 const struct YuvConstants* yuvconstants, int width) =
636 I422ToRGB24Row_C;
637 if (!src_y || !src_u || !src_v || !dst_rgb24 || width <= 0 || height == 0) {
638 return -1;
639 }
640 // Negative height means invert the image.
641 if (height < 0) {
642 height = -height;
643 dst_rgb24 = dst_rgb24 + (height - 1) * dst_stride_rgb24;
644 dst_stride_rgb24 = -dst_stride_rgb24;
645 }
646 #if defined(HAS_I422TORGB24ROW_SSSE3)
647 if (TestCpuFlag(kCpuHasSSSE3)) {
648 I422ToRGB24Row = I422ToRGB24Row_Any_SSSE3;
649 if (IS_ALIGNED(width, 8)) {
650 I422ToRGB24Row = I422ToRGB24Row_SSSE3;
651 }
652 }
653 #endif
654 #if defined(HAS_I422TORGB24ROW_AVX2)
655 if (TestCpuFlag(kCpuHasAVX2)) {
656 I422ToRGB24Row = I422ToRGB24Row_Any_AVX2;
657 if (IS_ALIGNED(width, 16)) {
658 I422ToRGB24Row = I422ToRGB24Row_AVX2;
659 }
660 }
661 #endif
662 #if defined(HAS_I422TORGB24ROW_NEON)
663 if (TestCpuFlag(kCpuHasNEON)) {
664 I422ToRGB24Row = I422ToRGB24Row_Any_NEON;
665 if (IS_ALIGNED(width, 8)) {
666 I422ToRGB24Row = I422ToRGB24Row_NEON;
667 }
668 }
669 #endif
670 #if defined(HAS_I422TORGB24ROW_MSA)
671 if (TestCpuFlag(kCpuHasMSA)) {
672 I422ToRGB24Row = I422ToRGB24Row_Any_MSA;
673 if (IS_ALIGNED(width, 16)) {
674 I422ToRGB24Row = I422ToRGB24Row_MSA;
675 }
676 }
677 #endif
678
679 for (y = 0; y < height; ++y) {
680 I422ToRGB24Row(src_y, src_u, src_v, dst_rgb24, yuvconstants, width);
681 dst_rgb24 += dst_stride_rgb24;
682 src_y += src_stride_y;
683 if (y & 1) {
684 src_u += src_stride_u;
685 src_v += src_stride_v;
686 }
687 }
688 return 0;
689 }
690
691 // Convert I420 to RGB24.
692 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)693 int I420ToRGB24(const uint8_t* src_y,
694 int src_stride_y,
695 const uint8_t* src_u,
696 int src_stride_u,
697 const uint8_t* src_v,
698 int src_stride_v,
699 uint8_t* dst_rgb24,
700 int dst_stride_rgb24,
701 int width,
702 int height) {
703 return I420ToRGB24Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
704 src_stride_v, dst_rgb24, dst_stride_rgb24,
705 &kYuvI601Constants, width, height);
706 }
707
708 // Convert I420 to RAW.
709 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)710 int I420ToRAW(const uint8_t* src_y,
711 int src_stride_y,
712 const uint8_t* src_u,
713 int src_stride_u,
714 const uint8_t* src_v,
715 int src_stride_v,
716 uint8_t* dst_raw,
717 int dst_stride_raw,
718 int width,
719 int height) {
720 return I420ToRGB24Matrix(src_y, src_stride_y, src_v,
721 src_stride_v, // Swap U and V
722 src_u, src_stride_u, dst_raw, dst_stride_raw,
723 &kYvuI601Constants, // Use Yvu matrix
724 width, height);
725 }
726
727 // Convert H420 to RGB24.
728 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)729 int H420ToRGB24(const uint8_t* src_y,
730 int src_stride_y,
731 const uint8_t* src_u,
732 int src_stride_u,
733 const uint8_t* src_v,
734 int src_stride_v,
735 uint8_t* dst_rgb24,
736 int dst_stride_rgb24,
737 int width,
738 int height) {
739 return I420ToRGB24Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
740 src_stride_v, dst_rgb24, dst_stride_rgb24,
741 &kYuvH709Constants, width, height);
742 }
743
744 // Convert H420 to RAW.
745 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)746 int H420ToRAW(const uint8_t* src_y,
747 int src_stride_y,
748 const uint8_t* src_u,
749 int src_stride_u,
750 const uint8_t* src_v,
751 int src_stride_v,
752 uint8_t* dst_raw,
753 int dst_stride_raw,
754 int width,
755 int height) {
756 return I420ToRGB24Matrix(src_y, src_stride_y, src_v,
757 src_stride_v, // Swap U and V
758 src_u, src_stride_u, dst_raw, dst_stride_raw,
759 &kYvuH709Constants, // Use Yvu matrix
760 width, height);
761 }
762
763 // Convert I420 to ARGB1555.
764 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)765 int I420ToARGB1555(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_argb1555,
772 int dst_stride_argb1555,
773 int width,
774 int height) {
775 int y;
776 void (*I422ToARGB1555Row)(const uint8_t* y_buf, const uint8_t* u_buf,
777 const uint8_t* v_buf, uint8_t* rgb_buf,
778 const struct YuvConstants* yuvconstants,
779 int width) = I422ToARGB1555Row_C;
780 if (!src_y || !src_u || !src_v || !dst_argb1555 || width <= 0 ||
781 height == 0) {
782 return -1;
783 }
784 // Negative height means invert the image.
785 if (height < 0) {
786 height = -height;
787 dst_argb1555 = dst_argb1555 + (height - 1) * dst_stride_argb1555;
788 dst_stride_argb1555 = -dst_stride_argb1555;
789 }
790 #if defined(HAS_I422TOARGB1555ROW_SSSE3)
791 if (TestCpuFlag(kCpuHasSSSE3)) {
792 I422ToARGB1555Row = I422ToARGB1555Row_Any_SSSE3;
793 if (IS_ALIGNED(width, 8)) {
794 I422ToARGB1555Row = I422ToARGB1555Row_SSSE3;
795 }
796 }
797 #endif
798 #if defined(HAS_I422TOARGB1555ROW_AVX2)
799 if (TestCpuFlag(kCpuHasAVX2)) {
800 I422ToARGB1555Row = I422ToARGB1555Row_Any_AVX2;
801 if (IS_ALIGNED(width, 16)) {
802 I422ToARGB1555Row = I422ToARGB1555Row_AVX2;
803 }
804 }
805 #endif
806 #if defined(HAS_I422TOARGB1555ROW_NEON)
807 if (TestCpuFlag(kCpuHasNEON)) {
808 I422ToARGB1555Row = I422ToARGB1555Row_Any_NEON;
809 if (IS_ALIGNED(width, 8)) {
810 I422ToARGB1555Row = I422ToARGB1555Row_NEON;
811 }
812 }
813 #endif
814 #if defined(HAS_I422TOARGB1555ROW_MSA)
815 if (TestCpuFlag(kCpuHasMSA)) {
816 I422ToARGB1555Row = I422ToARGB1555Row_Any_MSA;
817 if (IS_ALIGNED(width, 8)) {
818 I422ToARGB1555Row = I422ToARGB1555Row_MSA;
819 }
820 }
821 #endif
822
823 for (y = 0; y < height; ++y) {
824 I422ToARGB1555Row(src_y, src_u, src_v, dst_argb1555, &kYuvI601Constants,
825 width);
826 dst_argb1555 += dst_stride_argb1555;
827 src_y += src_stride_y;
828 if (y & 1) {
829 src_u += src_stride_u;
830 src_v += src_stride_v;
831 }
832 }
833 return 0;
834 }
835
836 // Convert I420 to ARGB4444.
837 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)838 int I420ToARGB4444(const uint8_t* src_y,
839 int src_stride_y,
840 const uint8_t* src_u,
841 int src_stride_u,
842 const uint8_t* src_v,
843 int src_stride_v,
844 uint8_t* dst_argb4444,
845 int dst_stride_argb4444,
846 int width,
847 int height) {
848 int y;
849 void (*I422ToARGB4444Row)(const uint8_t* y_buf, const uint8_t* u_buf,
850 const uint8_t* v_buf, uint8_t* rgb_buf,
851 const struct YuvConstants* yuvconstants,
852 int width) = I422ToARGB4444Row_C;
853 if (!src_y || !src_u || !src_v || !dst_argb4444 || width <= 0 ||
854 height == 0) {
855 return -1;
856 }
857 // Negative height means invert the image.
858 if (height < 0) {
859 height = -height;
860 dst_argb4444 = dst_argb4444 + (height - 1) * dst_stride_argb4444;
861 dst_stride_argb4444 = -dst_stride_argb4444;
862 }
863 #if defined(HAS_I422TOARGB4444ROW_SSSE3)
864 if (TestCpuFlag(kCpuHasSSSE3)) {
865 I422ToARGB4444Row = I422ToARGB4444Row_Any_SSSE3;
866 if (IS_ALIGNED(width, 8)) {
867 I422ToARGB4444Row = I422ToARGB4444Row_SSSE3;
868 }
869 }
870 #endif
871 #if defined(HAS_I422TOARGB4444ROW_AVX2)
872 if (TestCpuFlag(kCpuHasAVX2)) {
873 I422ToARGB4444Row = I422ToARGB4444Row_Any_AVX2;
874 if (IS_ALIGNED(width, 16)) {
875 I422ToARGB4444Row = I422ToARGB4444Row_AVX2;
876 }
877 }
878 #endif
879 #if defined(HAS_I422TOARGB4444ROW_NEON)
880 if (TestCpuFlag(kCpuHasNEON)) {
881 I422ToARGB4444Row = I422ToARGB4444Row_Any_NEON;
882 if (IS_ALIGNED(width, 8)) {
883 I422ToARGB4444Row = I422ToARGB4444Row_NEON;
884 }
885 }
886 #endif
887 #if defined(HAS_I422TOARGB4444ROW_MSA)
888 if (TestCpuFlag(kCpuHasMSA)) {
889 I422ToARGB4444Row = I422ToARGB4444Row_Any_MSA;
890 if (IS_ALIGNED(width, 8)) {
891 I422ToARGB4444Row = I422ToARGB4444Row_MSA;
892 }
893 }
894 #endif
895
896 for (y = 0; y < height; ++y) {
897 I422ToARGB4444Row(src_y, src_u, src_v, dst_argb4444, &kYuvI601Constants,
898 width);
899 dst_argb4444 += dst_stride_argb4444;
900 src_y += src_stride_y;
901 if (y & 1) {
902 src_u += src_stride_u;
903 src_v += src_stride_v;
904 }
905 }
906 return 0;
907 }
908
909 // Convert I420 to RGB565.
910 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)911 int I420ToRGB565(const uint8_t* src_y,
912 int src_stride_y,
913 const uint8_t* src_u,
914 int src_stride_u,
915 const uint8_t* src_v,
916 int src_stride_v,
917 uint8_t* dst_rgb565,
918 int dst_stride_rgb565,
919 int width,
920 int height) {
921 int y;
922 void (*I422ToRGB565Row)(const uint8_t* y_buf, const uint8_t* u_buf,
923 const uint8_t* v_buf, uint8_t* rgb_buf,
924 const struct YuvConstants* yuvconstants, int width) =
925 I422ToRGB565Row_C;
926 if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
927 return -1;
928 }
929 // Negative height means invert the image.
930 if (height < 0) {
931 height = -height;
932 dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
933 dst_stride_rgb565 = -dst_stride_rgb565;
934 }
935 #if defined(HAS_I422TORGB565ROW_SSSE3)
936 if (TestCpuFlag(kCpuHasSSSE3)) {
937 I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
938 if (IS_ALIGNED(width, 8)) {
939 I422ToRGB565Row = I422ToRGB565Row_SSSE3;
940 }
941 }
942 #endif
943 #if defined(HAS_I422TORGB565ROW_AVX2)
944 if (TestCpuFlag(kCpuHasAVX2)) {
945 I422ToRGB565Row = I422ToRGB565Row_Any_AVX2;
946 if (IS_ALIGNED(width, 16)) {
947 I422ToRGB565Row = I422ToRGB565Row_AVX2;
948 }
949 }
950 #endif
951 #if defined(HAS_I422TORGB565ROW_NEON)
952 if (TestCpuFlag(kCpuHasNEON)) {
953 I422ToRGB565Row = I422ToRGB565Row_Any_NEON;
954 if (IS_ALIGNED(width, 8)) {
955 I422ToRGB565Row = I422ToRGB565Row_NEON;
956 }
957 }
958 #endif
959 #if defined(HAS_I422TORGB565ROW_MSA)
960 if (TestCpuFlag(kCpuHasMSA)) {
961 I422ToRGB565Row = I422ToRGB565Row_Any_MSA;
962 if (IS_ALIGNED(width, 8)) {
963 I422ToRGB565Row = I422ToRGB565Row_MSA;
964 }
965 }
966 #endif
967
968 for (y = 0; y < height; ++y) {
969 I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, &kYuvI601Constants, width);
970 dst_rgb565 += dst_stride_rgb565;
971 src_y += src_stride_y;
972 if (y & 1) {
973 src_u += src_stride_u;
974 src_v += src_stride_v;
975 }
976 }
977 return 0;
978 }
979
980 // Convert I422 to RGB565.
981 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)982 int I422ToRGB565(const uint8_t* src_y,
983 int src_stride_y,
984 const uint8_t* src_u,
985 int src_stride_u,
986 const uint8_t* src_v,
987 int src_stride_v,
988 uint8_t* dst_rgb565,
989 int dst_stride_rgb565,
990 int width,
991 int height) {
992 int y;
993 void (*I422ToRGB565Row)(const uint8_t* y_buf, const uint8_t* u_buf,
994 const uint8_t* v_buf, uint8_t* rgb_buf,
995 const struct YuvConstants* yuvconstants, int width) =
996 I422ToRGB565Row_C;
997 if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
998 return -1;
999 }
1000 // Negative height means invert the image.
1001 if (height < 0) {
1002 height = -height;
1003 dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
1004 dst_stride_rgb565 = -dst_stride_rgb565;
1005 }
1006 #if defined(HAS_I422TORGB565ROW_SSSE3)
1007 if (TestCpuFlag(kCpuHasSSSE3)) {
1008 I422ToRGB565Row = I422ToRGB565Row_Any_SSSE3;
1009 if (IS_ALIGNED(width, 8)) {
1010 I422ToRGB565Row = I422ToRGB565Row_SSSE3;
1011 }
1012 }
1013 #endif
1014 #if defined(HAS_I422TORGB565ROW_AVX2)
1015 if (TestCpuFlag(kCpuHasAVX2)) {
1016 I422ToRGB565Row = I422ToRGB565Row_Any_AVX2;
1017 if (IS_ALIGNED(width, 16)) {
1018 I422ToRGB565Row = I422ToRGB565Row_AVX2;
1019 }
1020 }
1021 #endif
1022 #if defined(HAS_I422TORGB565ROW_NEON)
1023 if (TestCpuFlag(kCpuHasNEON)) {
1024 I422ToRGB565Row = I422ToRGB565Row_Any_NEON;
1025 if (IS_ALIGNED(width, 8)) {
1026 I422ToRGB565Row = I422ToRGB565Row_NEON;
1027 }
1028 }
1029 #endif
1030 #if defined(HAS_I422TORGB565ROW_MSA)
1031 if (TestCpuFlag(kCpuHasMSA)) {
1032 I422ToRGB565Row = I422ToRGB565Row_Any_MSA;
1033 if (IS_ALIGNED(width, 8)) {
1034 I422ToRGB565Row = I422ToRGB565Row_MSA;
1035 }
1036 }
1037 #endif
1038
1039 for (y = 0; y < height; ++y) {
1040 I422ToRGB565Row(src_y, src_u, src_v, dst_rgb565, &kYuvI601Constants, width);
1041 dst_rgb565 += dst_stride_rgb565;
1042 src_y += src_stride_y;
1043 src_u += src_stride_u;
1044 src_v += src_stride_v;
1045 }
1046 return 0;
1047 }
1048
1049 // Ordered 8x8 dither for 888 to 565. Values from 0 to 7.
1050 static const uint8_t kDither565_4x4[16] = {
1051 0, 4, 1, 5, 6, 2, 7, 3, 1, 5, 0, 4, 7, 3, 6, 2,
1052 };
1053
1054 // Convert I420 to RGB565 with dithering.
1055 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)1056 int I420ToRGB565Dither(const uint8_t* src_y,
1057 int src_stride_y,
1058 const uint8_t* src_u,
1059 int src_stride_u,
1060 const uint8_t* src_v,
1061 int src_stride_v,
1062 uint8_t* dst_rgb565,
1063 int dst_stride_rgb565,
1064 const uint8_t* dither4x4,
1065 int width,
1066 int height) {
1067 int y;
1068 void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
1069 const uint8_t* v_buf, uint8_t* rgb_buf,
1070 const struct YuvConstants* yuvconstants, int width) =
1071 I422ToARGBRow_C;
1072 void (*ARGBToRGB565DitherRow)(const uint8_t* src_argb, uint8_t* dst_rgb,
1073 const uint32_t dither4, int width) =
1074 ARGBToRGB565DitherRow_C;
1075 if (!src_y || !src_u || !src_v || !dst_rgb565 || width <= 0 || height == 0) {
1076 return -1;
1077 }
1078 // Negative height means invert the image.
1079 if (height < 0) {
1080 height = -height;
1081 dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
1082 dst_stride_rgb565 = -dst_stride_rgb565;
1083 }
1084 if (!dither4x4) {
1085 dither4x4 = kDither565_4x4;
1086 }
1087 #if defined(HAS_I422TOARGBROW_SSSE3)
1088 if (TestCpuFlag(kCpuHasSSSE3)) {
1089 I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
1090 if (IS_ALIGNED(width, 8)) {
1091 I422ToARGBRow = I422ToARGBRow_SSSE3;
1092 }
1093 }
1094 #endif
1095 #if defined(HAS_I422TOARGBROW_AVX2)
1096 if (TestCpuFlag(kCpuHasAVX2)) {
1097 I422ToARGBRow = I422ToARGBRow_Any_AVX2;
1098 if (IS_ALIGNED(width, 16)) {
1099 I422ToARGBRow = I422ToARGBRow_AVX2;
1100 }
1101 }
1102 #endif
1103 #if defined(HAS_I422TOARGBROW_NEON)
1104 if (TestCpuFlag(kCpuHasNEON)) {
1105 I422ToARGBRow = I422ToARGBRow_Any_NEON;
1106 if (IS_ALIGNED(width, 8)) {
1107 I422ToARGBRow = I422ToARGBRow_NEON;
1108 }
1109 }
1110 #endif
1111 #if defined(HAS_I422TOARGBROW_MSA)
1112 if (TestCpuFlag(kCpuHasMSA)) {
1113 I422ToARGBRow = I422ToARGBRow_Any_MSA;
1114 if (IS_ALIGNED(width, 8)) {
1115 I422ToARGBRow = I422ToARGBRow_MSA;
1116 }
1117 }
1118 #endif
1119 #if defined(HAS_ARGBTORGB565DITHERROW_SSE2)
1120 if (TestCpuFlag(kCpuHasSSE2)) {
1121 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_SSE2;
1122 if (IS_ALIGNED(width, 4)) {
1123 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_SSE2;
1124 }
1125 }
1126 #endif
1127 #if defined(HAS_ARGBTORGB565DITHERROW_AVX2)
1128 if (TestCpuFlag(kCpuHasAVX2)) {
1129 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_AVX2;
1130 if (IS_ALIGNED(width, 8)) {
1131 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_AVX2;
1132 }
1133 }
1134 #endif
1135 #if defined(HAS_ARGBTORGB565DITHERROW_NEON)
1136 if (TestCpuFlag(kCpuHasNEON)) {
1137 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_NEON;
1138 if (IS_ALIGNED(width, 8)) {
1139 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_NEON;
1140 }
1141 }
1142 #endif
1143 #if defined(HAS_ARGBTORGB565DITHERROW_MSA)
1144 if (TestCpuFlag(kCpuHasMSA)) {
1145 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_MSA;
1146 if (IS_ALIGNED(width, 8)) {
1147 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_MSA;
1148 }
1149 }
1150 #endif
1151 {
1152 // Allocate a row of argb.
1153 align_buffer_64(row_argb, width * 4);
1154 for (y = 0; y < height; ++y) {
1155 I422ToARGBRow(src_y, src_u, src_v, row_argb, &kYuvI601Constants, width);
1156 ARGBToRGB565DitherRow(row_argb, dst_rgb565,
1157 *(uint32_t*)(dither4x4 + ((y & 3) << 2)), // NOLINT
1158 width); // NOLINT
1159 dst_rgb565 += dst_stride_rgb565;
1160 src_y += src_stride_y;
1161 if (y & 1) {
1162 src_u += src_stride_u;
1163 src_v += src_stride_v;
1164 }
1165 }
1166 free_aligned_buffer_64(row_argb);
1167 }
1168 return 0;
1169 }
1170
1171 // 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)1172 static int I420ToAR30Matrix(const uint8_t* src_y,
1173 int src_stride_y,
1174 const uint8_t* src_u,
1175 int src_stride_u,
1176 const uint8_t* src_v,
1177 int src_stride_v,
1178 uint8_t* dst_ar30,
1179 int dst_stride_ar30,
1180 const struct YuvConstants* yuvconstants,
1181 int width,
1182 int height) {
1183 int y;
1184 void (*I422ToAR30Row)(const uint8_t* y_buf, const uint8_t* u_buf,
1185 const uint8_t* v_buf, uint8_t* rgb_buf,
1186 const struct YuvConstants* yuvconstants, int width) =
1187 I422ToAR30Row_C;
1188
1189 if (!src_y || !src_u || !src_v || !dst_ar30 || width <= 0 || height == 0) {
1190 return -1;
1191 }
1192 // Negative height means invert the image.
1193 if (height < 0) {
1194 height = -height;
1195 dst_ar30 = dst_ar30 + (height - 1) * dst_stride_ar30;
1196 dst_stride_ar30 = -dst_stride_ar30;
1197 }
1198
1199 #if defined(HAS_I422TOAR30ROW_SSSE3)
1200 if (TestCpuFlag(kCpuHasSSSE3)) {
1201 I422ToAR30Row = I422ToAR30Row_Any_SSSE3;
1202 if (IS_ALIGNED(width, 8)) {
1203 I422ToAR30Row = I422ToAR30Row_SSSE3;
1204 }
1205 }
1206 #endif
1207 #if defined(HAS_I422TOAR30ROW_AVX2)
1208 if (TestCpuFlag(kCpuHasAVX2)) {
1209 I422ToAR30Row = I422ToAR30Row_Any_AVX2;
1210 if (IS_ALIGNED(width, 16)) {
1211 I422ToAR30Row = I422ToAR30Row_AVX2;
1212 }
1213 }
1214 #endif
1215
1216 for (y = 0; y < height; ++y) {
1217 I422ToAR30Row(src_y, src_u, src_v, dst_ar30, yuvconstants, width);
1218 dst_ar30 += dst_stride_ar30;
1219 src_y += src_stride_y;
1220 if (y & 1) {
1221 src_u += src_stride_u;
1222 src_v += src_stride_v;
1223 }
1224 }
1225 return 0;
1226 }
1227
1228 // Convert I420 to AR30.
1229 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)1230 int I420ToAR30(const uint8_t* src_y,
1231 int src_stride_y,
1232 const uint8_t* src_u,
1233 int src_stride_u,
1234 const uint8_t* src_v,
1235 int src_stride_v,
1236 uint8_t* dst_ar30,
1237 int dst_stride_ar30,
1238 int width,
1239 int height) {
1240 return I420ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1241 src_stride_v, dst_ar30, dst_stride_ar30,
1242 &kYuvI601Constants, width, height);
1243 }
1244
1245 // Convert H420 to AR30.
1246 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)1247 int H420ToAR30(const uint8_t* src_y,
1248 int src_stride_y,
1249 const uint8_t* src_u,
1250 int src_stride_u,
1251 const uint8_t* src_v,
1252 int src_stride_v,
1253 uint8_t* dst_ar30,
1254 int dst_stride_ar30,
1255 int width,
1256 int height) {
1257 return I420ToAR30Matrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1258 src_stride_v, dst_ar30, dst_stride_ar30,
1259 &kYvuH709Constants, width, height);
1260 }
1261
1262 // Convert I420 to specified format
1263 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)1264 int ConvertFromI420(const uint8_t* y,
1265 int y_stride,
1266 const uint8_t* u,
1267 int u_stride,
1268 const uint8_t* v,
1269 int v_stride,
1270 uint8_t* dst_sample,
1271 int dst_sample_stride,
1272 int width,
1273 int height,
1274 uint32_t fourcc) {
1275 uint32_t format = CanonicalFourCC(fourcc);
1276 int r = 0;
1277 if (!y || !u || !v || !dst_sample || width <= 0 || height == 0) {
1278 return -1;
1279 }
1280 switch (format) {
1281 // Single plane formats
1282 case FOURCC_YUY2:
1283 r = I420ToYUY2(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1284 dst_sample_stride ? dst_sample_stride : width * 2, width,
1285 height);
1286 break;
1287 case FOURCC_UYVY:
1288 r = I420ToUYVY(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1289 dst_sample_stride ? dst_sample_stride : width * 2, width,
1290 height);
1291 break;
1292 case FOURCC_RGBP:
1293 r = I420ToRGB565(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1294 dst_sample_stride ? dst_sample_stride : width * 2, width,
1295 height);
1296 break;
1297 case FOURCC_RGBO:
1298 r = I420ToARGB1555(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1299 dst_sample_stride ? dst_sample_stride : width * 2,
1300 width, height);
1301 break;
1302 case FOURCC_R444:
1303 r = I420ToARGB4444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1304 dst_sample_stride ? dst_sample_stride : width * 2,
1305 width, height);
1306 break;
1307 case FOURCC_24BG:
1308 r = I420ToRGB24(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1309 dst_sample_stride ? dst_sample_stride : width * 3, width,
1310 height);
1311 break;
1312 case FOURCC_RAW:
1313 r = I420ToRAW(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1314 dst_sample_stride ? dst_sample_stride : width * 3, width,
1315 height);
1316 break;
1317 case FOURCC_ARGB:
1318 r = I420ToARGB(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1319 dst_sample_stride ? dst_sample_stride : width * 4, width,
1320 height);
1321 break;
1322 case FOURCC_BGRA:
1323 r = I420ToBGRA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1324 dst_sample_stride ? dst_sample_stride : width * 4, width,
1325 height);
1326 break;
1327 case FOURCC_ABGR:
1328 r = I420ToABGR(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1329 dst_sample_stride ? dst_sample_stride : width * 4, width,
1330 height);
1331 break;
1332 case FOURCC_RGBA:
1333 r = I420ToRGBA(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1334 dst_sample_stride ? dst_sample_stride : width * 4, width,
1335 height);
1336 break;
1337 case FOURCC_AR30:
1338 r = I420ToAR30(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1339 dst_sample_stride ? dst_sample_stride : width * 4, width,
1340 height);
1341 break;
1342 case FOURCC_I400:
1343 r = I400Copy(y, y_stride, dst_sample,
1344 dst_sample_stride ? dst_sample_stride : width, width,
1345 height);
1346 break;
1347 case FOURCC_NV12: {
1348 uint8_t* dst_uv = dst_sample + width * height;
1349 r = I420ToNV12(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1350 dst_sample_stride ? dst_sample_stride : width, dst_uv,
1351 dst_sample_stride ? dst_sample_stride : width, width,
1352 height);
1353 break;
1354 }
1355 case FOURCC_NV21: {
1356 uint8_t* dst_vu = dst_sample + width * height;
1357 r = I420ToNV21(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1358 dst_sample_stride ? dst_sample_stride : width, dst_vu,
1359 dst_sample_stride ? dst_sample_stride : width, width,
1360 height);
1361 break;
1362 }
1363 // TODO(fbarchard): Add M420.
1364 // Triplanar formats
1365 case FOURCC_I420:
1366 case FOURCC_YV12: {
1367 dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1368 int halfstride = (dst_sample_stride + 1) / 2;
1369 int halfheight = (height + 1) / 2;
1370 uint8_t* dst_u;
1371 uint8_t* dst_v;
1372 if (format == FOURCC_YV12) {
1373 dst_v = dst_sample + dst_sample_stride * height;
1374 dst_u = dst_v + halfstride * halfheight;
1375 } else {
1376 dst_u = dst_sample + dst_sample_stride * height;
1377 dst_v = dst_u + halfstride * halfheight;
1378 }
1379 r = I420Copy(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1380 dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
1381 width, height);
1382 break;
1383 }
1384 case FOURCC_I422:
1385 case FOURCC_YV16: {
1386 dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1387 int halfstride = (dst_sample_stride + 1) / 2;
1388 uint8_t* dst_u;
1389 uint8_t* dst_v;
1390 if (format == FOURCC_YV16) {
1391 dst_v = dst_sample + dst_sample_stride * height;
1392 dst_u = dst_v + halfstride * height;
1393 } else {
1394 dst_u = dst_sample + dst_sample_stride * height;
1395 dst_v = dst_u + halfstride * height;
1396 }
1397 r = I420ToI422(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1398 dst_sample_stride, dst_u, halfstride, dst_v, halfstride,
1399 width, height);
1400 break;
1401 }
1402 case FOURCC_I444:
1403 case FOURCC_YV24: {
1404 dst_sample_stride = dst_sample_stride ? dst_sample_stride : width;
1405 uint8_t* dst_u;
1406 uint8_t* dst_v;
1407 if (format == FOURCC_YV24) {
1408 dst_v = dst_sample + dst_sample_stride * height;
1409 dst_u = dst_v + dst_sample_stride * height;
1410 } else {
1411 dst_u = dst_sample + dst_sample_stride * height;
1412 dst_v = dst_u + dst_sample_stride * height;
1413 }
1414 r = I420ToI444(y, y_stride, u, u_stride, v, v_stride, dst_sample,
1415 dst_sample_stride, dst_u, dst_sample_stride, dst_v,
1416 dst_sample_stride, width, height);
1417 break;
1418 }
1419 // Formats not supported - MJPG, biplanar, some rgb formats.
1420 default:
1421 return -1; // unknown fourcc - return failure code.
1422 }
1423 return r;
1424 }
1425
1426 #ifdef __cplusplus
1427 } // extern "C"
1428 } // namespace libyuv
1429 #endif
1430