|
1 /* |
|
2 * Copyright 2011 The LibYuv Project Authors. All rights reserved. |
|
3 * |
|
4 * Use of this source code is governed by a BSD-style license |
|
5 * that can be found in the LICENSE file in the root of the source |
|
6 * tree. An additional intellectual property rights grant can be found |
|
7 * in the file PATENTS. All contributing project authors may |
|
8 * be found in the AUTHORS file in the root of the source tree. |
|
9 */ |
|
10 |
|
11 #include "libyuv/convert_argb.h" |
|
12 |
|
13 #include "libyuv/cpu_id.h" |
|
14 #include "libyuv/format_conversion.h" |
|
15 #ifdef HAVE_JPEG |
|
16 #include "libyuv/mjpeg_decoder.h" |
|
17 #endif |
|
18 #include "libyuv/rotate_argb.h" |
|
19 #include "libyuv/row.h" |
|
20 #include "libyuv/video_common.h" |
|
21 |
|
22 #ifdef __cplusplus |
|
23 namespace libyuv { |
|
24 extern "C" { |
|
25 #endif |
|
26 |
|
27 // Copy ARGB with optional flipping |
|
28 LIBYUV_API |
|
29 int ARGBCopy(const uint8* src_argb, int src_stride_argb, |
|
30 uint8* dst_argb, int dst_stride_argb, |
|
31 int width, int height) { |
|
32 if (!src_argb || !dst_argb || |
|
33 width <= 0 || height == 0) { |
|
34 return -1; |
|
35 } |
|
36 // Negative height means invert the image. |
|
37 if (height < 0) { |
|
38 height = -height; |
|
39 src_argb = src_argb + (height - 1) * src_stride_argb; |
|
40 src_stride_argb = -src_stride_argb; |
|
41 } |
|
42 |
|
43 CopyPlane(src_argb, src_stride_argb, dst_argb, dst_stride_argb, |
|
44 width * 4, height); |
|
45 return 0; |
|
46 } |
|
47 |
|
48 // Convert I444 to ARGB. |
|
49 LIBYUV_API |
|
50 int I444ToARGB(const uint8* src_y, int src_stride_y, |
|
51 const uint8* src_u, int src_stride_u, |
|
52 const uint8* src_v, int src_stride_v, |
|
53 uint8* dst_argb, int dst_stride_argb, |
|
54 int width, int height) { |
|
55 if (!src_y || !src_u || !src_v || |
|
56 !dst_argb || |
|
57 width <= 0 || height == 0) { |
|
58 return -1; |
|
59 } |
|
60 // Negative height means invert the image. |
|
61 if (height < 0) { |
|
62 height = -height; |
|
63 dst_argb = dst_argb + (height - 1) * dst_stride_argb; |
|
64 dst_stride_argb = -dst_stride_argb; |
|
65 } |
|
66 // Coalesce rows. |
|
67 if (src_stride_y == width && |
|
68 src_stride_u == width && |
|
69 src_stride_v == width && |
|
70 dst_stride_argb == width * 4) { |
|
71 width *= height; |
|
72 height = 1; |
|
73 src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0; |
|
74 } |
|
75 void (*I444ToARGBRow)(const uint8* y_buf, |
|
76 const uint8* u_buf, |
|
77 const uint8* v_buf, |
|
78 uint8* rgb_buf, |
|
79 int width) = I444ToARGBRow_C; |
|
80 #if defined(HAS_I444TOARGBROW_SSSE3) |
|
81 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { |
|
82 I444ToARGBRow = I444ToARGBRow_Any_SSSE3; |
|
83 if (IS_ALIGNED(width, 8)) { |
|
84 I444ToARGBRow = I444ToARGBRow_Unaligned_SSSE3; |
|
85 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { |
|
86 I444ToARGBRow = I444ToARGBRow_SSSE3; |
|
87 } |
|
88 } |
|
89 } |
|
90 #elif defined(HAS_I444TOARGBROW_NEON) |
|
91 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { |
|
92 I444ToARGBRow = I444ToARGBRow_Any_NEON; |
|
93 if (IS_ALIGNED(width, 8)) { |
|
94 I444ToARGBRow = I444ToARGBRow_NEON; |
|
95 } |
|
96 } |
|
97 #endif |
|
98 |
|
99 for (int y = 0; y < height; ++y) { |
|
100 I444ToARGBRow(src_y, src_u, src_v, dst_argb, width); |
|
101 dst_argb += dst_stride_argb; |
|
102 src_y += src_stride_y; |
|
103 src_u += src_stride_u; |
|
104 src_v += src_stride_v; |
|
105 } |
|
106 return 0; |
|
107 } |
|
108 |
|
109 // Convert I422 to ARGB. |
|
110 LIBYUV_API |
|
111 int I422ToARGB(const uint8* src_y, int src_stride_y, |
|
112 const uint8* src_u, int src_stride_u, |
|
113 const uint8* src_v, int src_stride_v, |
|
114 uint8* dst_argb, int dst_stride_argb, |
|
115 int width, int height) { |
|
116 if (!src_y || !src_u || !src_v || |
|
117 !dst_argb || |
|
118 width <= 0 || height == 0) { |
|
119 return -1; |
|
120 } |
|
121 // Negative height means invert the image. |
|
122 if (height < 0) { |
|
123 height = -height; |
|
124 dst_argb = dst_argb + (height - 1) * dst_stride_argb; |
|
125 dst_stride_argb = -dst_stride_argb; |
|
126 } |
|
127 // Coalesce rows. |
|
128 if (src_stride_y == width && |
|
129 src_stride_u * 2 == width && |
|
130 src_stride_v * 2 == width && |
|
131 dst_stride_argb == width * 4) { |
|
132 width *= height; |
|
133 height = 1; |
|
134 src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0; |
|
135 } |
|
136 void (*I422ToARGBRow)(const uint8* y_buf, |
|
137 const uint8* u_buf, |
|
138 const uint8* v_buf, |
|
139 uint8* rgb_buf, |
|
140 int width) = I422ToARGBRow_C; |
|
141 #if defined(HAS_I422TOARGBROW_SSSE3) |
|
142 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { |
|
143 I422ToARGBRow = I422ToARGBRow_Any_SSSE3; |
|
144 if (IS_ALIGNED(width, 8)) { |
|
145 I422ToARGBRow = I422ToARGBRow_Unaligned_SSSE3; |
|
146 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { |
|
147 I422ToARGBRow = I422ToARGBRow_SSSE3; |
|
148 } |
|
149 } |
|
150 } |
|
151 #endif |
|
152 #if defined(HAS_I422TOARGBROW_AVX2) |
|
153 if (TestCpuFlag(kCpuHasAVX2) && width >= 16) { |
|
154 I422ToARGBRow = I422ToARGBRow_Any_AVX2; |
|
155 if (IS_ALIGNED(width, 16)) { |
|
156 I422ToARGBRow = I422ToARGBRow_AVX2; |
|
157 } |
|
158 } |
|
159 #endif |
|
160 #if defined(HAS_I422TOARGBROW_NEON) |
|
161 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { |
|
162 I422ToARGBRow = I422ToARGBRow_Any_NEON; |
|
163 if (IS_ALIGNED(width, 8)) { |
|
164 I422ToARGBRow = I422ToARGBRow_NEON; |
|
165 } |
|
166 } |
|
167 #endif |
|
168 #if defined(HAS_I422TOARGBROW_MIPS_DSPR2) |
|
169 if (TestCpuFlag(kCpuHasMIPS_DSPR2) && IS_ALIGNED(width, 4) && |
|
170 IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) && |
|
171 IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) && |
|
172 IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) && |
|
173 IS_ALIGNED(dst_argb, 4) && IS_ALIGNED(dst_stride_argb, 4)) { |
|
174 I422ToARGBRow = I422ToARGBRow_MIPS_DSPR2; |
|
175 } |
|
176 #endif |
|
177 |
|
178 for (int y = 0; y < height; ++y) { |
|
179 I422ToARGBRow(src_y, src_u, src_v, dst_argb, width); |
|
180 dst_argb += dst_stride_argb; |
|
181 src_y += src_stride_y; |
|
182 src_u += src_stride_u; |
|
183 src_v += src_stride_v; |
|
184 } |
|
185 return 0; |
|
186 } |
|
187 |
|
188 // Convert I411 to ARGB. |
|
189 LIBYUV_API |
|
190 int I411ToARGB(const uint8* src_y, int src_stride_y, |
|
191 const uint8* src_u, int src_stride_u, |
|
192 const uint8* src_v, int src_stride_v, |
|
193 uint8* dst_argb, int dst_stride_argb, |
|
194 int width, int height) { |
|
195 if (!src_y || !src_u || !src_v || |
|
196 !dst_argb || |
|
197 width <= 0 || height == 0) { |
|
198 return -1; |
|
199 } |
|
200 // Negative height means invert the image. |
|
201 if (height < 0) { |
|
202 height = -height; |
|
203 dst_argb = dst_argb + (height - 1) * dst_stride_argb; |
|
204 dst_stride_argb = -dst_stride_argb; |
|
205 } |
|
206 // Coalesce rows. |
|
207 if (src_stride_y == width && |
|
208 src_stride_u * 4 == width && |
|
209 src_stride_v * 4 == width && |
|
210 dst_stride_argb == width * 4) { |
|
211 width *= height; |
|
212 height = 1; |
|
213 src_stride_y = src_stride_u = src_stride_v = dst_stride_argb = 0; |
|
214 } |
|
215 void (*I411ToARGBRow)(const uint8* y_buf, |
|
216 const uint8* u_buf, |
|
217 const uint8* v_buf, |
|
218 uint8* rgb_buf, |
|
219 int width) = I411ToARGBRow_C; |
|
220 #if defined(HAS_I411TOARGBROW_SSSE3) |
|
221 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { |
|
222 I411ToARGBRow = I411ToARGBRow_Any_SSSE3; |
|
223 if (IS_ALIGNED(width, 8)) { |
|
224 I411ToARGBRow = I411ToARGBRow_Unaligned_SSSE3; |
|
225 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { |
|
226 I411ToARGBRow = I411ToARGBRow_SSSE3; |
|
227 } |
|
228 } |
|
229 } |
|
230 #elif defined(HAS_I411TOARGBROW_NEON) |
|
231 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { |
|
232 I411ToARGBRow = I411ToARGBRow_Any_NEON; |
|
233 if (IS_ALIGNED(width, 8)) { |
|
234 I411ToARGBRow = I411ToARGBRow_NEON; |
|
235 } |
|
236 } |
|
237 #endif |
|
238 |
|
239 for (int y = 0; y < height; ++y) { |
|
240 I411ToARGBRow(src_y, src_u, src_v, dst_argb, width); |
|
241 dst_argb += dst_stride_argb; |
|
242 src_y += src_stride_y; |
|
243 src_u += src_stride_u; |
|
244 src_v += src_stride_v; |
|
245 } |
|
246 return 0; |
|
247 } |
|
248 |
|
249 // Convert I400 to ARGB. |
|
250 LIBYUV_API |
|
251 int I400ToARGB_Reference(const uint8* src_y, int src_stride_y, |
|
252 uint8* dst_argb, int dst_stride_argb, |
|
253 int width, int height) { |
|
254 if (!src_y || !dst_argb || |
|
255 width <= 0 || height == 0) { |
|
256 return -1; |
|
257 } |
|
258 // Negative height means invert the image. |
|
259 if (height < 0) { |
|
260 height = -height; |
|
261 dst_argb = dst_argb + (height - 1) * dst_stride_argb; |
|
262 dst_stride_argb = -dst_stride_argb; |
|
263 } |
|
264 // Coalesce rows. |
|
265 if (src_stride_y == width && |
|
266 dst_stride_argb == width * 4) { |
|
267 width *= height; |
|
268 height = 1; |
|
269 src_stride_y = dst_stride_argb = 0; |
|
270 } |
|
271 void (*YToARGBRow)(const uint8* y_buf, |
|
272 uint8* rgb_buf, |
|
273 int width) = YToARGBRow_C; |
|
274 #if defined(HAS_YTOARGBROW_SSE2) |
|
275 if (TestCpuFlag(kCpuHasSSE2) && width >= 8 && |
|
276 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { |
|
277 YToARGBRow = YToARGBRow_Any_SSE2; |
|
278 if (IS_ALIGNED(width, 8)) { |
|
279 YToARGBRow = YToARGBRow_SSE2; |
|
280 } |
|
281 } |
|
282 #elif defined(HAS_YTOARGBROW_NEON) |
|
283 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { |
|
284 YToARGBRow = YToARGBRow_Any_NEON; |
|
285 if (IS_ALIGNED(width, 8)) { |
|
286 YToARGBRow = YToARGBRow_NEON; |
|
287 } |
|
288 } |
|
289 #endif |
|
290 |
|
291 for (int y = 0; y < height; ++y) { |
|
292 YToARGBRow(src_y, dst_argb, width); |
|
293 dst_argb += dst_stride_argb; |
|
294 src_y += src_stride_y; |
|
295 } |
|
296 return 0; |
|
297 } |
|
298 |
|
299 // Convert I400 to ARGB. |
|
300 LIBYUV_API |
|
301 int I400ToARGB(const uint8* src_y, int src_stride_y, |
|
302 uint8* dst_argb, int dst_stride_argb, |
|
303 int width, int height) { |
|
304 if (!src_y || !dst_argb || |
|
305 width <= 0 || height == 0) { |
|
306 return -1; |
|
307 } |
|
308 // Negative height means invert the image. |
|
309 if (height < 0) { |
|
310 height = -height; |
|
311 src_y = src_y + (height - 1) * src_stride_y; |
|
312 src_stride_y = -src_stride_y; |
|
313 } |
|
314 // Coalesce rows. |
|
315 if (src_stride_y == width && |
|
316 dst_stride_argb == width * 4) { |
|
317 width *= height; |
|
318 height = 1; |
|
319 src_stride_y = dst_stride_argb = 0; |
|
320 } |
|
321 void (*I400ToARGBRow)(const uint8* src_y, uint8* dst_argb, int pix) = |
|
322 I400ToARGBRow_C; |
|
323 #if defined(HAS_I400TOARGBROW_SSE2) |
|
324 if (TestCpuFlag(kCpuHasSSE2) && width >= 8) { |
|
325 I400ToARGBRow = I400ToARGBRow_Any_SSE2; |
|
326 if (IS_ALIGNED(width, 8)) { |
|
327 I400ToARGBRow = I400ToARGBRow_Unaligned_SSE2; |
|
328 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { |
|
329 I400ToARGBRow = I400ToARGBRow_SSE2; |
|
330 } |
|
331 } |
|
332 } |
|
333 #elif defined(HAS_I400TOARGBROW_NEON) |
|
334 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { |
|
335 I400ToARGBRow = I400ToARGBRow_Any_NEON; |
|
336 if (IS_ALIGNED(width, 8)) { |
|
337 I400ToARGBRow = I400ToARGBRow_NEON; |
|
338 } |
|
339 } |
|
340 #endif |
|
341 for (int y = 0; y < height; ++y) { |
|
342 I400ToARGBRow(src_y, dst_argb, width); |
|
343 src_y += src_stride_y; |
|
344 dst_argb += dst_stride_argb; |
|
345 } |
|
346 return 0; |
|
347 } |
|
348 |
|
349 // Shuffle table for converting BGRA to ARGB. |
|
350 static uvec8 kShuffleMaskBGRAToARGB = { |
|
351 3u, 2u, 1u, 0u, 7u, 6u, 5u, 4u, 11u, 10u, 9u, 8u, 15u, 14u, 13u, 12u |
|
352 }; |
|
353 |
|
354 // Shuffle table for converting ABGR to ARGB. |
|
355 static uvec8 kShuffleMaskABGRToARGB = { |
|
356 2u, 1u, 0u, 3u, 6u, 5u, 4u, 7u, 10u, 9u, 8u, 11u, 14u, 13u, 12u, 15u |
|
357 }; |
|
358 |
|
359 // Shuffle table for converting RGBA to ARGB. |
|
360 static uvec8 kShuffleMaskRGBAToARGB = { |
|
361 1u, 2u, 3u, 0u, 5u, 6u, 7u, 4u, 9u, 10u, 11u, 8u, 13u, 14u, 15u, 12u |
|
362 }; |
|
363 |
|
364 // Convert BGRA to ARGB. |
|
365 LIBYUV_API |
|
366 int BGRAToARGB(const uint8* src_bgra, int src_stride_bgra, |
|
367 uint8* dst_argb, int dst_stride_argb, |
|
368 int width, int height) { |
|
369 return ARGBShuffle(src_bgra, src_stride_bgra, |
|
370 dst_argb, dst_stride_argb, |
|
371 (const uint8*)(&kShuffleMaskBGRAToARGB), |
|
372 width, height); |
|
373 } |
|
374 |
|
375 // Convert ABGR to ARGB. |
|
376 LIBYUV_API |
|
377 int ABGRToARGB(const uint8* src_abgr, int src_stride_abgr, |
|
378 uint8* dst_argb, int dst_stride_argb, |
|
379 int width, int height) { |
|
380 return ARGBShuffle(src_abgr, src_stride_abgr, |
|
381 dst_argb, dst_stride_argb, |
|
382 (const uint8*)(&kShuffleMaskABGRToARGB), |
|
383 width, height); |
|
384 } |
|
385 |
|
386 // Convert RGBA to ARGB. |
|
387 LIBYUV_API |
|
388 int RGBAToARGB(const uint8* src_rgba, int src_stride_rgba, |
|
389 uint8* dst_argb, int dst_stride_argb, |
|
390 int width, int height) { |
|
391 return ARGBShuffle(src_rgba, src_stride_rgba, |
|
392 dst_argb, dst_stride_argb, |
|
393 (const uint8*)(&kShuffleMaskRGBAToARGB), |
|
394 width, height); |
|
395 } |
|
396 |
|
397 // Convert RGB24 to ARGB. |
|
398 LIBYUV_API |
|
399 int RGB24ToARGB(const uint8* src_rgb24, int src_stride_rgb24, |
|
400 uint8* dst_argb, int dst_stride_argb, |
|
401 int width, int height) { |
|
402 if (!src_rgb24 || !dst_argb || |
|
403 width <= 0 || height == 0) { |
|
404 return -1; |
|
405 } |
|
406 // Negative height means invert the image. |
|
407 if (height < 0) { |
|
408 height = -height; |
|
409 src_rgb24 = src_rgb24 + (height - 1) * src_stride_rgb24; |
|
410 src_stride_rgb24 = -src_stride_rgb24; |
|
411 } |
|
412 // Coalesce rows. |
|
413 if (src_stride_rgb24 == width * 3 && |
|
414 dst_stride_argb == width * 4) { |
|
415 width *= height; |
|
416 height = 1; |
|
417 src_stride_rgb24 = dst_stride_argb = 0; |
|
418 } |
|
419 void (*RGB24ToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = |
|
420 RGB24ToARGBRow_C; |
|
421 #if defined(HAS_RGB24TOARGBROW_SSSE3) |
|
422 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16 && |
|
423 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { |
|
424 RGB24ToARGBRow = RGB24ToARGBRow_Any_SSSE3; |
|
425 if (IS_ALIGNED(width, 16)) { |
|
426 RGB24ToARGBRow = RGB24ToARGBRow_SSSE3; |
|
427 } |
|
428 } |
|
429 #elif defined(HAS_RGB24TOARGBROW_NEON) |
|
430 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { |
|
431 RGB24ToARGBRow = RGB24ToARGBRow_Any_NEON; |
|
432 if (IS_ALIGNED(width, 8)) { |
|
433 RGB24ToARGBRow = RGB24ToARGBRow_NEON; |
|
434 } |
|
435 } |
|
436 #endif |
|
437 |
|
438 for (int y = 0; y < height; ++y) { |
|
439 RGB24ToARGBRow(src_rgb24, dst_argb, width); |
|
440 src_rgb24 += src_stride_rgb24; |
|
441 dst_argb += dst_stride_argb; |
|
442 } |
|
443 return 0; |
|
444 } |
|
445 |
|
446 // Convert RAW to ARGB. |
|
447 LIBYUV_API |
|
448 int RAWToARGB(const uint8* src_raw, int src_stride_raw, |
|
449 uint8* dst_argb, int dst_stride_argb, |
|
450 int width, int height) { |
|
451 if (!src_raw || !dst_argb || |
|
452 width <= 0 || height == 0) { |
|
453 return -1; |
|
454 } |
|
455 // Negative height means invert the image. |
|
456 if (height < 0) { |
|
457 height = -height; |
|
458 src_raw = src_raw + (height - 1) * src_stride_raw; |
|
459 src_stride_raw = -src_stride_raw; |
|
460 } |
|
461 // Coalesce rows. |
|
462 if (src_stride_raw == width * 3 && |
|
463 dst_stride_argb == width * 4) { |
|
464 width *= height; |
|
465 height = 1; |
|
466 src_stride_raw = dst_stride_argb = 0; |
|
467 } |
|
468 void (*RAWToARGBRow)(const uint8* src_rgb, uint8* dst_argb, int pix) = |
|
469 RAWToARGBRow_C; |
|
470 #if defined(HAS_RAWTOARGBROW_SSSE3) |
|
471 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16 && |
|
472 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { |
|
473 RAWToARGBRow = RAWToARGBRow_Any_SSSE3; |
|
474 if (IS_ALIGNED(width, 16)) { |
|
475 RAWToARGBRow = RAWToARGBRow_SSSE3; |
|
476 } |
|
477 } |
|
478 #elif defined(HAS_RAWTOARGBROW_NEON) |
|
479 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { |
|
480 RAWToARGBRow = RAWToARGBRow_Any_NEON; |
|
481 if (IS_ALIGNED(width, 8)) { |
|
482 RAWToARGBRow = RAWToARGBRow_NEON; |
|
483 } |
|
484 } |
|
485 #endif |
|
486 |
|
487 for (int y = 0; y < height; ++y) { |
|
488 RAWToARGBRow(src_raw, dst_argb, width); |
|
489 src_raw += src_stride_raw; |
|
490 dst_argb += dst_stride_argb; |
|
491 } |
|
492 return 0; |
|
493 } |
|
494 |
|
495 // Convert RGB565 to ARGB. |
|
496 LIBYUV_API |
|
497 int RGB565ToARGB(const uint8* src_rgb565, int src_stride_rgb565, |
|
498 uint8* dst_argb, int dst_stride_argb, |
|
499 int width, int height) { |
|
500 if (!src_rgb565 || !dst_argb || |
|
501 width <= 0 || height == 0) { |
|
502 return -1; |
|
503 } |
|
504 // Negative height means invert the image. |
|
505 if (height < 0) { |
|
506 height = -height; |
|
507 src_rgb565 = src_rgb565 + (height - 1) * src_stride_rgb565; |
|
508 src_stride_rgb565 = -src_stride_rgb565; |
|
509 } |
|
510 // Coalesce rows. |
|
511 if (src_stride_rgb565 == width * 2 && |
|
512 dst_stride_argb == width * 4) { |
|
513 width *= height; |
|
514 height = 1; |
|
515 src_stride_rgb565 = dst_stride_argb = 0; |
|
516 } |
|
517 void (*RGB565ToARGBRow)(const uint8* src_rgb565, uint8* dst_argb, int pix) = |
|
518 RGB565ToARGBRow_C; |
|
519 #if defined(HAS_RGB565TOARGBROW_SSE2) |
|
520 if (TestCpuFlag(kCpuHasSSE2) && width >= 8 && |
|
521 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { |
|
522 RGB565ToARGBRow = RGB565ToARGBRow_Any_SSE2; |
|
523 if (IS_ALIGNED(width, 8)) { |
|
524 RGB565ToARGBRow = RGB565ToARGBRow_SSE2; |
|
525 } |
|
526 } |
|
527 #elif defined(HAS_RGB565TOARGBROW_NEON) |
|
528 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { |
|
529 RGB565ToARGBRow = RGB565ToARGBRow_Any_NEON; |
|
530 if (IS_ALIGNED(width, 8)) { |
|
531 RGB565ToARGBRow = RGB565ToARGBRow_NEON; |
|
532 } |
|
533 } |
|
534 #endif |
|
535 |
|
536 for (int y = 0; y < height; ++y) { |
|
537 RGB565ToARGBRow(src_rgb565, dst_argb, width); |
|
538 src_rgb565 += src_stride_rgb565; |
|
539 dst_argb += dst_stride_argb; |
|
540 } |
|
541 return 0; |
|
542 } |
|
543 |
|
544 // Convert ARGB1555 to ARGB. |
|
545 LIBYUV_API |
|
546 int ARGB1555ToARGB(const uint8* src_argb1555, int src_stride_argb1555, |
|
547 uint8* dst_argb, int dst_stride_argb, |
|
548 int width, int height) { |
|
549 if (!src_argb1555 || !dst_argb || |
|
550 width <= 0 || height == 0) { |
|
551 return -1; |
|
552 } |
|
553 // Negative height means invert the image. |
|
554 if (height < 0) { |
|
555 height = -height; |
|
556 src_argb1555 = src_argb1555 + (height - 1) * src_stride_argb1555; |
|
557 src_stride_argb1555 = -src_stride_argb1555; |
|
558 } |
|
559 // Coalesce rows. |
|
560 if (src_stride_argb1555 == width * 2 && |
|
561 dst_stride_argb == width * 4) { |
|
562 width *= height; |
|
563 height = 1; |
|
564 src_stride_argb1555 = dst_stride_argb = 0; |
|
565 } |
|
566 void (*ARGB1555ToARGBRow)(const uint8* src_argb1555, uint8* dst_argb, |
|
567 int pix) = ARGB1555ToARGBRow_C; |
|
568 #if defined(HAS_ARGB1555TOARGBROW_SSE2) |
|
569 if (TestCpuFlag(kCpuHasSSE2) && width >= 8 && |
|
570 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { |
|
571 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_SSE2; |
|
572 if (IS_ALIGNED(width, 8)) { |
|
573 ARGB1555ToARGBRow = ARGB1555ToARGBRow_SSE2; |
|
574 } |
|
575 } |
|
576 #elif defined(HAS_ARGB1555TOARGBROW_NEON) |
|
577 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { |
|
578 ARGB1555ToARGBRow = ARGB1555ToARGBRow_Any_NEON; |
|
579 if (IS_ALIGNED(width, 8)) { |
|
580 ARGB1555ToARGBRow = ARGB1555ToARGBRow_NEON; |
|
581 } |
|
582 } |
|
583 #endif |
|
584 |
|
585 for (int y = 0; y < height; ++y) { |
|
586 ARGB1555ToARGBRow(src_argb1555, dst_argb, width); |
|
587 src_argb1555 += src_stride_argb1555; |
|
588 dst_argb += dst_stride_argb; |
|
589 } |
|
590 return 0; |
|
591 } |
|
592 |
|
593 // Convert ARGB4444 to ARGB. |
|
594 LIBYUV_API |
|
595 int ARGB4444ToARGB(const uint8* src_argb4444, int src_stride_argb4444, |
|
596 uint8* dst_argb, int dst_stride_argb, |
|
597 int width, int height) { |
|
598 if (!src_argb4444 || !dst_argb || |
|
599 width <= 0 || height == 0) { |
|
600 return -1; |
|
601 } |
|
602 // Negative height means invert the image. |
|
603 if (height < 0) { |
|
604 height = -height; |
|
605 src_argb4444 = src_argb4444 + (height - 1) * src_stride_argb4444; |
|
606 src_stride_argb4444 = -src_stride_argb4444; |
|
607 } |
|
608 // Coalesce rows. |
|
609 if (src_stride_argb4444 == width * 2 && |
|
610 dst_stride_argb == width * 4) { |
|
611 width *= height; |
|
612 height = 1; |
|
613 src_stride_argb4444 = dst_stride_argb = 0; |
|
614 } |
|
615 void (*ARGB4444ToARGBRow)(const uint8* src_argb4444, uint8* dst_argb, |
|
616 int pix) = ARGB4444ToARGBRow_C; |
|
617 #if defined(HAS_ARGB4444TOARGBROW_SSE2) |
|
618 if (TestCpuFlag(kCpuHasSSE2) && width >= 8 && |
|
619 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { |
|
620 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_SSE2; |
|
621 if (IS_ALIGNED(width, 8)) { |
|
622 ARGB4444ToARGBRow = ARGB4444ToARGBRow_SSE2; |
|
623 } |
|
624 } |
|
625 #elif defined(HAS_ARGB4444TOARGBROW_NEON) |
|
626 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { |
|
627 ARGB4444ToARGBRow = ARGB4444ToARGBRow_Any_NEON; |
|
628 if (IS_ALIGNED(width, 8)) { |
|
629 ARGB4444ToARGBRow = ARGB4444ToARGBRow_NEON; |
|
630 } |
|
631 } |
|
632 #endif |
|
633 |
|
634 for (int y = 0; y < height; ++y) { |
|
635 ARGB4444ToARGBRow(src_argb4444, dst_argb, width); |
|
636 src_argb4444 += src_stride_argb4444; |
|
637 dst_argb += dst_stride_argb; |
|
638 } |
|
639 return 0; |
|
640 } |
|
641 |
|
642 // Convert NV12 to ARGB. |
|
643 LIBYUV_API |
|
644 int NV12ToARGB(const uint8* src_y, int src_stride_y, |
|
645 const uint8* src_uv, int src_stride_uv, |
|
646 uint8* dst_argb, int dst_stride_argb, |
|
647 int width, int height) { |
|
648 if (!src_y || !src_uv || !dst_argb || |
|
649 width <= 0 || height == 0) { |
|
650 return -1; |
|
651 } |
|
652 // Negative height means invert the image. |
|
653 if (height < 0) { |
|
654 height = -height; |
|
655 dst_argb = dst_argb + (height - 1) * dst_stride_argb; |
|
656 dst_stride_argb = -dst_stride_argb; |
|
657 } |
|
658 void (*NV12ToARGBRow)(const uint8* y_buf, |
|
659 const uint8* uv_buf, |
|
660 uint8* rgb_buf, |
|
661 int width) = NV12ToARGBRow_C; |
|
662 #if defined(HAS_NV12TOARGBROW_SSSE3) |
|
663 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { |
|
664 NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3; |
|
665 if (IS_ALIGNED(width, 8)) { |
|
666 NV12ToARGBRow = NV12ToARGBRow_Unaligned_SSSE3; |
|
667 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { |
|
668 NV12ToARGBRow = NV12ToARGBRow_SSSE3; |
|
669 } |
|
670 } |
|
671 } |
|
672 #elif defined(HAS_NV12TOARGBROW_NEON) |
|
673 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { |
|
674 NV12ToARGBRow = NV12ToARGBRow_Any_NEON; |
|
675 if (IS_ALIGNED(width, 8)) { |
|
676 NV12ToARGBRow = NV12ToARGBRow_NEON; |
|
677 } |
|
678 } |
|
679 #endif |
|
680 |
|
681 for (int y = 0; y < height; ++y) { |
|
682 NV12ToARGBRow(src_y, src_uv, dst_argb, width); |
|
683 dst_argb += dst_stride_argb; |
|
684 src_y += src_stride_y; |
|
685 if (y & 1) { |
|
686 src_uv += src_stride_uv; |
|
687 } |
|
688 } |
|
689 return 0; |
|
690 } |
|
691 |
|
692 // Convert NV21 to ARGB. |
|
693 LIBYUV_API |
|
694 int NV21ToARGB(const uint8* src_y, int src_stride_y, |
|
695 const uint8* src_uv, int src_stride_uv, |
|
696 uint8* dst_argb, int dst_stride_argb, |
|
697 int width, int height) { |
|
698 if (!src_y || !src_uv || !dst_argb || |
|
699 width <= 0 || height == 0) { |
|
700 return -1; |
|
701 } |
|
702 // Negative height means invert the image. |
|
703 if (height < 0) { |
|
704 height = -height; |
|
705 dst_argb = dst_argb + (height - 1) * dst_stride_argb; |
|
706 dst_stride_argb = -dst_stride_argb; |
|
707 } |
|
708 void (*NV21ToARGBRow)(const uint8* y_buf, |
|
709 const uint8* uv_buf, |
|
710 uint8* rgb_buf, |
|
711 int width) = NV21ToARGBRow_C; |
|
712 #if defined(HAS_NV21TOARGBROW_SSSE3) |
|
713 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { |
|
714 NV21ToARGBRow = NV21ToARGBRow_Any_SSSE3; |
|
715 if (IS_ALIGNED(width, 8)) { |
|
716 NV21ToARGBRow = NV21ToARGBRow_Unaligned_SSSE3; |
|
717 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { |
|
718 NV21ToARGBRow = NV21ToARGBRow_SSSE3; |
|
719 } |
|
720 } |
|
721 } |
|
722 #endif |
|
723 #if defined(HAS_NV21TOARGBROW_NEON) |
|
724 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { |
|
725 NV21ToARGBRow = NV21ToARGBRow_Any_NEON; |
|
726 if (IS_ALIGNED(width, 8)) { |
|
727 NV21ToARGBRow = NV21ToARGBRow_NEON; |
|
728 } |
|
729 } |
|
730 #endif |
|
731 |
|
732 for (int y = 0; y < height; ++y) { |
|
733 NV21ToARGBRow(src_y, src_uv, dst_argb, width); |
|
734 dst_argb += dst_stride_argb; |
|
735 src_y += src_stride_y; |
|
736 if (y & 1) { |
|
737 src_uv += src_stride_uv; |
|
738 } |
|
739 } |
|
740 return 0; |
|
741 } |
|
742 |
|
743 // Convert M420 to ARGB. |
|
744 LIBYUV_API |
|
745 int M420ToARGB(const uint8* src_m420, int src_stride_m420, |
|
746 uint8* dst_argb, int dst_stride_argb, |
|
747 int width, int height) { |
|
748 if (!src_m420 || !dst_argb || |
|
749 width <= 0 || height == 0) { |
|
750 return -1; |
|
751 } |
|
752 // Negative height means invert the image. |
|
753 if (height < 0) { |
|
754 height = -height; |
|
755 dst_argb = dst_argb + (height - 1) * dst_stride_argb; |
|
756 dst_stride_argb = -dst_stride_argb; |
|
757 } |
|
758 void (*NV12ToARGBRow)(const uint8* y_buf, |
|
759 const uint8* uv_buf, |
|
760 uint8* rgb_buf, |
|
761 int width) = NV12ToARGBRow_C; |
|
762 #if defined(HAS_NV12TOARGBROW_SSSE3) |
|
763 if (TestCpuFlag(kCpuHasSSSE3) && width >= 8) { |
|
764 NV12ToARGBRow = NV12ToARGBRow_Any_SSSE3; |
|
765 if (IS_ALIGNED(width, 8)) { |
|
766 NV12ToARGBRow = NV12ToARGBRow_Unaligned_SSSE3; |
|
767 if (IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { |
|
768 NV12ToARGBRow = NV12ToARGBRow_SSSE3; |
|
769 } |
|
770 } |
|
771 } |
|
772 #elif defined(HAS_NV12TOARGBROW_NEON) |
|
773 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { |
|
774 NV12ToARGBRow = NV12ToARGBRow_Any_NEON; |
|
775 if (IS_ALIGNED(width, 8)) { |
|
776 NV12ToARGBRow = NV12ToARGBRow_NEON; |
|
777 } |
|
778 } |
|
779 #endif |
|
780 |
|
781 for (int y = 0; y < height - 1; y += 2) { |
|
782 NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, width); |
|
783 NV12ToARGBRow(src_m420 + src_stride_m420, src_m420 + src_stride_m420 * 2, |
|
784 dst_argb + dst_stride_argb, width); |
|
785 dst_argb += dst_stride_argb * 2; |
|
786 src_m420 += src_stride_m420 * 3; |
|
787 } |
|
788 if (height & 1) { |
|
789 NV12ToARGBRow(src_m420, src_m420 + src_stride_m420 * 2, dst_argb, width); |
|
790 } |
|
791 return 0; |
|
792 } |
|
793 |
|
794 // Convert YUY2 to ARGB. |
|
795 LIBYUV_API |
|
796 int YUY2ToARGB(const uint8* src_yuy2, int src_stride_yuy2, |
|
797 uint8* dst_argb, int dst_stride_argb, |
|
798 int width, int height) { |
|
799 if (!src_yuy2 || !dst_argb || |
|
800 width <= 0 || height == 0) { |
|
801 return -1; |
|
802 } |
|
803 // Negative height means invert the image. |
|
804 if (height < 0) { |
|
805 height = -height; |
|
806 src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2; |
|
807 src_stride_yuy2 = -src_stride_yuy2; |
|
808 } |
|
809 // Coalesce rows. |
|
810 if (src_stride_yuy2 == width * 2 && |
|
811 dst_stride_argb == width * 4) { |
|
812 width *= height; |
|
813 height = 1; |
|
814 src_stride_yuy2 = dst_stride_argb = 0; |
|
815 } |
|
816 void (*YUY2ToARGBRow)(const uint8* src_yuy2, uint8* dst_argb, int pix) = |
|
817 YUY2ToARGBRow_C; |
|
818 #if defined(HAS_YUY2TOARGBROW_SSSE3) |
|
819 // Posix is 16, Windows is 8. |
|
820 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { |
|
821 YUY2ToARGBRow = YUY2ToARGBRow_Any_SSSE3; |
|
822 if (IS_ALIGNED(width, 16)) { |
|
823 YUY2ToARGBRow = YUY2ToARGBRow_Unaligned_SSSE3; |
|
824 if (IS_ALIGNED(src_yuy2, 16) && IS_ALIGNED(src_stride_yuy2, 16) && |
|
825 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { |
|
826 YUY2ToARGBRow = YUY2ToARGBRow_SSSE3; |
|
827 } |
|
828 } |
|
829 } |
|
830 #elif defined(HAS_YUY2TOARGBROW_NEON) |
|
831 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { |
|
832 YUY2ToARGBRow = YUY2ToARGBRow_Any_NEON; |
|
833 if (IS_ALIGNED(width, 8)) { |
|
834 YUY2ToARGBRow = YUY2ToARGBRow_NEON; |
|
835 } |
|
836 } |
|
837 #endif |
|
838 for (int y = 0; y < height; ++y) { |
|
839 YUY2ToARGBRow(src_yuy2, dst_argb, width); |
|
840 src_yuy2 += src_stride_yuy2; |
|
841 dst_argb += dst_stride_argb; |
|
842 } |
|
843 return 0; |
|
844 } |
|
845 |
|
846 // Convert UYVY to ARGB. |
|
847 LIBYUV_API |
|
848 int UYVYToARGB(const uint8* src_uyvy, int src_stride_uyvy, |
|
849 uint8* dst_argb, int dst_stride_argb, |
|
850 int width, int height) { |
|
851 if (!src_uyvy || !dst_argb || |
|
852 width <= 0 || height == 0) { |
|
853 return -1; |
|
854 } |
|
855 // Negative height means invert the image. |
|
856 if (height < 0) { |
|
857 height = -height; |
|
858 src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy; |
|
859 src_stride_uyvy = -src_stride_uyvy; |
|
860 } |
|
861 // Coalesce rows. |
|
862 if (src_stride_uyvy == width * 2 && |
|
863 dst_stride_argb == width * 4) { |
|
864 width *= height; |
|
865 height = 1; |
|
866 src_stride_uyvy = dst_stride_argb = 0; |
|
867 } |
|
868 void (*UYVYToARGBRow)(const uint8* src_uyvy, uint8* dst_argb, int pix) = |
|
869 UYVYToARGBRow_C; |
|
870 #if defined(HAS_UYVYTOARGBROW_SSSE3) |
|
871 // Posix is 16, Windows is 8. |
|
872 if (TestCpuFlag(kCpuHasSSSE3) && width >= 16) { |
|
873 UYVYToARGBRow = UYVYToARGBRow_Any_SSSE3; |
|
874 if (IS_ALIGNED(width, 16)) { |
|
875 UYVYToARGBRow = UYVYToARGBRow_Unaligned_SSSE3; |
|
876 if (IS_ALIGNED(src_uyvy, 16) && IS_ALIGNED(src_stride_uyvy, 16) && |
|
877 IS_ALIGNED(dst_argb, 16) && IS_ALIGNED(dst_stride_argb, 16)) { |
|
878 UYVYToARGBRow = UYVYToARGBRow_SSSE3; |
|
879 } |
|
880 } |
|
881 } |
|
882 #elif defined(HAS_UYVYTOARGBROW_NEON) |
|
883 if (TestCpuFlag(kCpuHasNEON) && width >= 8) { |
|
884 UYVYToARGBRow = UYVYToARGBRow_Any_NEON; |
|
885 if (IS_ALIGNED(width, 8)) { |
|
886 UYVYToARGBRow = UYVYToARGBRow_NEON; |
|
887 } |
|
888 } |
|
889 #endif |
|
890 for (int y = 0; y < height; ++y) { |
|
891 UYVYToARGBRow(src_uyvy, dst_argb, width); |
|
892 src_uyvy += src_stride_uyvy; |
|
893 dst_argb += dst_stride_argb; |
|
894 } |
|
895 return 0; |
|
896 } |
|
897 |
|
898 #ifdef __cplusplus |
|
899 } // extern "C" |
|
900 } // namespace libyuv |
|
901 #endif |