Line data Source code
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/planar_functions.h"
12 :
13 : #include <string.h> // for memset()
14 :
15 : #include "libyuv/cpu_id.h"
16 : #ifdef HAVE_JPEG
17 : #include "libyuv/mjpeg_decoder.h"
18 : #endif
19 : #include "libyuv/row.h"
20 : #include "libyuv/scale_row.h" // for ScaleRowDown2
21 :
22 : #ifdef __cplusplus
23 : namespace libyuv {
24 : extern "C" {
25 : #endif
26 :
27 : // Copy a plane of data
28 : LIBYUV_API
29 0 : void CopyPlane(const uint8* src_y,
30 : int src_stride_y,
31 : uint8* dst_y,
32 : int dst_stride_y,
33 : int width,
34 : int height) {
35 : int y;
36 0 : void (*CopyRow)(const uint8* src, uint8* dst, int width) = CopyRow_C;
37 : // Negative height means invert the image.
38 0 : if (height < 0) {
39 0 : height = -height;
40 0 : dst_y = dst_y + (height - 1) * dst_stride_y;
41 0 : dst_stride_y = -dst_stride_y;
42 : }
43 : // Coalesce rows.
44 0 : if (src_stride_y == width && dst_stride_y == width) {
45 0 : width *= height;
46 0 : height = 1;
47 0 : src_stride_y = dst_stride_y = 0;
48 : }
49 : // Nothing to do.
50 0 : if (src_y == dst_y && src_stride_y == dst_stride_y) {
51 0 : return;
52 : }
53 : #if defined(HAS_COPYROW_SSE2)
54 0 : if (TestCpuFlag(kCpuHasSSE2)) {
55 0 : CopyRow = IS_ALIGNED(width, 32) ? CopyRow_SSE2 : CopyRow_Any_SSE2;
56 : }
57 : #endif
58 : #if defined(HAS_COPYROW_AVX)
59 0 : if (TestCpuFlag(kCpuHasAVX)) {
60 0 : CopyRow = IS_ALIGNED(width, 64) ? CopyRow_AVX : CopyRow_Any_AVX;
61 : }
62 : #endif
63 : #if defined(HAS_COPYROW_ERMS)
64 0 : if (TestCpuFlag(kCpuHasERMS)) {
65 0 : CopyRow = CopyRow_ERMS;
66 : }
67 : #endif
68 : #if defined(HAS_COPYROW_NEON)
69 : if (TestCpuFlag(kCpuHasNEON)) {
70 : CopyRow = IS_ALIGNED(width, 32) ? CopyRow_NEON : CopyRow_Any_NEON;
71 : }
72 : #endif
73 : #if defined(HAS_COPYROW_MIPS)
74 : if (TestCpuFlag(kCpuHasMIPS)) {
75 : CopyRow = CopyRow_MIPS;
76 : }
77 : #endif
78 :
79 : // Copy plane
80 0 : for (y = 0; y < height; ++y) {
81 0 : CopyRow(src_y, dst_y, width);
82 0 : src_y += src_stride_y;
83 0 : dst_y += dst_stride_y;
84 : }
85 : }
86 :
87 : // TODO(fbarchard): Consider support for negative height.
88 : // TODO(fbarchard): Consider stride measured in bytes.
89 : LIBYUV_API
90 0 : void CopyPlane_16(const uint16* src_y,
91 : int src_stride_y,
92 : uint16* dst_y,
93 : int dst_stride_y,
94 : int width,
95 : int height) {
96 : int y;
97 0 : void (*CopyRow)(const uint16* src, uint16* dst, int width) = CopyRow_16_C;
98 : // Coalesce rows.
99 0 : if (src_stride_y == width && dst_stride_y == width) {
100 0 : width *= height;
101 0 : height = 1;
102 0 : src_stride_y = dst_stride_y = 0;
103 : }
104 : #if defined(HAS_COPYROW_16_SSE2)
105 : if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 32)) {
106 : CopyRow = CopyRow_16_SSE2;
107 : }
108 : #endif
109 : #if defined(HAS_COPYROW_16_ERMS)
110 : if (TestCpuFlag(kCpuHasERMS)) {
111 : CopyRow = CopyRow_16_ERMS;
112 : }
113 : #endif
114 : #if defined(HAS_COPYROW_16_NEON)
115 : if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 32)) {
116 : CopyRow = CopyRow_16_NEON;
117 : }
118 : #endif
119 : #if defined(HAS_COPYROW_16_MIPS)
120 : if (TestCpuFlag(kCpuHasMIPS)) {
121 : CopyRow = CopyRow_16_MIPS;
122 : }
123 : #endif
124 :
125 : // Copy plane
126 0 : for (y = 0; y < height; ++y) {
127 0 : CopyRow(src_y, dst_y, width);
128 0 : src_y += src_stride_y;
129 0 : dst_y += dst_stride_y;
130 : }
131 0 : }
132 :
133 : // Copy I422.
134 : LIBYUV_API
135 0 : int I422Copy(const uint8* src_y,
136 : int src_stride_y,
137 : const uint8* src_u,
138 : int src_stride_u,
139 : const uint8* src_v,
140 : int src_stride_v,
141 : uint8* dst_y,
142 : int dst_stride_y,
143 : uint8* dst_u,
144 : int dst_stride_u,
145 : uint8* dst_v,
146 : int dst_stride_v,
147 : int width,
148 : int height) {
149 0 : int halfwidth = (width + 1) >> 1;
150 0 : if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
151 0 : return -1;
152 : }
153 : // Negative height means invert the image.
154 0 : if (height < 0) {
155 0 : height = -height;
156 0 : src_y = src_y + (height - 1) * src_stride_y;
157 0 : src_u = src_u + (height - 1) * src_stride_u;
158 0 : src_v = src_v + (height - 1) * src_stride_v;
159 0 : src_stride_y = -src_stride_y;
160 0 : src_stride_u = -src_stride_u;
161 0 : src_stride_v = -src_stride_v;
162 : }
163 :
164 0 : if (dst_y) {
165 0 : CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
166 : }
167 0 : CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, height);
168 0 : CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, height);
169 0 : return 0;
170 : }
171 :
172 : // Copy I444.
173 : LIBYUV_API
174 0 : int I444Copy(const uint8* src_y,
175 : int src_stride_y,
176 : const uint8* src_u,
177 : int src_stride_u,
178 : const uint8* src_v,
179 : int src_stride_v,
180 : uint8* dst_y,
181 : int dst_stride_y,
182 : uint8* dst_u,
183 : int dst_stride_u,
184 : uint8* dst_v,
185 : int dst_stride_v,
186 : int width,
187 : int height) {
188 0 : if (!src_u || !src_v || !dst_u || !dst_v || width <= 0 || height == 0) {
189 0 : return -1;
190 : }
191 : // Negative height means invert the image.
192 0 : if (height < 0) {
193 0 : height = -height;
194 0 : src_y = src_y + (height - 1) * src_stride_y;
195 0 : src_u = src_u + (height - 1) * src_stride_u;
196 0 : src_v = src_v + (height - 1) * src_stride_v;
197 0 : src_stride_y = -src_stride_y;
198 0 : src_stride_u = -src_stride_u;
199 0 : src_stride_v = -src_stride_v;
200 : }
201 :
202 0 : if (dst_y) {
203 0 : CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
204 : }
205 0 : CopyPlane(src_u, src_stride_u, dst_u, dst_stride_u, width, height);
206 0 : CopyPlane(src_v, src_stride_v, dst_v, dst_stride_v, width, height);
207 0 : return 0;
208 : }
209 :
210 : // Copy I400.
211 : LIBYUV_API
212 0 : int I400ToI400(const uint8* src_y,
213 : int src_stride_y,
214 : uint8* dst_y,
215 : int dst_stride_y,
216 : int width,
217 : int height) {
218 0 : if (!src_y || !dst_y || width <= 0 || height == 0) {
219 0 : return -1;
220 : }
221 : // Negative height means invert the image.
222 0 : if (height < 0) {
223 0 : height = -height;
224 0 : src_y = src_y + (height - 1) * src_stride_y;
225 0 : src_stride_y = -src_stride_y;
226 : }
227 0 : CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
228 0 : return 0;
229 : }
230 :
231 : // Convert I420 to I400.
232 : LIBYUV_API
233 0 : int I420ToI400(const uint8* src_y,
234 : int src_stride_y,
235 : const uint8* src_u,
236 : int src_stride_u,
237 : const uint8* src_v,
238 : int src_stride_v,
239 : uint8* dst_y,
240 : int dst_stride_y,
241 : int width,
242 : int height) {
243 : (void)src_u;
244 : (void)src_stride_u;
245 : (void)src_v;
246 : (void)src_stride_v;
247 0 : if (!src_y || !dst_y || width <= 0 || height == 0) {
248 0 : return -1;
249 : }
250 : // Negative height means invert the image.
251 0 : if (height < 0) {
252 0 : height = -height;
253 0 : src_y = src_y + (height - 1) * src_stride_y;
254 0 : src_stride_y = -src_stride_y;
255 : }
256 :
257 0 : CopyPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
258 0 : return 0;
259 : }
260 :
261 : // Support function for NV12 etc UV channels.
262 : // Width and height are plane sizes (typically half pixel width).
263 : LIBYUV_API
264 0 : void SplitUVPlane(const uint8* src_uv,
265 : int src_stride_uv,
266 : uint8* dst_u,
267 : int dst_stride_u,
268 : uint8* dst_v,
269 : int dst_stride_v,
270 : int width,
271 : int height) {
272 : int y;
273 : void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
274 0 : int width) = SplitUVRow_C;
275 : // Negative height means invert the image.
276 0 : if (height < 0) {
277 0 : height = -height;
278 0 : dst_u = dst_u + (height - 1) * dst_stride_u;
279 0 : dst_v = dst_v + (height - 1) * dst_stride_v;
280 0 : dst_stride_u = -dst_stride_u;
281 0 : dst_stride_v = -dst_stride_v;
282 : }
283 : // Coalesce rows.
284 0 : if (src_stride_uv == width * 2 && dst_stride_u == width &&
285 : dst_stride_v == width) {
286 0 : width *= height;
287 0 : height = 1;
288 0 : src_stride_uv = dst_stride_u = dst_stride_v = 0;
289 : }
290 : #if defined(HAS_SPLITUVROW_SSE2)
291 0 : if (TestCpuFlag(kCpuHasSSE2)) {
292 0 : SplitUVRow = SplitUVRow_Any_SSE2;
293 0 : if (IS_ALIGNED(width, 16)) {
294 0 : SplitUVRow = SplitUVRow_SSE2;
295 : }
296 : }
297 : #endif
298 : #if defined(HAS_SPLITUVROW_AVX2)
299 0 : if (TestCpuFlag(kCpuHasAVX2)) {
300 0 : SplitUVRow = SplitUVRow_Any_AVX2;
301 0 : if (IS_ALIGNED(width, 32)) {
302 0 : SplitUVRow = SplitUVRow_AVX2;
303 : }
304 : }
305 : #endif
306 : #if defined(HAS_SPLITUVROW_NEON)
307 : if (TestCpuFlag(kCpuHasNEON)) {
308 : SplitUVRow = SplitUVRow_Any_NEON;
309 : if (IS_ALIGNED(width, 16)) {
310 : SplitUVRow = SplitUVRow_NEON;
311 : }
312 : }
313 : #endif
314 : #if defined(HAS_SPLITUVROW_DSPR2)
315 : if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(dst_u, 4) &&
316 : IS_ALIGNED(dst_stride_u, 4) && IS_ALIGNED(dst_v, 4) &&
317 : IS_ALIGNED(dst_stride_v, 4)) {
318 : SplitUVRow = SplitUVRow_Any_DSPR2;
319 : if (IS_ALIGNED(width, 16)) {
320 : SplitUVRow = SplitUVRow_DSPR2;
321 : }
322 : }
323 : #endif
324 :
325 0 : for (y = 0; y < height; ++y) {
326 : // Copy a row of UV.
327 0 : SplitUVRow(src_uv, dst_u, dst_v, width);
328 0 : dst_u += dst_stride_u;
329 0 : dst_v += dst_stride_v;
330 0 : src_uv += src_stride_uv;
331 : }
332 0 : }
333 :
334 : LIBYUV_API
335 0 : void MergeUVPlane(const uint8* src_u,
336 : int src_stride_u,
337 : const uint8* src_v,
338 : int src_stride_v,
339 : uint8* dst_uv,
340 : int dst_stride_uv,
341 : int width,
342 : int height) {
343 : int y;
344 : void (*MergeUVRow)(const uint8* src_u, const uint8* src_v, uint8* dst_uv,
345 0 : int width) = MergeUVRow_C;
346 : // Coalesce rows.
347 : // Negative height means invert the image.
348 0 : if (height < 0) {
349 0 : height = -height;
350 0 : dst_uv = dst_uv + (height - 1) * dst_stride_uv;
351 0 : dst_stride_uv = -dst_stride_uv;
352 : }
353 : // Coalesce rows.
354 0 : if (src_stride_u == width && src_stride_v == width &&
355 0 : dst_stride_uv == width * 2) {
356 0 : width *= height;
357 0 : height = 1;
358 0 : src_stride_u = src_stride_v = dst_stride_uv = 0;
359 : }
360 : #if defined(HAS_MERGEUVROW_SSE2)
361 0 : if (TestCpuFlag(kCpuHasSSE2)) {
362 0 : MergeUVRow = MergeUVRow_Any_SSE2;
363 0 : if (IS_ALIGNED(width, 16)) {
364 0 : MergeUVRow = MergeUVRow_SSE2;
365 : }
366 : }
367 : #endif
368 : #if defined(HAS_MERGEUVROW_AVX2)
369 0 : if (TestCpuFlag(kCpuHasAVX2)) {
370 0 : MergeUVRow = MergeUVRow_Any_AVX2;
371 0 : if (IS_ALIGNED(width, 32)) {
372 0 : MergeUVRow = MergeUVRow_AVX2;
373 : }
374 : }
375 : #endif
376 : #if defined(HAS_MERGEUVROW_NEON)
377 : if (TestCpuFlag(kCpuHasNEON)) {
378 : MergeUVRow = MergeUVRow_Any_NEON;
379 : if (IS_ALIGNED(width, 16)) {
380 : MergeUVRow = MergeUVRow_NEON;
381 : }
382 : }
383 : #endif
384 :
385 0 : for (y = 0; y < height; ++y) {
386 : // Merge a row of U and V into a row of UV.
387 0 : MergeUVRow(src_u, src_v, dst_uv, width);
388 0 : src_u += src_stride_u;
389 0 : src_v += src_stride_v;
390 0 : dst_uv += dst_stride_uv;
391 : }
392 0 : }
393 :
394 : // Mirror a plane of data.
395 0 : void MirrorPlane(const uint8* src_y,
396 : int src_stride_y,
397 : uint8* dst_y,
398 : int dst_stride_y,
399 : int width,
400 : int height) {
401 : int y;
402 0 : void (*MirrorRow)(const uint8* src, uint8* dst, int width) = MirrorRow_C;
403 : // Negative height means invert the image.
404 0 : if (height < 0) {
405 0 : height = -height;
406 0 : src_y = src_y + (height - 1) * src_stride_y;
407 0 : src_stride_y = -src_stride_y;
408 : }
409 : #if defined(HAS_MIRRORROW_NEON)
410 : if (TestCpuFlag(kCpuHasNEON)) {
411 : MirrorRow = MirrorRow_Any_NEON;
412 : if (IS_ALIGNED(width, 16)) {
413 : MirrorRow = MirrorRow_NEON;
414 : }
415 : }
416 : #endif
417 : #if defined(HAS_MIRRORROW_SSSE3)
418 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
419 0 : MirrorRow = MirrorRow_Any_SSSE3;
420 0 : if (IS_ALIGNED(width, 16)) {
421 0 : MirrorRow = MirrorRow_SSSE3;
422 : }
423 : }
424 : #endif
425 : #if defined(HAS_MIRRORROW_AVX2)
426 0 : if (TestCpuFlag(kCpuHasAVX2)) {
427 0 : MirrorRow = MirrorRow_Any_AVX2;
428 0 : if (IS_ALIGNED(width, 32)) {
429 0 : MirrorRow = MirrorRow_AVX2;
430 : }
431 : }
432 : #endif
433 : // TODO(fbarchard): Mirror on mips handle unaligned memory.
434 : #if defined(HAS_MIRRORROW_DSPR2)
435 : if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src_y, 4) &&
436 : IS_ALIGNED(src_stride_y, 4) && IS_ALIGNED(dst_y, 4) &&
437 : IS_ALIGNED(dst_stride_y, 4)) {
438 : MirrorRow = MirrorRow_DSPR2;
439 : }
440 : #endif
441 : #if defined(HAS_MIRRORROW_MSA)
442 : if (TestCpuFlag(kCpuHasMSA)) {
443 : MirrorRow = MirrorRow_Any_MSA;
444 : if (IS_ALIGNED(width, 64)) {
445 : MirrorRow = MirrorRow_MSA;
446 : }
447 : }
448 : #endif
449 :
450 : // Mirror plane
451 0 : for (y = 0; y < height; ++y) {
452 0 : MirrorRow(src_y, dst_y, width);
453 0 : src_y += src_stride_y;
454 0 : dst_y += dst_stride_y;
455 : }
456 0 : }
457 :
458 : // Convert YUY2 to I422.
459 : LIBYUV_API
460 0 : int YUY2ToI422(const uint8* src_yuy2,
461 : int src_stride_yuy2,
462 : uint8* dst_y,
463 : int dst_stride_y,
464 : uint8* dst_u,
465 : int dst_stride_u,
466 : uint8* dst_v,
467 : int dst_stride_v,
468 : int width,
469 : int height) {
470 : int y;
471 : void (*YUY2ToUV422Row)(const uint8* src_yuy2, uint8* dst_u, uint8* dst_v,
472 0 : int width) = YUY2ToUV422Row_C;
473 : void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int width) =
474 0 : YUY2ToYRow_C;
475 0 : if (!src_yuy2 || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
476 0 : return -1;
477 : }
478 : // Negative height means invert the image.
479 0 : if (height < 0) {
480 0 : height = -height;
481 0 : src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
482 0 : src_stride_yuy2 = -src_stride_yuy2;
483 : }
484 : // Coalesce rows.
485 0 : if (src_stride_yuy2 == width * 2 && dst_stride_y == width &&
486 0 : dst_stride_u * 2 == width && dst_stride_v * 2 == width &&
487 0 : width * height <= 32768) {
488 0 : width *= height;
489 0 : height = 1;
490 0 : src_stride_yuy2 = dst_stride_y = dst_stride_u = dst_stride_v = 0;
491 : }
492 : #if defined(HAS_YUY2TOYROW_SSE2)
493 0 : if (TestCpuFlag(kCpuHasSSE2)) {
494 0 : YUY2ToUV422Row = YUY2ToUV422Row_Any_SSE2;
495 0 : YUY2ToYRow = YUY2ToYRow_Any_SSE2;
496 0 : if (IS_ALIGNED(width, 16)) {
497 0 : YUY2ToUV422Row = YUY2ToUV422Row_SSE2;
498 0 : YUY2ToYRow = YUY2ToYRow_SSE2;
499 : }
500 : }
501 : #endif
502 : #if defined(HAS_YUY2TOYROW_AVX2)
503 0 : if (TestCpuFlag(kCpuHasAVX2)) {
504 0 : YUY2ToUV422Row = YUY2ToUV422Row_Any_AVX2;
505 0 : YUY2ToYRow = YUY2ToYRow_Any_AVX2;
506 0 : if (IS_ALIGNED(width, 32)) {
507 0 : YUY2ToUV422Row = YUY2ToUV422Row_AVX2;
508 0 : YUY2ToYRow = YUY2ToYRow_AVX2;
509 : }
510 : }
511 : #endif
512 : #if defined(HAS_YUY2TOYROW_NEON)
513 : if (TestCpuFlag(kCpuHasNEON)) {
514 : YUY2ToYRow = YUY2ToYRow_Any_NEON;
515 : YUY2ToUV422Row = YUY2ToUV422Row_Any_NEON;
516 : if (IS_ALIGNED(width, 16)) {
517 : YUY2ToYRow = YUY2ToYRow_NEON;
518 : YUY2ToUV422Row = YUY2ToUV422Row_NEON;
519 : }
520 : }
521 : #endif
522 : #if defined(HAS_YUY2TOYROW_MSA)
523 : if (TestCpuFlag(kCpuHasMSA)) {
524 : YUY2ToYRow = YUY2ToYRow_Any_MSA;
525 : YUY2ToUV422Row = YUY2ToUV422Row_Any_MSA;
526 : if (IS_ALIGNED(width, 32)) {
527 : YUY2ToYRow = YUY2ToYRow_MSA;
528 : YUY2ToUV422Row = YUY2ToUV422Row_MSA;
529 : }
530 : }
531 : #endif
532 :
533 0 : for (y = 0; y < height; ++y) {
534 0 : YUY2ToUV422Row(src_yuy2, dst_u, dst_v, width);
535 0 : YUY2ToYRow(src_yuy2, dst_y, width);
536 0 : src_yuy2 += src_stride_yuy2;
537 0 : dst_y += dst_stride_y;
538 0 : dst_u += dst_stride_u;
539 0 : dst_v += dst_stride_v;
540 : }
541 0 : return 0;
542 : }
543 :
544 : // Convert UYVY to I422.
545 : LIBYUV_API
546 0 : int UYVYToI422(const uint8* src_uyvy,
547 : int src_stride_uyvy,
548 : uint8* dst_y,
549 : int dst_stride_y,
550 : uint8* dst_u,
551 : int dst_stride_u,
552 : uint8* dst_v,
553 : int dst_stride_v,
554 : int width,
555 : int height) {
556 : int y;
557 : void (*UYVYToUV422Row)(const uint8* src_uyvy, uint8* dst_u, uint8* dst_v,
558 0 : int width) = UYVYToUV422Row_C;
559 : void (*UYVYToYRow)(const uint8* src_uyvy, uint8* dst_y, int width) =
560 0 : UYVYToYRow_C;
561 0 : if (!src_uyvy || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
562 0 : return -1;
563 : }
564 : // Negative height means invert the image.
565 0 : if (height < 0) {
566 0 : height = -height;
567 0 : src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
568 0 : src_stride_uyvy = -src_stride_uyvy;
569 : }
570 : // Coalesce rows.
571 0 : if (src_stride_uyvy == width * 2 && dst_stride_y == width &&
572 0 : dst_stride_u * 2 == width && dst_stride_v * 2 == width &&
573 0 : width * height <= 32768) {
574 0 : width *= height;
575 0 : height = 1;
576 0 : src_stride_uyvy = dst_stride_y = dst_stride_u = dst_stride_v = 0;
577 : }
578 : #if defined(HAS_UYVYTOYROW_SSE2)
579 0 : if (TestCpuFlag(kCpuHasSSE2)) {
580 0 : UYVYToUV422Row = UYVYToUV422Row_Any_SSE2;
581 0 : UYVYToYRow = UYVYToYRow_Any_SSE2;
582 0 : if (IS_ALIGNED(width, 16)) {
583 0 : UYVYToUV422Row = UYVYToUV422Row_SSE2;
584 0 : UYVYToYRow = UYVYToYRow_SSE2;
585 : }
586 : }
587 : #endif
588 : #if defined(HAS_UYVYTOYROW_AVX2)
589 0 : if (TestCpuFlag(kCpuHasAVX2)) {
590 0 : UYVYToUV422Row = UYVYToUV422Row_Any_AVX2;
591 0 : UYVYToYRow = UYVYToYRow_Any_AVX2;
592 0 : if (IS_ALIGNED(width, 32)) {
593 0 : UYVYToUV422Row = UYVYToUV422Row_AVX2;
594 0 : UYVYToYRow = UYVYToYRow_AVX2;
595 : }
596 : }
597 : #endif
598 : #if defined(HAS_UYVYTOYROW_NEON)
599 : if (TestCpuFlag(kCpuHasNEON)) {
600 : UYVYToYRow = UYVYToYRow_Any_NEON;
601 : UYVYToUV422Row = UYVYToUV422Row_Any_NEON;
602 : if (IS_ALIGNED(width, 16)) {
603 : UYVYToYRow = UYVYToYRow_NEON;
604 : UYVYToUV422Row = UYVYToUV422Row_NEON;
605 : }
606 : }
607 : #endif
608 : #if defined(HAS_UYVYTOYROW_MSA)
609 : if (TestCpuFlag(kCpuHasMSA)) {
610 : UYVYToYRow = UYVYToYRow_Any_MSA;
611 : UYVYToUV422Row = UYVYToUV422Row_Any_MSA;
612 : if (IS_ALIGNED(width, 32)) {
613 : UYVYToYRow = UYVYToYRow_MSA;
614 : UYVYToUV422Row = UYVYToUV422Row_MSA;
615 : }
616 : }
617 : #endif
618 :
619 0 : for (y = 0; y < height; ++y) {
620 0 : UYVYToUV422Row(src_uyvy, dst_u, dst_v, width);
621 0 : UYVYToYRow(src_uyvy, dst_y, width);
622 0 : src_uyvy += src_stride_uyvy;
623 0 : dst_y += dst_stride_y;
624 0 : dst_u += dst_stride_u;
625 0 : dst_v += dst_stride_v;
626 : }
627 0 : return 0;
628 : }
629 :
630 : // Convert YUY2 to Y.
631 : LIBYUV_API
632 0 : int YUY2ToY(const uint8* src_yuy2,
633 : int src_stride_yuy2,
634 : uint8* dst_y,
635 : int dst_stride_y,
636 : int width,
637 : int height) {
638 : int y;
639 : void (*YUY2ToYRow)(const uint8* src_yuy2, uint8* dst_y, int width) =
640 0 : YUY2ToYRow_C;
641 0 : if (!src_yuy2 || !dst_y || width <= 0 || height == 0) {
642 0 : return -1;
643 : }
644 : // Negative height means invert the image.
645 0 : if (height < 0) {
646 0 : height = -height;
647 0 : src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
648 0 : src_stride_yuy2 = -src_stride_yuy2;
649 : }
650 : // Coalesce rows.
651 0 : if (src_stride_yuy2 == width * 2 && dst_stride_y == width) {
652 0 : width *= height;
653 0 : height = 1;
654 0 : src_stride_yuy2 = dst_stride_y = 0;
655 : }
656 : #if defined(HAS_YUY2TOYROW_SSE2)
657 0 : if (TestCpuFlag(kCpuHasSSE2)) {
658 0 : YUY2ToYRow = YUY2ToYRow_Any_SSE2;
659 0 : if (IS_ALIGNED(width, 16)) {
660 0 : YUY2ToYRow = YUY2ToYRow_SSE2;
661 : }
662 : }
663 : #endif
664 : #if defined(HAS_YUY2TOYROW_AVX2)
665 0 : if (TestCpuFlag(kCpuHasAVX2)) {
666 0 : YUY2ToYRow = YUY2ToYRow_Any_AVX2;
667 0 : if (IS_ALIGNED(width, 32)) {
668 0 : YUY2ToYRow = YUY2ToYRow_AVX2;
669 : }
670 : }
671 : #endif
672 : #if defined(HAS_YUY2TOYROW_NEON)
673 : if (TestCpuFlag(kCpuHasNEON)) {
674 : YUY2ToYRow = YUY2ToYRow_Any_NEON;
675 : if (IS_ALIGNED(width, 16)) {
676 : YUY2ToYRow = YUY2ToYRow_NEON;
677 : }
678 : }
679 : #endif
680 : #if defined(HAS_YUY2TOYROW_MSA)
681 : if (TestCpuFlag(kCpuHasMSA)) {
682 : YUY2ToYRow = YUY2ToYRow_Any_MSA;
683 : if (IS_ALIGNED(width, 32)) {
684 : YUY2ToYRow = YUY2ToYRow_MSA;
685 : }
686 : }
687 : #endif
688 :
689 0 : for (y = 0; y < height; ++y) {
690 0 : YUY2ToYRow(src_yuy2, dst_y, width);
691 0 : src_yuy2 += src_stride_yuy2;
692 0 : dst_y += dst_stride_y;
693 : }
694 0 : return 0;
695 : }
696 :
697 : // Mirror I400 with optional flipping
698 : LIBYUV_API
699 0 : int I400Mirror(const uint8* src_y,
700 : int src_stride_y,
701 : uint8* dst_y,
702 : int dst_stride_y,
703 : int width,
704 : int height) {
705 0 : if (!src_y || !dst_y || width <= 0 || height == 0) {
706 0 : return -1;
707 : }
708 : // Negative height means invert the image.
709 0 : if (height < 0) {
710 0 : height = -height;
711 0 : src_y = src_y + (height - 1) * src_stride_y;
712 0 : src_stride_y = -src_stride_y;
713 : }
714 :
715 0 : MirrorPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
716 0 : return 0;
717 : }
718 :
719 : // Mirror I420 with optional flipping
720 : LIBYUV_API
721 0 : int I420Mirror(const uint8* src_y,
722 : int src_stride_y,
723 : const uint8* src_u,
724 : int src_stride_u,
725 : const uint8* src_v,
726 : int src_stride_v,
727 : uint8* dst_y,
728 : int dst_stride_y,
729 : uint8* dst_u,
730 : int dst_stride_u,
731 : uint8* dst_v,
732 : int dst_stride_v,
733 : int width,
734 : int height) {
735 0 : int halfwidth = (width + 1) >> 1;
736 0 : int halfheight = (height + 1) >> 1;
737 0 : if (!src_y || !src_u || !src_v || !dst_y || !dst_u || !dst_v || width <= 0 ||
738 : height == 0) {
739 0 : return -1;
740 : }
741 : // Negative height means invert the image.
742 0 : if (height < 0) {
743 0 : height = -height;
744 0 : halfheight = (height + 1) >> 1;
745 0 : src_y = src_y + (height - 1) * src_stride_y;
746 0 : src_u = src_u + (halfheight - 1) * src_stride_u;
747 0 : src_v = src_v + (halfheight - 1) * src_stride_v;
748 0 : src_stride_y = -src_stride_y;
749 0 : src_stride_u = -src_stride_u;
750 0 : src_stride_v = -src_stride_v;
751 : }
752 :
753 0 : if (dst_y) {
754 0 : MirrorPlane(src_y, src_stride_y, dst_y, dst_stride_y, width, height);
755 : }
756 0 : MirrorPlane(src_u, src_stride_u, dst_u, dst_stride_u, halfwidth, halfheight);
757 0 : MirrorPlane(src_v, src_stride_v, dst_v, dst_stride_v, halfwidth, halfheight);
758 0 : return 0;
759 : }
760 :
761 : // ARGB mirror.
762 : LIBYUV_API
763 0 : int ARGBMirror(const uint8* src_argb,
764 : int src_stride_argb,
765 : uint8* dst_argb,
766 : int dst_stride_argb,
767 : int width,
768 : int height) {
769 : int y;
770 : void (*ARGBMirrorRow)(const uint8* src, uint8* dst, int width) =
771 0 : ARGBMirrorRow_C;
772 0 : if (!src_argb || !dst_argb || width <= 0 || height == 0) {
773 0 : return -1;
774 : }
775 : // Negative height means invert the image.
776 0 : if (height < 0) {
777 0 : height = -height;
778 0 : src_argb = src_argb + (height - 1) * src_stride_argb;
779 0 : src_stride_argb = -src_stride_argb;
780 : }
781 : #if defined(HAS_ARGBMIRRORROW_NEON)
782 : if (TestCpuFlag(kCpuHasNEON)) {
783 : ARGBMirrorRow = ARGBMirrorRow_Any_NEON;
784 : if (IS_ALIGNED(width, 4)) {
785 : ARGBMirrorRow = ARGBMirrorRow_NEON;
786 : }
787 : }
788 : #endif
789 : #if defined(HAS_ARGBMIRRORROW_SSE2)
790 0 : if (TestCpuFlag(kCpuHasSSE2)) {
791 0 : ARGBMirrorRow = ARGBMirrorRow_Any_SSE2;
792 0 : if (IS_ALIGNED(width, 4)) {
793 0 : ARGBMirrorRow = ARGBMirrorRow_SSE2;
794 : }
795 : }
796 : #endif
797 : #if defined(HAS_ARGBMIRRORROW_AVX2)
798 0 : if (TestCpuFlag(kCpuHasAVX2)) {
799 0 : ARGBMirrorRow = ARGBMirrorRow_Any_AVX2;
800 0 : if (IS_ALIGNED(width, 8)) {
801 0 : ARGBMirrorRow = ARGBMirrorRow_AVX2;
802 : }
803 : }
804 : #endif
805 : #if defined(HAS_ARGBMIRRORROW_MSA)
806 : if (TestCpuFlag(kCpuHasMSA)) {
807 : ARGBMirrorRow = ARGBMirrorRow_Any_MSA;
808 : if (IS_ALIGNED(width, 16)) {
809 : ARGBMirrorRow = ARGBMirrorRow_MSA;
810 : }
811 : }
812 : #endif
813 :
814 : // Mirror plane
815 0 : for (y = 0; y < height; ++y) {
816 0 : ARGBMirrorRow(src_argb, dst_argb, width);
817 0 : src_argb += src_stride_argb;
818 0 : dst_argb += dst_stride_argb;
819 : }
820 0 : return 0;
821 : }
822 :
823 : // Get a blender that optimized for the CPU and pixel count.
824 : // As there are 6 blenders to choose from, the caller should try to use
825 : // the same blend function for all pixels if possible.
826 : LIBYUV_API
827 0 : ARGBBlendRow GetARGBBlend() {
828 : void (*ARGBBlendRow)(const uint8* src_argb, const uint8* src_argb1,
829 0 : uint8* dst_argb, int width) = ARGBBlendRow_C;
830 : #if defined(HAS_ARGBBLENDROW_SSSE3)
831 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
832 0 : ARGBBlendRow = ARGBBlendRow_SSSE3;
833 0 : return ARGBBlendRow;
834 : }
835 : #endif
836 : #if defined(HAS_ARGBBLENDROW_NEON)
837 : if (TestCpuFlag(kCpuHasNEON)) {
838 : ARGBBlendRow = ARGBBlendRow_NEON;
839 : }
840 : #endif
841 0 : return ARGBBlendRow;
842 : }
843 :
844 : // Alpha Blend 2 ARGB images and store to destination.
845 : LIBYUV_API
846 0 : int ARGBBlend(const uint8* src_argb0,
847 : int src_stride_argb0,
848 : const uint8* src_argb1,
849 : int src_stride_argb1,
850 : uint8* dst_argb,
851 : int dst_stride_argb,
852 : int width,
853 : int height) {
854 : int y;
855 : void (*ARGBBlendRow)(const uint8* src_argb, const uint8* src_argb1,
856 0 : uint8* dst_argb, int width) = GetARGBBlend();
857 0 : if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
858 0 : return -1;
859 : }
860 : // Negative height means invert the image.
861 0 : if (height < 0) {
862 0 : height = -height;
863 0 : dst_argb = dst_argb + (height - 1) * dst_stride_argb;
864 0 : dst_stride_argb = -dst_stride_argb;
865 : }
866 : // Coalesce rows.
867 0 : if (src_stride_argb0 == width * 4 && src_stride_argb1 == width * 4 &&
868 0 : dst_stride_argb == width * 4) {
869 0 : width *= height;
870 0 : height = 1;
871 0 : src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
872 : }
873 :
874 0 : for (y = 0; y < height; ++y) {
875 0 : ARGBBlendRow(src_argb0, src_argb1, dst_argb, width);
876 0 : src_argb0 += src_stride_argb0;
877 0 : src_argb1 += src_stride_argb1;
878 0 : dst_argb += dst_stride_argb;
879 : }
880 0 : return 0;
881 : }
882 :
883 : // Alpha Blend plane and store to destination.
884 : LIBYUV_API
885 0 : int BlendPlane(const uint8* src_y0,
886 : int src_stride_y0,
887 : const uint8* src_y1,
888 : int src_stride_y1,
889 : const uint8* alpha,
890 : int alpha_stride,
891 : uint8* dst_y,
892 : int dst_stride_y,
893 : int width,
894 : int height) {
895 : int y;
896 : void (*BlendPlaneRow)(const uint8* src0, const uint8* src1,
897 : const uint8* alpha, uint8* dst, int width) =
898 0 : BlendPlaneRow_C;
899 0 : if (!src_y0 || !src_y1 || !alpha || !dst_y || width <= 0 || height == 0) {
900 0 : return -1;
901 : }
902 : // Negative height means invert the image.
903 0 : if (height < 0) {
904 0 : height = -height;
905 0 : dst_y = dst_y + (height - 1) * dst_stride_y;
906 0 : dst_stride_y = -dst_stride_y;
907 : }
908 :
909 : // Coalesce rows for Y plane.
910 0 : if (src_stride_y0 == width && src_stride_y1 == width &&
911 0 : alpha_stride == width && dst_stride_y == width) {
912 0 : width *= height;
913 0 : height = 1;
914 0 : src_stride_y0 = src_stride_y1 = alpha_stride = dst_stride_y = 0;
915 : }
916 :
917 : #if defined(HAS_BLENDPLANEROW_SSSE3)
918 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
919 0 : BlendPlaneRow = BlendPlaneRow_Any_SSSE3;
920 0 : if (IS_ALIGNED(width, 8)) {
921 0 : BlendPlaneRow = BlendPlaneRow_SSSE3;
922 : }
923 : }
924 : #endif
925 : #if defined(HAS_BLENDPLANEROW_AVX2)
926 0 : if (TestCpuFlag(kCpuHasAVX2)) {
927 0 : BlendPlaneRow = BlendPlaneRow_Any_AVX2;
928 0 : if (IS_ALIGNED(width, 32)) {
929 0 : BlendPlaneRow = BlendPlaneRow_AVX2;
930 : }
931 : }
932 : #endif
933 :
934 0 : for (y = 0; y < height; ++y) {
935 0 : BlendPlaneRow(src_y0, src_y1, alpha, dst_y, width);
936 0 : src_y0 += src_stride_y0;
937 0 : src_y1 += src_stride_y1;
938 0 : alpha += alpha_stride;
939 0 : dst_y += dst_stride_y;
940 : }
941 0 : return 0;
942 : }
943 :
944 : #define MAXTWIDTH 2048
945 : // Alpha Blend YUV images and store to destination.
946 : LIBYUV_API
947 0 : int I420Blend(const uint8* src_y0,
948 : int src_stride_y0,
949 : const uint8* src_u0,
950 : int src_stride_u0,
951 : const uint8* src_v0,
952 : int src_stride_v0,
953 : const uint8* src_y1,
954 : int src_stride_y1,
955 : const uint8* src_u1,
956 : int src_stride_u1,
957 : const uint8* src_v1,
958 : int src_stride_v1,
959 : const uint8* alpha,
960 : int alpha_stride,
961 : uint8* dst_y,
962 : int dst_stride_y,
963 : uint8* dst_u,
964 : int dst_stride_u,
965 : uint8* dst_v,
966 : int dst_stride_v,
967 : int width,
968 : int height) {
969 : int y;
970 : // Half width/height for UV.
971 0 : int halfwidth = (width + 1) >> 1;
972 : void (*BlendPlaneRow)(const uint8* src0, const uint8* src1,
973 : const uint8* alpha, uint8* dst, int width) =
974 0 : BlendPlaneRow_C;
975 : void (*ScaleRowDown2)(const uint8* src_ptr, ptrdiff_t src_stride,
976 0 : uint8* dst_ptr, int dst_width) = ScaleRowDown2Box_C;
977 0 : if (!src_y0 || !src_u0 || !src_v0 || !src_y1 || !src_u1 || !src_v1 ||
978 0 : !alpha || !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
979 0 : return -1;
980 : }
981 :
982 : // Negative height means invert the image.
983 0 : if (height < 0) {
984 0 : height = -height;
985 0 : dst_y = dst_y + (height - 1) * dst_stride_y;
986 0 : dst_stride_y = -dst_stride_y;
987 : }
988 :
989 : // Blend Y plane.
990 : BlendPlane(src_y0, src_stride_y0, src_y1, src_stride_y1, alpha, alpha_stride,
991 0 : dst_y, dst_stride_y, width, height);
992 :
993 : #if defined(HAS_BLENDPLANEROW_SSSE3)
994 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
995 0 : BlendPlaneRow = BlendPlaneRow_Any_SSSE3;
996 0 : if (IS_ALIGNED(halfwidth, 8)) {
997 0 : BlendPlaneRow = BlendPlaneRow_SSSE3;
998 : }
999 : }
1000 : #endif
1001 : #if defined(HAS_BLENDPLANEROW_AVX2)
1002 0 : if (TestCpuFlag(kCpuHasAVX2)) {
1003 0 : BlendPlaneRow = BlendPlaneRow_Any_AVX2;
1004 0 : if (IS_ALIGNED(halfwidth, 32)) {
1005 0 : BlendPlaneRow = BlendPlaneRow_AVX2;
1006 : }
1007 : }
1008 : #endif
1009 0 : if (!IS_ALIGNED(width, 2)) {
1010 0 : ScaleRowDown2 = ScaleRowDown2Box_Odd_C;
1011 : }
1012 : #if defined(HAS_SCALEROWDOWN2_NEON)
1013 : if (TestCpuFlag(kCpuHasNEON)) {
1014 : ScaleRowDown2 = ScaleRowDown2Box_Odd_NEON;
1015 : if (IS_ALIGNED(width, 2)) {
1016 : ScaleRowDown2 = ScaleRowDown2Box_Any_NEON;
1017 : if (IS_ALIGNED(halfwidth, 16)) {
1018 : ScaleRowDown2 = ScaleRowDown2Box_NEON;
1019 : }
1020 : }
1021 : }
1022 : #endif
1023 : #if defined(HAS_SCALEROWDOWN2_SSSE3)
1024 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
1025 0 : ScaleRowDown2 = ScaleRowDown2Box_Odd_SSSE3;
1026 0 : if (IS_ALIGNED(width, 2)) {
1027 0 : ScaleRowDown2 = ScaleRowDown2Box_Any_SSSE3;
1028 0 : if (IS_ALIGNED(halfwidth, 16)) {
1029 0 : ScaleRowDown2 = ScaleRowDown2Box_SSSE3;
1030 : }
1031 : }
1032 : }
1033 : #endif
1034 : #if defined(HAS_SCALEROWDOWN2_AVX2)
1035 0 : if (TestCpuFlag(kCpuHasAVX2)) {
1036 0 : ScaleRowDown2 = ScaleRowDown2Box_Odd_AVX2;
1037 0 : if (IS_ALIGNED(width, 2)) {
1038 0 : ScaleRowDown2 = ScaleRowDown2Box_Any_AVX2;
1039 0 : if (IS_ALIGNED(halfwidth, 32)) {
1040 0 : ScaleRowDown2 = ScaleRowDown2Box_AVX2;
1041 : }
1042 : }
1043 : }
1044 : #endif
1045 :
1046 : // Row buffer for intermediate alpha pixels.
1047 0 : align_buffer_64(halfalpha, halfwidth);
1048 0 : for (y = 0; y < height; y += 2) {
1049 : // last row of odd height image use 1 row of alpha instead of 2.
1050 0 : if (y == (height - 1)) {
1051 0 : alpha_stride = 0;
1052 : }
1053 : // Subsample 2 rows of UV to half width and half height.
1054 0 : ScaleRowDown2(alpha, alpha_stride, halfalpha, halfwidth);
1055 0 : alpha += alpha_stride * 2;
1056 0 : BlendPlaneRow(src_u0, src_u1, halfalpha, dst_u, halfwidth);
1057 0 : BlendPlaneRow(src_v0, src_v1, halfalpha, dst_v, halfwidth);
1058 0 : src_u0 += src_stride_u0;
1059 0 : src_u1 += src_stride_u1;
1060 0 : dst_u += dst_stride_u;
1061 0 : src_v0 += src_stride_v0;
1062 0 : src_v1 += src_stride_v1;
1063 0 : dst_v += dst_stride_v;
1064 : }
1065 0 : free_aligned_buffer_64(halfalpha);
1066 0 : return 0;
1067 : }
1068 :
1069 : // Multiply 2 ARGB images and store to destination.
1070 : LIBYUV_API
1071 0 : int ARGBMultiply(const uint8* src_argb0,
1072 : int src_stride_argb0,
1073 : const uint8* src_argb1,
1074 : int src_stride_argb1,
1075 : uint8* dst_argb,
1076 : int dst_stride_argb,
1077 : int width,
1078 : int height) {
1079 : int y;
1080 : void (*ARGBMultiplyRow)(const uint8* src0, const uint8* src1, uint8* dst,
1081 0 : int width) = ARGBMultiplyRow_C;
1082 0 : if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
1083 0 : return -1;
1084 : }
1085 : // Negative height means invert the image.
1086 0 : if (height < 0) {
1087 0 : height = -height;
1088 0 : dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1089 0 : dst_stride_argb = -dst_stride_argb;
1090 : }
1091 : // Coalesce rows.
1092 0 : if (src_stride_argb0 == width * 4 && src_stride_argb1 == width * 4 &&
1093 0 : dst_stride_argb == width * 4) {
1094 0 : width *= height;
1095 0 : height = 1;
1096 0 : src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
1097 : }
1098 : #if defined(HAS_ARGBMULTIPLYROW_SSE2)
1099 0 : if (TestCpuFlag(kCpuHasSSE2)) {
1100 0 : ARGBMultiplyRow = ARGBMultiplyRow_Any_SSE2;
1101 0 : if (IS_ALIGNED(width, 4)) {
1102 0 : ARGBMultiplyRow = ARGBMultiplyRow_SSE2;
1103 : }
1104 : }
1105 : #endif
1106 : #if defined(HAS_ARGBMULTIPLYROW_AVX2)
1107 0 : if (TestCpuFlag(kCpuHasAVX2)) {
1108 0 : ARGBMultiplyRow = ARGBMultiplyRow_Any_AVX2;
1109 0 : if (IS_ALIGNED(width, 8)) {
1110 0 : ARGBMultiplyRow = ARGBMultiplyRow_AVX2;
1111 : }
1112 : }
1113 : #endif
1114 : #if defined(HAS_ARGBMULTIPLYROW_NEON)
1115 : if (TestCpuFlag(kCpuHasNEON)) {
1116 : ARGBMultiplyRow = ARGBMultiplyRow_Any_NEON;
1117 : if (IS_ALIGNED(width, 8)) {
1118 : ARGBMultiplyRow = ARGBMultiplyRow_NEON;
1119 : }
1120 : }
1121 : #endif
1122 : #if defined(HAS_ARGBMULTIPLYROW_MSA)
1123 : if (TestCpuFlag(kCpuHasMSA)) {
1124 : ARGBMultiplyRow = ARGBMultiplyRow_Any_MSA;
1125 : if (IS_ALIGNED(width, 4)) {
1126 : ARGBMultiplyRow = ARGBMultiplyRow_MSA;
1127 : }
1128 : }
1129 : #endif
1130 :
1131 : // Multiply plane
1132 0 : for (y = 0; y < height; ++y) {
1133 0 : ARGBMultiplyRow(src_argb0, src_argb1, dst_argb, width);
1134 0 : src_argb0 += src_stride_argb0;
1135 0 : src_argb1 += src_stride_argb1;
1136 0 : dst_argb += dst_stride_argb;
1137 : }
1138 0 : return 0;
1139 : }
1140 :
1141 : // Add 2 ARGB images and store to destination.
1142 : LIBYUV_API
1143 0 : int ARGBAdd(const uint8* src_argb0,
1144 : int src_stride_argb0,
1145 : const uint8* src_argb1,
1146 : int src_stride_argb1,
1147 : uint8* dst_argb,
1148 : int dst_stride_argb,
1149 : int width,
1150 : int height) {
1151 : int y;
1152 : void (*ARGBAddRow)(const uint8* src0, const uint8* src1, uint8* dst,
1153 0 : int width) = ARGBAddRow_C;
1154 0 : if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
1155 0 : return -1;
1156 : }
1157 : // Negative height means invert the image.
1158 0 : if (height < 0) {
1159 0 : height = -height;
1160 0 : dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1161 0 : dst_stride_argb = -dst_stride_argb;
1162 : }
1163 : // Coalesce rows.
1164 0 : if (src_stride_argb0 == width * 4 && src_stride_argb1 == width * 4 &&
1165 0 : dst_stride_argb == width * 4) {
1166 0 : width *= height;
1167 0 : height = 1;
1168 0 : src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
1169 : }
1170 : #if defined(HAS_ARGBADDROW_SSE2) && (defined(_MSC_VER) && !defined(__clang__))
1171 : if (TestCpuFlag(kCpuHasSSE2)) {
1172 : ARGBAddRow = ARGBAddRow_SSE2;
1173 : }
1174 : #endif
1175 : #if defined(HAS_ARGBADDROW_SSE2) && !(defined(_MSC_VER) && !defined(__clang__))
1176 0 : if (TestCpuFlag(kCpuHasSSE2)) {
1177 0 : ARGBAddRow = ARGBAddRow_Any_SSE2;
1178 0 : if (IS_ALIGNED(width, 4)) {
1179 0 : ARGBAddRow = ARGBAddRow_SSE2;
1180 : }
1181 : }
1182 : #endif
1183 : #if defined(HAS_ARGBADDROW_AVX2)
1184 0 : if (TestCpuFlag(kCpuHasAVX2)) {
1185 0 : ARGBAddRow = ARGBAddRow_Any_AVX2;
1186 0 : if (IS_ALIGNED(width, 8)) {
1187 0 : ARGBAddRow = ARGBAddRow_AVX2;
1188 : }
1189 : }
1190 : #endif
1191 : #if defined(HAS_ARGBADDROW_NEON)
1192 : if (TestCpuFlag(kCpuHasNEON)) {
1193 : ARGBAddRow = ARGBAddRow_Any_NEON;
1194 : if (IS_ALIGNED(width, 8)) {
1195 : ARGBAddRow = ARGBAddRow_NEON;
1196 : }
1197 : }
1198 : #endif
1199 : #if defined(HAS_ARGBADDROW_MSA)
1200 : if (TestCpuFlag(kCpuHasMSA)) {
1201 : ARGBAddRow = ARGBAddRow_Any_MSA;
1202 : if (IS_ALIGNED(width, 8)) {
1203 : ARGBAddRow = ARGBAddRow_MSA;
1204 : }
1205 : }
1206 : #endif
1207 :
1208 : // Add plane
1209 0 : for (y = 0; y < height; ++y) {
1210 0 : ARGBAddRow(src_argb0, src_argb1, dst_argb, width);
1211 0 : src_argb0 += src_stride_argb0;
1212 0 : src_argb1 += src_stride_argb1;
1213 0 : dst_argb += dst_stride_argb;
1214 : }
1215 0 : return 0;
1216 : }
1217 :
1218 : // Subtract 2 ARGB images and store to destination.
1219 : LIBYUV_API
1220 0 : int ARGBSubtract(const uint8* src_argb0,
1221 : int src_stride_argb0,
1222 : const uint8* src_argb1,
1223 : int src_stride_argb1,
1224 : uint8* dst_argb,
1225 : int dst_stride_argb,
1226 : int width,
1227 : int height) {
1228 : int y;
1229 : void (*ARGBSubtractRow)(const uint8* src0, const uint8* src1, uint8* dst,
1230 0 : int width) = ARGBSubtractRow_C;
1231 0 : if (!src_argb0 || !src_argb1 || !dst_argb || width <= 0 || height == 0) {
1232 0 : return -1;
1233 : }
1234 : // Negative height means invert the image.
1235 0 : if (height < 0) {
1236 0 : height = -height;
1237 0 : dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1238 0 : dst_stride_argb = -dst_stride_argb;
1239 : }
1240 : // Coalesce rows.
1241 0 : if (src_stride_argb0 == width * 4 && src_stride_argb1 == width * 4 &&
1242 0 : dst_stride_argb == width * 4) {
1243 0 : width *= height;
1244 0 : height = 1;
1245 0 : src_stride_argb0 = src_stride_argb1 = dst_stride_argb = 0;
1246 : }
1247 : #if defined(HAS_ARGBSUBTRACTROW_SSE2)
1248 0 : if (TestCpuFlag(kCpuHasSSE2)) {
1249 0 : ARGBSubtractRow = ARGBSubtractRow_Any_SSE2;
1250 0 : if (IS_ALIGNED(width, 4)) {
1251 0 : ARGBSubtractRow = ARGBSubtractRow_SSE2;
1252 : }
1253 : }
1254 : #endif
1255 : #if defined(HAS_ARGBSUBTRACTROW_AVX2)
1256 0 : if (TestCpuFlag(kCpuHasAVX2)) {
1257 0 : ARGBSubtractRow = ARGBSubtractRow_Any_AVX2;
1258 0 : if (IS_ALIGNED(width, 8)) {
1259 0 : ARGBSubtractRow = ARGBSubtractRow_AVX2;
1260 : }
1261 : }
1262 : #endif
1263 : #if defined(HAS_ARGBSUBTRACTROW_NEON)
1264 : if (TestCpuFlag(kCpuHasNEON)) {
1265 : ARGBSubtractRow = ARGBSubtractRow_Any_NEON;
1266 : if (IS_ALIGNED(width, 8)) {
1267 : ARGBSubtractRow = ARGBSubtractRow_NEON;
1268 : }
1269 : }
1270 : #endif
1271 : #if defined(HAS_ARGBSUBTRACTROW_MSA)
1272 : if (TestCpuFlag(kCpuHasMSA)) {
1273 : ARGBSubtractRow = ARGBSubtractRow_Any_MSA;
1274 : if (IS_ALIGNED(width, 8)) {
1275 : ARGBSubtractRow = ARGBSubtractRow_MSA;
1276 : }
1277 : }
1278 : #endif
1279 :
1280 : // Subtract plane
1281 0 : for (y = 0; y < height; ++y) {
1282 0 : ARGBSubtractRow(src_argb0, src_argb1, dst_argb, width);
1283 0 : src_argb0 += src_stride_argb0;
1284 0 : src_argb1 += src_stride_argb1;
1285 0 : dst_argb += dst_stride_argb;
1286 : }
1287 0 : return 0;
1288 : }
1289 : // Convert I422 to RGBA with matrix
1290 0 : static int I422ToRGBAMatrix(const uint8* src_y,
1291 : int src_stride_y,
1292 : const uint8* src_u,
1293 : int src_stride_u,
1294 : const uint8* src_v,
1295 : int src_stride_v,
1296 : uint8* dst_rgba,
1297 : int dst_stride_rgba,
1298 : const struct YuvConstants* yuvconstants,
1299 : int width,
1300 : int height) {
1301 : int y;
1302 : void (*I422ToRGBARow)(const uint8* y_buf, const uint8* u_buf,
1303 : const uint8* v_buf, uint8* rgb_buf,
1304 : const struct YuvConstants* yuvconstants, int width) =
1305 0 : I422ToRGBARow_C;
1306 0 : if (!src_y || !src_u || !src_v || !dst_rgba || width <= 0 || height == 0) {
1307 0 : return -1;
1308 : }
1309 : // Negative height means invert the image.
1310 0 : if (height < 0) {
1311 0 : height = -height;
1312 0 : dst_rgba = dst_rgba + (height - 1) * dst_stride_rgba;
1313 0 : dst_stride_rgba = -dst_stride_rgba;
1314 : }
1315 : #if defined(HAS_I422TORGBAROW_SSSE3)
1316 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
1317 0 : I422ToRGBARow = I422ToRGBARow_Any_SSSE3;
1318 0 : if (IS_ALIGNED(width, 8)) {
1319 0 : I422ToRGBARow = I422ToRGBARow_SSSE3;
1320 : }
1321 : }
1322 : #endif
1323 : #if defined(HAS_I422TORGBAROW_AVX2)
1324 0 : if (TestCpuFlag(kCpuHasAVX2)) {
1325 0 : I422ToRGBARow = I422ToRGBARow_Any_AVX2;
1326 0 : if (IS_ALIGNED(width, 16)) {
1327 0 : I422ToRGBARow = I422ToRGBARow_AVX2;
1328 : }
1329 : }
1330 : #endif
1331 : #if defined(HAS_I422TORGBAROW_NEON)
1332 : if (TestCpuFlag(kCpuHasNEON)) {
1333 : I422ToRGBARow = I422ToRGBARow_Any_NEON;
1334 : if (IS_ALIGNED(width, 8)) {
1335 : I422ToRGBARow = I422ToRGBARow_NEON;
1336 : }
1337 : }
1338 : #endif
1339 : #if defined(HAS_I422TORGBAROW_DSPR2)
1340 : if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(width, 4) &&
1341 : IS_ALIGNED(src_y, 4) && IS_ALIGNED(src_stride_y, 4) &&
1342 : IS_ALIGNED(src_u, 2) && IS_ALIGNED(src_stride_u, 2) &&
1343 : IS_ALIGNED(src_v, 2) && IS_ALIGNED(src_stride_v, 2) &&
1344 : IS_ALIGNED(dst_rgba, 4) && IS_ALIGNED(dst_stride_rgba, 4)) {
1345 : I422ToRGBARow = I422ToRGBARow_DSPR2;
1346 : }
1347 : #endif
1348 : #if defined(HAS_I422TORGBAROW_MSA)
1349 : if (TestCpuFlag(kCpuHasMSA)) {
1350 : I422ToRGBARow = I422ToRGBARow_Any_MSA;
1351 : if (IS_ALIGNED(width, 8)) {
1352 : I422ToRGBARow = I422ToRGBARow_MSA;
1353 : }
1354 : }
1355 : #endif
1356 :
1357 0 : for (y = 0; y < height; ++y) {
1358 0 : I422ToRGBARow(src_y, src_u, src_v, dst_rgba, yuvconstants, width);
1359 0 : dst_rgba += dst_stride_rgba;
1360 0 : src_y += src_stride_y;
1361 0 : src_u += src_stride_u;
1362 0 : src_v += src_stride_v;
1363 : }
1364 0 : return 0;
1365 : }
1366 :
1367 : // Convert I422 to RGBA.
1368 : LIBYUV_API
1369 0 : int I422ToRGBA(const uint8* src_y,
1370 : int src_stride_y,
1371 : const uint8* src_u,
1372 : int src_stride_u,
1373 : const uint8* src_v,
1374 : int src_stride_v,
1375 : uint8* dst_rgba,
1376 : int dst_stride_rgba,
1377 : int width,
1378 : int height) {
1379 : return I422ToRGBAMatrix(src_y, src_stride_y, src_u, src_stride_u, src_v,
1380 : src_stride_v, dst_rgba, dst_stride_rgba,
1381 0 : &kYuvI601Constants, width, height);
1382 : }
1383 :
1384 : // Convert I422 to BGRA.
1385 : LIBYUV_API
1386 0 : int I422ToBGRA(const uint8* src_y,
1387 : int src_stride_y,
1388 : const uint8* src_u,
1389 : int src_stride_u,
1390 : const uint8* src_v,
1391 : int src_stride_v,
1392 : uint8* dst_bgra,
1393 : int dst_stride_bgra,
1394 : int width,
1395 : int height) {
1396 : return I422ToRGBAMatrix(src_y, src_stride_y, src_v,
1397 : src_stride_v, // Swap U and V
1398 : src_u, src_stride_u, dst_bgra, dst_stride_bgra,
1399 : &kYvuI601Constants, // Use Yvu matrix
1400 0 : width, height);
1401 : }
1402 :
1403 : // Convert NV12 to RGB565.
1404 : LIBYUV_API
1405 0 : int NV12ToRGB565(const uint8* src_y,
1406 : int src_stride_y,
1407 : const uint8* src_uv,
1408 : int src_stride_uv,
1409 : uint8* dst_rgb565,
1410 : int dst_stride_rgb565,
1411 : int width,
1412 : int height) {
1413 : int y;
1414 : void (*NV12ToRGB565Row)(
1415 : const uint8* y_buf, const uint8* uv_buf, uint8* rgb_buf,
1416 0 : const struct YuvConstants* yuvconstants, int width) = NV12ToRGB565Row_C;
1417 0 : if (!src_y || !src_uv || !dst_rgb565 || width <= 0 || height == 0) {
1418 0 : return -1;
1419 : }
1420 : // Negative height means invert the image.
1421 0 : if (height < 0) {
1422 0 : height = -height;
1423 0 : dst_rgb565 = dst_rgb565 + (height - 1) * dst_stride_rgb565;
1424 0 : dst_stride_rgb565 = -dst_stride_rgb565;
1425 : }
1426 : #if defined(HAS_NV12TORGB565ROW_SSSE3)
1427 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
1428 0 : NV12ToRGB565Row = NV12ToRGB565Row_Any_SSSE3;
1429 0 : if (IS_ALIGNED(width, 8)) {
1430 0 : NV12ToRGB565Row = NV12ToRGB565Row_SSSE3;
1431 : }
1432 : }
1433 : #endif
1434 : #if defined(HAS_NV12TORGB565ROW_AVX2)
1435 0 : if (TestCpuFlag(kCpuHasAVX2)) {
1436 0 : NV12ToRGB565Row = NV12ToRGB565Row_Any_AVX2;
1437 0 : if (IS_ALIGNED(width, 16)) {
1438 0 : NV12ToRGB565Row = NV12ToRGB565Row_AVX2;
1439 : }
1440 : }
1441 : #endif
1442 : #if defined(HAS_NV12TORGB565ROW_NEON)
1443 : if (TestCpuFlag(kCpuHasNEON)) {
1444 : NV12ToRGB565Row = NV12ToRGB565Row_Any_NEON;
1445 : if (IS_ALIGNED(width, 8)) {
1446 : NV12ToRGB565Row = NV12ToRGB565Row_NEON;
1447 : }
1448 : }
1449 : #endif
1450 : #if defined(HAS_NV12TORGB565ROW_MSA)
1451 : if (TestCpuFlag(kCpuHasMSA)) {
1452 : NV12ToRGB565Row = NV12ToRGB565Row_Any_MSA;
1453 : if (IS_ALIGNED(width, 8)) {
1454 : NV12ToRGB565Row = NV12ToRGB565Row_MSA;
1455 : }
1456 : }
1457 : #endif
1458 :
1459 0 : for (y = 0; y < height; ++y) {
1460 0 : NV12ToRGB565Row(src_y, src_uv, dst_rgb565, &kYuvI601Constants, width);
1461 0 : dst_rgb565 += dst_stride_rgb565;
1462 0 : src_y += src_stride_y;
1463 0 : if (y & 1) {
1464 0 : src_uv += src_stride_uv;
1465 : }
1466 : }
1467 0 : return 0;
1468 : }
1469 :
1470 : // Convert RAW to RGB24.
1471 : LIBYUV_API
1472 0 : int RAWToRGB24(const uint8* src_raw,
1473 : int src_stride_raw,
1474 : uint8* dst_rgb24,
1475 : int dst_stride_rgb24,
1476 : int width,
1477 : int height) {
1478 : int y;
1479 : void (*RAWToRGB24Row)(const uint8* src_rgb, uint8* dst_rgb24, int width) =
1480 0 : RAWToRGB24Row_C;
1481 0 : if (!src_raw || !dst_rgb24 || width <= 0 || height == 0) {
1482 0 : return -1;
1483 : }
1484 : // Negative height means invert the image.
1485 0 : if (height < 0) {
1486 0 : height = -height;
1487 0 : src_raw = src_raw + (height - 1) * src_stride_raw;
1488 0 : src_stride_raw = -src_stride_raw;
1489 : }
1490 : // Coalesce rows.
1491 0 : if (src_stride_raw == width * 3 && dst_stride_rgb24 == width * 3) {
1492 0 : width *= height;
1493 0 : height = 1;
1494 0 : src_stride_raw = dst_stride_rgb24 = 0;
1495 : }
1496 : #if defined(HAS_RAWTORGB24ROW_SSSE3)
1497 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
1498 0 : RAWToRGB24Row = RAWToRGB24Row_Any_SSSE3;
1499 0 : if (IS_ALIGNED(width, 8)) {
1500 0 : RAWToRGB24Row = RAWToRGB24Row_SSSE3;
1501 : }
1502 : }
1503 : #endif
1504 : #if defined(HAS_RAWTORGB24ROW_NEON)
1505 : if (TestCpuFlag(kCpuHasNEON)) {
1506 : RAWToRGB24Row = RAWToRGB24Row_Any_NEON;
1507 : if (IS_ALIGNED(width, 8)) {
1508 : RAWToRGB24Row = RAWToRGB24Row_NEON;
1509 : }
1510 : }
1511 : #endif
1512 :
1513 0 : for (y = 0; y < height; ++y) {
1514 0 : RAWToRGB24Row(src_raw, dst_rgb24, width);
1515 0 : src_raw += src_stride_raw;
1516 0 : dst_rgb24 += dst_stride_rgb24;
1517 : }
1518 0 : return 0;
1519 : }
1520 :
1521 : LIBYUV_API
1522 0 : void SetPlane(uint8* dst_y,
1523 : int dst_stride_y,
1524 : int width,
1525 : int height,
1526 : uint32 value) {
1527 : int y;
1528 0 : void (*SetRow)(uint8 * dst, uint8 value, int width) = SetRow_C;
1529 0 : if (height < 0) {
1530 0 : height = -height;
1531 0 : dst_y = dst_y + (height - 1) * dst_stride_y;
1532 0 : dst_stride_y = -dst_stride_y;
1533 : }
1534 : // Coalesce rows.
1535 0 : if (dst_stride_y == width) {
1536 0 : width *= height;
1537 0 : height = 1;
1538 0 : dst_stride_y = 0;
1539 : }
1540 : #if defined(HAS_SETROW_NEON)
1541 : if (TestCpuFlag(kCpuHasNEON)) {
1542 : SetRow = SetRow_Any_NEON;
1543 : if (IS_ALIGNED(width, 16)) {
1544 : SetRow = SetRow_NEON;
1545 : }
1546 : }
1547 : #endif
1548 : #if defined(HAS_SETROW_X86)
1549 0 : if (TestCpuFlag(kCpuHasX86)) {
1550 0 : SetRow = SetRow_Any_X86;
1551 0 : if (IS_ALIGNED(width, 4)) {
1552 0 : SetRow = SetRow_X86;
1553 : }
1554 : }
1555 : #endif
1556 : #if defined(HAS_SETROW_ERMS)
1557 0 : if (TestCpuFlag(kCpuHasERMS)) {
1558 0 : SetRow = SetRow_ERMS;
1559 : }
1560 : #endif
1561 :
1562 : // Set plane
1563 0 : for (y = 0; y < height; ++y) {
1564 0 : SetRow(dst_y, value, width);
1565 0 : dst_y += dst_stride_y;
1566 : }
1567 0 : }
1568 :
1569 : // Draw a rectangle into I420
1570 : LIBYUV_API
1571 0 : int I420Rect(uint8* dst_y,
1572 : int dst_stride_y,
1573 : uint8* dst_u,
1574 : int dst_stride_u,
1575 : uint8* dst_v,
1576 : int dst_stride_v,
1577 : int x,
1578 : int y,
1579 : int width,
1580 : int height,
1581 : int value_y,
1582 : int value_u,
1583 : int value_v) {
1584 0 : int halfwidth = (width + 1) >> 1;
1585 0 : int halfheight = (height + 1) >> 1;
1586 0 : uint8* start_y = dst_y + y * dst_stride_y + x;
1587 0 : uint8* start_u = dst_u + (y / 2) * dst_stride_u + (x / 2);
1588 0 : uint8* start_v = dst_v + (y / 2) * dst_stride_v + (x / 2);
1589 0 : if (!dst_y || !dst_u || !dst_v || width <= 0 || height == 0 || x < 0 ||
1590 0 : y < 0 || value_y < 0 || value_y > 255 || value_u < 0 || value_u > 255 ||
1591 0 : value_v < 0 || value_v > 255) {
1592 0 : return -1;
1593 : }
1594 :
1595 0 : SetPlane(start_y, dst_stride_y, width, height, value_y);
1596 0 : SetPlane(start_u, dst_stride_u, halfwidth, halfheight, value_u);
1597 0 : SetPlane(start_v, dst_stride_v, halfwidth, halfheight, value_v);
1598 0 : return 0;
1599 : }
1600 :
1601 : // Draw a rectangle into ARGB
1602 : LIBYUV_API
1603 5 : int ARGBRect(uint8* dst_argb,
1604 : int dst_stride_argb,
1605 : int dst_x,
1606 : int dst_y,
1607 : int width,
1608 : int height,
1609 : uint32 value) {
1610 : int y;
1611 5 : void (*ARGBSetRow)(uint8 * dst_argb, uint32 value, int width) = ARGBSetRow_C;
1612 5 : if (!dst_argb || width <= 0 || height == 0 || dst_x < 0 || dst_y < 0) {
1613 0 : return -1;
1614 : }
1615 5 : if (height < 0) {
1616 0 : height = -height;
1617 0 : dst_argb = dst_argb + (height - 1) * dst_stride_argb;
1618 0 : dst_stride_argb = -dst_stride_argb;
1619 : }
1620 5 : dst_argb += dst_y * dst_stride_argb + dst_x * 4;
1621 : // Coalesce rows.
1622 5 : if (dst_stride_argb == width * 4) {
1623 5 : width *= height;
1624 5 : height = 1;
1625 5 : dst_stride_argb = 0;
1626 : }
1627 :
1628 : #if defined(HAS_ARGBSETROW_NEON)
1629 : if (TestCpuFlag(kCpuHasNEON)) {
1630 : ARGBSetRow = ARGBSetRow_Any_NEON;
1631 : if (IS_ALIGNED(width, 4)) {
1632 : ARGBSetRow = ARGBSetRow_NEON;
1633 : }
1634 : }
1635 : #endif
1636 : #if defined(HAS_ARGBSETROW_X86)
1637 5 : if (TestCpuFlag(kCpuHasX86)) {
1638 5 : ARGBSetRow = ARGBSetRow_X86;
1639 : }
1640 : #endif
1641 :
1642 : // Set plane
1643 10 : for (y = 0; y < height; ++y) {
1644 5 : ARGBSetRow(dst_argb, value, width);
1645 5 : dst_argb += dst_stride_argb;
1646 : }
1647 5 : return 0;
1648 : }
1649 :
1650 : // Convert unattentuated ARGB to preattenuated ARGB.
1651 : // An unattenutated ARGB alpha blend uses the formula
1652 : // p = a * f + (1 - a) * b
1653 : // where
1654 : // p is output pixel
1655 : // f is foreground pixel
1656 : // b is background pixel
1657 : // a is alpha value from foreground pixel
1658 : // An preattenutated ARGB alpha blend uses the formula
1659 : // p = f + (1 - a) * b
1660 : // where
1661 : // f is foreground pixel premultiplied by alpha
1662 :
1663 : LIBYUV_API
1664 0 : int ARGBAttenuate(const uint8* src_argb,
1665 : int src_stride_argb,
1666 : uint8* dst_argb,
1667 : int dst_stride_argb,
1668 : int width,
1669 : int height) {
1670 : int y;
1671 : void (*ARGBAttenuateRow)(const uint8* src_argb, uint8* dst_argb, int width) =
1672 0 : ARGBAttenuateRow_C;
1673 0 : if (!src_argb || !dst_argb || width <= 0 || height == 0) {
1674 0 : return -1;
1675 : }
1676 0 : if (height < 0) {
1677 0 : height = -height;
1678 0 : src_argb = src_argb + (height - 1) * src_stride_argb;
1679 0 : src_stride_argb = -src_stride_argb;
1680 : }
1681 : // Coalesce rows.
1682 0 : if (src_stride_argb == width * 4 && dst_stride_argb == width * 4) {
1683 0 : width *= height;
1684 0 : height = 1;
1685 0 : src_stride_argb = dst_stride_argb = 0;
1686 : }
1687 : #if defined(HAS_ARGBATTENUATEROW_SSSE3)
1688 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
1689 0 : ARGBAttenuateRow = ARGBAttenuateRow_Any_SSSE3;
1690 0 : if (IS_ALIGNED(width, 4)) {
1691 0 : ARGBAttenuateRow = ARGBAttenuateRow_SSSE3;
1692 : }
1693 : }
1694 : #endif
1695 : #if defined(HAS_ARGBATTENUATEROW_AVX2)
1696 0 : if (TestCpuFlag(kCpuHasAVX2)) {
1697 0 : ARGBAttenuateRow = ARGBAttenuateRow_Any_AVX2;
1698 0 : if (IS_ALIGNED(width, 8)) {
1699 0 : ARGBAttenuateRow = ARGBAttenuateRow_AVX2;
1700 : }
1701 : }
1702 : #endif
1703 : #if defined(HAS_ARGBATTENUATEROW_NEON)
1704 : if (TestCpuFlag(kCpuHasNEON)) {
1705 : ARGBAttenuateRow = ARGBAttenuateRow_Any_NEON;
1706 : if (IS_ALIGNED(width, 8)) {
1707 : ARGBAttenuateRow = ARGBAttenuateRow_NEON;
1708 : }
1709 : }
1710 : #endif
1711 : #if defined(HAS_ARGBATTENUATEROW_MSA)
1712 : if (TestCpuFlag(kCpuHasMSA)) {
1713 : ARGBAttenuateRow = ARGBAttenuateRow_Any_MSA;
1714 : if (IS_ALIGNED(width, 8)) {
1715 : ARGBAttenuateRow = ARGBAttenuateRow_MSA;
1716 : }
1717 : }
1718 : #endif
1719 :
1720 0 : for (y = 0; y < height; ++y) {
1721 0 : ARGBAttenuateRow(src_argb, dst_argb, width);
1722 0 : src_argb += src_stride_argb;
1723 0 : dst_argb += dst_stride_argb;
1724 : }
1725 0 : return 0;
1726 : }
1727 :
1728 : // Convert preattentuated ARGB to unattenuated ARGB.
1729 : LIBYUV_API
1730 0 : int ARGBUnattenuate(const uint8* src_argb,
1731 : int src_stride_argb,
1732 : uint8* dst_argb,
1733 : int dst_stride_argb,
1734 : int width,
1735 : int height) {
1736 : int y;
1737 : void (*ARGBUnattenuateRow)(const uint8* src_argb, uint8* dst_argb,
1738 0 : int width) = ARGBUnattenuateRow_C;
1739 0 : if (!src_argb || !dst_argb || width <= 0 || height == 0) {
1740 0 : return -1;
1741 : }
1742 0 : if (height < 0) {
1743 0 : height = -height;
1744 0 : src_argb = src_argb + (height - 1) * src_stride_argb;
1745 0 : src_stride_argb = -src_stride_argb;
1746 : }
1747 : // Coalesce rows.
1748 0 : if (src_stride_argb == width * 4 && dst_stride_argb == width * 4) {
1749 0 : width *= height;
1750 0 : height = 1;
1751 0 : src_stride_argb = dst_stride_argb = 0;
1752 : }
1753 : #if defined(HAS_ARGBUNATTENUATEROW_SSE2)
1754 0 : if (TestCpuFlag(kCpuHasSSE2)) {
1755 0 : ARGBUnattenuateRow = ARGBUnattenuateRow_Any_SSE2;
1756 0 : if (IS_ALIGNED(width, 4)) {
1757 0 : ARGBUnattenuateRow = ARGBUnattenuateRow_SSE2;
1758 : }
1759 : }
1760 : #endif
1761 : #if defined(HAS_ARGBUNATTENUATEROW_AVX2)
1762 0 : if (TestCpuFlag(kCpuHasAVX2)) {
1763 0 : ARGBUnattenuateRow = ARGBUnattenuateRow_Any_AVX2;
1764 0 : if (IS_ALIGNED(width, 8)) {
1765 0 : ARGBUnattenuateRow = ARGBUnattenuateRow_AVX2;
1766 : }
1767 : }
1768 : #endif
1769 : // TODO(fbarchard): Neon version.
1770 :
1771 0 : for (y = 0; y < height; ++y) {
1772 0 : ARGBUnattenuateRow(src_argb, dst_argb, width);
1773 0 : src_argb += src_stride_argb;
1774 0 : dst_argb += dst_stride_argb;
1775 : }
1776 0 : return 0;
1777 : }
1778 :
1779 : // Convert ARGB to Grayed ARGB.
1780 : LIBYUV_API
1781 0 : int ARGBGrayTo(const uint8* src_argb,
1782 : int src_stride_argb,
1783 : uint8* dst_argb,
1784 : int dst_stride_argb,
1785 : int width,
1786 : int height) {
1787 : int y;
1788 : void (*ARGBGrayRow)(const uint8* src_argb, uint8* dst_argb, int width) =
1789 0 : ARGBGrayRow_C;
1790 0 : if (!src_argb || !dst_argb || width <= 0 || height == 0) {
1791 0 : return -1;
1792 : }
1793 0 : if (height < 0) {
1794 0 : height = -height;
1795 0 : src_argb = src_argb + (height - 1) * src_stride_argb;
1796 0 : src_stride_argb = -src_stride_argb;
1797 : }
1798 : // Coalesce rows.
1799 0 : if (src_stride_argb == width * 4 && dst_stride_argb == width * 4) {
1800 0 : width *= height;
1801 0 : height = 1;
1802 0 : src_stride_argb = dst_stride_argb = 0;
1803 : }
1804 : #if defined(HAS_ARGBGRAYROW_SSSE3)
1805 0 : if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8)) {
1806 0 : ARGBGrayRow = ARGBGrayRow_SSSE3;
1807 : }
1808 : #endif
1809 : #if defined(HAS_ARGBGRAYROW_NEON)
1810 : if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
1811 : ARGBGrayRow = ARGBGrayRow_NEON;
1812 : }
1813 : #endif
1814 : #if defined(HAS_ARGBGRAYROW_MSA)
1815 : if (TestCpuFlag(kCpuHasMSA) && IS_ALIGNED(width, 8)) {
1816 : ARGBGrayRow = ARGBGrayRow_MSA;
1817 : }
1818 : #endif
1819 :
1820 0 : for (y = 0; y < height; ++y) {
1821 0 : ARGBGrayRow(src_argb, dst_argb, width);
1822 0 : src_argb += src_stride_argb;
1823 0 : dst_argb += dst_stride_argb;
1824 : }
1825 0 : return 0;
1826 : }
1827 :
1828 : // Make a rectangle of ARGB gray scale.
1829 : LIBYUV_API
1830 0 : int ARGBGray(uint8* dst_argb,
1831 : int dst_stride_argb,
1832 : int dst_x,
1833 : int dst_y,
1834 : int width,
1835 : int height) {
1836 : int y;
1837 : void (*ARGBGrayRow)(const uint8* src_argb, uint8* dst_argb, int width) =
1838 0 : ARGBGrayRow_C;
1839 0 : uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
1840 0 : if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0) {
1841 0 : return -1;
1842 : }
1843 : // Coalesce rows.
1844 0 : if (dst_stride_argb == width * 4) {
1845 0 : width *= height;
1846 0 : height = 1;
1847 0 : dst_stride_argb = 0;
1848 : }
1849 : #if defined(HAS_ARGBGRAYROW_SSSE3)
1850 0 : if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8)) {
1851 0 : ARGBGrayRow = ARGBGrayRow_SSSE3;
1852 : }
1853 : #endif
1854 : #if defined(HAS_ARGBGRAYROW_NEON)
1855 : if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
1856 : ARGBGrayRow = ARGBGrayRow_NEON;
1857 : }
1858 : #endif
1859 : #if defined(HAS_ARGBGRAYROW_MSA)
1860 : if (TestCpuFlag(kCpuHasMSA) && IS_ALIGNED(width, 8)) {
1861 : ARGBGrayRow = ARGBGrayRow_MSA;
1862 : }
1863 : #endif
1864 :
1865 0 : for (y = 0; y < height; ++y) {
1866 0 : ARGBGrayRow(dst, dst, width);
1867 0 : dst += dst_stride_argb;
1868 : }
1869 0 : return 0;
1870 : }
1871 :
1872 : // Make a rectangle of ARGB Sepia tone.
1873 : LIBYUV_API
1874 0 : int ARGBSepia(uint8* dst_argb,
1875 : int dst_stride_argb,
1876 : int dst_x,
1877 : int dst_y,
1878 : int width,
1879 : int height) {
1880 : int y;
1881 0 : void (*ARGBSepiaRow)(uint8 * dst_argb, int width) = ARGBSepiaRow_C;
1882 0 : uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
1883 0 : if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0) {
1884 0 : return -1;
1885 : }
1886 : // Coalesce rows.
1887 0 : if (dst_stride_argb == width * 4) {
1888 0 : width *= height;
1889 0 : height = 1;
1890 0 : dst_stride_argb = 0;
1891 : }
1892 : #if defined(HAS_ARGBSEPIAROW_SSSE3)
1893 0 : if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8)) {
1894 0 : ARGBSepiaRow = ARGBSepiaRow_SSSE3;
1895 : }
1896 : #endif
1897 : #if defined(HAS_ARGBSEPIAROW_NEON)
1898 : if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
1899 : ARGBSepiaRow = ARGBSepiaRow_NEON;
1900 : }
1901 : #endif
1902 : #if defined(HAS_ARGBSEPIAROW_MSA)
1903 : if (TestCpuFlag(kCpuHasMSA) && IS_ALIGNED(width, 8)) {
1904 : ARGBSepiaRow = ARGBSepiaRow_MSA;
1905 : }
1906 : #endif
1907 :
1908 0 : for (y = 0; y < height; ++y) {
1909 0 : ARGBSepiaRow(dst, width);
1910 0 : dst += dst_stride_argb;
1911 : }
1912 0 : return 0;
1913 : }
1914 :
1915 : // Apply a 4x4 matrix to each ARGB pixel.
1916 : // Note: Normally for shading, but can be used to swizzle or invert.
1917 : LIBYUV_API
1918 0 : int ARGBColorMatrix(const uint8* src_argb,
1919 : int src_stride_argb,
1920 : uint8* dst_argb,
1921 : int dst_stride_argb,
1922 : const int8* matrix_argb,
1923 : int width,
1924 : int height) {
1925 : int y;
1926 : void (*ARGBColorMatrixRow)(const uint8* src_argb, uint8* dst_argb,
1927 : const int8* matrix_argb, int width) =
1928 0 : ARGBColorMatrixRow_C;
1929 0 : if (!src_argb || !dst_argb || !matrix_argb || width <= 0 || height == 0) {
1930 0 : return -1;
1931 : }
1932 0 : if (height < 0) {
1933 0 : height = -height;
1934 0 : src_argb = src_argb + (height - 1) * src_stride_argb;
1935 0 : src_stride_argb = -src_stride_argb;
1936 : }
1937 : // Coalesce rows.
1938 0 : if (src_stride_argb == width * 4 && dst_stride_argb == width * 4) {
1939 0 : width *= height;
1940 0 : height = 1;
1941 0 : src_stride_argb = dst_stride_argb = 0;
1942 : }
1943 : #if defined(HAS_ARGBCOLORMATRIXROW_SSSE3)
1944 0 : if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 8)) {
1945 0 : ARGBColorMatrixRow = ARGBColorMatrixRow_SSSE3;
1946 : }
1947 : #endif
1948 : #if defined(HAS_ARGBCOLORMATRIXROW_NEON)
1949 : if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
1950 : ARGBColorMatrixRow = ARGBColorMatrixRow_NEON;
1951 : }
1952 : #endif
1953 0 : for (y = 0; y < height; ++y) {
1954 0 : ARGBColorMatrixRow(src_argb, dst_argb, matrix_argb, width);
1955 0 : src_argb += src_stride_argb;
1956 0 : dst_argb += dst_stride_argb;
1957 : }
1958 0 : return 0;
1959 : }
1960 :
1961 : // Apply a 4x3 matrix to each ARGB pixel.
1962 : // Deprecated.
1963 : LIBYUV_API
1964 0 : int RGBColorMatrix(uint8* dst_argb,
1965 : int dst_stride_argb,
1966 : const int8* matrix_rgb,
1967 : int dst_x,
1968 : int dst_y,
1969 : int width,
1970 : int height) {
1971 : SIMD_ALIGNED(int8 matrix_argb[16]);
1972 0 : uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
1973 0 : if (!dst_argb || !matrix_rgb || width <= 0 || height <= 0 || dst_x < 0 ||
1974 : dst_y < 0) {
1975 0 : return -1;
1976 : }
1977 :
1978 : // Convert 4x3 7 bit matrix to 4x4 6 bit matrix.
1979 0 : matrix_argb[0] = matrix_rgb[0] / 2;
1980 0 : matrix_argb[1] = matrix_rgb[1] / 2;
1981 0 : matrix_argb[2] = matrix_rgb[2] / 2;
1982 0 : matrix_argb[3] = matrix_rgb[3] / 2;
1983 0 : matrix_argb[4] = matrix_rgb[4] / 2;
1984 0 : matrix_argb[5] = matrix_rgb[5] / 2;
1985 0 : matrix_argb[6] = matrix_rgb[6] / 2;
1986 0 : matrix_argb[7] = matrix_rgb[7] / 2;
1987 0 : matrix_argb[8] = matrix_rgb[8] / 2;
1988 0 : matrix_argb[9] = matrix_rgb[9] / 2;
1989 0 : matrix_argb[10] = matrix_rgb[10] / 2;
1990 0 : matrix_argb[11] = matrix_rgb[11] / 2;
1991 0 : matrix_argb[14] = matrix_argb[13] = matrix_argb[12] = 0;
1992 0 : matrix_argb[15] = 64; // 1.0
1993 :
1994 : return ARGBColorMatrix((const uint8*)(dst), dst_stride_argb, dst,
1995 0 : dst_stride_argb, &matrix_argb[0], width, height);
1996 : }
1997 :
1998 : // Apply a color table each ARGB pixel.
1999 : // Table contains 256 ARGB values.
2000 : LIBYUV_API
2001 0 : int ARGBColorTable(uint8* dst_argb,
2002 : int dst_stride_argb,
2003 : const uint8* table_argb,
2004 : int dst_x,
2005 : int dst_y,
2006 : int width,
2007 : int height) {
2008 : int y;
2009 : void (*ARGBColorTableRow)(uint8 * dst_argb, const uint8* table_argb,
2010 0 : int width) = ARGBColorTableRow_C;
2011 0 : uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
2012 0 : if (!dst_argb || !table_argb || width <= 0 || height <= 0 || dst_x < 0 ||
2013 : dst_y < 0) {
2014 0 : return -1;
2015 : }
2016 : // Coalesce rows.
2017 0 : if (dst_stride_argb == width * 4) {
2018 0 : width *= height;
2019 0 : height = 1;
2020 0 : dst_stride_argb = 0;
2021 : }
2022 : #if defined(HAS_ARGBCOLORTABLEROW_X86)
2023 0 : if (TestCpuFlag(kCpuHasX86)) {
2024 0 : ARGBColorTableRow = ARGBColorTableRow_X86;
2025 : }
2026 : #endif
2027 0 : for (y = 0; y < height; ++y) {
2028 0 : ARGBColorTableRow(dst, table_argb, width);
2029 0 : dst += dst_stride_argb;
2030 : }
2031 0 : return 0;
2032 : }
2033 :
2034 : // Apply a color table each ARGB pixel but preserve destination alpha.
2035 : // Table contains 256 ARGB values.
2036 : LIBYUV_API
2037 0 : int RGBColorTable(uint8* dst_argb,
2038 : int dst_stride_argb,
2039 : const uint8* table_argb,
2040 : int dst_x,
2041 : int dst_y,
2042 : int width,
2043 : int height) {
2044 : int y;
2045 : void (*RGBColorTableRow)(uint8 * dst_argb, const uint8* table_argb,
2046 0 : int width) = RGBColorTableRow_C;
2047 0 : uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
2048 0 : if (!dst_argb || !table_argb || width <= 0 || height <= 0 || dst_x < 0 ||
2049 : dst_y < 0) {
2050 0 : return -1;
2051 : }
2052 : // Coalesce rows.
2053 0 : if (dst_stride_argb == width * 4) {
2054 0 : width *= height;
2055 0 : height = 1;
2056 0 : dst_stride_argb = 0;
2057 : }
2058 : #if defined(HAS_RGBCOLORTABLEROW_X86)
2059 0 : if (TestCpuFlag(kCpuHasX86)) {
2060 0 : RGBColorTableRow = RGBColorTableRow_X86;
2061 : }
2062 : #endif
2063 0 : for (y = 0; y < height; ++y) {
2064 0 : RGBColorTableRow(dst, table_argb, width);
2065 0 : dst += dst_stride_argb;
2066 : }
2067 0 : return 0;
2068 : }
2069 :
2070 : // ARGBQuantize is used to posterize art.
2071 : // e.g. rgb / qvalue * qvalue + qvalue / 2
2072 : // But the low levels implement efficiently with 3 parameters, and could be
2073 : // used for other high level operations.
2074 : // dst_argb[0] = (b * scale >> 16) * interval_size + interval_offset;
2075 : // where scale is 1 / interval_size as a fixed point value.
2076 : // The divide is replaces with a multiply by reciprocal fixed point multiply.
2077 : // Caveat - although SSE2 saturates, the C function does not and should be used
2078 : // with care if doing anything but quantization.
2079 : LIBYUV_API
2080 0 : int ARGBQuantize(uint8* dst_argb,
2081 : int dst_stride_argb,
2082 : int scale,
2083 : int interval_size,
2084 : int interval_offset,
2085 : int dst_x,
2086 : int dst_y,
2087 : int width,
2088 : int height) {
2089 : int y;
2090 : void (*ARGBQuantizeRow)(uint8 * dst_argb, int scale, int interval_size,
2091 0 : int interval_offset, int width) = ARGBQuantizeRow_C;
2092 0 : uint8* dst = dst_argb + dst_y * dst_stride_argb + dst_x * 4;
2093 0 : if (!dst_argb || width <= 0 || height <= 0 || dst_x < 0 || dst_y < 0 ||
2094 0 : interval_size < 1 || interval_size > 255) {
2095 0 : return -1;
2096 : }
2097 : // Coalesce rows.
2098 0 : if (dst_stride_argb == width * 4) {
2099 0 : width *= height;
2100 0 : height = 1;
2101 0 : dst_stride_argb = 0;
2102 : }
2103 : #if defined(HAS_ARGBQUANTIZEROW_SSE2)
2104 0 : if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 4)) {
2105 0 : ARGBQuantizeRow = ARGBQuantizeRow_SSE2;
2106 : }
2107 : #endif
2108 : #if defined(HAS_ARGBQUANTIZEROW_NEON)
2109 : if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
2110 : ARGBQuantizeRow = ARGBQuantizeRow_NEON;
2111 : }
2112 : #endif
2113 0 : for (y = 0; y < height; ++y) {
2114 0 : ARGBQuantizeRow(dst, scale, interval_size, interval_offset, width);
2115 0 : dst += dst_stride_argb;
2116 : }
2117 0 : return 0;
2118 : }
2119 :
2120 : // Computes table of cumulative sum for image where the value is the sum
2121 : // of all values above and to the left of the entry. Used by ARGBBlur.
2122 : LIBYUV_API
2123 0 : int ARGBComputeCumulativeSum(const uint8* src_argb,
2124 : int src_stride_argb,
2125 : int32* dst_cumsum,
2126 : int dst_stride32_cumsum,
2127 : int width,
2128 : int height) {
2129 : int y;
2130 : void (*ComputeCumulativeSumRow)(const uint8* row, int32* cumsum,
2131 : const int32* previous_cumsum, int width) =
2132 0 : ComputeCumulativeSumRow_C;
2133 0 : int32* previous_cumsum = dst_cumsum;
2134 0 : if (!dst_cumsum || !src_argb || width <= 0 || height <= 0) {
2135 0 : return -1;
2136 : }
2137 : #if defined(HAS_CUMULATIVESUMTOAVERAGEROW_SSE2)
2138 0 : if (TestCpuFlag(kCpuHasSSE2)) {
2139 0 : ComputeCumulativeSumRow = ComputeCumulativeSumRow_SSE2;
2140 : }
2141 : #endif
2142 0 : memset(dst_cumsum, 0, width * sizeof(dst_cumsum[0]) * 4); // 4 int per pixel.
2143 0 : for (y = 0; y < height; ++y) {
2144 0 : ComputeCumulativeSumRow(src_argb, dst_cumsum, previous_cumsum, width);
2145 0 : previous_cumsum = dst_cumsum;
2146 0 : dst_cumsum += dst_stride32_cumsum;
2147 0 : src_argb += src_stride_argb;
2148 : }
2149 0 : return 0;
2150 : }
2151 :
2152 : // Blur ARGB image.
2153 : // Caller should allocate CumulativeSum table of width * height * 16 bytes
2154 : // aligned to 16 byte boundary. height can be radius * 2 + 2 to save memory
2155 : // as the buffer is treated as circular.
2156 : LIBYUV_API
2157 0 : int ARGBBlur(const uint8* src_argb,
2158 : int src_stride_argb,
2159 : uint8* dst_argb,
2160 : int dst_stride_argb,
2161 : int32* dst_cumsum,
2162 : int dst_stride32_cumsum,
2163 : int width,
2164 : int height,
2165 : int radius) {
2166 : int y;
2167 : void (*ComputeCumulativeSumRow)(const uint8* row, int32* cumsum,
2168 : const int32* previous_cumsum, int width) =
2169 0 : ComputeCumulativeSumRow_C;
2170 : void (*CumulativeSumToAverageRow)(const int32* topleft, const int32* botleft,
2171 : int width, int area, uint8* dst,
2172 0 : int count) = CumulativeSumToAverageRow_C;
2173 : int32* cumsum_bot_row;
2174 : int32* max_cumsum_bot_row;
2175 : int32* cumsum_top_row;
2176 :
2177 0 : if (!src_argb || !dst_argb || width <= 0 || height == 0) {
2178 0 : return -1;
2179 : }
2180 0 : if (height < 0) {
2181 0 : height = -height;
2182 0 : src_argb = src_argb + (height - 1) * src_stride_argb;
2183 0 : src_stride_argb = -src_stride_argb;
2184 : }
2185 0 : if (radius > height) {
2186 0 : radius = height;
2187 : }
2188 0 : if (radius > (width / 2 - 1)) {
2189 0 : radius = width / 2 - 1;
2190 : }
2191 0 : if (radius <= 0) {
2192 0 : return -1;
2193 : }
2194 : #if defined(HAS_CUMULATIVESUMTOAVERAGEROW_SSE2)
2195 0 : if (TestCpuFlag(kCpuHasSSE2)) {
2196 0 : ComputeCumulativeSumRow = ComputeCumulativeSumRow_SSE2;
2197 0 : CumulativeSumToAverageRow = CumulativeSumToAverageRow_SSE2;
2198 : }
2199 : #endif
2200 : // Compute enough CumulativeSum for first row to be blurred. After this
2201 : // one row of CumulativeSum is updated at a time.
2202 : ARGBComputeCumulativeSum(src_argb, src_stride_argb, dst_cumsum,
2203 0 : dst_stride32_cumsum, width, radius);
2204 :
2205 0 : src_argb = src_argb + radius * src_stride_argb;
2206 0 : cumsum_bot_row = &dst_cumsum[(radius - 1) * dst_stride32_cumsum];
2207 :
2208 0 : max_cumsum_bot_row = &dst_cumsum[(radius * 2 + 2) * dst_stride32_cumsum];
2209 0 : cumsum_top_row = &dst_cumsum[0];
2210 :
2211 0 : for (y = 0; y < height; ++y) {
2212 0 : int top_y = ((y - radius - 1) >= 0) ? (y - radius - 1) : 0;
2213 0 : int bot_y = ((y + radius) < height) ? (y + radius) : (height - 1);
2214 0 : int area = radius * (bot_y - top_y);
2215 0 : int boxwidth = radius * 4;
2216 : int x;
2217 : int n;
2218 :
2219 : // Increment cumsum_top_row pointer with circular buffer wrap around.
2220 0 : if (top_y) {
2221 0 : cumsum_top_row += dst_stride32_cumsum;
2222 0 : if (cumsum_top_row >= max_cumsum_bot_row) {
2223 0 : cumsum_top_row = dst_cumsum;
2224 : }
2225 : }
2226 : // Increment cumsum_bot_row pointer with circular buffer wrap around and
2227 : // then fill in a row of CumulativeSum.
2228 0 : if ((y + radius) < height) {
2229 0 : const int32* prev_cumsum_bot_row = cumsum_bot_row;
2230 0 : cumsum_bot_row += dst_stride32_cumsum;
2231 0 : if (cumsum_bot_row >= max_cumsum_bot_row) {
2232 0 : cumsum_bot_row = dst_cumsum;
2233 : }
2234 : ComputeCumulativeSumRow(src_argb, cumsum_bot_row, prev_cumsum_bot_row,
2235 0 : width);
2236 0 : src_argb += src_stride_argb;
2237 : }
2238 :
2239 : // Left clipped.
2240 0 : for (x = 0; x < radius + 1; ++x) {
2241 0 : CumulativeSumToAverageRow(cumsum_top_row, cumsum_bot_row, boxwidth, area,
2242 0 : &dst_argb[x * 4], 1);
2243 0 : area += (bot_y - top_y);
2244 0 : boxwidth += 4;
2245 : }
2246 :
2247 : // Middle unclipped.
2248 0 : n = (width - 1) - radius - x + 1;
2249 0 : CumulativeSumToAverageRow(cumsum_top_row, cumsum_bot_row, boxwidth, area,
2250 0 : &dst_argb[x * 4], n);
2251 :
2252 : // Right clipped.
2253 0 : for (x += n; x <= width - 1; ++x) {
2254 0 : area -= (bot_y - top_y);
2255 0 : boxwidth -= 4;
2256 0 : CumulativeSumToAverageRow(cumsum_top_row + (x - radius - 1) * 4,
2257 0 : cumsum_bot_row + (x - radius - 1) * 4, boxwidth,
2258 0 : area, &dst_argb[x * 4], 1);
2259 : }
2260 0 : dst_argb += dst_stride_argb;
2261 : }
2262 0 : return 0;
2263 : }
2264 :
2265 : // Multiply ARGB image by a specified ARGB value.
2266 : LIBYUV_API
2267 0 : int ARGBShade(const uint8* src_argb,
2268 : int src_stride_argb,
2269 : uint8* dst_argb,
2270 : int dst_stride_argb,
2271 : int width,
2272 : int height,
2273 : uint32 value) {
2274 : int y;
2275 : void (*ARGBShadeRow)(const uint8* src_argb, uint8* dst_argb, int width,
2276 0 : uint32 value) = ARGBShadeRow_C;
2277 0 : if (!src_argb || !dst_argb || width <= 0 || height == 0 || value == 0u) {
2278 0 : return -1;
2279 : }
2280 0 : if (height < 0) {
2281 0 : height = -height;
2282 0 : src_argb = src_argb + (height - 1) * src_stride_argb;
2283 0 : src_stride_argb = -src_stride_argb;
2284 : }
2285 : // Coalesce rows.
2286 0 : if (src_stride_argb == width * 4 && dst_stride_argb == width * 4) {
2287 0 : width *= height;
2288 0 : height = 1;
2289 0 : src_stride_argb = dst_stride_argb = 0;
2290 : }
2291 : #if defined(HAS_ARGBSHADEROW_SSE2)
2292 0 : if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 4)) {
2293 0 : ARGBShadeRow = ARGBShadeRow_SSE2;
2294 : }
2295 : #endif
2296 : #if defined(HAS_ARGBSHADEROW_NEON)
2297 : if (TestCpuFlag(kCpuHasNEON) && IS_ALIGNED(width, 8)) {
2298 : ARGBShadeRow = ARGBShadeRow_NEON;
2299 : }
2300 : #endif
2301 : #if defined(HAS_ARGBSHADEROW_MSA)
2302 : if (TestCpuFlag(kCpuHasMSA) && IS_ALIGNED(width, 4)) {
2303 : ARGBShadeRow = ARGBShadeRow_MSA;
2304 : }
2305 : #endif
2306 :
2307 0 : for (y = 0; y < height; ++y) {
2308 0 : ARGBShadeRow(src_argb, dst_argb, width, value);
2309 0 : src_argb += src_stride_argb;
2310 0 : dst_argb += dst_stride_argb;
2311 : }
2312 0 : return 0;
2313 : }
2314 :
2315 : // Interpolate 2 planes by specified amount (0 to 255).
2316 : LIBYUV_API
2317 0 : int InterpolatePlane(const uint8* src0,
2318 : int src_stride0,
2319 : const uint8* src1,
2320 : int src_stride1,
2321 : uint8* dst,
2322 : int dst_stride,
2323 : int width,
2324 : int height,
2325 : int interpolation) {
2326 : int y;
2327 : void (*InterpolateRow)(uint8 * dst_ptr, const uint8* src_ptr,
2328 : ptrdiff_t src_stride, int dst_width,
2329 0 : int source_y_fraction) = InterpolateRow_C;
2330 0 : if (!src0 || !src1 || !dst || width <= 0 || height == 0) {
2331 0 : return -1;
2332 : }
2333 : // Negative height means invert the image.
2334 0 : if (height < 0) {
2335 0 : height = -height;
2336 0 : dst = dst + (height - 1) * dst_stride;
2337 0 : dst_stride = -dst_stride;
2338 : }
2339 : // Coalesce rows.
2340 0 : if (src_stride0 == width && src_stride1 == width && dst_stride == width) {
2341 0 : width *= height;
2342 0 : height = 1;
2343 0 : src_stride0 = src_stride1 = dst_stride = 0;
2344 : }
2345 : #if defined(HAS_INTERPOLATEROW_SSSE3)
2346 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
2347 0 : InterpolateRow = InterpolateRow_Any_SSSE3;
2348 0 : if (IS_ALIGNED(width, 16)) {
2349 0 : InterpolateRow = InterpolateRow_SSSE3;
2350 : }
2351 : }
2352 : #endif
2353 : #if defined(HAS_INTERPOLATEROW_AVX2)
2354 0 : if (TestCpuFlag(kCpuHasAVX2)) {
2355 0 : InterpolateRow = InterpolateRow_Any_AVX2;
2356 0 : if (IS_ALIGNED(width, 32)) {
2357 0 : InterpolateRow = InterpolateRow_AVX2;
2358 : }
2359 : }
2360 : #endif
2361 : #if defined(HAS_INTERPOLATEROW_NEON)
2362 : if (TestCpuFlag(kCpuHasNEON)) {
2363 : InterpolateRow = InterpolateRow_Any_NEON;
2364 : if (IS_ALIGNED(width, 16)) {
2365 : InterpolateRow = InterpolateRow_NEON;
2366 : }
2367 : }
2368 : #endif
2369 : #if defined(HAS_INTERPOLATEROW_DSPR2)
2370 : if (TestCpuFlag(kCpuHasDSPR2) && IS_ALIGNED(src0, 4) &&
2371 : IS_ALIGNED(src_stride0, 4) && IS_ALIGNED(src1, 4) &&
2372 : IS_ALIGNED(src_stride1, 4) && IS_ALIGNED(dst, 4) &&
2373 : IS_ALIGNED(dst_stride, 4) && IS_ALIGNED(width, 4)) {
2374 : InterpolateRow = InterpolateRow_DSPR2;
2375 : }
2376 : #endif
2377 :
2378 0 : for (y = 0; y < height; ++y) {
2379 0 : InterpolateRow(dst, src0, src1 - src0, width, interpolation);
2380 0 : src0 += src_stride0;
2381 0 : src1 += src_stride1;
2382 0 : dst += dst_stride;
2383 : }
2384 0 : return 0;
2385 : }
2386 :
2387 : // Interpolate 2 ARGB images by specified amount (0 to 255).
2388 : LIBYUV_API
2389 0 : int ARGBInterpolate(const uint8* src_argb0,
2390 : int src_stride_argb0,
2391 : const uint8* src_argb1,
2392 : int src_stride_argb1,
2393 : uint8* dst_argb,
2394 : int dst_stride_argb,
2395 : int width,
2396 : int height,
2397 : int interpolation) {
2398 0 : return InterpolatePlane(src_argb0, src_stride_argb0, src_argb1,
2399 : src_stride_argb1, dst_argb, dst_stride_argb,
2400 0 : width * 4, height, interpolation);
2401 : }
2402 :
2403 : // Interpolate 2 YUV images by specified amount (0 to 255).
2404 : LIBYUV_API
2405 0 : int I420Interpolate(const uint8* src0_y,
2406 : int src0_stride_y,
2407 : const uint8* src0_u,
2408 : int src0_stride_u,
2409 : const uint8* src0_v,
2410 : int src0_stride_v,
2411 : const uint8* src1_y,
2412 : int src1_stride_y,
2413 : const uint8* src1_u,
2414 : int src1_stride_u,
2415 : const uint8* src1_v,
2416 : int src1_stride_v,
2417 : uint8* dst_y,
2418 : int dst_stride_y,
2419 : uint8* dst_u,
2420 : int dst_stride_u,
2421 : uint8* dst_v,
2422 : int dst_stride_v,
2423 : int width,
2424 : int height,
2425 : int interpolation) {
2426 0 : int halfwidth = (width + 1) >> 1;
2427 0 : int halfheight = (height + 1) >> 1;
2428 0 : if (!src0_y || !src0_u || !src0_v || !src1_y || !src1_u || !src1_v ||
2429 0 : !dst_y || !dst_u || !dst_v || width <= 0 || height == 0) {
2430 0 : return -1;
2431 : }
2432 : InterpolatePlane(src0_y, src0_stride_y, src1_y, src1_stride_y, dst_y,
2433 0 : dst_stride_y, width, height, interpolation);
2434 : InterpolatePlane(src0_u, src0_stride_u, src1_u, src1_stride_u, dst_u,
2435 0 : dst_stride_u, halfwidth, halfheight, interpolation);
2436 : InterpolatePlane(src0_v, src0_stride_v, src1_v, src1_stride_v, dst_v,
2437 0 : dst_stride_v, halfwidth, halfheight, interpolation);
2438 0 : return 0;
2439 : }
2440 :
2441 : // Shuffle ARGB channel order. e.g. BGRA to ARGB.
2442 : LIBYUV_API
2443 0 : int ARGBShuffle(const uint8* src_bgra,
2444 : int src_stride_bgra,
2445 : uint8* dst_argb,
2446 : int dst_stride_argb,
2447 : const uint8* shuffler,
2448 : int width,
2449 : int height) {
2450 : int y;
2451 : void (*ARGBShuffleRow)(const uint8* src_bgra, uint8* dst_argb,
2452 0 : const uint8* shuffler, int width) = ARGBShuffleRow_C;
2453 0 : if (!src_bgra || !dst_argb || width <= 0 || height == 0) {
2454 0 : return -1;
2455 : }
2456 : // Negative height means invert the image.
2457 0 : if (height < 0) {
2458 0 : height = -height;
2459 0 : src_bgra = src_bgra + (height - 1) * src_stride_bgra;
2460 0 : src_stride_bgra = -src_stride_bgra;
2461 : }
2462 : // Coalesce rows.
2463 0 : if (src_stride_bgra == width * 4 && dst_stride_argb == width * 4) {
2464 0 : width *= height;
2465 0 : height = 1;
2466 0 : src_stride_bgra = dst_stride_argb = 0;
2467 : }
2468 : #if defined(HAS_ARGBSHUFFLEROW_SSE2)
2469 0 : if (TestCpuFlag(kCpuHasSSE2)) {
2470 0 : ARGBShuffleRow = ARGBShuffleRow_Any_SSE2;
2471 0 : if (IS_ALIGNED(width, 4)) {
2472 0 : ARGBShuffleRow = ARGBShuffleRow_SSE2;
2473 : }
2474 : }
2475 : #endif
2476 : #if defined(HAS_ARGBSHUFFLEROW_SSSE3)
2477 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
2478 0 : ARGBShuffleRow = ARGBShuffleRow_Any_SSSE3;
2479 0 : if (IS_ALIGNED(width, 8)) {
2480 0 : ARGBShuffleRow = ARGBShuffleRow_SSSE3;
2481 : }
2482 : }
2483 : #endif
2484 : #if defined(HAS_ARGBSHUFFLEROW_AVX2)
2485 0 : if (TestCpuFlag(kCpuHasAVX2)) {
2486 0 : ARGBShuffleRow = ARGBShuffleRow_Any_AVX2;
2487 0 : if (IS_ALIGNED(width, 16)) {
2488 0 : ARGBShuffleRow = ARGBShuffleRow_AVX2;
2489 : }
2490 : }
2491 : #endif
2492 : #if defined(HAS_ARGBSHUFFLEROW_NEON)
2493 : if (TestCpuFlag(kCpuHasNEON)) {
2494 : ARGBShuffleRow = ARGBShuffleRow_Any_NEON;
2495 : if (IS_ALIGNED(width, 4)) {
2496 : ARGBShuffleRow = ARGBShuffleRow_NEON;
2497 : }
2498 : }
2499 : #endif
2500 : #if defined(HAS_ARGBSHUFFLEROW_MSA)
2501 : if (TestCpuFlag(kCpuHasMSA)) {
2502 : ARGBShuffleRow = ARGBShuffleRow_Any_MSA;
2503 : if (IS_ALIGNED(width, 8)) {
2504 : ARGBShuffleRow = ARGBShuffleRow_MSA;
2505 : }
2506 : }
2507 : #endif
2508 :
2509 0 : for (y = 0; y < height; ++y) {
2510 0 : ARGBShuffleRow(src_bgra, dst_argb, shuffler, width);
2511 0 : src_bgra += src_stride_bgra;
2512 0 : dst_argb += dst_stride_argb;
2513 : }
2514 0 : return 0;
2515 : }
2516 :
2517 : // Sobel ARGB effect.
2518 0 : static int ARGBSobelize(const uint8* src_argb,
2519 : int src_stride_argb,
2520 : uint8* dst_argb,
2521 : int dst_stride_argb,
2522 : int width,
2523 : int height,
2524 : void (*SobelRow)(const uint8* src_sobelx,
2525 : const uint8* src_sobely,
2526 : uint8* dst,
2527 : int width)) {
2528 : int y;
2529 : void (*ARGBToYJRow)(const uint8* src_argb, uint8* dst_g, int width) =
2530 0 : ARGBToYJRow_C;
2531 : void (*SobelYRow)(const uint8* src_y0, const uint8* src_y1, uint8* dst_sobely,
2532 0 : int width) = SobelYRow_C;
2533 : void (*SobelXRow)(const uint8* src_y0, const uint8* src_y1,
2534 : const uint8* src_y2, uint8* dst_sobely, int width) =
2535 0 : SobelXRow_C;
2536 0 : const int kEdge = 16; // Extra pixels at start of row for extrude/align.
2537 0 : if (!src_argb || !dst_argb || width <= 0 || height == 0) {
2538 0 : return -1;
2539 : }
2540 : // Negative height means invert the image.
2541 0 : if (height < 0) {
2542 0 : height = -height;
2543 0 : src_argb = src_argb + (height - 1) * src_stride_argb;
2544 0 : src_stride_argb = -src_stride_argb;
2545 : }
2546 :
2547 : #if defined(HAS_ARGBTOYJROW_SSSE3)
2548 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
2549 0 : ARGBToYJRow = ARGBToYJRow_Any_SSSE3;
2550 0 : if (IS_ALIGNED(width, 16)) {
2551 0 : ARGBToYJRow = ARGBToYJRow_SSSE3;
2552 : }
2553 : }
2554 : #endif
2555 : #if defined(HAS_ARGBTOYJROW_AVX2)
2556 0 : if (TestCpuFlag(kCpuHasAVX2)) {
2557 0 : ARGBToYJRow = ARGBToYJRow_Any_AVX2;
2558 0 : if (IS_ALIGNED(width, 32)) {
2559 0 : ARGBToYJRow = ARGBToYJRow_AVX2;
2560 : }
2561 : }
2562 : #endif
2563 : #if defined(HAS_ARGBTOYJROW_NEON)
2564 : if (TestCpuFlag(kCpuHasNEON)) {
2565 : ARGBToYJRow = ARGBToYJRow_Any_NEON;
2566 : if (IS_ALIGNED(width, 8)) {
2567 : ARGBToYJRow = ARGBToYJRow_NEON;
2568 : }
2569 : }
2570 : #endif
2571 : #if defined(HAS_ARGBTOYJROW_MSA)
2572 : if (TestCpuFlag(kCpuHasMSA)) {
2573 : ARGBToYJRow = ARGBToYJRow_Any_MSA;
2574 : if (IS_ALIGNED(width, 16)) {
2575 : ARGBToYJRow = ARGBToYJRow_MSA;
2576 : }
2577 : }
2578 : #endif
2579 :
2580 : #if defined(HAS_SOBELYROW_SSE2)
2581 0 : if (TestCpuFlag(kCpuHasSSE2)) {
2582 0 : SobelYRow = SobelYRow_SSE2;
2583 : }
2584 : #endif
2585 : #if defined(HAS_SOBELYROW_NEON)
2586 : if (TestCpuFlag(kCpuHasNEON)) {
2587 : SobelYRow = SobelYRow_NEON;
2588 : }
2589 : #endif
2590 : #if defined(HAS_SOBELXROW_SSE2)
2591 0 : if (TestCpuFlag(kCpuHasSSE2)) {
2592 0 : SobelXRow = SobelXRow_SSE2;
2593 : }
2594 : #endif
2595 : #if defined(HAS_SOBELXROW_NEON)
2596 : if (TestCpuFlag(kCpuHasNEON)) {
2597 : SobelXRow = SobelXRow_NEON;
2598 : }
2599 : #endif
2600 : {
2601 : // 3 rows with edges before/after.
2602 0 : const int kRowSize = (width + kEdge + 31) & ~31;
2603 0 : align_buffer_64(rows, kRowSize * 2 + (kEdge + kRowSize * 3 + kEdge));
2604 0 : uint8* row_sobelx = rows;
2605 0 : uint8* row_sobely = rows + kRowSize;
2606 0 : uint8* row_y = rows + kRowSize * 2;
2607 :
2608 : // Convert first row.
2609 0 : uint8* row_y0 = row_y + kEdge;
2610 0 : uint8* row_y1 = row_y0 + kRowSize;
2611 0 : uint8* row_y2 = row_y1 + kRowSize;
2612 0 : ARGBToYJRow(src_argb, row_y0, width);
2613 0 : row_y0[-1] = row_y0[0];
2614 0 : memset(row_y0 + width, row_y0[width - 1], 16); // Extrude 16 for valgrind.
2615 0 : ARGBToYJRow(src_argb, row_y1, width);
2616 0 : row_y1[-1] = row_y1[0];
2617 0 : memset(row_y1 + width, row_y1[width - 1], 16);
2618 0 : memset(row_y2 + width, 0, 16);
2619 :
2620 0 : for (y = 0; y < height; ++y) {
2621 : // Convert next row of ARGB to G.
2622 0 : if (y < (height - 1)) {
2623 0 : src_argb += src_stride_argb;
2624 : }
2625 0 : ARGBToYJRow(src_argb, row_y2, width);
2626 0 : row_y2[-1] = row_y2[0];
2627 0 : row_y2[width] = row_y2[width - 1];
2628 :
2629 0 : SobelXRow(row_y0 - 1, row_y1 - 1, row_y2 - 1, row_sobelx, width);
2630 0 : SobelYRow(row_y0 - 1, row_y2 - 1, row_sobely, width);
2631 0 : SobelRow(row_sobelx, row_sobely, dst_argb, width);
2632 :
2633 : // Cycle thru circular queue of 3 row_y buffers.
2634 : {
2635 0 : uint8* row_yt = row_y0;
2636 0 : row_y0 = row_y1;
2637 0 : row_y1 = row_y2;
2638 0 : row_y2 = row_yt;
2639 : }
2640 :
2641 0 : dst_argb += dst_stride_argb;
2642 : }
2643 0 : free_aligned_buffer_64(rows);
2644 : }
2645 0 : return 0;
2646 : }
2647 :
2648 : // Sobel ARGB effect.
2649 : LIBYUV_API
2650 0 : int ARGBSobel(const uint8* src_argb,
2651 : int src_stride_argb,
2652 : uint8* dst_argb,
2653 : int dst_stride_argb,
2654 : int width,
2655 : int height) {
2656 : void (*SobelRow)(const uint8* src_sobelx, const uint8* src_sobely,
2657 0 : uint8* dst_argb, int width) = SobelRow_C;
2658 : #if defined(HAS_SOBELROW_SSE2)
2659 0 : if (TestCpuFlag(kCpuHasSSE2)) {
2660 0 : SobelRow = SobelRow_Any_SSE2;
2661 0 : if (IS_ALIGNED(width, 16)) {
2662 0 : SobelRow = SobelRow_SSE2;
2663 : }
2664 : }
2665 : #endif
2666 : #if defined(HAS_SOBELROW_NEON)
2667 : if (TestCpuFlag(kCpuHasNEON)) {
2668 : SobelRow = SobelRow_Any_NEON;
2669 : if (IS_ALIGNED(width, 8)) {
2670 : SobelRow = SobelRow_NEON;
2671 : }
2672 : }
2673 : #endif
2674 : #if defined(HAS_SOBELROW_MSA)
2675 : if (TestCpuFlag(kCpuHasMSA)) {
2676 : SobelRow = SobelRow_Any_MSA;
2677 : if (IS_ALIGNED(width, 16)) {
2678 : SobelRow = SobelRow_MSA;
2679 : }
2680 : }
2681 : #endif
2682 : return ARGBSobelize(src_argb, src_stride_argb, dst_argb, dst_stride_argb,
2683 0 : width, height, SobelRow);
2684 : }
2685 :
2686 : // Sobel ARGB effect with planar output.
2687 : LIBYUV_API
2688 0 : int ARGBSobelToPlane(const uint8* src_argb,
2689 : int src_stride_argb,
2690 : uint8* dst_y,
2691 : int dst_stride_y,
2692 : int width,
2693 : int height) {
2694 : void (*SobelToPlaneRow)(const uint8* src_sobelx, const uint8* src_sobely,
2695 0 : uint8* dst_, int width) = SobelToPlaneRow_C;
2696 : #if defined(HAS_SOBELTOPLANEROW_SSE2)
2697 0 : if (TestCpuFlag(kCpuHasSSE2)) {
2698 0 : SobelToPlaneRow = SobelToPlaneRow_Any_SSE2;
2699 0 : if (IS_ALIGNED(width, 16)) {
2700 0 : SobelToPlaneRow = SobelToPlaneRow_SSE2;
2701 : }
2702 : }
2703 : #endif
2704 : #if defined(HAS_SOBELTOPLANEROW_NEON)
2705 : if (TestCpuFlag(kCpuHasNEON)) {
2706 : SobelToPlaneRow = SobelToPlaneRow_Any_NEON;
2707 : if (IS_ALIGNED(width, 16)) {
2708 : SobelToPlaneRow = SobelToPlaneRow_NEON;
2709 : }
2710 : }
2711 : #endif
2712 : #if defined(HAS_SOBELTOPLANEROW_MSA)
2713 : if (TestCpuFlag(kCpuHasMSA)) {
2714 : SobelToPlaneRow = SobelToPlaneRow_Any_MSA;
2715 : if (IS_ALIGNED(width, 32)) {
2716 : SobelToPlaneRow = SobelToPlaneRow_MSA;
2717 : }
2718 : }
2719 : #endif
2720 : return ARGBSobelize(src_argb, src_stride_argb, dst_y, dst_stride_y, width,
2721 0 : height, SobelToPlaneRow);
2722 : }
2723 :
2724 : // SobelXY ARGB effect.
2725 : // Similar to Sobel, but also stores Sobel X in R and Sobel Y in B. G = Sobel.
2726 : LIBYUV_API
2727 0 : int ARGBSobelXY(const uint8* src_argb,
2728 : int src_stride_argb,
2729 : uint8* dst_argb,
2730 : int dst_stride_argb,
2731 : int width,
2732 : int height) {
2733 : void (*SobelXYRow)(const uint8* src_sobelx, const uint8* src_sobely,
2734 0 : uint8* dst_argb, int width) = SobelXYRow_C;
2735 : #if defined(HAS_SOBELXYROW_SSE2)
2736 0 : if (TestCpuFlag(kCpuHasSSE2)) {
2737 0 : SobelXYRow = SobelXYRow_Any_SSE2;
2738 0 : if (IS_ALIGNED(width, 16)) {
2739 0 : SobelXYRow = SobelXYRow_SSE2;
2740 : }
2741 : }
2742 : #endif
2743 : #if defined(HAS_SOBELXYROW_NEON)
2744 : if (TestCpuFlag(kCpuHasNEON)) {
2745 : SobelXYRow = SobelXYRow_Any_NEON;
2746 : if (IS_ALIGNED(width, 8)) {
2747 : SobelXYRow = SobelXYRow_NEON;
2748 : }
2749 : }
2750 : #endif
2751 : #if defined(HAS_SOBELXYROW_MSA)
2752 : if (TestCpuFlag(kCpuHasMSA)) {
2753 : SobelXYRow = SobelXYRow_Any_MSA;
2754 : if (IS_ALIGNED(width, 16)) {
2755 : SobelXYRow = SobelXYRow_MSA;
2756 : }
2757 : }
2758 : #endif
2759 : return ARGBSobelize(src_argb, src_stride_argb, dst_argb, dst_stride_argb,
2760 0 : width, height, SobelXYRow);
2761 : }
2762 :
2763 : // Apply a 4x4 polynomial to each ARGB pixel.
2764 : LIBYUV_API
2765 0 : int ARGBPolynomial(const uint8* src_argb,
2766 : int src_stride_argb,
2767 : uint8* dst_argb,
2768 : int dst_stride_argb,
2769 : const float* poly,
2770 : int width,
2771 : int height) {
2772 : int y;
2773 : void (*ARGBPolynomialRow)(const uint8* src_argb, uint8* dst_argb,
2774 0 : const float* poly, int width) = ARGBPolynomialRow_C;
2775 0 : if (!src_argb || !dst_argb || !poly || width <= 0 || height == 0) {
2776 0 : return -1;
2777 : }
2778 : // Negative height means invert the image.
2779 0 : if (height < 0) {
2780 0 : height = -height;
2781 0 : src_argb = src_argb + (height - 1) * src_stride_argb;
2782 0 : src_stride_argb = -src_stride_argb;
2783 : }
2784 : // Coalesce rows.
2785 0 : if (src_stride_argb == width * 4 && dst_stride_argb == width * 4) {
2786 0 : width *= height;
2787 0 : height = 1;
2788 0 : src_stride_argb = dst_stride_argb = 0;
2789 : }
2790 : #if defined(HAS_ARGBPOLYNOMIALROW_SSE2)
2791 0 : if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(width, 2)) {
2792 0 : ARGBPolynomialRow = ARGBPolynomialRow_SSE2;
2793 : }
2794 : #endif
2795 : #if defined(HAS_ARGBPOLYNOMIALROW_AVX2)
2796 0 : if (TestCpuFlag(kCpuHasAVX2) && TestCpuFlag(kCpuHasFMA3) &&
2797 0 : IS_ALIGNED(width, 2)) {
2798 0 : ARGBPolynomialRow = ARGBPolynomialRow_AVX2;
2799 : }
2800 : #endif
2801 :
2802 0 : for (y = 0; y < height; ++y) {
2803 0 : ARGBPolynomialRow(src_argb, dst_argb, poly, width);
2804 0 : src_argb += src_stride_argb;
2805 0 : dst_argb += dst_stride_argb;
2806 : }
2807 0 : return 0;
2808 : }
2809 :
2810 : // Convert plane of 16 bit shorts to half floats.
2811 : // Source values are multiplied by scale before storing as half float.
2812 : LIBYUV_API
2813 0 : int HalfFloatPlane(const uint16* src_y,
2814 : int src_stride_y,
2815 : uint16* dst_y,
2816 : int dst_stride_y,
2817 : float scale,
2818 : int width,
2819 : int height) {
2820 : int y;
2821 : void (*HalfFloatRow)(const uint16* src, uint16* dst, float scale, int width) =
2822 0 : HalfFloatRow_C;
2823 0 : if (!src_y || !dst_y || width <= 0 || height == 0) {
2824 0 : return -1;
2825 : }
2826 0 : src_stride_y >>= 1;
2827 0 : dst_stride_y >>= 1;
2828 : // Negative height means invert the image.
2829 0 : if (height < 0) {
2830 0 : height = -height;
2831 0 : src_y = src_y + (height - 1) * src_stride_y;
2832 0 : src_stride_y = -src_stride_y;
2833 : }
2834 : // Coalesce rows.
2835 0 : if (src_stride_y == width && dst_stride_y == width) {
2836 0 : width *= height;
2837 0 : height = 1;
2838 0 : src_stride_y = dst_stride_y = 0;
2839 : }
2840 : #if defined(HAS_HALFFLOATROW_SSE2)
2841 0 : if (TestCpuFlag(kCpuHasSSE2)) {
2842 0 : HalfFloatRow = HalfFloatRow_Any_SSE2;
2843 0 : if (IS_ALIGNED(width, 8)) {
2844 0 : HalfFloatRow = HalfFloatRow_SSE2;
2845 : }
2846 : }
2847 : #endif
2848 : #if defined(HAS_HALFFLOATROW_AVX2)
2849 0 : if (TestCpuFlag(kCpuHasAVX2)) {
2850 0 : HalfFloatRow = HalfFloatRow_Any_AVX2;
2851 0 : if (IS_ALIGNED(width, 16)) {
2852 0 : HalfFloatRow = HalfFloatRow_AVX2;
2853 : }
2854 : }
2855 : #endif
2856 : #if defined(HAS_HALFFLOATROW_F16C)
2857 : if (TestCpuFlag(kCpuHasAVX2) && TestCpuFlag(kCpuHasF16C)) {
2858 : HalfFloatRow =
2859 : (scale == 1.0f) ? HalfFloat1Row_Any_F16C : HalfFloatRow_Any_F16C;
2860 : if (IS_ALIGNED(width, 16)) {
2861 : HalfFloatRow = (scale == 1.0f) ? HalfFloat1Row_F16C : HalfFloatRow_F16C;
2862 : }
2863 : }
2864 : #endif
2865 : #if defined(HAS_HALFFLOATROW_NEON)
2866 : if (TestCpuFlag(kCpuHasNEON)) {
2867 : HalfFloatRow =
2868 : (scale == 1.0f) ? HalfFloat1Row_Any_NEON : HalfFloatRow_Any_NEON;
2869 : if (IS_ALIGNED(width, 8)) {
2870 : HalfFloatRow = (scale == 1.0f) ? HalfFloat1Row_NEON : HalfFloatRow_NEON;
2871 : }
2872 : }
2873 : #endif
2874 :
2875 0 : for (y = 0; y < height; ++y) {
2876 0 : HalfFloatRow(src_y, dst_y, scale, width);
2877 0 : src_y += src_stride_y;
2878 0 : dst_y += dst_stride_y;
2879 : }
2880 0 : return 0;
2881 : }
2882 :
2883 : // Apply a lumacolortable to each ARGB pixel.
2884 : LIBYUV_API
2885 0 : int ARGBLumaColorTable(const uint8* src_argb,
2886 : int src_stride_argb,
2887 : uint8* dst_argb,
2888 : int dst_stride_argb,
2889 : const uint8* luma,
2890 : int width,
2891 : int height) {
2892 : int y;
2893 : void (*ARGBLumaColorTableRow)(
2894 : const uint8* src_argb, uint8* dst_argb, int width, const uint8* luma,
2895 0 : const uint32 lumacoeff) = ARGBLumaColorTableRow_C;
2896 0 : if (!src_argb || !dst_argb || !luma || width <= 0 || height == 0) {
2897 0 : return -1;
2898 : }
2899 : // Negative height means invert the image.
2900 0 : if (height < 0) {
2901 0 : height = -height;
2902 0 : src_argb = src_argb + (height - 1) * src_stride_argb;
2903 0 : src_stride_argb = -src_stride_argb;
2904 : }
2905 : // Coalesce rows.
2906 0 : if (src_stride_argb == width * 4 && dst_stride_argb == width * 4) {
2907 0 : width *= height;
2908 0 : height = 1;
2909 0 : src_stride_argb = dst_stride_argb = 0;
2910 : }
2911 : #if defined(HAS_ARGBLUMACOLORTABLEROW_SSSE3)
2912 0 : if (TestCpuFlag(kCpuHasSSSE3) && IS_ALIGNED(width, 4)) {
2913 0 : ARGBLumaColorTableRow = ARGBLumaColorTableRow_SSSE3;
2914 : }
2915 : #endif
2916 :
2917 0 : for (y = 0; y < height; ++y) {
2918 0 : ARGBLumaColorTableRow(src_argb, dst_argb, width, luma, 0x00264b0f);
2919 0 : src_argb += src_stride_argb;
2920 0 : dst_argb += dst_stride_argb;
2921 : }
2922 0 : return 0;
2923 : }
2924 :
2925 : // Copy Alpha from one ARGB image to another.
2926 : LIBYUV_API
2927 0 : int ARGBCopyAlpha(const uint8* src_argb,
2928 : int src_stride_argb,
2929 : uint8* dst_argb,
2930 : int dst_stride_argb,
2931 : int width,
2932 : int height) {
2933 : int y;
2934 : void (*ARGBCopyAlphaRow)(const uint8* src_argb, uint8* dst_argb, int width) =
2935 0 : ARGBCopyAlphaRow_C;
2936 0 : if (!src_argb || !dst_argb || width <= 0 || height == 0) {
2937 0 : return -1;
2938 : }
2939 : // Negative height means invert the image.
2940 0 : if (height < 0) {
2941 0 : height = -height;
2942 0 : src_argb = src_argb + (height - 1) * src_stride_argb;
2943 0 : src_stride_argb = -src_stride_argb;
2944 : }
2945 : // Coalesce rows.
2946 0 : if (src_stride_argb == width * 4 && dst_stride_argb == width * 4) {
2947 0 : width *= height;
2948 0 : height = 1;
2949 0 : src_stride_argb = dst_stride_argb = 0;
2950 : }
2951 : #if defined(HAS_ARGBCOPYALPHAROW_SSE2)
2952 0 : if (TestCpuFlag(kCpuHasSSE2)) {
2953 0 : ARGBCopyAlphaRow = ARGBCopyAlphaRow_Any_SSE2;
2954 0 : if (IS_ALIGNED(width, 8)) {
2955 0 : ARGBCopyAlphaRow = ARGBCopyAlphaRow_SSE2;
2956 : }
2957 : }
2958 : #endif
2959 : #if defined(HAS_ARGBCOPYALPHAROW_AVX2)
2960 0 : if (TestCpuFlag(kCpuHasAVX2)) {
2961 0 : ARGBCopyAlphaRow = ARGBCopyAlphaRow_Any_AVX2;
2962 0 : if (IS_ALIGNED(width, 16)) {
2963 0 : ARGBCopyAlphaRow = ARGBCopyAlphaRow_AVX2;
2964 : }
2965 : }
2966 : #endif
2967 :
2968 0 : for (y = 0; y < height; ++y) {
2969 0 : ARGBCopyAlphaRow(src_argb, dst_argb, width);
2970 0 : src_argb += src_stride_argb;
2971 0 : dst_argb += dst_stride_argb;
2972 : }
2973 0 : return 0;
2974 : }
2975 :
2976 : // Extract just the alpha channel from ARGB.
2977 : LIBYUV_API
2978 0 : int ARGBExtractAlpha(const uint8* src_argb,
2979 : int src_stride,
2980 : uint8* dst_a,
2981 : int dst_stride,
2982 : int width,
2983 : int height) {
2984 0 : if (!src_argb || !dst_a || width <= 0 || height == 0) {
2985 0 : return -1;
2986 : }
2987 : // Negative height means invert the image.
2988 0 : if (height < 0) {
2989 0 : height = -height;
2990 0 : src_argb += (height - 1) * src_stride;
2991 0 : src_stride = -src_stride;
2992 : }
2993 : // Coalesce rows.
2994 0 : if (src_stride == width * 4 && dst_stride == width) {
2995 0 : width *= height;
2996 0 : height = 1;
2997 0 : src_stride = dst_stride = 0;
2998 : }
2999 : void (*ARGBExtractAlphaRow)(const uint8* src_argb, uint8* dst_a, int width) =
3000 0 : ARGBExtractAlphaRow_C;
3001 : #if defined(HAS_ARGBEXTRACTALPHAROW_SSE2)
3002 0 : if (TestCpuFlag(kCpuHasSSE2)) {
3003 0 : ARGBExtractAlphaRow = IS_ALIGNED(width, 8) ? ARGBExtractAlphaRow_SSE2
3004 : : ARGBExtractAlphaRow_Any_SSE2;
3005 : }
3006 : #endif
3007 : #if defined(HAS_ARGBEXTRACTALPHAROW_AVX2)
3008 0 : if (TestCpuFlag(kCpuHasAVX2)) {
3009 0 : ARGBExtractAlphaRow = IS_ALIGNED(width, 32) ? ARGBExtractAlphaRow_AVX2
3010 : : ARGBExtractAlphaRow_Any_AVX2;
3011 : }
3012 : #endif
3013 : #if defined(HAS_ARGBEXTRACTALPHAROW_NEON)
3014 : if (TestCpuFlag(kCpuHasNEON)) {
3015 : ARGBExtractAlphaRow = IS_ALIGNED(width, 16) ? ARGBExtractAlphaRow_NEON
3016 : : ARGBExtractAlphaRow_Any_NEON;
3017 : }
3018 : #endif
3019 :
3020 0 : for (int y = 0; y < height; ++y) {
3021 0 : ARGBExtractAlphaRow(src_argb, dst_a, width);
3022 0 : src_argb += src_stride;
3023 0 : dst_a += dst_stride;
3024 : }
3025 0 : return 0;
3026 : }
3027 :
3028 : // Copy a planar Y channel to the alpha channel of a destination ARGB image.
3029 : LIBYUV_API
3030 0 : int ARGBCopyYToAlpha(const uint8* src_y,
3031 : int src_stride_y,
3032 : uint8* dst_argb,
3033 : int dst_stride_argb,
3034 : int width,
3035 : int height) {
3036 : int y;
3037 : void (*ARGBCopyYToAlphaRow)(const uint8* src_y, uint8* dst_argb, int width) =
3038 0 : ARGBCopyYToAlphaRow_C;
3039 0 : if (!src_y || !dst_argb || width <= 0 || height == 0) {
3040 0 : return -1;
3041 : }
3042 : // Negative height means invert the image.
3043 0 : if (height < 0) {
3044 0 : height = -height;
3045 0 : src_y = src_y + (height - 1) * src_stride_y;
3046 0 : src_stride_y = -src_stride_y;
3047 : }
3048 : // Coalesce rows.
3049 0 : if (src_stride_y == width && dst_stride_argb == width * 4) {
3050 0 : width *= height;
3051 0 : height = 1;
3052 0 : src_stride_y = dst_stride_argb = 0;
3053 : }
3054 : #if defined(HAS_ARGBCOPYYTOALPHAROW_SSE2)
3055 0 : if (TestCpuFlag(kCpuHasSSE2)) {
3056 0 : ARGBCopyYToAlphaRow = ARGBCopyYToAlphaRow_Any_SSE2;
3057 0 : if (IS_ALIGNED(width, 8)) {
3058 0 : ARGBCopyYToAlphaRow = ARGBCopyYToAlphaRow_SSE2;
3059 : }
3060 : }
3061 : #endif
3062 : #if defined(HAS_ARGBCOPYYTOALPHAROW_AVX2)
3063 0 : if (TestCpuFlag(kCpuHasAVX2)) {
3064 0 : ARGBCopyYToAlphaRow = ARGBCopyYToAlphaRow_Any_AVX2;
3065 0 : if (IS_ALIGNED(width, 16)) {
3066 0 : ARGBCopyYToAlphaRow = ARGBCopyYToAlphaRow_AVX2;
3067 : }
3068 : }
3069 : #endif
3070 :
3071 0 : for (y = 0; y < height; ++y) {
3072 0 : ARGBCopyYToAlphaRow(src_y, dst_argb, width);
3073 0 : src_y += src_stride_y;
3074 0 : dst_argb += dst_stride_argb;
3075 : }
3076 0 : return 0;
3077 : }
3078 :
3079 : // TODO(fbarchard): Consider if width is even Y channel can be split
3080 : // directly. A SplitUVRow_Odd function could copy the remaining chroma.
3081 :
3082 : LIBYUV_API
3083 0 : int YUY2ToNV12(const uint8* src_yuy2,
3084 : int src_stride_yuy2,
3085 : uint8* dst_y,
3086 : int dst_stride_y,
3087 : uint8* dst_uv,
3088 : int dst_stride_uv,
3089 : int width,
3090 : int height) {
3091 : int y;
3092 0 : int halfwidth = (width + 1) >> 1;
3093 : void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
3094 0 : int width) = SplitUVRow_C;
3095 : void (*InterpolateRow)(uint8 * dst_ptr, const uint8* src_ptr,
3096 : ptrdiff_t src_stride, int dst_width,
3097 0 : int source_y_fraction) = InterpolateRow_C;
3098 0 : if (!src_yuy2 || !dst_y || !dst_uv || width <= 0 || height == 0) {
3099 0 : return -1;
3100 : }
3101 : // Negative height means invert the image.
3102 0 : if (height < 0) {
3103 0 : height = -height;
3104 0 : src_yuy2 = src_yuy2 + (height - 1) * src_stride_yuy2;
3105 0 : src_stride_yuy2 = -src_stride_yuy2;
3106 : }
3107 : #if defined(HAS_SPLITUVROW_SSE2)
3108 0 : if (TestCpuFlag(kCpuHasSSE2)) {
3109 0 : SplitUVRow = SplitUVRow_Any_SSE2;
3110 0 : if (IS_ALIGNED(width, 16)) {
3111 0 : SplitUVRow = SplitUVRow_SSE2;
3112 : }
3113 : }
3114 : #endif
3115 : #if defined(HAS_SPLITUVROW_AVX2)
3116 0 : if (TestCpuFlag(kCpuHasAVX2)) {
3117 0 : SplitUVRow = SplitUVRow_Any_AVX2;
3118 0 : if (IS_ALIGNED(width, 32)) {
3119 0 : SplitUVRow = SplitUVRow_AVX2;
3120 : }
3121 : }
3122 : #endif
3123 : #if defined(HAS_SPLITUVROW_NEON)
3124 : if (TestCpuFlag(kCpuHasNEON)) {
3125 : SplitUVRow = SplitUVRow_Any_NEON;
3126 : if (IS_ALIGNED(width, 16)) {
3127 : SplitUVRow = SplitUVRow_NEON;
3128 : }
3129 : }
3130 : #endif
3131 : #if defined(HAS_INTERPOLATEROW_SSSE3)
3132 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
3133 0 : InterpolateRow = InterpolateRow_Any_SSSE3;
3134 0 : if (IS_ALIGNED(width, 16)) {
3135 0 : InterpolateRow = InterpolateRow_SSSE3;
3136 : }
3137 : }
3138 : #endif
3139 : #if defined(HAS_INTERPOLATEROW_AVX2)
3140 0 : if (TestCpuFlag(kCpuHasAVX2)) {
3141 0 : InterpolateRow = InterpolateRow_Any_AVX2;
3142 0 : if (IS_ALIGNED(width, 32)) {
3143 0 : InterpolateRow = InterpolateRow_AVX2;
3144 : }
3145 : }
3146 : #endif
3147 : #if defined(HAS_INTERPOLATEROW_NEON)
3148 : if (TestCpuFlag(kCpuHasNEON)) {
3149 : InterpolateRow = InterpolateRow_Any_NEON;
3150 : if (IS_ALIGNED(width, 16)) {
3151 : InterpolateRow = InterpolateRow_NEON;
3152 : }
3153 : }
3154 : #endif
3155 :
3156 : {
3157 0 : int awidth = halfwidth * 2;
3158 : // row of y and 2 rows of uv
3159 0 : align_buffer_64(rows, awidth * 3);
3160 :
3161 0 : for (y = 0; y < height - 1; y += 2) {
3162 : // Split Y from UV.
3163 0 : SplitUVRow(src_yuy2, rows, rows + awidth, awidth);
3164 0 : memcpy(dst_y, rows, width);
3165 0 : SplitUVRow(src_yuy2 + src_stride_yuy2, rows, rows + awidth * 2, awidth);
3166 0 : memcpy(dst_y + dst_stride_y, rows, width);
3167 0 : InterpolateRow(dst_uv, rows + awidth, awidth, awidth, 128);
3168 0 : src_yuy2 += src_stride_yuy2 * 2;
3169 0 : dst_y += dst_stride_y * 2;
3170 0 : dst_uv += dst_stride_uv;
3171 : }
3172 0 : if (height & 1) {
3173 : // Split Y from UV.
3174 0 : SplitUVRow(src_yuy2, rows, dst_uv, awidth);
3175 0 : memcpy(dst_y, rows, width);
3176 : }
3177 0 : free_aligned_buffer_64(rows);
3178 : }
3179 0 : return 0;
3180 : }
3181 :
3182 : LIBYUV_API
3183 0 : int UYVYToNV12(const uint8* src_uyvy,
3184 : int src_stride_uyvy,
3185 : uint8* dst_y,
3186 : int dst_stride_y,
3187 : uint8* dst_uv,
3188 : int dst_stride_uv,
3189 : int width,
3190 : int height) {
3191 : int y;
3192 0 : int halfwidth = (width + 1) >> 1;
3193 : void (*SplitUVRow)(const uint8* src_uv, uint8* dst_u, uint8* dst_v,
3194 0 : int width) = SplitUVRow_C;
3195 : void (*InterpolateRow)(uint8 * dst_ptr, const uint8* src_ptr,
3196 : ptrdiff_t src_stride, int dst_width,
3197 0 : int source_y_fraction) = InterpolateRow_C;
3198 0 : if (!src_uyvy || !dst_y || !dst_uv || width <= 0 || height == 0) {
3199 0 : return -1;
3200 : }
3201 : // Negative height means invert the image.
3202 0 : if (height < 0) {
3203 0 : height = -height;
3204 0 : src_uyvy = src_uyvy + (height - 1) * src_stride_uyvy;
3205 0 : src_stride_uyvy = -src_stride_uyvy;
3206 : }
3207 : #if defined(HAS_SPLITUVROW_SSE2)
3208 0 : if (TestCpuFlag(kCpuHasSSE2)) {
3209 0 : SplitUVRow = SplitUVRow_Any_SSE2;
3210 0 : if (IS_ALIGNED(width, 16)) {
3211 0 : SplitUVRow = SplitUVRow_SSE2;
3212 : }
3213 : }
3214 : #endif
3215 : #if defined(HAS_SPLITUVROW_AVX2)
3216 0 : if (TestCpuFlag(kCpuHasAVX2)) {
3217 0 : SplitUVRow = SplitUVRow_Any_AVX2;
3218 0 : if (IS_ALIGNED(width, 32)) {
3219 0 : SplitUVRow = SplitUVRow_AVX2;
3220 : }
3221 : }
3222 : #endif
3223 : #if defined(HAS_SPLITUVROW_NEON)
3224 : if (TestCpuFlag(kCpuHasNEON)) {
3225 : SplitUVRow = SplitUVRow_Any_NEON;
3226 : if (IS_ALIGNED(width, 16)) {
3227 : SplitUVRow = SplitUVRow_NEON;
3228 : }
3229 : }
3230 : #endif
3231 : #if defined(HAS_INTERPOLATEROW_SSSE3)
3232 0 : if (TestCpuFlag(kCpuHasSSSE3)) {
3233 0 : InterpolateRow = InterpolateRow_Any_SSSE3;
3234 0 : if (IS_ALIGNED(width, 16)) {
3235 0 : InterpolateRow = InterpolateRow_SSSE3;
3236 : }
3237 : }
3238 : #endif
3239 : #if defined(HAS_INTERPOLATEROW_AVX2)
3240 0 : if (TestCpuFlag(kCpuHasAVX2)) {
3241 0 : InterpolateRow = InterpolateRow_Any_AVX2;
3242 0 : if (IS_ALIGNED(width, 32)) {
3243 0 : InterpolateRow = InterpolateRow_AVX2;
3244 : }
3245 : }
3246 : #endif
3247 : #if defined(HAS_INTERPOLATEROW_NEON)
3248 : if (TestCpuFlag(kCpuHasNEON)) {
3249 : InterpolateRow = InterpolateRow_Any_NEON;
3250 : if (IS_ALIGNED(width, 16)) {
3251 : InterpolateRow = InterpolateRow_NEON;
3252 : }
3253 : }
3254 : #endif
3255 :
3256 : {
3257 0 : int awidth = halfwidth * 2;
3258 : // row of y and 2 rows of uv
3259 0 : align_buffer_64(rows, awidth * 3);
3260 :
3261 0 : for (y = 0; y < height - 1; y += 2) {
3262 : // Split Y from UV.
3263 0 : SplitUVRow(src_uyvy, rows + awidth, rows, awidth);
3264 0 : memcpy(dst_y, rows, width);
3265 0 : SplitUVRow(src_uyvy + src_stride_uyvy, rows + awidth * 2, rows, awidth);
3266 0 : memcpy(dst_y + dst_stride_y, rows, width);
3267 0 : InterpolateRow(dst_uv, rows + awidth, awidth, awidth, 128);
3268 0 : src_uyvy += src_stride_uyvy * 2;
3269 0 : dst_y += dst_stride_y * 2;
3270 0 : dst_uv += dst_stride_uv;
3271 : }
3272 0 : if (height & 1) {
3273 : // Split Y from UV.
3274 0 : SplitUVRow(src_uyvy, dst_uv, rows, awidth);
3275 0 : memcpy(dst_y, rows, width);
3276 : }
3277 0 : free_aligned_buffer_64(rows);
3278 : }
3279 0 : return 0;
3280 : }
3281 :
3282 : #ifdef __cplusplus
3283 : } // extern "C"
3284 : } // namespace libyuv
3285 : #endif
|