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_argb.h"
12
13 #include "libyuv/basic_types.h"
14 #include "libyuv/cpu_id.h"
15 #include "libyuv/planar_functions.h"
16 #include "libyuv/row.h"
17
18 #ifdef __cplusplus
19 namespace libyuv {
20 extern "C" {
21 #endif
22
23 // ARGB little endian (bgra in memory) to I444
24 LIBYUV_API
ARGBToI444(const uint8 * src_argb,int src_stride_argb,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)25 int ARGBToI444(const uint8* src_argb, int src_stride_argb,
26 uint8* dst_y, int dst_stride_y,
27 uint8* dst_u, int dst_stride_u,
28 uint8* dst_v, int dst_stride_v,
29 int width, int height) {
30 int y;
31 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
32 ARGBToYRow_C;
33 void (*ARGBToUV444Row)(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
34 int width) = ARGBToUV444Row_C;
35 if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
36 return -1;
37 }
38 if (height < 0) {
39 height = -height;
40 src_argb = src_argb + (height - 1) * src_stride_argb;
41 src_stride_argb = -src_stride_argb;
42 }
43 // Coalesce rows.
44 if (src_stride_argb == width * 4 &&
45 dst_stride_y == width &&
46 dst_stride_u == width &&
47 dst_stride_v == width) {
48 width *= height;
49 height = 1;
50 src_stride_argb = dst_stride_y = dst_stride_u = dst_stride_v = 0;
51 }
52 #if defined(HAS_ARGBTOUV444ROW_SSSE3)
53 if (TestCpuFlag(kCpuHasSSSE3)) {
54 ARGBToUV444Row = ARGBToUV444Row_Any_SSSE3;
55 if (IS_ALIGNED(width, 16)) {
56 ARGBToUV444Row = ARGBToUV444Row_SSSE3;
57 }
58 }
59 #endif
60 #if defined(HAS_ARGBTOUV444ROW_NEON)
61 if (TestCpuFlag(kCpuHasNEON)) {
62 ARGBToUV444Row = ARGBToUV444Row_Any_NEON;
63 if (IS_ALIGNED(width, 8)) {
64 ARGBToUV444Row = ARGBToUV444Row_NEON;
65 }
66 }
67 #endif
68 #if defined(HAS_ARGBTOYROW_SSSE3)
69 if (TestCpuFlag(kCpuHasSSSE3)) {
70 ARGBToYRow = ARGBToYRow_Any_SSSE3;
71 if (IS_ALIGNED(width, 16)) {
72 ARGBToYRow = ARGBToYRow_SSSE3;
73 }
74 }
75 #endif
76 #if defined(HAS_ARGBTOYROW_AVX2)
77 if (TestCpuFlag(kCpuHasAVX2)) {
78 ARGBToYRow = ARGBToYRow_Any_AVX2;
79 if (IS_ALIGNED(width, 32)) {
80 ARGBToYRow = ARGBToYRow_AVX2;
81 }
82 }
83 #endif
84 #if defined(HAS_ARGBTOYROW_NEON)
85 if (TestCpuFlag(kCpuHasNEON)) {
86 ARGBToYRow = ARGBToYRow_Any_NEON;
87 if (IS_ALIGNED(width, 8)) {
88 ARGBToYRow = ARGBToYRow_NEON;
89 }
90 }
91 #endif
92
93 for (y = 0; y < height; ++y) {
94 ARGBToUV444Row(src_argb, dst_u, dst_v, width);
95 ARGBToYRow(src_argb, dst_y, width);
96 src_argb += src_stride_argb;
97 dst_y += dst_stride_y;
98 dst_u += dst_stride_u;
99 dst_v += dst_stride_v;
100 }
101 return 0;
102 }
103
104 // ARGB little endian (bgra in memory) to I422
105 LIBYUV_API
ARGBToI422(const uint8 * src_argb,int src_stride_argb,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)106 int ARGBToI422(const uint8* src_argb, int src_stride_argb,
107 uint8* dst_y, int dst_stride_y,
108 uint8* dst_u, int dst_stride_u,
109 uint8* dst_v, int dst_stride_v,
110 int width, int height) {
111 int y;
112 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
113 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
114 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
115 ARGBToYRow_C;
116 if (!src_argb ||
117 !dst_y || !dst_u || !dst_v ||
118 width <= 0 || height == 0) {
119 return -1;
120 }
121 // Negative height means invert the image.
122 if (height < 0) {
123 height = -height;
124 src_argb = src_argb + (height - 1) * src_stride_argb;
125 src_stride_argb = -src_stride_argb;
126 }
127 // Coalesce rows.
128 if (src_stride_argb == width * 4 &&
129 dst_stride_y == width &&
130 dst_stride_u * 2 == width &&
131 dst_stride_v * 2 == width) {
132 width *= height;
133 height = 1;
134 src_stride_argb = dst_stride_y = dst_stride_u = dst_stride_v = 0;
135 }
136 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
137 if (TestCpuFlag(kCpuHasSSSE3)) {
138 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
139 ARGBToYRow = ARGBToYRow_Any_SSSE3;
140 if (IS_ALIGNED(width, 16)) {
141 ARGBToUVRow = ARGBToUVRow_SSSE3;
142 ARGBToYRow = ARGBToYRow_SSSE3;
143 }
144 }
145 #endif
146 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
147 if (TestCpuFlag(kCpuHasAVX2)) {
148 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
149 ARGBToYRow = ARGBToYRow_Any_AVX2;
150 if (IS_ALIGNED(width, 32)) {
151 ARGBToUVRow = ARGBToUVRow_AVX2;
152 ARGBToYRow = ARGBToYRow_AVX2;
153 }
154 }
155 #endif
156 #if defined(HAS_ARGBTOYROW_NEON)
157 if (TestCpuFlag(kCpuHasNEON)) {
158 ARGBToYRow = ARGBToYRow_Any_NEON;
159 if (IS_ALIGNED(width, 8)) {
160 ARGBToYRow = ARGBToYRow_NEON;
161 }
162 }
163 #endif
164 #if defined(HAS_ARGBTOUVROW_NEON)
165 if (TestCpuFlag(kCpuHasNEON)) {
166 ARGBToUVRow = ARGBToUVRow_Any_NEON;
167 if (IS_ALIGNED(width, 16)) {
168 ARGBToUVRow = ARGBToUVRow_NEON;
169 }
170 }
171 #endif
172
173 for (y = 0; y < height; ++y) {
174 ARGBToUVRow(src_argb, 0, dst_u, dst_v, width);
175 ARGBToYRow(src_argb, dst_y, width);
176 src_argb += src_stride_argb;
177 dst_y += dst_stride_y;
178 dst_u += dst_stride_u;
179 dst_v += dst_stride_v;
180 }
181 return 0;
182 }
183
184 // ARGB little endian (bgra in memory) to I411
185 LIBYUV_API
ARGBToI411(const uint8 * src_argb,int src_stride_argb,uint8 * dst_y,int dst_stride_y,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)186 int ARGBToI411(const uint8* src_argb, int src_stride_argb,
187 uint8* dst_y, int dst_stride_y,
188 uint8* dst_u, int dst_stride_u,
189 uint8* dst_v, int dst_stride_v,
190 int width, int height) {
191 int y;
192 void (*ARGBToUV411Row)(const uint8* src_argb, uint8* dst_u, uint8* dst_v,
193 int width) = ARGBToUV411Row_C;
194 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
195 ARGBToYRow_C;
196 if (!src_argb || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
197 return -1;
198 }
199 if (height < 0) {
200 height = -height;
201 src_argb = src_argb + (height - 1) * src_stride_argb;
202 src_stride_argb = -src_stride_argb;
203 }
204 // Coalesce rows.
205 if (src_stride_argb == width * 4 &&
206 dst_stride_y == width &&
207 dst_stride_u * 4 == width &&
208 dst_stride_v * 4 == width) {
209 width *= height;
210 height = 1;
211 src_stride_argb = dst_stride_y = dst_stride_u = dst_stride_v = 0;
212 }
213 #if defined(HAS_ARGBTOYROW_SSSE3)
214 if (TestCpuFlag(kCpuHasSSSE3)) {
215 ARGBToYRow = ARGBToYRow_Any_SSSE3;
216 if (IS_ALIGNED(width, 16)) {
217 ARGBToYRow = ARGBToYRow_SSSE3;
218 }
219 }
220 #endif
221 #if defined(HAS_ARGBTOYROW_AVX2)
222 if (TestCpuFlag(kCpuHasAVX2)) {
223 ARGBToYRow = ARGBToYRow_Any_AVX2;
224 if (IS_ALIGNED(width, 32)) {
225 ARGBToYRow = ARGBToYRow_AVX2;
226 }
227 }
228 #endif
229 #if defined(HAS_ARGBTOYROW_NEON)
230 if (TestCpuFlag(kCpuHasNEON)) {
231 ARGBToYRow = ARGBToYRow_Any_NEON;
232 if (IS_ALIGNED(width, 8)) {
233 ARGBToYRow = ARGBToYRow_NEON;
234 }
235 }
236 #endif
237 #if defined(HAS_ARGBTOUV411ROW_NEON)
238 if (TestCpuFlag(kCpuHasNEON)) {
239 ARGBToUV411Row = ARGBToUV411Row_Any_NEON;
240 if (IS_ALIGNED(width, 32)) {
241 ARGBToUV411Row = ARGBToUV411Row_NEON;
242 }
243 }
244 #endif
245
246 for (y = 0; y < height; ++y) {
247 ARGBToUV411Row(src_argb, dst_u, dst_v, width);
248 ARGBToYRow(src_argb, dst_y, width);
249 src_argb += src_stride_argb;
250 dst_y += dst_stride_y;
251 dst_u += dst_stride_u;
252 dst_v += dst_stride_v;
253 }
254 return 0;
255 }
256
257 LIBYUV_API
ARGBToNV12(const uint8 * src_argb,int src_stride_argb,uint8 * dst_y,int dst_stride_y,uint8 * dst_uv,int dst_stride_uv,int width,int height)258 int ARGBToNV12(const uint8* src_argb, int src_stride_argb,
259 uint8* dst_y, int dst_stride_y,
260 uint8* dst_uv, int dst_stride_uv,
261 int width, int height) {
262 int y;
263 int halfwidth = (width + 1) >> 1;
264 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
265 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
266 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
267 ARGBToYRow_C;
268 void (*MergeUVRow_)(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
269 int width) = MergeUVRow_C;
270 if (!src_argb ||
271 !dst_y || !dst_uv ||
272 width <= 0 || height == 0) {
273 return -1;
274 }
275 // Negative height means invert the image.
276 if (height < 0) {
277 height = -height;
278 src_argb = src_argb + (height - 1) * src_stride_argb;
279 src_stride_argb = -src_stride_argb;
280 }
281 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
282 if (TestCpuFlag(kCpuHasSSSE3)) {
283 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
284 ARGBToYRow = ARGBToYRow_Any_SSSE3;
285 if (IS_ALIGNED(width, 16)) {
286 ARGBToUVRow = ARGBToUVRow_SSSE3;
287 ARGBToYRow = ARGBToYRow_SSSE3;
288 }
289 }
290 #endif
291 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
292 if (TestCpuFlag(kCpuHasAVX2)) {
293 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
294 ARGBToYRow = ARGBToYRow_Any_AVX2;
295 if (IS_ALIGNED(width, 32)) {
296 ARGBToUVRow = ARGBToUVRow_AVX2;
297 ARGBToYRow = ARGBToYRow_AVX2;
298 }
299 }
300 #endif
301 #if defined(HAS_ARGBTOYROW_NEON)
302 if (TestCpuFlag(kCpuHasNEON)) {
303 ARGBToYRow = ARGBToYRow_Any_NEON;
304 if (IS_ALIGNED(width, 8)) {
305 ARGBToYRow = ARGBToYRow_NEON;
306 }
307 }
308 #endif
309 #if defined(HAS_ARGBTOUVROW_NEON)
310 if (TestCpuFlag(kCpuHasNEON)) {
311 ARGBToUVRow = ARGBToUVRow_Any_NEON;
312 if (IS_ALIGNED(width, 16)) {
313 ARGBToUVRow = ARGBToUVRow_NEON;
314 }
315 }
316 #endif
317 #if defined(HAS_MERGEUVROW_SSE2)
318 if (TestCpuFlag(kCpuHasSSE2)) {
319 MergeUVRow_ = MergeUVRow_Any_SSE2;
320 if (IS_ALIGNED(halfwidth, 16)) {
321 MergeUVRow_ = MergeUVRow_SSE2;
322 }
323 }
324 #endif
325 #if defined(HAS_MERGEUVROW_AVX2)
326 if (TestCpuFlag(kCpuHasAVX2)) {
327 MergeUVRow_ = MergeUVRow_Any_AVX2;
328 if (IS_ALIGNED(halfwidth, 32)) {
329 MergeUVRow_ = MergeUVRow_AVX2;
330 }
331 }
332 #endif
333 #if defined(HAS_MERGEUVROW_NEON)
334 if (TestCpuFlag(kCpuHasNEON)) {
335 MergeUVRow_ = MergeUVRow_Any_NEON;
336 if (IS_ALIGNED(halfwidth, 16)) {
337 MergeUVRow_ = MergeUVRow_NEON;
338 }
339 }
340 #endif
341 {
342 // Allocate a rows of uv.
343 align_buffer_64(row_u, ((halfwidth + 31) & ~31) * 2);
344 uint8* row_v = row_u + ((halfwidth + 31) & ~31);
345
346 for (y = 0; y < height - 1; y += 2) {
347 ARGBToUVRow(src_argb, src_stride_argb, row_u, row_v, width);
348 MergeUVRow_(row_u, row_v, dst_uv, halfwidth);
349 ARGBToYRow(src_argb, dst_y, width);
350 ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
351 src_argb += src_stride_argb * 2;
352 dst_y += dst_stride_y * 2;
353 dst_uv += dst_stride_uv;
354 }
355 if (height & 1) {
356 ARGBToUVRow(src_argb, 0, row_u, row_v, width);
357 MergeUVRow_(row_u, row_v, dst_uv, halfwidth);
358 ARGBToYRow(src_argb, dst_y, width);
359 }
360 free_aligned_buffer_64(row_u);
361 }
362 return 0;
363 }
364
365 // Same as NV12 but U and V swapped.
366 LIBYUV_API
ARGBToNV21(const uint8 * src_argb,int src_stride_argb,uint8 * dst_y,int dst_stride_y,uint8 * dst_uv,int dst_stride_uv,int width,int height)367 int ARGBToNV21(const uint8* src_argb, int src_stride_argb,
368 uint8* dst_y, int dst_stride_y,
369 uint8* dst_uv, int dst_stride_uv,
370 int width, int height) {
371 int y;
372 int halfwidth = (width + 1) >> 1;
373 void (*ARGBToUVRow)(const uint8* src_argb0, int src_stride_argb,
374 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
375 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
376 ARGBToYRow_C;
377 void (*MergeUVRow_)(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
378 int width) = MergeUVRow_C;
379 if (!src_argb ||
380 !dst_y || !dst_uv ||
381 width <= 0 || height == 0) {
382 return -1;
383 }
384 // Negative height means invert the image.
385 if (height < 0) {
386 height = -height;
387 src_argb = src_argb + (height - 1) * src_stride_argb;
388 src_stride_argb = -src_stride_argb;
389 }
390 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
391 if (TestCpuFlag(kCpuHasSSSE3)) {
392 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
393 ARGBToYRow = ARGBToYRow_Any_SSSE3;
394 if (IS_ALIGNED(width, 16)) {
395 ARGBToUVRow = ARGBToUVRow_SSSE3;
396 ARGBToYRow = ARGBToYRow_SSSE3;
397 }
398 }
399 #endif
400 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
401 if (TestCpuFlag(kCpuHasAVX2)) {
402 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
403 ARGBToYRow = ARGBToYRow_Any_AVX2;
404 if (IS_ALIGNED(width, 32)) {
405 ARGBToUVRow = ARGBToUVRow_AVX2;
406 ARGBToYRow = ARGBToYRow_AVX2;
407 }
408 }
409 #endif
410 #if defined(HAS_ARGBTOYROW_NEON)
411 if (TestCpuFlag(kCpuHasNEON)) {
412 ARGBToYRow = ARGBToYRow_Any_NEON;
413 if (IS_ALIGNED(width, 8)) {
414 ARGBToYRow = ARGBToYRow_NEON;
415 }
416 }
417 #endif
418 #if defined(HAS_ARGBTOUVROW_NEON)
419 if (TestCpuFlag(kCpuHasNEON)) {
420 ARGBToUVRow = ARGBToUVRow_Any_NEON;
421 if (IS_ALIGNED(width, 16)) {
422 ARGBToUVRow = ARGBToUVRow_NEON;
423 }
424 }
425 #endif
426 #if defined(HAS_MERGEUVROW_SSE2)
427 if (TestCpuFlag(kCpuHasSSE2)) {
428 MergeUVRow_ = MergeUVRow_Any_SSE2;
429 if (IS_ALIGNED(halfwidth, 16)) {
430 MergeUVRow_ = MergeUVRow_SSE2;
431 }
432 }
433 #endif
434 #if defined(HAS_MERGEUVROW_AVX2)
435 if (TestCpuFlag(kCpuHasAVX2)) {
436 MergeUVRow_ = MergeUVRow_Any_AVX2;
437 if (IS_ALIGNED(halfwidth, 32)) {
438 MergeUVRow_ = MergeUVRow_AVX2;
439 }
440 }
441 #endif
442 #if defined(HAS_MERGEUVROW_NEON)
443 if (TestCpuFlag(kCpuHasNEON)) {
444 MergeUVRow_ = MergeUVRow_Any_NEON;
445 if (IS_ALIGNED(halfwidth, 16)) {
446 MergeUVRow_ = MergeUVRow_NEON;
447 }
448 }
449 #endif
450 {
451 // Allocate a rows of uv.
452 align_buffer_64(row_u, ((halfwidth + 31) & ~31) * 2);
453 uint8* row_v = row_u + ((halfwidth + 31) & ~31);
454
455 for (y = 0; y < height - 1; y += 2) {
456 ARGBToUVRow(src_argb, src_stride_argb, row_u, row_v, width);
457 MergeUVRow_(row_v, row_u, dst_uv, halfwidth);
458 ARGBToYRow(src_argb, dst_y, width);
459 ARGBToYRow(src_argb + src_stride_argb, dst_y + dst_stride_y, width);
460 src_argb += src_stride_argb * 2;
461 dst_y += dst_stride_y * 2;
462 dst_uv += dst_stride_uv;
463 }
464 if (height & 1) {
465 ARGBToUVRow(src_argb, 0, row_u, row_v, width);
466 MergeUVRow_(row_v, row_u, dst_uv, halfwidth);
467 ARGBToYRow(src_argb, dst_y, width);
468 }
469 free_aligned_buffer_64(row_u);
470 }
471 return 0;
472 }
473
474 // Convert ARGB to YUY2.
475 LIBYUV_API
ARGBToYUY2(const uint8 * src_argb,int src_stride_argb,uint8 * dst_yuy2,int dst_stride_yuy2,int width,int height)476 int ARGBToYUY2(const uint8* src_argb, int src_stride_argb,
477 uint8* dst_yuy2, int dst_stride_yuy2,
478 int width, int height) {
479 int y;
480 void (*ARGBToUVRow)(const uint8* src_argb, int src_stride_argb,
481 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
482 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
483 ARGBToYRow_C;
484 void (*I422ToYUY2Row)(const uint8* src_y, const uint8* src_u,
485 const uint8* src_v, uint8* dst_yuy2, int width) = I422ToYUY2Row_C;
486
487 if (!src_argb || !dst_yuy2 ||
488 width <= 0 || height == 0) {
489 return -1;
490 }
491 // Negative height means invert the image.
492 if (height < 0) {
493 height = -height;
494 dst_yuy2 = dst_yuy2 + (height - 1) * dst_stride_yuy2;
495 dst_stride_yuy2 = -dst_stride_yuy2;
496 }
497 // Coalesce rows.
498 if (src_stride_argb == width * 4 &&
499 dst_stride_yuy2 == width * 2) {
500 width *= height;
501 height = 1;
502 src_stride_argb = dst_stride_yuy2 = 0;
503 }
504 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
505 if (TestCpuFlag(kCpuHasSSSE3)) {
506 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
507 ARGBToYRow = ARGBToYRow_Any_SSSE3;
508 if (IS_ALIGNED(width, 16)) {
509 ARGBToUVRow = ARGBToUVRow_SSSE3;
510 ARGBToYRow = ARGBToYRow_SSSE3;
511 }
512 }
513 #endif
514 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
515 if (TestCpuFlag(kCpuHasAVX2)) {
516 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
517 ARGBToYRow = ARGBToYRow_Any_AVX2;
518 if (IS_ALIGNED(width, 32)) {
519 ARGBToUVRow = ARGBToUVRow_AVX2;
520 ARGBToYRow = ARGBToYRow_AVX2;
521 }
522 }
523 #endif
524 #if defined(HAS_ARGBTOYROW_NEON)
525 if (TestCpuFlag(kCpuHasNEON)) {
526 ARGBToYRow = ARGBToYRow_Any_NEON;
527 if (IS_ALIGNED(width, 8)) {
528 ARGBToYRow = ARGBToYRow_NEON;
529 }
530 }
531 #endif
532 #if defined(HAS_ARGBTOUVROW_NEON)
533 if (TestCpuFlag(kCpuHasNEON)) {
534 ARGBToUVRow = ARGBToUVRow_Any_NEON;
535 if (IS_ALIGNED(width, 16)) {
536 ARGBToUVRow = ARGBToUVRow_NEON;
537 }
538 }
539 #endif
540 #if defined(HAS_I422TOYUY2ROW_SSE2)
541 if (TestCpuFlag(kCpuHasSSE2)) {
542 I422ToYUY2Row = I422ToYUY2Row_Any_SSE2;
543 if (IS_ALIGNED(width, 16)) {
544 I422ToYUY2Row = I422ToYUY2Row_SSE2;
545 }
546 }
547 #endif
548 #if defined(HAS_I422TOYUY2ROW_NEON)
549 if (TestCpuFlag(kCpuHasNEON)) {
550 I422ToYUY2Row = I422ToYUY2Row_Any_NEON;
551 if (IS_ALIGNED(width, 16)) {
552 I422ToYUY2Row = I422ToYUY2Row_NEON;
553 }
554 }
555 #endif
556
557 {
558 // Allocate a rows of yuv.
559 align_buffer_64(row_y, ((width + 63) & ~63) * 2);
560 uint8* row_u = row_y + ((width + 63) & ~63);
561 uint8* row_v = row_u + ((width + 63) & ~63) / 2;
562
563 for (y = 0; y < height; ++y) {
564 ARGBToUVRow(src_argb, 0, row_u, row_v, width);
565 ARGBToYRow(src_argb, row_y, width);
566 I422ToYUY2Row(row_y, row_u, row_v, dst_yuy2, width);
567 src_argb += src_stride_argb;
568 dst_yuy2 += dst_stride_yuy2;
569 }
570
571 free_aligned_buffer_64(row_y);
572 }
573 return 0;
574 }
575
576 // Convert ARGB to UYVY.
577 LIBYUV_API
ARGBToUYVY(const uint8 * src_argb,int src_stride_argb,uint8 * dst_uyvy,int dst_stride_uyvy,int width,int height)578 int ARGBToUYVY(const uint8* src_argb, int src_stride_argb,
579 uint8* dst_uyvy, int dst_stride_uyvy,
580 int width, int height) {
581 int y;
582 void (*ARGBToUVRow)(const uint8* src_argb, int src_stride_argb,
583 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVRow_C;
584 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
585 ARGBToYRow_C;
586 void (*I422ToUYVYRow)(const uint8* src_y, const uint8* src_u,
587 const uint8* src_v, uint8* dst_uyvy, int width) = I422ToUYVYRow_C;
588
589 if (!src_argb || !dst_uyvy ||
590 width <= 0 || height == 0) {
591 return -1;
592 }
593 // Negative height means invert the image.
594 if (height < 0) {
595 height = -height;
596 dst_uyvy = dst_uyvy + (height - 1) * dst_stride_uyvy;
597 dst_stride_uyvy = -dst_stride_uyvy;
598 }
599 // Coalesce rows.
600 if (src_stride_argb == width * 4 &&
601 dst_stride_uyvy == width * 2) {
602 width *= height;
603 height = 1;
604 src_stride_argb = dst_stride_uyvy = 0;
605 }
606 #if defined(HAS_ARGBTOYROW_SSSE3) && defined(HAS_ARGBTOUVROW_SSSE3)
607 if (TestCpuFlag(kCpuHasSSSE3)) {
608 ARGBToUVRow = ARGBToUVRow_Any_SSSE3;
609 ARGBToYRow = ARGBToYRow_Any_SSSE3;
610 if (IS_ALIGNED(width, 16)) {
611 ARGBToUVRow = ARGBToUVRow_SSSE3;
612 ARGBToYRow = ARGBToYRow_SSSE3;
613 }
614 }
615 #endif
616 #if defined(HAS_ARGBTOYROW_AVX2) && defined(HAS_ARGBTOUVROW_AVX2)
617 if (TestCpuFlag(kCpuHasAVX2)) {
618 ARGBToUVRow = ARGBToUVRow_Any_AVX2;
619 ARGBToYRow = ARGBToYRow_Any_AVX2;
620 if (IS_ALIGNED(width, 32)) {
621 ARGBToUVRow = ARGBToUVRow_AVX2;
622 ARGBToYRow = ARGBToYRow_AVX2;
623 }
624 }
625 #endif
626 #if defined(HAS_ARGBTOYROW_NEON)
627 if (TestCpuFlag(kCpuHasNEON)) {
628 ARGBToYRow = ARGBToYRow_Any_NEON;
629 if (IS_ALIGNED(width, 8)) {
630 ARGBToYRow = ARGBToYRow_NEON;
631 }
632 }
633 #endif
634 #if defined(HAS_ARGBTOUVROW_NEON)
635 if (TestCpuFlag(kCpuHasNEON)) {
636 ARGBToUVRow = ARGBToUVRow_Any_NEON;
637 if (IS_ALIGNED(width, 16)) {
638 ARGBToUVRow = ARGBToUVRow_NEON;
639 }
640 }
641 #endif
642 #if defined(HAS_I422TOUYVYROW_SSE2)
643 if (TestCpuFlag(kCpuHasSSE2)) {
644 I422ToUYVYRow = I422ToUYVYRow_Any_SSE2;
645 if (IS_ALIGNED(width, 16)) {
646 I422ToUYVYRow = I422ToUYVYRow_SSE2;
647 }
648 }
649 #endif
650 #if defined(HAS_I422TOUYVYROW_NEON)
651 if (TestCpuFlag(kCpuHasNEON)) {
652 I422ToUYVYRow = I422ToUYVYRow_Any_NEON;
653 if (IS_ALIGNED(width, 16)) {
654 I422ToUYVYRow = I422ToUYVYRow_NEON;
655 }
656 }
657 #endif
658
659 {
660 // Allocate a rows of yuv.
661 align_buffer_64(row_y, ((width + 63) & ~63) * 2);
662 uint8* row_u = row_y + ((width + 63) & ~63);
663 uint8* row_v = row_u + ((width + 63) & ~63) / 2;
664
665 for (y = 0; y < height; ++y) {
666 ARGBToUVRow(src_argb, 0, row_u, row_v, width);
667 ARGBToYRow(src_argb, row_y, width);
668 I422ToUYVYRow(row_y, row_u, row_v, dst_uyvy, width);
669 src_argb += src_stride_argb;
670 dst_uyvy += dst_stride_uyvy;
671 }
672
673 free_aligned_buffer_64(row_y);
674 }
675 return 0;
676 }
677
678 // Convert ARGB to I400.
679 LIBYUV_API
ARGBToI400(const uint8 * src_argb,int src_stride_argb,uint8 * dst_y,int dst_stride_y,int width,int height)680 int ARGBToI400(const uint8* src_argb, int src_stride_argb,
681 uint8* dst_y, int dst_stride_y,
682 int width, int height) {
683 int y;
684 void (*ARGBToYRow)(const uint8* src_argb, uint8* dst_y, int width) =
685 ARGBToYRow_C;
686 if (!src_argb || !dst_y || width <= 0 || height == 0) {
687 return -1;
688 }
689 if (height < 0) {
690 height = -height;
691 src_argb = src_argb + (height - 1) * src_stride_argb;
692 src_stride_argb = -src_stride_argb;
693 }
694 // Coalesce rows.
695 if (src_stride_argb == width * 4 &&
696 dst_stride_y == width) {
697 width *= height;
698 height = 1;
699 src_stride_argb = dst_stride_y = 0;
700 }
701 #if defined(HAS_ARGBTOYROW_SSSE3)
702 if (TestCpuFlag(kCpuHasSSSE3)) {
703 ARGBToYRow = ARGBToYRow_Any_SSSE3;
704 if (IS_ALIGNED(width, 16)) {
705 ARGBToYRow = ARGBToYRow_SSSE3;
706 }
707 }
708 #endif
709 #if defined(HAS_ARGBTOYROW_AVX2)
710 if (TestCpuFlag(kCpuHasAVX2)) {
711 ARGBToYRow = ARGBToYRow_Any_AVX2;
712 if (IS_ALIGNED(width, 32)) {
713 ARGBToYRow = ARGBToYRow_AVX2;
714 }
715 }
716 #endif
717 #if defined(HAS_ARGBTOYROW_NEON)
718 if (TestCpuFlag(kCpuHasNEON)) {
719 ARGBToYRow = ARGBToYRow_Any_NEON;
720 if (IS_ALIGNED(width, 8)) {
721 ARGBToYRow = ARGBToYRow_NEON;
722 }
723 }
724 #endif
725
726 for (y = 0; y < height; ++y) {
727 ARGBToYRow(src_argb, dst_y, width);
728 src_argb += src_stride_argb;
729 dst_y += dst_stride_y;
730 }
731 return 0;
732 }
733
734 // Shuffle table for converting ARGB to RGBA.
735 static uvec8 kShuffleMaskARGBToRGBA = {
736 3u, 0u, 1u, 2u, 7u, 4u, 5u, 6u, 11u, 8u, 9u, 10u, 15u, 12u, 13u, 14u
737 };
738
739 // Convert ARGB to RGBA.
740 LIBYUV_API
ARGBToRGBA(const uint8 * src_argb,int src_stride_argb,uint8 * dst_rgba,int dst_stride_rgba,int width,int height)741 int ARGBToRGBA(const uint8* src_argb, int src_stride_argb,
742 uint8* dst_rgba, int dst_stride_rgba,
743 int width, int height) {
744 return ARGBShuffle(src_argb, src_stride_argb,
745 dst_rgba, dst_stride_rgba,
746 (const uint8*)(&kShuffleMaskARGBToRGBA),
747 width, height);
748 }
749
750 // Convert ARGB To RGB24.
751 LIBYUV_API
ARGBToRGB24(const uint8 * src_argb,int src_stride_argb,uint8 * dst_rgb24,int dst_stride_rgb24,int width,int height)752 int ARGBToRGB24(const uint8* src_argb, int src_stride_argb,
753 uint8* dst_rgb24, int dst_stride_rgb24,
754 int width, int height) {
755 int y;
756 void (*ARGBToRGB24Row)(const uint8* src_argb, uint8* dst_rgb, int width) =
757 ARGBToRGB24Row_C;
758 if (!src_argb || !dst_rgb24 || width <= 0 || height == 0) {
759 return -1;
760 }
761 if (height < 0) {
762 height = -height;
763 src_argb = src_argb + (height - 1) * src_stride_argb;
764 src_stride_argb = -src_stride_argb;
765 }
766 // Coalesce rows.
767 if (src_stride_argb == width * 4 &&
768 dst_stride_rgb24 == width * 3) {
769 width *= height;
770 height = 1;
771 src_stride_argb = dst_stride_rgb24 = 0;
772 }
773 #if defined(HAS_ARGBTORGB24ROW_SSSE3)
774 if (TestCpuFlag(kCpuHasSSSE3)) {
775 ARGBToRGB24Row = ARGBToRGB24Row_Any_SSSE3;
776 if (IS_ALIGNED(width, 16)) {
777 ARGBToRGB24Row = ARGBToRGB24Row_SSSE3;
778 }
779 }
780 #endif
781 #if defined(HAS_ARGBTORGB24ROW_NEON)
782 if (TestCpuFlag(kCpuHasNEON)) {
783 ARGBToRGB24Row = ARGBToRGB24Row_Any_NEON;
784 if (IS_ALIGNED(width, 8)) {
785 ARGBToRGB24Row = ARGBToRGB24Row_NEON;
786 }
787 }
788 #endif
789
790 for (y = 0; y < height; ++y) {
791 ARGBToRGB24Row(src_argb, dst_rgb24, width);
792 src_argb += src_stride_argb;
793 dst_rgb24 += dst_stride_rgb24;
794 }
795 return 0;
796 }
797
798 // Convert ARGB To RAW.
799 LIBYUV_API
ARGBToRAW(const uint8 * src_argb,int src_stride_argb,uint8 * dst_raw,int dst_stride_raw,int width,int height)800 int ARGBToRAW(const uint8* src_argb, int src_stride_argb,
801 uint8* dst_raw, int dst_stride_raw,
802 int width, int height) {
803 int y;
804 void (*ARGBToRAWRow)(const uint8* src_argb, uint8* dst_rgb, int width) =
805 ARGBToRAWRow_C;
806 if (!src_argb || !dst_raw || width <= 0 || height == 0) {
807 return -1;
808 }
809 if (height < 0) {
810 height = -height;
811 src_argb = src_argb + (height - 1) * src_stride_argb;
812 src_stride_argb = -src_stride_argb;
813 }
814 // Coalesce rows.
815 if (src_stride_argb == width * 4 &&
816 dst_stride_raw == width * 3) {
817 width *= height;
818 height = 1;
819 src_stride_argb = dst_stride_raw = 0;
820 }
821 #if defined(HAS_ARGBTORAWROW_SSSE3)
822 if (TestCpuFlag(kCpuHasSSSE3)) {
823 ARGBToRAWRow = ARGBToRAWRow_Any_SSSE3;
824 if (IS_ALIGNED(width, 16)) {
825 ARGBToRAWRow = ARGBToRAWRow_SSSE3;
826 }
827 }
828 #endif
829 #if defined(HAS_ARGBTORAWROW_NEON)
830 if (TestCpuFlag(kCpuHasNEON)) {
831 ARGBToRAWRow = ARGBToRAWRow_Any_NEON;
832 if (IS_ALIGNED(width, 8)) {
833 ARGBToRAWRow = ARGBToRAWRow_NEON;
834 }
835 }
836 #endif
837
838 for (y = 0; y < height; ++y) {
839 ARGBToRAWRow(src_argb, dst_raw, width);
840 src_argb += src_stride_argb;
841 dst_raw += dst_stride_raw;
842 }
843 return 0;
844 }
845
846 // Ordered 8x8 dither for 888 to 565. Values from 0 to 7.
847 static const uint8 kDither565_4x4[16] = {
848 0, 4, 1, 5,
849 6, 2, 7, 3,
850 1, 5, 0, 4,
851 7, 3, 6, 2,
852 };
853
854 // Convert ARGB To RGB565 with 4x4 dither matrix (16 bytes).
855 LIBYUV_API
ARGBToRGB565Dither(const uint8 * src_argb,int src_stride_argb,uint8 * dst_rgb565,int dst_stride_rgb565,const uint8 * dither4x4,int width,int height)856 int ARGBToRGB565Dither(const uint8* src_argb, int src_stride_argb,
857 uint8* dst_rgb565, int dst_stride_rgb565,
858 const uint8* dither4x4, int width, int height) {
859 int y;
860 void (*ARGBToRGB565DitherRow)(const uint8* src_argb, uint8* dst_rgb,
861 const uint32 dither4, int width) = ARGBToRGB565DitherRow_C;
862 if (!src_argb || !dst_rgb565 || width <= 0 || height == 0) {
863 return -1;
864 }
865 if (height < 0) {
866 height = -height;
867 src_argb = src_argb + (height - 1) * src_stride_argb;
868 src_stride_argb = -src_stride_argb;
869 }
870 if (!dither4x4) {
871 dither4x4 = kDither565_4x4;
872 }
873 #if defined(HAS_ARGBTORGB565DITHERROW_SSE2)
874 if (TestCpuFlag(kCpuHasSSE2)) {
875 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_SSE2;
876 if (IS_ALIGNED(width, 4)) {
877 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_SSE2;
878 }
879 }
880 #endif
881 #if defined(HAS_ARGBTORGB565DITHERROW_AVX2)
882 if (TestCpuFlag(kCpuHasAVX2)) {
883 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_AVX2;
884 if (IS_ALIGNED(width, 8)) {
885 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_AVX2;
886 }
887 }
888 #endif
889 #if defined(HAS_ARGBTORGB565DITHERROW_NEON)
890 if (TestCpuFlag(kCpuHasNEON)) {
891 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_Any_NEON;
892 if (IS_ALIGNED(width, 8)) {
893 ARGBToRGB565DitherRow = ARGBToRGB565DitherRow_NEON;
894 }
895 }
896 #endif
897 for (y = 0; y < height; ++y) {
898 ARGBToRGB565DitherRow(src_argb, dst_rgb565,
899 *(uint32*)(dither4x4 + ((y & 3) << 2)), width);
900 src_argb += src_stride_argb;
901 dst_rgb565 += dst_stride_rgb565;
902 }
903 return 0;
904 }
905
906 // Convert ARGB To RGB565.
907 // TODO(fbarchard): Consider using dither function low level with zeros.
908 LIBYUV_API
ARGBToRGB565(const uint8 * src_argb,int src_stride_argb,uint8 * dst_rgb565,int dst_stride_rgb565,int width,int height)909 int ARGBToRGB565(const uint8* src_argb, int src_stride_argb,
910 uint8* dst_rgb565, int dst_stride_rgb565,
911 int width, int height) {
912 int y;
913 void (*ARGBToRGB565Row)(const uint8* src_argb, uint8* dst_rgb, int width) =
914 ARGBToRGB565Row_C;
915 if (!src_argb || !dst_rgb565 || width <= 0 || height == 0) {
916 return -1;
917 }
918 if (height < 0) {
919 height = -height;
920 src_argb = src_argb + (height - 1) * src_stride_argb;
921 src_stride_argb = -src_stride_argb;
922 }
923 // Coalesce rows.
924 if (src_stride_argb == width * 4 &&
925 dst_stride_rgb565 == width * 2) {
926 width *= height;
927 height = 1;
928 src_stride_argb = dst_stride_rgb565 = 0;
929 }
930 #if defined(HAS_ARGBTORGB565ROW_SSE2)
931 if (TestCpuFlag(kCpuHasSSE2)) {
932 ARGBToRGB565Row = ARGBToRGB565Row_Any_SSE2;
933 if (IS_ALIGNED(width, 4)) {
934 ARGBToRGB565Row = ARGBToRGB565Row_SSE2;
935 }
936 }
937 #endif
938 #if defined(HAS_ARGBTORGB565ROW_AVX2)
939 if (TestCpuFlag(kCpuHasAVX2)) {
940 ARGBToRGB565Row = ARGBToRGB565Row_Any_AVX2;
941 if (IS_ALIGNED(width, 8)) {
942 ARGBToRGB565Row = ARGBToRGB565Row_AVX2;
943 }
944 }
945 #endif
946 #if defined(HAS_ARGBTORGB565ROW_NEON)
947 if (TestCpuFlag(kCpuHasNEON)) {
948 ARGBToRGB565Row = ARGBToRGB565Row_Any_NEON;
949 if (IS_ALIGNED(width, 8)) {
950 ARGBToRGB565Row = ARGBToRGB565Row_NEON;
951 }
952 }
953 #endif
954
955 for (y = 0; y < height; ++y) {
956 ARGBToRGB565Row(src_argb, dst_rgb565, width);
957 src_argb += src_stride_argb;
958 dst_rgb565 += dst_stride_rgb565;
959 }
960 return 0;
961 }
962
963 // Convert ARGB To ARGB1555.
964 LIBYUV_API
ARGBToARGB1555(const uint8 * src_argb,int src_stride_argb,uint8 * dst_argb1555,int dst_stride_argb1555,int width,int height)965 int ARGBToARGB1555(const uint8* src_argb, int src_stride_argb,
966 uint8* dst_argb1555, int dst_stride_argb1555,
967 int width, int height) {
968 int y;
969 void (*ARGBToARGB1555Row)(const uint8* src_argb, uint8* dst_rgb, int width) =
970 ARGBToARGB1555Row_C;
971 if (!src_argb || !dst_argb1555 || width <= 0 || height == 0) {
972 return -1;
973 }
974 if (height < 0) {
975 height = -height;
976 src_argb = src_argb + (height - 1) * src_stride_argb;
977 src_stride_argb = -src_stride_argb;
978 }
979 // Coalesce rows.
980 if (src_stride_argb == width * 4 &&
981 dst_stride_argb1555 == width * 2) {
982 width *= height;
983 height = 1;
984 src_stride_argb = dst_stride_argb1555 = 0;
985 }
986 #if defined(HAS_ARGBTOARGB1555ROW_SSE2)
987 if (TestCpuFlag(kCpuHasSSE2)) {
988 ARGBToARGB1555Row = ARGBToARGB1555Row_Any_SSE2;
989 if (IS_ALIGNED(width, 4)) {
990 ARGBToARGB1555Row = ARGBToARGB1555Row_SSE2;
991 }
992 }
993 #endif
994 #if defined(HAS_ARGBTOARGB1555ROW_AVX2)
995 if (TestCpuFlag(kCpuHasAVX2)) {
996 ARGBToARGB1555Row = ARGBToARGB1555Row_Any_AVX2;
997 if (IS_ALIGNED(width, 8)) {
998 ARGBToARGB1555Row = ARGBToARGB1555Row_AVX2;
999 }
1000 }
1001 #endif
1002 #if defined(HAS_ARGBTOARGB1555ROW_NEON)
1003 if (TestCpuFlag(kCpuHasNEON)) {
1004 ARGBToARGB1555Row = ARGBToARGB1555Row_Any_NEON;
1005 if (IS_ALIGNED(width, 8)) {
1006 ARGBToARGB1555Row = ARGBToARGB1555Row_NEON;
1007 }
1008 }
1009 #endif
1010
1011 for (y = 0; y < height; ++y) {
1012 ARGBToARGB1555Row(src_argb, dst_argb1555, width);
1013 src_argb += src_stride_argb;
1014 dst_argb1555 += dst_stride_argb1555;
1015 }
1016 return 0;
1017 }
1018
1019 // Convert ARGB To ARGB4444.
1020 LIBYUV_API
ARGBToARGB4444(const uint8 * src_argb,int src_stride_argb,uint8 * dst_argb4444,int dst_stride_argb4444,int width,int height)1021 int ARGBToARGB4444(const uint8* src_argb, int src_stride_argb,
1022 uint8* dst_argb4444, int dst_stride_argb4444,
1023 int width, int height) {
1024 int y;
1025 void (*ARGBToARGB4444Row)(const uint8* src_argb, uint8* dst_rgb, int width) =
1026 ARGBToARGB4444Row_C;
1027 if (!src_argb || !dst_argb4444 || width <= 0 || height == 0) {
1028 return -1;
1029 }
1030 if (height < 0) {
1031 height = -height;
1032 src_argb = src_argb + (height - 1) * src_stride_argb;
1033 src_stride_argb = -src_stride_argb;
1034 }
1035 // Coalesce rows.
1036 if (src_stride_argb == width * 4 &&
1037 dst_stride_argb4444 == width * 2) {
1038 width *= height;
1039 height = 1;
1040 src_stride_argb = dst_stride_argb4444 = 0;
1041 }
1042 #if defined(HAS_ARGBTOARGB4444ROW_SSE2)
1043 if (TestCpuFlag(kCpuHasSSE2)) {
1044 ARGBToARGB4444Row = ARGBToARGB4444Row_Any_SSE2;
1045 if (IS_ALIGNED(width, 4)) {
1046 ARGBToARGB4444Row = ARGBToARGB4444Row_SSE2;
1047 }
1048 }
1049 #endif
1050 #if defined(HAS_ARGBTOARGB4444ROW_AVX2)
1051 if (TestCpuFlag(kCpuHasAVX2)) {
1052 ARGBToARGB4444Row = ARGBToARGB4444Row_Any_AVX2;
1053 if (IS_ALIGNED(width, 8)) {
1054 ARGBToARGB4444Row = ARGBToARGB4444Row_AVX2;
1055 }
1056 }
1057 #endif
1058 #if defined(HAS_ARGBTOARGB4444ROW_NEON)
1059 if (TestCpuFlag(kCpuHasNEON)) {
1060 ARGBToARGB4444Row = ARGBToARGB4444Row_Any_NEON;
1061 if (IS_ALIGNED(width, 8)) {
1062 ARGBToARGB4444Row = ARGBToARGB4444Row_NEON;
1063 }
1064 }
1065 #endif
1066
1067 for (y = 0; y < height; ++y) {
1068 ARGBToARGB4444Row(src_argb, dst_argb4444, width);
1069 src_argb += src_stride_argb;
1070 dst_argb4444 += dst_stride_argb4444;
1071 }
1072 return 0;
1073 }
1074
1075 // Convert ARGB to J420. (JPeg full range I420).
1076 LIBYUV_API
ARGBToJ420(const uint8 * src_argb,int src_stride_argb,uint8 * dst_yj,int dst_stride_yj,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)1077 int ARGBToJ420(const uint8* src_argb, int src_stride_argb,
1078 uint8* dst_yj, int dst_stride_yj,
1079 uint8* dst_u, int dst_stride_u,
1080 uint8* dst_v, int dst_stride_v,
1081 int width, int height) {
1082 int y;
1083 void (*ARGBToUVJRow)(const uint8* src_argb0, int src_stride_argb,
1084 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVJRow_C;
1085 void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_yj, int width) =
1086 ARGBToYJRow_C;
1087 if (!src_argb ||
1088 !dst_yj || !dst_u || !dst_v ||
1089 width <= 0 || height == 0) {
1090 return -1;
1091 }
1092 // Negative height means invert the image.
1093 if (height < 0) {
1094 height = -height;
1095 src_argb = src_argb + (height - 1) * src_stride_argb;
1096 src_stride_argb = -src_stride_argb;
1097 }
1098 #if defined(HAS_ARGBTOYJROW_SSSE3) && defined(HAS_ARGBTOUVJROW_SSSE3)
1099 if (TestCpuFlag(kCpuHasSSSE3)) {
1100 ARGBToUVJRow = ARGBToUVJRow_Any_SSSE3;
1101 ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
1102 if (IS_ALIGNED(width, 16)) {
1103 ARGBToUVJRow = ARGBToUVJRow_SSSE3;
1104 ARGBToYJRow = ARGBToYJRow_SSSE3;
1105 }
1106 }
1107 #endif
1108 #if defined(HAS_ARGBTOYJROW_AVX2)
1109 if (TestCpuFlag(kCpuHasAVX2)) {
1110 ARGBToYJRow = ARGBToYJRow_Any_AVX2;
1111 if (IS_ALIGNED(width, 32)) {
1112 ARGBToYJRow = ARGBToYJRow_AVX2;
1113 }
1114 }
1115 #endif
1116 #if defined(HAS_ARGBTOYJROW_NEON)
1117 if (TestCpuFlag(kCpuHasNEON)) {
1118 ARGBToYJRow = ARGBToYJRow_Any_NEON;
1119 if (IS_ALIGNED(width, 8)) {
1120 ARGBToYJRow = ARGBToYJRow_NEON;
1121 }
1122 }
1123 #endif
1124 #if defined(HAS_ARGBTOUVJROW_NEON)
1125 if (TestCpuFlag(kCpuHasNEON)) {
1126 ARGBToUVJRow = ARGBToUVJRow_Any_NEON;
1127 if (IS_ALIGNED(width, 16)) {
1128 ARGBToUVJRow = ARGBToUVJRow_NEON;
1129 }
1130 }
1131 #endif
1132
1133 for (y = 0; y < height - 1; y += 2) {
1134 ARGBToUVJRow(src_argb, src_stride_argb, dst_u, dst_v, width);
1135 ARGBToYJRow(src_argb, dst_yj, width);
1136 ARGBToYJRow(src_argb + src_stride_argb, dst_yj + dst_stride_yj, width);
1137 src_argb += src_stride_argb * 2;
1138 dst_yj += dst_stride_yj * 2;
1139 dst_u += dst_stride_u;
1140 dst_v += dst_stride_v;
1141 }
1142 if (height & 1) {
1143 ARGBToUVJRow(src_argb, 0, dst_u, dst_v, width);
1144 ARGBToYJRow(src_argb, dst_yj, width);
1145 }
1146 return 0;
1147 }
1148
1149 // Convert ARGB to J422. (JPeg full range I422).
1150 LIBYUV_API
ARGBToJ422(const uint8 * src_argb,int src_stride_argb,uint8 * dst_yj,int dst_stride_yj,uint8 * dst_u,int dst_stride_u,uint8 * dst_v,int dst_stride_v,int width,int height)1151 int ARGBToJ422(const uint8* src_argb, int src_stride_argb,
1152 uint8* dst_yj, int dst_stride_yj,
1153 uint8* dst_u, int dst_stride_u,
1154 uint8* dst_v, int dst_stride_v,
1155 int width, int height) {
1156 int y;
1157 void (*ARGBToUVJRow)(const uint8* src_argb0, int src_stride_argb,
1158 uint8* dst_u, uint8* dst_v, int width) = ARGBToUVJRow_C;
1159 void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_yj, int width) =
1160 ARGBToYJRow_C;
1161 if (!src_argb ||
1162 !dst_yj || !dst_u || !dst_v ||
1163 width <= 0 || height == 0) {
1164 return -1;
1165 }
1166 // Negative height means invert the image.
1167 if (height < 0) {
1168 height = -height;
1169 src_argb = src_argb + (height - 1) * src_stride_argb;
1170 src_stride_argb = -src_stride_argb;
1171 }
1172 // Coalesce rows.
1173 if (src_stride_argb == width * 4 &&
1174 dst_stride_yj == width &&
1175 dst_stride_u * 2 == width &&
1176 dst_stride_v * 2 == width) {
1177 width *= height;
1178 height = 1;
1179 src_stride_argb = dst_stride_yj = dst_stride_u = dst_stride_v = 0;
1180 }
1181 #if defined(HAS_ARGBTOYJROW_SSSE3) && defined(HAS_ARGBTOUVJROW_SSSE3)
1182 if (TestCpuFlag(kCpuHasSSSE3)) {
1183 ARGBToUVJRow = ARGBToUVJRow_Any_SSSE3;
1184 ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
1185 if (IS_ALIGNED(width, 16)) {
1186 ARGBToUVJRow = ARGBToUVJRow_SSSE3;
1187 ARGBToYJRow = ARGBToYJRow_SSSE3;
1188 }
1189 }
1190 #endif
1191 #if defined(HAS_ARGBTOYJROW_AVX2)
1192 if (TestCpuFlag(kCpuHasAVX2)) {
1193 ARGBToYJRow = ARGBToYJRow_Any_AVX2;
1194 if (IS_ALIGNED(width, 32)) {
1195 ARGBToYJRow = ARGBToYJRow_AVX2;
1196 }
1197 }
1198 #endif
1199 #if defined(HAS_ARGBTOYJROW_NEON)
1200 if (TestCpuFlag(kCpuHasNEON)) {
1201 ARGBToYJRow = ARGBToYJRow_Any_NEON;
1202 if (IS_ALIGNED(width, 8)) {
1203 ARGBToYJRow = ARGBToYJRow_NEON;
1204 }
1205 }
1206 #endif
1207 #if defined(HAS_ARGBTOUVJROW_NEON)
1208 if (TestCpuFlag(kCpuHasNEON)) {
1209 ARGBToUVJRow = ARGBToUVJRow_Any_NEON;
1210 if (IS_ALIGNED(width, 16)) {
1211 ARGBToUVJRow = ARGBToUVJRow_NEON;
1212 }
1213 }
1214 #endif
1215
1216 for (y = 0; y < height; ++y) {
1217 ARGBToUVJRow(src_argb, 0, dst_u, dst_v, width);
1218 ARGBToYJRow(src_argb, dst_yj, width);
1219 src_argb += src_stride_argb;
1220 dst_yj += dst_stride_yj;
1221 dst_u += dst_stride_u;
1222 dst_v += dst_stride_v;
1223 }
1224 return 0;
1225 }
1226
1227 // Convert ARGB to J400.
1228 LIBYUV_API
ARGBToJ400(const uint8 * src_argb,int src_stride_argb,uint8 * dst_yj,int dst_stride_yj,int width,int height)1229 int ARGBToJ400(const uint8* src_argb, int src_stride_argb,
1230 uint8* dst_yj, int dst_stride_yj,
1231 int width, int height) {
1232 int y;
1233 void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_yj, int width) =
1234 ARGBToYJRow_C;
1235 if (!src_argb || !dst_yj || width <= 0 || height == 0) {
1236 return -1;
1237 }
1238 if (height < 0) {
1239 height = -height;
1240 src_argb = src_argb + (height - 1) * src_stride_argb;
1241 src_stride_argb = -src_stride_argb;
1242 }
1243 // Coalesce rows.
1244 if (src_stride_argb == width * 4 &&
1245 dst_stride_yj == width) {
1246 width *= height;
1247 height = 1;
1248 src_stride_argb = dst_stride_yj = 0;
1249 }
1250 #if defined(HAS_ARGBTOYJROW_SSSE3)
1251 if (TestCpuFlag(kCpuHasSSSE3)) {
1252 ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
1253 if (IS_ALIGNED(width, 16)) {
1254 ARGBToYJRow = ARGBToYJRow_SSSE3;
1255 }
1256 }
1257 #endif
1258 #if defined(HAS_ARGBTOYJROW_AVX2)
1259 if (TestCpuFlag(kCpuHasAVX2)) {
1260 ARGBToYJRow = ARGBToYJRow_Any_AVX2;
1261 if (IS_ALIGNED(width, 32)) {
1262 ARGBToYJRow = ARGBToYJRow_AVX2;
1263 }
1264 }
1265 #endif
1266 #if defined(HAS_ARGBTOYJROW_NEON)
1267 if (TestCpuFlag(kCpuHasNEON)) {
1268 ARGBToYJRow = ARGBToYJRow_Any_NEON;
1269 if (IS_ALIGNED(width, 8)) {
1270 ARGBToYJRow = ARGBToYJRow_NEON;
1271 }
1272 }
1273 #endif
1274
1275 for (y = 0; y < height; ++y) {
1276 ARGBToYJRow(src_argb, dst_yj, width);
1277 src_argb += src_stride_argb;
1278 dst_yj += dst_stride_yj;
1279 }
1280 return 0;
1281 }
1282
1283 #ifdef __cplusplus
1284 } // extern "C"
1285 } // namespace libyuv
1286 #endif
1287