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