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/scale.h"
12
13 #include <assert.h>
14 #include <string.h>
15
16 #include "libyuv/cpu_id.h"
17 #include "libyuv/planar_functions.h" // For CopyARGB
18 #include "libyuv/row.h"
19 #include "libyuv/scale_argb.h"
20 #include "libyuv/scale_row.h"
21
22 #ifdef __cplusplus
23 namespace libyuv {
24 extern "C" {
25 #endif
26
Abs(int v)27 static __inline int Abs(int v) {
28 return v >= 0 ? v : -v;
29 }
30
31 // ScaleARGB ARGB, 1/2
32 // This is an optimized version for scaling down a ARGB to 1/2 of
33 // its original size.
ScaleARGBDown2(int src_width,int src_height,int dst_width,int dst_height,int src_stride,int dst_stride,const uint8_t * src_argb,uint8_t * dst_argb,int x,int dx,int y,int dy,enum FilterMode filtering)34 static void ScaleARGBDown2(int src_width,
35 int src_height,
36 int dst_width,
37 int dst_height,
38 int src_stride,
39 int dst_stride,
40 const uint8_t* src_argb,
41 uint8_t* dst_argb,
42 int x,
43 int dx,
44 int y,
45 int dy,
46 enum FilterMode filtering) {
47 int j;
48 int row_stride = src_stride * (dy >> 16);
49 void (*ScaleARGBRowDown2)(const uint8_t* src_argb, ptrdiff_t src_stride,
50 uint8_t* dst_argb, int dst_width) =
51 filtering == kFilterNone
52 ? ScaleARGBRowDown2_C
53 : (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_C
54 : ScaleARGBRowDown2Box_C);
55 (void)src_width;
56 (void)src_height;
57 (void)dx;
58 assert(dx == 65536 * 2); // Test scale factor of 2.
59 assert((dy & 0x1ffff) == 0); // Test vertical scale is multiple of 2.
60 // Advance to odd row, even column.
61 if (filtering == kFilterBilinear) {
62 src_argb += (y >> 16) * (intptr_t)src_stride + (x >> 16) * 4;
63 } else {
64 src_argb += (y >> 16) * (intptr_t)src_stride + ((x >> 16) - 1) * 4;
65 }
66
67 #if defined(HAS_SCALEARGBROWDOWN2_SSE2)
68 if (TestCpuFlag(kCpuHasSSE2)) {
69 ScaleARGBRowDown2 =
70 filtering == kFilterNone
71 ? ScaleARGBRowDown2_Any_SSE2
72 : (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_Any_SSE2
73 : ScaleARGBRowDown2Box_Any_SSE2);
74 if (IS_ALIGNED(dst_width, 4)) {
75 ScaleARGBRowDown2 =
76 filtering == kFilterNone
77 ? ScaleARGBRowDown2_SSE2
78 : (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_SSE2
79 : ScaleARGBRowDown2Box_SSE2);
80 }
81 }
82 #endif
83 #if defined(HAS_SCALEARGBROWDOWN2_NEON)
84 if (TestCpuFlag(kCpuHasNEON)) {
85 ScaleARGBRowDown2 =
86 filtering == kFilterNone
87 ? ScaleARGBRowDown2_Any_NEON
88 : (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_Any_NEON
89 : ScaleARGBRowDown2Box_Any_NEON);
90 if (IS_ALIGNED(dst_width, 8)) {
91 ScaleARGBRowDown2 =
92 filtering == kFilterNone
93 ? ScaleARGBRowDown2_NEON
94 : (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_NEON
95 : ScaleARGBRowDown2Box_NEON);
96 }
97 }
98 #endif
99 #if defined(HAS_SCALEARGBROWDOWN2_MSA)
100 if (TestCpuFlag(kCpuHasMSA)) {
101 ScaleARGBRowDown2 =
102 filtering == kFilterNone
103 ? ScaleARGBRowDown2_Any_MSA
104 : (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_Any_MSA
105 : ScaleARGBRowDown2Box_Any_MSA);
106 if (IS_ALIGNED(dst_width, 4)) {
107 ScaleARGBRowDown2 =
108 filtering == kFilterNone
109 ? ScaleARGBRowDown2_MSA
110 : (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_MSA
111 : ScaleARGBRowDown2Box_MSA);
112 }
113 }
114 #endif
115 #if defined(HAS_SCALEARGBROWDOWN2_LSX)
116 if (TestCpuFlag(kCpuHasLSX)) {
117 ScaleARGBRowDown2 =
118 filtering == kFilterNone
119 ? ScaleARGBRowDown2_Any_LSX
120 : (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_Any_LSX
121 : ScaleARGBRowDown2Box_Any_LSX);
122 if (IS_ALIGNED(dst_width, 4)) {
123 ScaleARGBRowDown2 =
124 filtering == kFilterNone
125 ? ScaleARGBRowDown2_LSX
126 : (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_LSX
127 : ScaleARGBRowDown2Box_LSX);
128 }
129 }
130 #endif
131 #if defined(HAS_SCALEARGBROWDOWN2_RVV)
132 if (TestCpuFlag(kCpuHasRVV)) {
133 ScaleARGBRowDown2 =
134 filtering == kFilterNone
135 ? ScaleARGBRowDown2_RVV
136 : (filtering == kFilterLinear ? ScaleARGBRowDown2Linear_RVV
137 : ScaleARGBRowDown2Box_RVV);
138 }
139 #endif
140
141 if (filtering == kFilterLinear) {
142 src_stride = 0;
143 }
144 for (j = 0; j < dst_height; ++j) {
145 ScaleARGBRowDown2(src_argb, src_stride, dst_argb, dst_width);
146 src_argb += row_stride;
147 dst_argb += dst_stride;
148 }
149 }
150
151 // ScaleARGB ARGB, 1/4
152 // This is an optimized version for scaling down a ARGB to 1/4 of
153 // its original size.
ScaleARGBDown4Box(int src_width,int src_height,int dst_width,int dst_height,int src_stride,int dst_stride,const uint8_t * src_argb,uint8_t * dst_argb,int x,int dx,int y,int dy)154 static int ScaleARGBDown4Box(int src_width,
155 int src_height,
156 int dst_width,
157 int dst_height,
158 int src_stride,
159 int dst_stride,
160 const uint8_t* src_argb,
161 uint8_t* dst_argb,
162 int x,
163 int dx,
164 int y,
165 int dy) {
166 int j;
167 // Allocate 2 rows of ARGB.
168 const int row_size = (dst_width * 2 * 4 + 31) & ~31;
169 // TODO(fbarchard): Remove this row buffer and implement a ScaleARGBRowDown4
170 // but implemented via a 2 pass wrapper that uses a very small array on the
171 // stack with a horizontal loop.
172 align_buffer_64(row, row_size * 2);
173 if (!row)
174 return 1;
175 int row_stride = src_stride * (dy >> 16);
176 void (*ScaleARGBRowDown2)(const uint8_t* src_argb, ptrdiff_t src_stride,
177 uint8_t* dst_argb, int dst_width) =
178 ScaleARGBRowDown2Box_C;
179 // Advance to odd row, even column.
180 src_argb += (y >> 16) * (intptr_t)src_stride + (x >> 16) * 4;
181 (void)src_width;
182 (void)src_height;
183 (void)dx;
184 assert(dx == 65536 * 4); // Test scale factor of 4.
185 assert((dy & 0x3ffff) == 0); // Test vertical scale is multiple of 4.
186 #if defined(HAS_SCALEARGBROWDOWN2_SSE2)
187 if (TestCpuFlag(kCpuHasSSE2)) {
188 ScaleARGBRowDown2 = ScaleARGBRowDown2Box_Any_SSE2;
189 if (IS_ALIGNED(dst_width, 4)) {
190 ScaleARGBRowDown2 = ScaleARGBRowDown2Box_SSE2;
191 }
192 }
193 #endif
194 #if defined(HAS_SCALEARGBROWDOWN2_NEON)
195 if (TestCpuFlag(kCpuHasNEON)) {
196 ScaleARGBRowDown2 = ScaleARGBRowDown2Box_Any_NEON;
197 if (IS_ALIGNED(dst_width, 8)) {
198 ScaleARGBRowDown2 = ScaleARGBRowDown2Box_NEON;
199 }
200 }
201 #endif
202 #if defined(HAS_SCALEARGBROWDOWN2_RVV)
203 if (TestCpuFlag(kCpuHasRVV)) {
204 ScaleARGBRowDown2 = ScaleARGBRowDown2Box_RVV;
205 }
206 #endif
207
208 for (j = 0; j < dst_height; ++j) {
209 ScaleARGBRowDown2(src_argb, src_stride, row, dst_width * 2);
210 ScaleARGBRowDown2(src_argb + src_stride * 2, src_stride, row + row_size,
211 dst_width * 2);
212 ScaleARGBRowDown2(row, row_size, dst_argb, dst_width);
213 src_argb += row_stride;
214 dst_argb += dst_stride;
215 }
216 free_aligned_buffer_64(row);
217 return 0;
218 }
219
220 // ScaleARGB ARGB Even
221 // This is an optimized version for scaling down a ARGB to even
222 // multiple of its original size.
ScaleARGBDownEven(int src_width,int src_height,int dst_width,int dst_height,int src_stride,int dst_stride,const uint8_t * src_argb,uint8_t * dst_argb,int x,int dx,int y,int dy,enum FilterMode filtering)223 static void ScaleARGBDownEven(int src_width,
224 int src_height,
225 int dst_width,
226 int dst_height,
227 int src_stride,
228 int dst_stride,
229 const uint8_t* src_argb,
230 uint8_t* dst_argb,
231 int x,
232 int dx,
233 int y,
234 int dy,
235 enum FilterMode filtering) {
236 int j;
237 int col_step = dx >> 16;
238 ptrdiff_t row_stride = (ptrdiff_t)((dy >> 16) * (intptr_t)src_stride);
239 void (*ScaleARGBRowDownEven)(const uint8_t* src_argb, ptrdiff_t src_stride,
240 int src_step, uint8_t* dst_argb, int dst_width) =
241 filtering ? ScaleARGBRowDownEvenBox_C : ScaleARGBRowDownEven_C;
242 (void)src_width;
243 (void)src_height;
244 assert(IS_ALIGNED(src_width, 2));
245 assert(IS_ALIGNED(src_height, 2));
246 src_argb += (y >> 16) * (intptr_t)src_stride + (x >> 16) * 4;
247 #if defined(HAS_SCALEARGBROWDOWNEVEN_SSE2)
248 if (TestCpuFlag(kCpuHasSSE2)) {
249 ScaleARGBRowDownEven = filtering ? ScaleARGBRowDownEvenBox_Any_SSE2
250 : ScaleARGBRowDownEven_Any_SSE2;
251 if (IS_ALIGNED(dst_width, 4)) {
252 ScaleARGBRowDownEven =
253 filtering ? ScaleARGBRowDownEvenBox_SSE2 : ScaleARGBRowDownEven_SSE2;
254 }
255 }
256 #endif
257 #if defined(HAS_SCALEARGBROWDOWNEVEN_NEON)
258 if (TestCpuFlag(kCpuHasNEON)) {
259 ScaleARGBRowDownEven = filtering ? ScaleARGBRowDownEvenBox_Any_NEON
260 : ScaleARGBRowDownEven_Any_NEON;
261 if (IS_ALIGNED(dst_width, 4)) {
262 ScaleARGBRowDownEven =
263 filtering ? ScaleARGBRowDownEvenBox_NEON : ScaleARGBRowDownEven_NEON;
264 }
265 }
266 #endif
267 #if defined(HAS_SCALEARGBROWDOWNEVEN_MSA)
268 if (TestCpuFlag(kCpuHasMSA)) {
269 ScaleARGBRowDownEven = filtering ? ScaleARGBRowDownEvenBox_Any_MSA
270 : ScaleARGBRowDownEven_Any_MSA;
271 if (IS_ALIGNED(dst_width, 4)) {
272 ScaleARGBRowDownEven =
273 filtering ? ScaleARGBRowDownEvenBox_MSA : ScaleARGBRowDownEven_MSA;
274 }
275 }
276 #endif
277 #if defined(HAS_SCALEARGBROWDOWNEVEN_LSX)
278 if (TestCpuFlag(kCpuHasLSX)) {
279 ScaleARGBRowDownEven = filtering ? ScaleARGBRowDownEvenBox_Any_LSX
280 : ScaleARGBRowDownEven_Any_LSX;
281 if (IS_ALIGNED(dst_width, 4)) {
282 ScaleARGBRowDownEven =
283 filtering ? ScaleARGBRowDownEvenBox_LSX : ScaleARGBRowDownEven_LSX;
284 }
285 }
286 #endif
287 #if defined(HAS_SCALEARGBROWDOWNEVENBOX_RVV)
288 if (filtering && TestCpuFlag(kCpuHasRVV)) {
289 ScaleARGBRowDownEven = ScaleARGBRowDownEvenBox_RVV;
290 }
291 #endif
292 #if defined(HAS_SCALEARGBROWDOWNEVEN_RVV)
293 if (!filtering && TestCpuFlag(kCpuHasRVV)) {
294 ScaleARGBRowDownEven = ScaleARGBRowDownEven_RVV;
295 }
296 #endif
297
298 if (filtering == kFilterLinear) {
299 src_stride = 0;
300 }
301 for (j = 0; j < dst_height; ++j) {
302 ScaleARGBRowDownEven(src_argb, src_stride, col_step, dst_argb, dst_width);
303 src_argb += row_stride;
304 dst_argb += dst_stride;
305 }
306 }
307
308 // Scale ARGB down with bilinear interpolation.
ScaleARGBBilinearDown(int src_width,int src_height,int dst_width,int dst_height,int src_stride,int dst_stride,const uint8_t * src_argb,uint8_t * dst_argb,int x,int dx,int y,int dy,enum FilterMode filtering)309 static int ScaleARGBBilinearDown(int src_width,
310 int src_height,
311 int dst_width,
312 int dst_height,
313 int src_stride,
314 int dst_stride,
315 const uint8_t* src_argb,
316 uint8_t* dst_argb,
317 int x,
318 int dx,
319 int y,
320 int dy,
321 enum FilterMode filtering) {
322 int j;
323 void (*InterpolateRow)(uint8_t* dst_argb, const uint8_t* src_argb,
324 ptrdiff_t src_stride, int dst_width,
325 int source_y_fraction) = InterpolateRow_C;
326 void (*ScaleARGBFilterCols)(uint8_t* dst_argb, const uint8_t* src_argb,
327 int dst_width, int x, int dx) =
328 (src_width >= 32768) ? ScaleARGBFilterCols64_C : ScaleARGBFilterCols_C;
329 int64_t xlast = x + (int64_t)(dst_width - 1) * dx;
330 int64_t xl = (dx >= 0) ? x : xlast;
331 int64_t xr = (dx >= 0) ? xlast : x;
332 int clip_src_width;
333 xl = (xl >> 16) & ~3; // Left edge aligned.
334 xr = (xr >> 16) + 1; // Right most pixel used. Bilinear uses 2 pixels.
335 xr = (xr + 1 + 3) & ~3; // 1 beyond 4 pixel aligned right most pixel.
336 if (xr > src_width) {
337 xr = src_width;
338 }
339 clip_src_width = (int)(xr - xl) * 4; // Width aligned to 4.
340 src_argb += xl * 4;
341 x -= (int)(xl << 16);
342 #if defined(HAS_INTERPOLATEROW_SSSE3)
343 if (TestCpuFlag(kCpuHasSSSE3)) {
344 InterpolateRow = InterpolateRow_Any_SSSE3;
345 if (IS_ALIGNED(clip_src_width, 16)) {
346 InterpolateRow = InterpolateRow_SSSE3;
347 }
348 }
349 #endif
350 #if defined(HAS_INTERPOLATEROW_AVX2)
351 if (TestCpuFlag(kCpuHasAVX2)) {
352 InterpolateRow = InterpolateRow_Any_AVX2;
353 if (IS_ALIGNED(clip_src_width, 32)) {
354 InterpolateRow = InterpolateRow_AVX2;
355 }
356 }
357 #endif
358 #if defined(HAS_INTERPOLATEROW_NEON)
359 if (TestCpuFlag(kCpuHasNEON)) {
360 InterpolateRow = InterpolateRow_Any_NEON;
361 if (IS_ALIGNED(clip_src_width, 16)) {
362 InterpolateRow = InterpolateRow_NEON;
363 }
364 }
365 #endif
366 #if defined(HAS_INTERPOLATEROW_MSA)
367 if (TestCpuFlag(kCpuHasMSA)) {
368 InterpolateRow = InterpolateRow_Any_MSA;
369 if (IS_ALIGNED(clip_src_width, 32)) {
370 InterpolateRow = InterpolateRow_MSA;
371 }
372 }
373 #endif
374 #if defined(HAS_INTERPOLATEROW_LSX)
375 if (TestCpuFlag(kCpuHasLSX)) {
376 InterpolateRow = InterpolateRow_Any_LSX;
377 if (IS_ALIGNED(clip_src_width, 32)) {
378 InterpolateRow = InterpolateRow_LSX;
379 }
380 }
381 #endif
382 #if defined(HAS_INTERPOLATEROW_RVV)
383 if (TestCpuFlag(kCpuHasRVV)) {
384 InterpolateRow = InterpolateRow_RVV;
385 }
386 #endif
387 #if defined(HAS_SCALEARGBFILTERCOLS_SSSE3)
388 if (TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
389 ScaleARGBFilterCols = ScaleARGBFilterCols_SSSE3;
390 }
391 #endif
392 #if defined(HAS_SCALEARGBFILTERCOLS_NEON)
393 if (TestCpuFlag(kCpuHasNEON)) {
394 ScaleARGBFilterCols = ScaleARGBFilterCols_Any_NEON;
395 if (IS_ALIGNED(dst_width, 4)) {
396 ScaleARGBFilterCols = ScaleARGBFilterCols_NEON;
397 }
398 }
399 #endif
400 #if defined(HAS_SCALEARGBFILTERCOLS_MSA)
401 if (TestCpuFlag(kCpuHasMSA)) {
402 ScaleARGBFilterCols = ScaleARGBFilterCols_Any_MSA;
403 if (IS_ALIGNED(dst_width, 8)) {
404 ScaleARGBFilterCols = ScaleARGBFilterCols_MSA;
405 }
406 }
407 #endif
408 #if defined(HAS_SCALEARGBFILTERCOLS_LSX)
409 if (TestCpuFlag(kCpuHasLSX)) {
410 ScaleARGBFilterCols = ScaleARGBFilterCols_Any_LSX;
411 if (IS_ALIGNED(dst_width, 8)) {
412 ScaleARGBFilterCols = ScaleARGBFilterCols_LSX;
413 }
414 }
415 #endif
416 // TODO(fbarchard): Consider not allocating row buffer for kFilterLinear.
417 // Allocate a row of ARGB.
418 {
419 align_buffer_64(row, clip_src_width * 4);
420 if (!row)
421 return 1;
422
423 const int max_y = (src_height - 1) << 16;
424 if (y > max_y) {
425 y = max_y;
426 }
427 for (j = 0; j < dst_height; ++j) {
428 int yi = y >> 16;
429 const uint8_t* src = src_argb + yi * (intptr_t)src_stride;
430 if (filtering == kFilterLinear) {
431 ScaleARGBFilterCols(dst_argb, src, dst_width, x, dx);
432 } else {
433 int yf = (y >> 8) & 255;
434 InterpolateRow(row, src, src_stride, clip_src_width, yf);
435 ScaleARGBFilterCols(dst_argb, row, dst_width, x, dx);
436 }
437 dst_argb += dst_stride;
438 y += dy;
439 if (y > max_y) {
440 y = max_y;
441 }
442 }
443 free_aligned_buffer_64(row);
444 }
445 return 0;
446 }
447
448 // Scale ARGB up with bilinear interpolation.
ScaleARGBBilinearUp(int src_width,int src_height,int dst_width,int dst_height,int src_stride,int dst_stride,const uint8_t * src_argb,uint8_t * dst_argb,int x,int dx,int y,int dy,enum FilterMode filtering)449 static int ScaleARGBBilinearUp(int src_width,
450 int src_height,
451 int dst_width,
452 int dst_height,
453 int src_stride,
454 int dst_stride,
455 const uint8_t* src_argb,
456 uint8_t* dst_argb,
457 int x,
458 int dx,
459 int y,
460 int dy,
461 enum FilterMode filtering) {
462 int j;
463 void (*InterpolateRow)(uint8_t* dst_argb, const uint8_t* src_argb,
464 ptrdiff_t src_stride, int dst_width,
465 int source_y_fraction) = InterpolateRow_C;
466 void (*ScaleARGBFilterCols)(uint8_t* dst_argb, const uint8_t* src_argb,
467 int dst_width, int x, int dx) =
468 filtering ? ScaleARGBFilterCols_C : ScaleARGBCols_C;
469 const int max_y = (src_height - 1) << 16;
470 #if defined(HAS_INTERPOLATEROW_SSSE3)
471 if (TestCpuFlag(kCpuHasSSSE3)) {
472 InterpolateRow = InterpolateRow_Any_SSSE3;
473 if (IS_ALIGNED(dst_width, 4)) {
474 InterpolateRow = InterpolateRow_SSSE3;
475 }
476 }
477 #endif
478 #if defined(HAS_INTERPOLATEROW_AVX2)
479 if (TestCpuFlag(kCpuHasAVX2)) {
480 InterpolateRow = InterpolateRow_Any_AVX2;
481 if (IS_ALIGNED(dst_width, 8)) {
482 InterpolateRow = InterpolateRow_AVX2;
483 }
484 }
485 #endif
486 #if defined(HAS_INTERPOLATEROW_NEON)
487 if (TestCpuFlag(kCpuHasNEON)) {
488 InterpolateRow = InterpolateRow_Any_NEON;
489 if (IS_ALIGNED(dst_width, 4)) {
490 InterpolateRow = InterpolateRow_NEON;
491 }
492 }
493 #endif
494 #if defined(HAS_INTERPOLATEROW_MSA)
495 if (TestCpuFlag(kCpuHasMSA)) {
496 InterpolateRow = InterpolateRow_Any_MSA;
497 if (IS_ALIGNED(dst_width, 8)) {
498 InterpolateRow = InterpolateRow_MSA;
499 }
500 }
501 #endif
502 #if defined(HAS_INTERPOLATEROW_LSX)
503 if (TestCpuFlag(kCpuHasLSX)) {
504 InterpolateRow = InterpolateRow_Any_LSX;
505 if (IS_ALIGNED(dst_width, 8)) {
506 InterpolateRow = InterpolateRow_LSX;
507 }
508 }
509 #endif
510 #if defined(HAS_INTERPOLATEROW_RVV)
511 if (TestCpuFlag(kCpuHasRVV)) {
512 InterpolateRow = InterpolateRow_RVV;
513 }
514 #endif
515 if (src_width >= 32768) {
516 ScaleARGBFilterCols =
517 filtering ? ScaleARGBFilterCols64_C : ScaleARGBCols64_C;
518 }
519 #if defined(HAS_SCALEARGBFILTERCOLS_SSSE3)
520 if (filtering && TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
521 ScaleARGBFilterCols = ScaleARGBFilterCols_SSSE3;
522 }
523 #endif
524 #if defined(HAS_SCALEARGBFILTERCOLS_NEON)
525 if (filtering && TestCpuFlag(kCpuHasNEON)) {
526 ScaleARGBFilterCols = ScaleARGBFilterCols_Any_NEON;
527 if (IS_ALIGNED(dst_width, 4)) {
528 ScaleARGBFilterCols = ScaleARGBFilterCols_NEON;
529 }
530 }
531 #endif
532 #if defined(HAS_SCALEARGBFILTERCOLS_MSA)
533 if (filtering && TestCpuFlag(kCpuHasMSA)) {
534 ScaleARGBFilterCols = ScaleARGBFilterCols_Any_MSA;
535 if (IS_ALIGNED(dst_width, 8)) {
536 ScaleARGBFilterCols = ScaleARGBFilterCols_MSA;
537 }
538 }
539 #endif
540 #if defined(HAS_SCALEARGBFILTERCOLS_LSX)
541 if (filtering && TestCpuFlag(kCpuHasLSX)) {
542 ScaleARGBFilterCols = ScaleARGBFilterCols_Any_LSX;
543 if (IS_ALIGNED(dst_width, 8)) {
544 ScaleARGBFilterCols = ScaleARGBFilterCols_LSX;
545 }
546 }
547 #endif
548 #if defined(HAS_SCALEARGBCOLS_SSE2)
549 if (!filtering && TestCpuFlag(kCpuHasSSE2) && src_width < 32768) {
550 ScaleARGBFilterCols = ScaleARGBCols_SSE2;
551 }
552 #endif
553 #if defined(HAS_SCALEARGBCOLS_NEON)
554 if (!filtering && TestCpuFlag(kCpuHasNEON)) {
555 ScaleARGBFilterCols = ScaleARGBCols_Any_NEON;
556 if (IS_ALIGNED(dst_width, 8)) {
557 ScaleARGBFilterCols = ScaleARGBCols_NEON;
558 }
559 }
560 #endif
561 #if defined(HAS_SCALEARGBCOLS_MSA)
562 if (!filtering && TestCpuFlag(kCpuHasMSA)) {
563 ScaleARGBFilterCols = ScaleARGBCols_Any_MSA;
564 if (IS_ALIGNED(dst_width, 4)) {
565 ScaleARGBFilterCols = ScaleARGBCols_MSA;
566 }
567 }
568 #endif
569 #if defined(HAS_SCALEARGBCOLS_LSX)
570 if (!filtering && TestCpuFlag(kCpuHasLSX)) {
571 ScaleARGBFilterCols = ScaleARGBCols_Any_LSX;
572 if (IS_ALIGNED(dst_width, 4)) {
573 ScaleARGBFilterCols = ScaleARGBCols_LSX;
574 }
575 }
576 #endif
577 if (!filtering && src_width * 2 == dst_width && x < 0x8000) {
578 ScaleARGBFilterCols = ScaleARGBColsUp2_C;
579 #if defined(HAS_SCALEARGBCOLSUP2_SSE2)
580 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8)) {
581 ScaleARGBFilterCols = ScaleARGBColsUp2_SSE2;
582 }
583 #endif
584 }
585
586 if (y > max_y) {
587 y = max_y;
588 }
589
590 {
591 int yi = y >> 16;
592 const uint8_t* src = src_argb + yi * (intptr_t)src_stride;
593
594 // Allocate 2 rows of ARGB.
595 const int row_size = (dst_width * 4 + 31) & ~31;
596 align_buffer_64(row, row_size * 2);
597 if (!row)
598 return 1;
599
600 uint8_t* rowptr = row;
601 int rowstride = row_size;
602 int lasty = yi;
603
604 ScaleARGBFilterCols(rowptr, src, dst_width, x, dx);
605 if (src_height > 1) {
606 src += src_stride;
607 }
608 ScaleARGBFilterCols(rowptr + rowstride, src, dst_width, x, dx);
609 if (src_height > 2) {
610 src += src_stride;
611 }
612
613 for (j = 0; j < dst_height; ++j) {
614 yi = y >> 16;
615 if (yi != lasty) {
616 if (y > max_y) {
617 y = max_y;
618 yi = y >> 16;
619 src = src_argb + yi * (intptr_t)src_stride;
620 }
621 if (yi != lasty) {
622 ScaleARGBFilterCols(rowptr, src, dst_width, x, dx);
623 rowptr += rowstride;
624 rowstride = -rowstride;
625 lasty = yi;
626 if ((y + 65536) < max_y) {
627 src += src_stride;
628 }
629 }
630 }
631 if (filtering == kFilterLinear) {
632 InterpolateRow(dst_argb, rowptr, 0, dst_width * 4, 0);
633 } else {
634 int yf = (y >> 8) & 255;
635 InterpolateRow(dst_argb, rowptr, rowstride, dst_width * 4, yf);
636 }
637 dst_argb += dst_stride;
638 y += dy;
639 }
640 free_aligned_buffer_64(row);
641 }
642 return 0;
643 }
644
645 #ifdef YUVSCALEUP
646 // Scale YUV to ARGB up with bilinear interpolation.
ScaleYUVToARGBBilinearUp(int src_width,int src_height,int dst_width,int dst_height,int src_stride_y,int src_stride_u,int src_stride_v,int dst_stride_argb,const uint8_t * src_y,const uint8_t * src_u,const uint8_t * src_v,uint8_t * dst_argb,int x,int dx,int y,int dy,enum FilterMode filtering)647 static int ScaleYUVToARGBBilinearUp(int src_width,
648 int src_height,
649 int dst_width,
650 int dst_height,
651 int src_stride_y,
652 int src_stride_u,
653 int src_stride_v,
654 int dst_stride_argb,
655 const uint8_t* src_y,
656 const uint8_t* src_u,
657 const uint8_t* src_v,
658 uint8_t* dst_argb,
659 int x,
660 int dx,
661 int y,
662 int dy,
663 enum FilterMode filtering) {
664 int j;
665 void (*I422ToARGBRow)(const uint8_t* y_buf, const uint8_t* u_buf,
666 const uint8_t* v_buf, uint8_t* rgb_buf, int width) =
667 I422ToARGBRow_C;
668 #if defined(HAS_I422TOARGBROW_SSSE3)
669 if (TestCpuFlag(kCpuHasSSSE3)) {
670 I422ToARGBRow = I422ToARGBRow_Any_SSSE3;
671 if (IS_ALIGNED(src_width, 8)) {
672 I422ToARGBRow = I422ToARGBRow_SSSE3;
673 }
674 }
675 #endif
676 #if defined(HAS_I422TOARGBROW_AVX2)
677 if (TestCpuFlag(kCpuHasAVX2)) {
678 I422ToARGBRow = I422ToARGBRow_Any_AVX2;
679 if (IS_ALIGNED(src_width, 16)) {
680 I422ToARGBRow = I422ToARGBRow_AVX2;
681 }
682 }
683 #endif
684 #if defined(HAS_I422TOARGBROW_AVX512BW)
685 if (TestCpuFlag(kCpuHasAVX512BW | kCpuHasAVX512VL) ==
686 (kCpuHasAVX512BW | kCpuHasAVX512VL)) {
687 I422ToARGBRow = I422ToARGBRow_Any_AVX512BW;
688 if (IS_ALIGNED(src_width, 32)) {
689 I422ToARGBRow = I422ToARGBRow_AVX512BW;
690 }
691 }
692 #endif
693 #if defined(HAS_I422TOARGBROW_NEON)
694 if (TestCpuFlag(kCpuHasNEON)) {
695 I422ToARGBRow = I422ToARGBRow_Any_NEON;
696 if (IS_ALIGNED(src_width, 8)) {
697 I422ToARGBRow = I422ToARGBRow_NEON;
698 }
699 }
700 #endif
701 #if defined(HAS_I422TOARGBROW_MSA)
702 if (TestCpuFlag(kCpuHasMSA)) {
703 I422ToARGBRow = I422ToARGBRow_Any_MSA;
704 if (IS_ALIGNED(src_width, 8)) {
705 I422ToARGBRow = I422ToARGBRow_MSA;
706 }
707 }
708 #endif
709 #if defined(HAS_I422TOARGBROW_LSX)
710 if (TestCpuFlag(kCpuHasLSX)) {
711 I422ToARGBRow = I422ToARGBRow_Any_LSX;
712 if (IS_ALIGNED(src_width, 16)) {
713 I422ToARGBRow = I422ToARGBRow_LSX;
714 }
715 }
716 #endif
717 #if defined(HAS_I422TOARGBROW_LASX)
718 if (TestCpuFlag(kCpuHasLASX)) {
719 I422ToARGBRow = I422ToARGBRow_Any_LASX;
720 if (IS_ALIGNED(src_width, 32)) {
721 I422ToARGBRow = I422ToARGBRow_LASX;
722 }
723 }
724 #endif
725 #if defined(HAS_I422TOARGBROW_RVV)
726 if (TestCpuFlag(kCpuHasRVV)) {
727 I422ToARGBRow = I422ToARGBRow_RVV;
728 }
729 #endif
730
731 void (*InterpolateRow)(uint8_t* dst_argb, const uint8_t* src_argb,
732 ptrdiff_t src_stride, int dst_width,
733 int source_y_fraction) = InterpolateRow_C;
734 #if defined(HAS_INTERPOLATEROW_SSSE3)
735 if (TestCpuFlag(kCpuHasSSSE3)) {
736 InterpolateRow = InterpolateRow_Any_SSSE3;
737 if (IS_ALIGNED(dst_width, 4)) {
738 InterpolateRow = InterpolateRow_SSSE3;
739 }
740 }
741 #endif
742 #if defined(HAS_INTERPOLATEROW_AVX2)
743 if (TestCpuFlag(kCpuHasAVX2)) {
744 InterpolateRow = InterpolateRow_Any_AVX2;
745 if (IS_ALIGNED(dst_width, 8)) {
746 InterpolateRow = InterpolateRow_AVX2;
747 }
748 }
749 #endif
750 #if defined(HAS_INTERPOLATEROW_NEON)
751 if (TestCpuFlag(kCpuHasNEON)) {
752 InterpolateRow = InterpolateRow_Any_NEON;
753 if (IS_ALIGNED(dst_width, 4)) {
754 InterpolateRow = InterpolateRow_NEON;
755 }
756 }
757 #endif
758 #if defined(HAS_INTERPOLATEROW_MSA)
759 if (TestCpuFlag(kCpuHasMSA)) {
760 InterpolateRow = InterpolateRow_Any_MSA;
761 if (IS_ALIGNED(dst_width, 8)) {
762 InterpolateRow = InterpolateRow_MSA;
763 }
764 }
765 #endif
766 #if defined(HAS_INTERPOLATEROW_LSX)
767 if (TestCpuFlag(kCpuHasLSX)) {
768 InterpolateRow = InterpolateRow_Any_LSX;
769 if (IS_ALIGNED(dst_width, 8)) {
770 InterpolateRow = InterpolateRow_LSX;
771 }
772 }
773 #endif
774 #if defined(HAS_INTERPOLATEROW_RVV)
775 if (TestCpuFlag(kCpuHasRVV)) {
776 InterpolateRow = InterpolateRow_RVV;
777 }
778 #endif
779
780 void (*ScaleARGBFilterCols)(uint8_t* dst_argb, const uint8_t* src_argb,
781 int dst_width, int x, int dx) =
782 filtering ? ScaleARGBFilterCols_C : ScaleARGBCols_C;
783 if (src_width >= 32768) {
784 ScaleARGBFilterCols =
785 filtering ? ScaleARGBFilterCols64_C : ScaleARGBCols64_C;
786 }
787 #if defined(HAS_SCALEARGBFILTERCOLS_SSSE3)
788 if (filtering && TestCpuFlag(kCpuHasSSSE3) && src_width < 32768) {
789 ScaleARGBFilterCols = ScaleARGBFilterCols_SSSE3;
790 }
791 #endif
792 #if defined(HAS_SCALEARGBFILTERCOLS_NEON)
793 if (filtering && TestCpuFlag(kCpuHasNEON)) {
794 ScaleARGBFilterCols = ScaleARGBFilterCols_Any_NEON;
795 if (IS_ALIGNED(dst_width, 4)) {
796 ScaleARGBFilterCols = ScaleARGBFilterCols_NEON;
797 }
798 }
799 #endif
800 #if defined(HAS_SCALEARGBFILTERCOLS_MSA)
801 if (filtering && TestCpuFlag(kCpuHasMSA)) {
802 ScaleARGBFilterCols = ScaleARGBFilterCols_Any_MSA;
803 if (IS_ALIGNED(dst_width, 8)) {
804 ScaleARGBFilterCols = ScaleARGBFilterCols_MSA;
805 }
806 }
807 #endif
808 #if defined(HAS_SCALEARGBFILTERCOLS_LSX)
809 if (filtering && TestCpuFlag(kCpuHasLSX)) {
810 ScaleARGBFilterCols = ScaleARGBFilterCols_Any_LSX;
811 if (IS_ALIGNED(dst_width, 8)) {
812 ScaleARGBFilterCols = ScaleARGBFilterCols_LSX;
813 }
814 }
815 #endif
816 #if defined(HAS_SCALEARGBCOLS_SSE2)
817 if (!filtering && TestCpuFlag(kCpuHasSSE2) && src_width < 32768) {
818 ScaleARGBFilterCols = ScaleARGBCols_SSE2;
819 }
820 #endif
821 #if defined(HAS_SCALEARGBCOLS_NEON)
822 if (!filtering && TestCpuFlag(kCpuHasNEON)) {
823 ScaleARGBFilterCols = ScaleARGBCols_Any_NEON;
824 if (IS_ALIGNED(dst_width, 8)) {
825 ScaleARGBFilterCols = ScaleARGBCols_NEON;
826 }
827 }
828 #endif
829 #if defined(HAS_SCALEARGBCOLS_MSA)
830 if (!filtering && TestCpuFlag(kCpuHasMSA)) {
831 ScaleARGBFilterCols = ScaleARGBCols_Any_MSA;
832 if (IS_ALIGNED(dst_width, 4)) {
833 ScaleARGBFilterCols = ScaleARGBCols_MSA;
834 }
835 }
836 #endif
837 #if defined(HAS_SCALEARGBCOLS_LSX)
838 if (!filtering && TestCpuFlag(kCpuHasLSX)) {
839 ScaleARGBFilterCols = ScaleARGBCols_Any_LSX;
840 if (IS_ALIGNED(dst_width, 4)) {
841 ScaleARGBFilterCols = ScaleARGBCols_LSX;
842 }
843 }
844 #endif
845 if (!filtering && src_width * 2 == dst_width && x < 0x8000) {
846 ScaleARGBFilterCols = ScaleARGBColsUp2_C;
847 #if defined(HAS_SCALEARGBCOLSUP2_SSE2)
848 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8)) {
849 ScaleARGBFilterCols = ScaleARGBColsUp2_SSE2;
850 }
851 #endif
852 }
853
854 const int max_y = (src_height - 1) << 16;
855 if (y > max_y) {
856 y = max_y;
857 }
858 const int kYShift = 1; // Shift Y by 1 to convert Y plane to UV coordinate.
859 int yi = y >> 16;
860 int uv_yi = yi >> kYShift;
861 const uint8_t* src_row_y = src_y + yi * (intptr_t)src_stride_y;
862 const uint8_t* src_row_u = src_u + uv_yi * (intptr_t)src_stride_u;
863 const uint8_t* src_row_v = src_v + uv_yi * (intptr_t)src_stride_v;
864
865 // Allocate 1 row of ARGB for source conversion and 2 rows of ARGB
866 // scaled horizontally to the destination width.
867 const int row_size = (dst_width * 4 + 31) & ~31;
868 align_buffer_64(row, row_size * 2 + src_width * 4);
869
870 uint8_t* argb_row = row + row_size * 2;
871 uint8_t* rowptr = row;
872 int rowstride = row_size;
873 int lasty = yi;
874 if (!row)
875 return 1;
876
877 // TODO(fbarchard): Convert first 2 rows of YUV to ARGB.
878 ScaleARGBFilterCols(rowptr, src_row_y, dst_width, x, dx);
879 if (src_height > 1) {
880 src_row_y += src_stride_y;
881 if (yi & 1) {
882 src_row_u += src_stride_u;
883 src_row_v += src_stride_v;
884 }
885 }
886 ScaleARGBFilterCols(rowptr + rowstride, src_row_y, dst_width, x, dx);
887 if (src_height > 2) {
888 src_row_y += src_stride_y;
889 if (!(yi & 1)) {
890 src_row_u += src_stride_u;
891 src_row_v += src_stride_v;
892 }
893 }
894
895 for (j = 0; j < dst_height; ++j) {
896 yi = y >> 16;
897 if (yi != lasty) {
898 if (y > max_y) {
899 y = max_y;
900 yi = y >> 16;
901 uv_yi = yi >> kYShift;
902 src_row_y = src_y + yi * (intptr_t)src_stride_y;
903 src_row_u = src_u + uv_yi * (intptr_t)src_stride_u;
904 src_row_v = src_v + uv_yi * (intptr_t)src_stride_v;
905 }
906 if (yi != lasty) {
907 // TODO(fbarchard): Convert the clipped region of row.
908 I422ToARGBRow(src_row_y, src_row_u, src_row_v, argb_row, src_width);
909 ScaleARGBFilterCols(rowptr, argb_row, dst_width, x, dx);
910 rowptr += rowstride;
911 rowstride = -rowstride;
912 lasty = yi;
913 src_row_y += src_stride_y;
914 if (yi & 1) {
915 src_row_u += src_stride_u;
916 src_row_v += src_stride_v;
917 }
918 }
919 }
920 if (filtering == kFilterLinear) {
921 InterpolateRow(dst_argb, rowptr, 0, dst_width * 4, 0);
922 } else {
923 int yf = (y >> 8) & 255;
924 InterpolateRow(dst_argb, rowptr, rowstride, dst_width * 4, yf);
925 }
926 dst_argb += dst_stride_argb;
927 y += dy;
928 }
929 free_aligned_buffer_64(row);
930 return 0;
931 }
932 #endif
933
934 // Scale ARGB to/from any dimensions, without interpolation.
935 // Fixed point math is used for performance: The upper 16 bits
936 // of x and dx is the integer part of the source position and
937 // the lower 16 bits are the fixed decimal part.
938
ScaleARGBSimple(int src_width,int src_height,int dst_width,int dst_height,int src_stride,int dst_stride,const uint8_t * src_argb,uint8_t * dst_argb,int x,int dx,int y,int dy)939 static void ScaleARGBSimple(int src_width,
940 int src_height,
941 int dst_width,
942 int dst_height,
943 int src_stride,
944 int dst_stride,
945 const uint8_t* src_argb,
946 uint8_t* dst_argb,
947 int x,
948 int dx,
949 int y,
950 int dy) {
951 int j;
952 void (*ScaleARGBCols)(uint8_t* dst_argb, const uint8_t* src_argb,
953 int dst_width, int x, int dx) =
954 (src_width >= 32768) ? ScaleARGBCols64_C : ScaleARGBCols_C;
955 (void)src_height;
956 #if defined(HAS_SCALEARGBCOLS_SSE2)
957 if (TestCpuFlag(kCpuHasSSE2) && src_width < 32768) {
958 ScaleARGBCols = ScaleARGBCols_SSE2;
959 }
960 #endif
961 #if defined(HAS_SCALEARGBCOLS_NEON)
962 if (TestCpuFlag(kCpuHasNEON)) {
963 ScaleARGBCols = ScaleARGBCols_Any_NEON;
964 if (IS_ALIGNED(dst_width, 8)) {
965 ScaleARGBCols = ScaleARGBCols_NEON;
966 }
967 }
968 #endif
969 #if defined(HAS_SCALEARGBCOLS_MSA)
970 if (TestCpuFlag(kCpuHasMSA)) {
971 ScaleARGBCols = ScaleARGBCols_Any_MSA;
972 if (IS_ALIGNED(dst_width, 4)) {
973 ScaleARGBCols = ScaleARGBCols_MSA;
974 }
975 }
976 #endif
977 #if defined(HAS_SCALEARGBCOLS_LSX)
978 if (TestCpuFlag(kCpuHasLSX)) {
979 ScaleARGBCols = ScaleARGBCols_Any_LSX;
980 if (IS_ALIGNED(dst_width, 4)) {
981 ScaleARGBCols = ScaleARGBCols_LSX;
982 }
983 }
984 #endif
985 if (src_width * 2 == dst_width && x < 0x8000) {
986 ScaleARGBCols = ScaleARGBColsUp2_C;
987 #if defined(HAS_SCALEARGBCOLSUP2_SSE2)
988 if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(dst_width, 8)) {
989 ScaleARGBCols = ScaleARGBColsUp2_SSE2;
990 }
991 #endif
992 }
993
994 for (j = 0; j < dst_height; ++j) {
995 ScaleARGBCols(dst_argb, src_argb + (y >> 16) * (intptr_t)src_stride,
996 dst_width, x, dx);
997 dst_argb += dst_stride;
998 y += dy;
999 }
1000 }
1001
1002 // ScaleARGB a ARGB.
1003 // This function in turn calls a scaling function
1004 // suitable for handling the desired resolutions.
ScaleARGB(const uint8_t * src,int src_stride,int src_width,int src_height,uint8_t * dst,int dst_stride,int dst_width,int dst_height,int clip_x,int clip_y,int clip_width,int clip_height,enum FilterMode filtering)1005 static int ScaleARGB(const uint8_t* src,
1006 int src_stride,
1007 int src_width,
1008 int src_height,
1009 uint8_t* dst,
1010 int dst_stride,
1011 int dst_width,
1012 int dst_height,
1013 int clip_x,
1014 int clip_y,
1015 int clip_width,
1016 int clip_height,
1017 enum FilterMode filtering) {
1018 // Initial source x/y coordinate and step values as 16.16 fixed point.
1019 int x = 0;
1020 int y = 0;
1021 int dx = 0;
1022 int dy = 0;
1023 // ARGB does not support box filter yet, but allow the user to pass it.
1024 // Simplify filtering when possible.
1025 filtering = ScaleFilterReduce(src_width, src_height, dst_width, dst_height,
1026 filtering);
1027
1028 // Negative src_height means invert the image.
1029 if (src_height < 0) {
1030 src_height = -src_height;
1031 src = src + (src_height - 1) * (intptr_t)src_stride;
1032 src_stride = -src_stride;
1033 }
1034 ScaleSlope(src_width, src_height, dst_width, dst_height, filtering, &x, &y,
1035 &dx, &dy);
1036 src_width = Abs(src_width);
1037 if (clip_x) {
1038 int64_t clipf = (int64_t)(clip_x)*dx;
1039 x += (clipf & 0xffff);
1040 src += (clipf >> 16) * 4;
1041 dst += clip_x * 4;
1042 }
1043 if (clip_y) {
1044 int64_t clipf = (int64_t)(clip_y)*dy;
1045 y += (clipf & 0xffff);
1046 src += (clipf >> 16) * (intptr_t)src_stride;
1047 dst += clip_y * dst_stride;
1048 }
1049
1050 // Special case for integer step values.
1051 if (((dx | dy) & 0xffff) == 0) {
1052 if (!dx || !dy) { // 1 pixel wide and/or tall.
1053 filtering = kFilterNone;
1054 } else {
1055 // Optimized even scale down. ie 2, 4, 6, 8, 10x.
1056 if (!(dx & 0x10000) && !(dy & 0x10000)) {
1057 if (dx == 0x20000) {
1058 // Optimized 1/2 downsample.
1059 ScaleARGBDown2(src_width, src_height, clip_width, clip_height,
1060 src_stride, dst_stride, src, dst, x, dx, y, dy,
1061 filtering);
1062 return 0;
1063 }
1064 if (dx == 0x40000 && filtering == kFilterBox) {
1065 // Optimized 1/4 box downsample.
1066 return ScaleARGBDown4Box(src_width, src_height, clip_width,
1067 clip_height, src_stride, dst_stride, src,
1068 dst, x, dx, y, dy);
1069 }
1070 ScaleARGBDownEven(src_width, src_height, clip_width, clip_height,
1071 src_stride, dst_stride, src, dst, x, dx, y, dy,
1072 filtering);
1073 return 0;
1074 }
1075 // Optimized odd scale down. ie 3, 5, 7, 9x.
1076 if ((dx & 0x10000) && (dy & 0x10000)) {
1077 filtering = kFilterNone;
1078 if (dx == 0x10000 && dy == 0x10000) {
1079 // Straight copy.
1080 ARGBCopy(src + (y >> 16) * (intptr_t)src_stride + (x >> 16) * 4,
1081 src_stride, dst, dst_stride, clip_width, clip_height);
1082 return 0;
1083 }
1084 }
1085 }
1086 }
1087 if (dx == 0x10000 && (x & 0xffff) == 0) {
1088 // Arbitrary scale vertically, but unscaled horizontally.
1089 ScalePlaneVertical(src_height, clip_width, clip_height, src_stride,
1090 dst_stride, src, dst, x, y, dy, /*bpp=*/4, filtering);
1091 return 0;
1092 }
1093 if (filtering && dy < 65536) {
1094 return ScaleARGBBilinearUp(src_width, src_height, clip_width, clip_height,
1095 src_stride, dst_stride, src, dst, x, dx, y, dy,
1096 filtering);
1097 }
1098 if (filtering) {
1099 return ScaleARGBBilinearDown(src_width, src_height, clip_width, clip_height,
1100 src_stride, dst_stride, src, dst, x, dx, y, dy,
1101 filtering);
1102 }
1103 ScaleARGBSimple(src_width, src_height, clip_width, clip_height, src_stride,
1104 dst_stride, src, dst, x, dx, y, dy);
1105 return 0;
1106 }
1107
1108 LIBYUV_API
ARGBScaleClip(const uint8_t * src_argb,int src_stride_argb,int src_width,int src_height,uint8_t * dst_argb,int dst_stride_argb,int dst_width,int dst_height,int clip_x,int clip_y,int clip_width,int clip_height,enum FilterMode filtering)1109 int ARGBScaleClip(const uint8_t* src_argb,
1110 int src_stride_argb,
1111 int src_width,
1112 int src_height,
1113 uint8_t* dst_argb,
1114 int dst_stride_argb,
1115 int dst_width,
1116 int dst_height,
1117 int clip_x,
1118 int clip_y,
1119 int clip_width,
1120 int clip_height,
1121 enum FilterMode filtering) {
1122 if (!src_argb || src_width == 0 || src_height == 0 || !dst_argb ||
1123 dst_width <= 0 || dst_height <= 0 || clip_x < 0 || clip_y < 0 ||
1124 clip_width > 32768 || clip_height > 32768 ||
1125 (clip_x + clip_width) > dst_width ||
1126 (clip_y + clip_height) > dst_height) {
1127 return -1;
1128 }
1129 return ScaleARGB(src_argb, src_stride_argb, src_width, src_height, dst_argb,
1130 dst_stride_argb, dst_width, dst_height, clip_x, clip_y,
1131 clip_width, clip_height, filtering);
1132 }
1133
1134 // Scale an ARGB image.
1135 LIBYUV_API
ARGBScale(const uint8_t * src_argb,int src_stride_argb,int src_width,int src_height,uint8_t * dst_argb,int dst_stride_argb,int dst_width,int dst_height,enum FilterMode filtering)1136 int ARGBScale(const uint8_t* src_argb,
1137 int src_stride_argb,
1138 int src_width,
1139 int src_height,
1140 uint8_t* dst_argb,
1141 int dst_stride_argb,
1142 int dst_width,
1143 int dst_height,
1144 enum FilterMode filtering) {
1145 if (!src_argb || src_width == 0 || src_height == 0 || src_width > 32768 ||
1146 src_height > 32768 || !dst_argb || dst_width <= 0 || dst_height <= 0) {
1147 return -1;
1148 }
1149 return ScaleARGB(src_argb, src_stride_argb, src_width, src_height, dst_argb,
1150 dst_stride_argb, dst_width, dst_height, 0, 0, dst_width,
1151 dst_height, filtering);
1152 }
1153
1154 // Scale with YUV conversion to ARGB and clipping.
1155 LIBYUV_API
YUVToARGBScaleClip(const uint8_t * src_y,int src_stride_y,const uint8_t * src_u,int src_stride_u,const uint8_t * src_v,int src_stride_v,uint32_t src_fourcc,int src_width,int src_height,uint8_t * dst_argb,int dst_stride_argb,uint32_t dst_fourcc,int dst_width,int dst_height,int clip_x,int clip_y,int clip_width,int clip_height,enum FilterMode filtering)1156 int YUVToARGBScaleClip(const uint8_t* src_y,
1157 int src_stride_y,
1158 const uint8_t* src_u,
1159 int src_stride_u,
1160 const uint8_t* src_v,
1161 int src_stride_v,
1162 uint32_t src_fourcc,
1163 int src_width,
1164 int src_height,
1165 uint8_t* dst_argb,
1166 int dst_stride_argb,
1167 uint32_t dst_fourcc,
1168 int dst_width,
1169 int dst_height,
1170 int clip_x,
1171 int clip_y,
1172 int clip_width,
1173 int clip_height,
1174 enum FilterMode filtering) {
1175 int r;
1176 uint8_t* argb_buffer = (uint8_t*)malloc(src_width * src_height * 4);
1177 if (!argb_buffer) {
1178 return 1; // Out of memory runtime error.
1179 }
1180 (void)src_fourcc; // TODO(fbarchard): implement and/or assert.
1181 (void)dst_fourcc;
1182 I420ToARGB(src_y, src_stride_y, src_u, src_stride_u, src_v, src_stride_v,
1183 argb_buffer, src_width * 4, src_width, src_height);
1184
1185 r = ARGBScaleClip(argb_buffer, src_width * 4, src_width, src_height, dst_argb,
1186 dst_stride_argb, dst_width, dst_height, clip_x, clip_y,
1187 clip_width, clip_height, filtering);
1188 free(argb_buffer);
1189 return r;
1190 }
1191
1192 #ifdef __cplusplus
1193 } // extern "C"
1194 } // namespace libyuv
1195 #endif
1196