/src/libavif/third_party/libyuv/source/scale.c
Line | Count | Source |
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/planar_functions.h" // For CopyPlane |
17 | | #include "libyuv/row.h" |
18 | | #include "libyuv/scale_row.h" |
19 | | |
20 | 3.17k | static __inline int Abs(int v) { |
21 | 3.17k | return v >= 0 ? v : -v; |
22 | 3.17k | } |
23 | | |
24 | 270 | #define CENTERSTART(dx, s) (dx < 0) ? -((-dx >> 1) + s) : ((dx >> 1) + s) |
25 | | |
26 | 226k | #define MIN1(x) ((x) < 1 ? 1 : (x)) |
27 | | |
28 | 95.7k | static __inline uint32_t SumPixels(int iboxwidth, const uint16_t* src_ptr) { |
29 | 95.7k | uint32_t sum = 0u; |
30 | 95.7k | int x; |
31 | 95.7k | assert(iboxwidth > 0); |
32 | 343k | for (x = 0; x < iboxwidth; ++x) { |
33 | 247k | sum += src_ptr[x]; |
34 | 247k | } |
35 | 95.7k | return sum; |
36 | 95.7k | } |
37 | | |
38 | 135k | static __inline uint32_t SumPixels_16(int iboxwidth, const uint32_t* src_ptr) { |
39 | 135k | uint32_t sum = 0u; |
40 | 135k | int x; |
41 | 135k | assert(iboxwidth > 0); |
42 | 636k | for (x = 0; x < iboxwidth; ++x) { |
43 | 501k | sum += src_ptr[x]; |
44 | 501k | } |
45 | 135k | return sum; |
46 | 135k | } |
47 | | |
48 | | static void ScaleAddCols2_C(int dst_width, |
49 | | int boxheight, |
50 | | int x, |
51 | | int dx, |
52 | | const uint16_t* src_ptr, |
53 | 2.49k | uint8_t* dst_ptr) { |
54 | 2.49k | int i; |
55 | 2.49k | int scaletbl[2]; |
56 | 2.49k | int minboxwidth = dx >> 16; |
57 | 2.49k | int boxwidth; |
58 | 2.49k | scaletbl[0] = 65536 / (MIN1(minboxwidth) * boxheight); |
59 | 2.49k | scaletbl[1] = 65536 / (MIN1(minboxwidth + 1) * boxheight); |
60 | 75.9k | for (i = 0; i < dst_width; ++i) { |
61 | 73.4k | int ix = x >> 16; |
62 | 73.4k | x += dx; |
63 | 73.4k | boxwidth = MIN1((x >> 16) - ix); |
64 | 73.4k | int scaletbl_index = boxwidth - minboxwidth; |
65 | 73.4k | assert((scaletbl_index == 0) || (scaletbl_index == 1)); |
66 | 73.4k | *dst_ptr++ = (uint8_t)(SumPixels(boxwidth, src_ptr + ix) * |
67 | 73.4k | scaletbl[scaletbl_index] >> |
68 | 73.4k | 16); |
69 | 73.4k | } |
70 | 2.49k | } |
71 | | |
72 | | static void ScaleAddCols2_16_C(int dst_width, |
73 | | int boxheight, |
74 | | int x, |
75 | | int dx, |
76 | | const uint32_t* src_ptr, |
77 | 2.95k | uint16_t* dst_ptr) { |
78 | 2.95k | int i; |
79 | 2.95k | int scaletbl[2]; |
80 | 2.95k | int minboxwidth = dx >> 16; |
81 | 2.95k | int boxwidth; |
82 | 2.95k | scaletbl[0] = 65536 / (MIN1(minboxwidth) * boxheight); |
83 | 2.95k | scaletbl[1] = 65536 / (MIN1(minboxwidth + 1) * boxheight); |
84 | 137k | for (i = 0; i < dst_width; ++i) { |
85 | 134k | int ix = x >> 16; |
86 | 134k | x += dx; |
87 | 134k | boxwidth = MIN1((x >> 16) - ix); |
88 | 134k | int scaletbl_index = boxwidth - minboxwidth; |
89 | 134k | assert((scaletbl_index == 0) || (scaletbl_index == 1)); |
90 | 134k | *dst_ptr++ = |
91 | 134k | SumPixels_16(boxwidth, src_ptr + ix) * scaletbl[scaletbl_index] >> 16; |
92 | 134k | } |
93 | 2.95k | } |
94 | | |
95 | | static void ScaleAddCols0_C(int dst_width, |
96 | | int boxheight, |
97 | | int x, |
98 | | int dx, |
99 | | const uint16_t* src_ptr, |
100 | 0 | uint8_t* dst_ptr) { |
101 | 0 | int scaleval = 65536 / boxheight; |
102 | 0 | int i; |
103 | 0 | (void)dx; |
104 | 0 | src_ptr += (x >> 16); |
105 | 0 | for (i = 0; i < dst_width; ++i) { |
106 | 0 | *dst_ptr++ = (uint8_t)(src_ptr[i] * scaleval >> 16); |
107 | 0 | } |
108 | 0 | } |
109 | | |
110 | | static void ScaleAddCols1_C(int dst_width, |
111 | | int boxheight, |
112 | | int x, |
113 | | int dx, |
114 | | const uint16_t* src_ptr, |
115 | 849 | uint8_t* dst_ptr) { |
116 | 849 | int boxwidth = MIN1(dx >> 16); |
117 | 849 | int scaleval = 65536 / (boxwidth * boxheight); |
118 | 849 | int i; |
119 | 849 | x >>= 16; |
120 | 23.0k | for (i = 0; i < dst_width; ++i) { |
121 | 22.2k | *dst_ptr++ = (uint8_t)(SumPixels(boxwidth, src_ptr + x) * scaleval >> 16); |
122 | 22.2k | x += boxwidth; |
123 | 22.2k | } |
124 | 849 | } |
125 | | |
126 | | static void ScaleAddCols1_16_C(int dst_width, |
127 | | int boxheight, |
128 | | int x, |
129 | | int dx, |
130 | | const uint32_t* src_ptr, |
131 | 267 | uint16_t* dst_ptr) { |
132 | 267 | int boxwidth = MIN1(dx >> 16); |
133 | 267 | int scaleval = 65536 / (boxwidth * boxheight); |
134 | 267 | int i; |
135 | 1.28k | for (i = 0; i < dst_width; ++i) { |
136 | 1.02k | *dst_ptr++ = SumPixels_16(boxwidth, src_ptr + x) * scaleval >> 16; |
137 | 1.02k | x += boxwidth; |
138 | 1.02k | } |
139 | 267 | } |
140 | | |
141 | | // Scale plane down to any dimensions, with interpolation. |
142 | | // (boxfilter). |
143 | | // |
144 | | // Same method as SimpleScale, which is fixed point, outputting |
145 | | // one pixel of destination using fixed point (16.16) to step |
146 | | // through source, sampling a box of pixel with simple |
147 | | // averaging. |
148 | | static int ScalePlaneBox(int src_width, |
149 | | int src_height, |
150 | | int dst_width, |
151 | | int dst_height, |
152 | | int src_stride, |
153 | | int dst_stride, |
154 | | const uint8_t* src_ptr, |
155 | 93 | uint8_t* dst_ptr) { |
156 | 93 | int j, k; |
157 | | // Initial source x/y coordinate and step values as 16.16 fixed point. |
158 | 93 | int x = 0; |
159 | 93 | int y = 0; |
160 | 93 | int dx = 0; |
161 | 93 | int dy = 0; |
162 | 93 | const int max_y = (src_height << 16); |
163 | 93 | ScaleSlope(src_width, src_height, dst_width, dst_height, kFilterBox, &x, &y, |
164 | 93 | &dx, &dy); |
165 | 93 | src_width = Abs(src_width); |
166 | 93 | { |
167 | | // Allocate a row buffer of uint16_t. |
168 | 93 | align_buffer_64(row16, src_width * 2); |
169 | 93 | if (!row16) |
170 | 0 | return 1; |
171 | 93 | void (*ScaleAddCols)(int dst_width, int boxheight, int x, int dx, |
172 | 93 | const uint16_t* src_ptr, uint8_t* dst_ptr) = |
173 | 93 | (dx & 0xffff) ? ScaleAddCols2_C |
174 | 93 | : ((dx != 0x10000) ? ScaleAddCols1_C : ScaleAddCols0_C); |
175 | 93 | void (*ScaleAddRow)(const uint8_t* src_ptr, uint16_t* dst_ptr, |
176 | 93 | int src_width) = ScaleAddRow_C; |
177 | | |
178 | 3.43k | for (j = 0; j < dst_height; ++j) { |
179 | 3.34k | int boxheight; |
180 | 3.34k | int iy = y >> 16; |
181 | 3.34k | const uint8_t* src = src_ptr + iy * (int64_t)src_stride; |
182 | 3.34k | y += dy; |
183 | 3.34k | if (y > max_y) { |
184 | 0 | y = max_y; |
185 | 0 | } |
186 | 3.34k | boxheight = MIN1((y >> 16) - iy); |
187 | 3.34k | memset(row16, 0, src_width * 2); |
188 | 34.2k | for (k = 0; k < boxheight; ++k) { |
189 | 30.9k | ScaleAddRow(src, (uint16_t*)(row16), src_width); |
190 | 30.9k | src += src_stride; |
191 | 30.9k | } |
192 | 3.34k | ScaleAddCols(dst_width, boxheight, x, dx, (uint16_t*)(row16), dst_ptr); |
193 | 3.34k | dst_ptr += dst_stride; |
194 | 3.34k | } |
195 | 93 | free_aligned_buffer_64(row16); |
196 | 93 | } |
197 | 0 | return 0; |
198 | 93 | } |
199 | | |
200 | | static int ScalePlaneBox_16(int src_width, |
201 | | int src_height, |
202 | | int dst_width, |
203 | | int dst_height, |
204 | | int src_stride, |
205 | | int dst_stride, |
206 | | const uint16_t* src_ptr, |
207 | 88 | uint16_t* dst_ptr) { |
208 | 88 | int j, k; |
209 | | // Initial source x/y coordinate and step values as 16.16 fixed point. |
210 | 88 | int x = 0; |
211 | 88 | int y = 0; |
212 | 88 | int dx = 0; |
213 | 88 | int dy = 0; |
214 | 88 | const int max_y = (src_height << 16); |
215 | 88 | ScaleSlope(src_width, src_height, dst_width, dst_height, kFilterBox, &x, &y, |
216 | 88 | &dx, &dy); |
217 | 88 | src_width = Abs(src_width); |
218 | 88 | { |
219 | | // Allocate a row buffer of uint32_t. |
220 | 88 | align_buffer_64(row32, src_width * 4); |
221 | 88 | if (!row32) |
222 | 0 | return 1; |
223 | 88 | void (*ScaleAddCols)(int dst_width, int boxheight, int x, int dx, |
224 | 88 | const uint32_t* src_ptr, uint16_t* dst_ptr) = |
225 | 88 | (dx & 0xffff) ? ScaleAddCols2_16_C : ScaleAddCols1_16_C; |
226 | 88 | void (*ScaleAddRow)(const uint16_t* src_ptr, uint32_t* dst_ptr, |
227 | 88 | int src_width) = ScaleAddRow_16_C; |
228 | | |
229 | | #if defined(HAS_SCALEADDROW_16_SSE2) |
230 | | if (TestCpuFlag(kCpuHasSSE2) && IS_ALIGNED(src_width, 16)) { |
231 | | ScaleAddRow = ScaleAddRow_16_SSE2; |
232 | | } |
233 | | #endif |
234 | | |
235 | 3.30k | for (j = 0; j < dst_height; ++j) { |
236 | 3.22k | int boxheight; |
237 | 3.22k | int iy = y >> 16; |
238 | 3.22k | const uint16_t* src = src_ptr + iy * (int64_t)src_stride; |
239 | 3.22k | y += dy; |
240 | 3.22k | if (y > max_y) { |
241 | 0 | y = max_y; |
242 | 0 | } |
243 | 3.22k | boxheight = MIN1((y >> 16) - iy); |
244 | 3.22k | memset(row32, 0, src_width * 4); |
245 | 32.0k | for (k = 0; k < boxheight; ++k) { |
246 | 28.7k | ScaleAddRow(src, (uint32_t*)(row32), src_width); |
247 | 28.7k | src += src_stride; |
248 | 28.7k | } |
249 | 3.22k | ScaleAddCols(dst_width, boxheight, x, dx, (uint32_t*)(row32), dst_ptr); |
250 | 3.22k | dst_ptr += dst_stride; |
251 | 3.22k | } |
252 | 88 | free_aligned_buffer_64(row32); |
253 | 88 | } |
254 | 0 | return 0; |
255 | 88 | } |
256 | | |
257 | | // Scale plane down with bilinear interpolation. |
258 | | static int ScalePlaneBilinearDown(int src_width, |
259 | | int src_height, |
260 | | int dst_width, |
261 | | int dst_height, |
262 | | int src_stride, |
263 | | int dst_stride, |
264 | | const uint8_t* src_ptr, |
265 | | uint8_t* dst_ptr, |
266 | 356 | enum FilterMode filtering) { |
267 | | // Initial source x/y coordinate and step values as 16.16 fixed point. |
268 | 356 | int x = 0; |
269 | 356 | int y = 0; |
270 | 356 | int dx = 0; |
271 | 356 | int dy = 0; |
272 | | // TODO(fbarchard): Consider not allocating row buffer for kFilterLinear. |
273 | | // Allocate a row buffer. |
274 | 356 | align_buffer_64(row, src_width); |
275 | 356 | if (!row) |
276 | 0 | return 1; |
277 | | |
278 | 356 | const int max_y = (src_height - 1) << 16; |
279 | 356 | int j; |
280 | 356 | void (*ScaleFilterCols)(uint8_t* dst_ptr, const uint8_t* src_ptr, |
281 | 356 | int dst_width, int x, int dx) = |
282 | 356 | (src_width >= 32768) ? ScaleFilterCols64_C : ScaleFilterCols_C; |
283 | 356 | void (*InterpolateRow)(uint8_t* dst_ptr, const uint8_t* src_ptr, |
284 | 356 | ptrdiff_t src_stride, int dst_width, |
285 | 356 | int source_y_fraction) = InterpolateRow_C; |
286 | 356 | ScaleSlope(src_width, src_height, dst_width, dst_height, filtering, &x, &y, |
287 | 356 | &dx, &dy); |
288 | 356 | src_width = Abs(src_width); |
289 | | |
290 | 356 | if (y > max_y) { |
291 | 22 | y = max_y; |
292 | 22 | } |
293 | | |
294 | 30.0k | for (j = 0; j < dst_height; ++j) { |
295 | 29.7k | int yi = y >> 16; |
296 | 29.7k | const uint8_t* src = src_ptr + yi * (int64_t)src_stride; |
297 | 29.7k | if (filtering == kFilterLinear) { |
298 | 2.51k | ScaleFilterCols(dst_ptr, src, dst_width, x, dx); |
299 | 27.2k | } else { |
300 | 27.2k | int yf = (y >> 8) & 255; |
301 | 27.2k | InterpolateRow(row, src, src_stride, src_width, yf); |
302 | 27.2k | ScaleFilterCols(dst_ptr, row, dst_width, x, dx); |
303 | 27.2k | } |
304 | 29.7k | dst_ptr += dst_stride; |
305 | 29.7k | y += dy; |
306 | 29.7k | if (y > max_y) { |
307 | 380 | y = max_y; |
308 | 380 | } |
309 | 29.7k | } |
310 | 356 | free_aligned_buffer_64(row); |
311 | 356 | return 0; |
312 | 356 | } |
313 | | |
314 | | static int ScalePlaneBilinearDown_16(int src_width, |
315 | | int src_height, |
316 | | int dst_width, |
317 | | int dst_height, |
318 | | int src_stride, |
319 | | int dst_stride, |
320 | | const uint16_t* src_ptr, |
321 | | uint16_t* dst_ptr, |
322 | 483 | enum FilterMode filtering) { |
323 | | // Initial source x/y coordinate and step values as 16.16 fixed point. |
324 | 483 | int x = 0; |
325 | 483 | int y = 0; |
326 | 483 | int dx = 0; |
327 | 483 | int dy = 0; |
328 | | // TODO(fbarchard): Consider not allocating row buffer for kFilterLinear. |
329 | | // Allocate a row buffer. |
330 | 483 | align_buffer_64(row, src_width * 2); |
331 | 483 | if (!row) |
332 | 0 | return 1; |
333 | | |
334 | 483 | const int max_y = (src_height - 1) << 16; |
335 | 483 | int j; |
336 | 483 | void (*ScaleFilterCols)(uint16_t* dst_ptr, const uint16_t* src_ptr, |
337 | 483 | int dst_width, int x, int dx) = |
338 | 483 | (src_width >= 32768) ? ScaleFilterCols64_16_C : ScaleFilterCols_16_C; |
339 | 483 | void (*InterpolateRow)(uint16_t* dst_ptr, const uint16_t* src_ptr, |
340 | 483 | ptrdiff_t src_stride, int dst_width, |
341 | 483 | int source_y_fraction) = InterpolateRow_16_C; |
342 | 483 | ScaleSlope(src_width, src_height, dst_width, dst_height, filtering, &x, &y, |
343 | 483 | &dx, &dy); |
344 | 483 | src_width = Abs(src_width); |
345 | | |
346 | 483 | if (y > max_y) { |
347 | 11 | y = max_y; |
348 | 11 | } |
349 | | |
350 | 47.4k | for (j = 0; j < dst_height; ++j) { |
351 | 46.9k | int yi = y >> 16; |
352 | 46.9k | const uint16_t* src = src_ptr + yi * (int64_t)src_stride; |
353 | 46.9k | if (filtering == kFilterLinear) { |
354 | 1.02k | ScaleFilterCols(dst_ptr, src, dst_width, x, dx); |
355 | 45.8k | } else { |
356 | 45.8k | int yf = (y >> 8) & 255; |
357 | 45.8k | InterpolateRow((uint16_t*)row, src, src_stride, src_width, yf); |
358 | 45.8k | ScaleFilterCols(dst_ptr, (uint16_t*)row, dst_width, x, dx); |
359 | 45.8k | } |
360 | 46.9k | dst_ptr += dst_stride; |
361 | 46.9k | y += dy; |
362 | 46.9k | if (y > max_y) { |
363 | 509 | y = max_y; |
364 | 509 | } |
365 | 46.9k | } |
366 | 483 | free_aligned_buffer_64(row); |
367 | 483 | return 0; |
368 | 483 | } |
369 | | |
370 | | // Scale up down with bilinear interpolation. |
371 | | static int ScalePlaneBilinearUp(int src_width, |
372 | | int src_height, |
373 | | int dst_width, |
374 | | int dst_height, |
375 | | int src_stride, |
376 | | int dst_stride, |
377 | | const uint8_t* src_ptr, |
378 | | uint8_t* dst_ptr, |
379 | 570 | enum FilterMode filtering) { |
380 | 570 | int j; |
381 | | // Initial source x/y coordinate and step values as 16.16 fixed point. |
382 | 570 | int x = 0; |
383 | 570 | int y = 0; |
384 | 570 | int dx = 0; |
385 | 570 | int dy = 0; |
386 | 570 | const int max_y = (src_height - 1) << 16; |
387 | 570 | void (*InterpolateRow)(uint8_t* dst_ptr, const uint8_t* src_ptr, |
388 | 570 | ptrdiff_t src_stride, int dst_width, |
389 | 570 | int source_y_fraction) = InterpolateRow_C; |
390 | 570 | void (*ScaleFilterCols)(uint8_t* dst_ptr, const uint8_t* src_ptr, |
391 | 570 | int dst_width, int x, int dx) = |
392 | 570 | filtering ? ScaleFilterCols_C : ScaleCols_C; |
393 | 570 | ScaleSlope(src_width, src_height, dst_width, dst_height, filtering, &x, &y, |
394 | 570 | &dx, &dy); |
395 | 570 | src_width = Abs(src_width); |
396 | | |
397 | 570 | if (filtering && src_width >= 32768) { |
398 | 0 | ScaleFilterCols = ScaleFilterCols64_C; |
399 | 0 | } |
400 | 570 | if (!filtering && src_width * 2 == dst_width && x < 0x8000) { |
401 | 0 | ScaleFilterCols = ScaleColsUp2_C; |
402 | 0 | } |
403 | | |
404 | 570 | if (y > max_y) { |
405 | 66 | y = max_y; |
406 | 66 | } |
407 | 570 | { |
408 | 570 | int yi = y >> 16; |
409 | 570 | const uint8_t* src = src_ptr + yi * (int64_t)src_stride; |
410 | | |
411 | | // Allocate 2 row buffers. |
412 | 570 | const int row_size = (dst_width + 31) & ~31; |
413 | 570 | align_buffer_64(row, row_size * 2); |
414 | 570 | if (!row) |
415 | 0 | return 1; |
416 | | |
417 | 570 | uint8_t* rowptr = row; |
418 | 570 | int rowstride = row_size; |
419 | 570 | int lasty = yi; |
420 | | |
421 | 570 | ScaleFilterCols(rowptr, src, dst_width, x, dx); |
422 | 570 | if (src_height > 1) { |
423 | 486 | src += src_stride; |
424 | 486 | } |
425 | 570 | ScaleFilterCols(rowptr + rowstride, src, dst_width, x, dx); |
426 | 570 | if (src_height > 2) { |
427 | 448 | src += src_stride; |
428 | 448 | } |
429 | | |
430 | 7.81M | for (j = 0; j < dst_height; ++j) { |
431 | 7.81M | yi = y >> 16; |
432 | 7.81M | if (yi != lasty) { |
433 | 77.4k | if (y > max_y) { |
434 | 0 | y = max_y; |
435 | 0 | yi = y >> 16; |
436 | 0 | src = src_ptr + yi * (int64_t)src_stride; |
437 | 0 | } |
438 | 77.4k | if (yi != lasty) { |
439 | 77.4k | ScaleFilterCols(rowptr, src, dst_width, x, dx); |
440 | 77.4k | rowptr += rowstride; |
441 | 77.4k | rowstride = -rowstride; |
442 | 77.4k | lasty = yi; |
443 | 77.4k | if ((y + 65536) < max_y) { |
444 | 76.9k | src += src_stride; |
445 | 76.9k | } |
446 | 77.4k | } |
447 | 77.4k | } |
448 | 7.81M | if (filtering == kFilterLinear) { |
449 | 981k | InterpolateRow(dst_ptr, rowptr, 0, dst_width, 0); |
450 | 6.83M | } else { |
451 | 6.83M | int yf = (y >> 8) & 255; |
452 | 6.83M | InterpolateRow(dst_ptr, rowptr, rowstride, dst_width, yf); |
453 | 6.83M | } |
454 | 7.81M | dst_ptr += dst_stride; |
455 | 7.81M | y += dy; |
456 | 7.81M | } |
457 | 570 | free_aligned_buffer_64(row); |
458 | 570 | } |
459 | 0 | return 0; |
460 | 570 | } |
461 | | |
462 | | // Scale plane, horizontally up by 2 times. |
463 | | // Uses linear filter horizontally, nearest vertically. |
464 | | // This is an optimized version for scaling up a plane to 2 times of |
465 | | // its original width, using linear interpolation. |
466 | | // This is used to scale U and V planes of I422 to I444. |
467 | | static void ScalePlaneUp2_Linear(int src_width, |
468 | | int src_height, |
469 | | int dst_width, |
470 | | int dst_height, |
471 | | int src_stride, |
472 | | int dst_stride, |
473 | | const uint8_t* src_ptr, |
474 | 56 | uint8_t* dst_ptr) { |
475 | 56 | void (*ScaleRowUp)(const uint8_t* src_ptr, uint8_t* dst_ptr, int dst_width) = |
476 | 56 | ScaleRowUp2_Linear_Any_C; |
477 | 56 | int i; |
478 | 56 | int y; |
479 | 56 | int dy; |
480 | | |
481 | 56 | (void)src_width; |
482 | | // This function can only scale up by 2 times horizontally. |
483 | 56 | assert(src_width == ((dst_width + 1) / 2)); |
484 | | |
485 | 56 | if (dst_height == 1) { |
486 | 9 | ScaleRowUp(src_ptr + ((src_height - 1) / 2) * (int64_t)src_stride, dst_ptr, |
487 | 9 | dst_width); |
488 | 47 | } else { |
489 | 47 | dy = FixedDiv(src_height - 1, dst_height - 1); |
490 | 47 | y = (1 << 15) - 1; |
491 | 325k | for (i = 0; i < dst_height; ++i) { |
492 | 324k | ScaleRowUp(src_ptr + (y >> 16) * (int64_t)src_stride, dst_ptr, dst_width); |
493 | 324k | dst_ptr += dst_stride; |
494 | 324k | y += dy; |
495 | 324k | } |
496 | 47 | } |
497 | 56 | } |
498 | | |
499 | | // Scale plane, up by 2 times. |
500 | | // This is an optimized version for scaling up a plane to 2 times of |
501 | | // its original size, using bilinear interpolation. |
502 | | // This is used to scale U and V planes of I420 to I444. |
503 | | static void ScalePlaneUp2_Bilinear(int src_width, |
504 | | int src_height, |
505 | | int dst_width, |
506 | | int dst_height, |
507 | | int src_stride, |
508 | | int dst_stride, |
509 | | const uint8_t* src_ptr, |
510 | 36 | uint8_t* dst_ptr) { |
511 | 36 | void (*Scale2RowUp)(const uint8_t* src_ptr, ptrdiff_t src_stride, |
512 | 36 | uint8_t* dst_ptr, ptrdiff_t dst_stride, int dst_width) = |
513 | 36 | ScaleRowUp2_Bilinear_Any_C; |
514 | 36 | int x; |
515 | | |
516 | 36 | (void)src_width; |
517 | | // This function can only scale up by 2 times. |
518 | 36 | assert(src_width == ((dst_width + 1) / 2)); |
519 | 36 | assert(src_height == ((dst_height + 1) / 2)); |
520 | | |
521 | 36 | Scale2RowUp(src_ptr, 0, dst_ptr, 0, dst_width); |
522 | 36 | dst_ptr += dst_stride; |
523 | 310 | for (x = 0; x < src_height - 1; ++x) { |
524 | 274 | Scale2RowUp(src_ptr, src_stride, dst_ptr, dst_stride, dst_width); |
525 | 274 | src_ptr += src_stride; |
526 | | // TODO(fbarchard): Test performance of writing one row of destination at a |
527 | | // time. |
528 | 274 | dst_ptr += 2 * dst_stride; |
529 | 274 | } |
530 | 36 | if (!(dst_height & 1)) { |
531 | 14 | Scale2RowUp(src_ptr, 0, dst_ptr, 0, dst_width); |
532 | 14 | } |
533 | 36 | } |
534 | | |
535 | | // Scale at most 14 bit plane, horizontally up by 2 times. |
536 | | // This is an optimized version for scaling up a plane to 2 times of |
537 | | // its original width, using linear interpolation. |
538 | | // stride is in count of uint16_t. |
539 | | // This is used to scale U and V planes of I210 to I410 and I212 to I412. |
540 | | static void ScalePlaneUp2_12_Linear(int src_width, |
541 | | int src_height, |
542 | | int dst_width, |
543 | | int dst_height, |
544 | | int src_stride, |
545 | | int dst_stride, |
546 | | const uint16_t* src_ptr, |
547 | 31 | uint16_t* dst_ptr) { |
548 | 31 | void (*ScaleRowUp)(const uint16_t* src_ptr, uint16_t* dst_ptr, |
549 | 31 | int dst_width) = ScaleRowUp2_Linear_16_Any_C; |
550 | 31 | int i; |
551 | 31 | int y; |
552 | 31 | int dy; |
553 | | |
554 | 31 | (void)src_width; |
555 | | // This function can only scale up by 2 times horizontally. |
556 | 31 | assert(src_width == ((dst_width + 1) / 2)); |
557 | | |
558 | 31 | if (dst_height == 1) { |
559 | 7 | ScaleRowUp(src_ptr + ((src_height - 1) / 2) * (int64_t)src_stride, dst_ptr, |
560 | 7 | dst_width); |
561 | 24 | } else { |
562 | 24 | dy = FixedDiv(src_height - 1, dst_height - 1); |
563 | 24 | y = (1 << 15) - 1; |
564 | 84.9k | for (i = 0; i < dst_height; ++i) { |
565 | 84.9k | ScaleRowUp(src_ptr + (y >> 16) * (int64_t)src_stride, dst_ptr, dst_width); |
566 | 84.9k | dst_ptr += dst_stride; |
567 | 84.9k | y += dy; |
568 | 84.9k | } |
569 | 24 | } |
570 | 31 | } |
571 | | |
572 | | // Scale at most 12 bit plane, up by 2 times. |
573 | | // This is an optimized version for scaling up a plane to 2 times of |
574 | | // its original size, using bilinear interpolation. |
575 | | // stride is in count of uint16_t. |
576 | | // This is used to scale U and V planes of I010 to I410 and I012 to I412. |
577 | | static void ScalePlaneUp2_12_Bilinear(int src_width, |
578 | | int src_height, |
579 | | int dst_width, |
580 | | int dst_height, |
581 | | int src_stride, |
582 | | int dst_stride, |
583 | | const uint16_t* src_ptr, |
584 | 29 | uint16_t* dst_ptr) { |
585 | 29 | void (*Scale2RowUp)(const uint16_t* src_ptr, ptrdiff_t src_stride, |
586 | 29 | uint16_t* dst_ptr, ptrdiff_t dst_stride, int dst_width) = |
587 | 29 | ScaleRowUp2_Bilinear_16_Any_C; |
588 | 29 | int x; |
589 | | |
590 | 29 | (void)src_width; |
591 | | // This function can only scale up by 2 times. |
592 | 29 | assert(src_width == ((dst_width + 1) / 2)); |
593 | 29 | assert(src_height == ((dst_height + 1) / 2)); |
594 | | |
595 | 29 | Scale2RowUp(src_ptr, 0, dst_ptr, 0, dst_width); |
596 | 29 | dst_ptr += dst_stride; |
597 | 109 | for (x = 0; x < src_height - 1; ++x) { |
598 | 80 | Scale2RowUp(src_ptr, src_stride, dst_ptr, dst_stride, dst_width); |
599 | 80 | src_ptr += src_stride; |
600 | 80 | dst_ptr += 2 * dst_stride; |
601 | 80 | } |
602 | 29 | if (!(dst_height & 1)) { |
603 | 23 | Scale2RowUp(src_ptr, 0, dst_ptr, 0, dst_width); |
604 | 23 | } |
605 | 29 | } |
606 | | |
607 | | static void ScalePlaneUp2_16_Linear(int src_width, |
608 | | int src_height, |
609 | | int dst_width, |
610 | | int dst_height, |
611 | | int src_stride, |
612 | | int dst_stride, |
613 | | const uint16_t* src_ptr, |
614 | 0 | uint16_t* dst_ptr) { |
615 | 0 | void (*ScaleRowUp)(const uint16_t* src_ptr, uint16_t* dst_ptr, |
616 | 0 | int dst_width) = ScaleRowUp2_Linear_16_Any_C; |
617 | 0 | int i; |
618 | 0 | int y; |
619 | 0 | int dy; |
620 | |
|
621 | 0 | (void)src_width; |
622 | | // This function can only scale up by 2 times horizontally. |
623 | 0 | assert(src_width == ((dst_width + 1) / 2)); |
624 | |
|
625 | 0 | if (dst_height == 1) { |
626 | 0 | ScaleRowUp(src_ptr + ((src_height - 1) / 2) * (int64_t)src_stride, dst_ptr, |
627 | 0 | dst_width); |
628 | 0 | } else { |
629 | 0 | dy = FixedDiv(src_height - 1, dst_height - 1); |
630 | 0 | y = (1 << 15) - 1; |
631 | 0 | for (i = 0; i < dst_height; ++i) { |
632 | 0 | ScaleRowUp(src_ptr + (y >> 16) * (int64_t)src_stride, dst_ptr, dst_width); |
633 | 0 | dst_ptr += dst_stride; |
634 | 0 | y += dy; |
635 | 0 | } |
636 | 0 | } |
637 | 0 | } |
638 | | |
639 | | static void ScalePlaneUp2_16_Bilinear(int src_width, |
640 | | int src_height, |
641 | | int dst_width, |
642 | | int dst_height, |
643 | | int src_stride, |
644 | | int dst_stride, |
645 | | const uint16_t* src_ptr, |
646 | 0 | uint16_t* dst_ptr) { |
647 | 0 | void (*Scale2RowUp)(const uint16_t* src_ptr, ptrdiff_t src_stride, |
648 | 0 | uint16_t* dst_ptr, ptrdiff_t dst_stride, int dst_width) = |
649 | 0 | ScaleRowUp2_Bilinear_16_Any_C; |
650 | 0 | int x; |
651 | |
|
652 | 0 | (void)src_width; |
653 | | // This function can only scale up by 2 times. |
654 | 0 | assert(src_width == ((dst_width + 1) / 2)); |
655 | 0 | assert(src_height == ((dst_height + 1) / 2)); |
656 | |
|
657 | 0 | Scale2RowUp(src_ptr, 0, dst_ptr, 0, dst_width); |
658 | 0 | dst_ptr += dst_stride; |
659 | 0 | for (x = 0; x < src_height - 1; ++x) { |
660 | 0 | Scale2RowUp(src_ptr, src_stride, dst_ptr, dst_stride, dst_width); |
661 | 0 | src_ptr += src_stride; |
662 | 0 | dst_ptr += 2 * dst_stride; |
663 | 0 | } |
664 | 0 | if (!(dst_height & 1)) { |
665 | 0 | Scale2RowUp(src_ptr, 0, dst_ptr, 0, dst_width); |
666 | 0 | } |
667 | 0 | } |
668 | | |
669 | | static int ScalePlaneBilinearUp_16(int src_width, |
670 | | int src_height, |
671 | | int dst_width, |
672 | | int dst_height, |
673 | | int src_stride, |
674 | | int dst_stride, |
675 | | const uint16_t* src_ptr, |
676 | | uint16_t* dst_ptr, |
677 | 864 | enum FilterMode filtering) { |
678 | 864 | int j; |
679 | | // Initial source x/y coordinate and step values as 16.16 fixed point. |
680 | 864 | int x = 0; |
681 | 864 | int y = 0; |
682 | 864 | int dx = 0; |
683 | 864 | int dy = 0; |
684 | 864 | const int max_y = (src_height - 1) << 16; |
685 | 864 | void (*InterpolateRow)(uint16_t* dst_ptr, const uint16_t* src_ptr, |
686 | 864 | ptrdiff_t src_stride, int dst_width, |
687 | 864 | int source_y_fraction) = InterpolateRow_16_C; |
688 | 864 | void (*ScaleFilterCols)(uint16_t* dst_ptr, const uint16_t* src_ptr, |
689 | 864 | int dst_width, int x, int dx) = |
690 | 864 | filtering ? ScaleFilterCols_16_C : ScaleCols_16_C; |
691 | 864 | ScaleSlope(src_width, src_height, dst_width, dst_height, filtering, &x, &y, |
692 | 864 | &dx, &dy); |
693 | 864 | src_width = Abs(src_width); |
694 | | |
695 | 864 | if (filtering && src_width >= 32768) { |
696 | 0 | ScaleFilterCols = ScaleFilterCols64_16_C; |
697 | 0 | } |
698 | 864 | if (!filtering && src_width * 2 == dst_width && x < 0x8000) { |
699 | 0 | ScaleFilterCols = ScaleColsUp2_16_C; |
700 | 0 | } |
701 | 864 | if (y > max_y) { |
702 | 190 | y = max_y; |
703 | 190 | } |
704 | 864 | { |
705 | 864 | int yi = y >> 16; |
706 | 864 | const uint16_t* src = src_ptr + yi * (int64_t)src_stride; |
707 | | |
708 | | // Allocate 2 row buffers. |
709 | 864 | const int row_size = (dst_width + 31) & ~31; |
710 | 864 | align_buffer_64(row, row_size * 4); |
711 | 864 | int rowstride = row_size; |
712 | 864 | int lasty = yi; |
713 | 864 | uint16_t* rowptr = (uint16_t*)row; |
714 | 864 | if (!row) |
715 | 0 | return 1; |
716 | | |
717 | 864 | ScaleFilterCols(rowptr, src, dst_width, x, dx); |
718 | 864 | if (src_height > 1) { |
719 | 663 | src += src_stride; |
720 | 663 | } |
721 | 864 | ScaleFilterCols(rowptr + rowstride, src, dst_width, x, dx); |
722 | 864 | if (src_height > 2) { |
723 | 528 | src += src_stride; |
724 | 528 | } |
725 | | |
726 | 6.78M | for (j = 0; j < dst_height; ++j) { |
727 | 6.78M | yi = y >> 16; |
728 | 6.78M | if (yi != lasty) { |
729 | 102k | if (y > max_y) { |
730 | 0 | y = max_y; |
731 | 0 | yi = y >> 16; |
732 | 0 | src = src_ptr + yi * (int64_t)src_stride; |
733 | 0 | } |
734 | 102k | if (yi != lasty) { |
735 | 102k | ScaleFilterCols(rowptr, src, dst_width, x, dx); |
736 | 102k | rowptr += rowstride; |
737 | 102k | rowstride = -rowstride; |
738 | 102k | lasty = yi; |
739 | 102k | if ((y + 65536) < max_y) { |
740 | 102k | src += src_stride; |
741 | 102k | } |
742 | 102k | } |
743 | 102k | } |
744 | 6.78M | if (filtering == kFilterLinear) { |
745 | 950k | InterpolateRow(dst_ptr, rowptr, 0, dst_width, 0); |
746 | 5.83M | } else { |
747 | 5.83M | int yf = (y >> 8) & 255; |
748 | 5.83M | InterpolateRow(dst_ptr, rowptr, rowstride, dst_width, yf); |
749 | 5.83M | } |
750 | 6.78M | dst_ptr += dst_stride; |
751 | 6.78M | y += dy; |
752 | 6.78M | } |
753 | 864 | free_aligned_buffer_64(row); |
754 | 864 | } |
755 | 0 | return 0; |
756 | 864 | } |
757 | | |
758 | | // Scale Plane to/from any dimensions, without interpolation. |
759 | | // Fixed point math is used for performance: The upper 16 bits |
760 | | // of x and dx is the integer part of the source position and |
761 | | // the lower 16 bits are the fixed decimal part. |
762 | | |
763 | | static void ScalePlaneSimple(int src_width, |
764 | | int src_height, |
765 | | int dst_width, |
766 | | int dst_height, |
767 | | int src_stride, |
768 | | int dst_stride, |
769 | | const uint8_t* src_ptr, |
770 | 450 | uint8_t* dst_ptr) { |
771 | 450 | int i; |
772 | 450 | void (*ScaleCols)(uint8_t* dst_ptr, const uint8_t* src_ptr, int dst_width, |
773 | 450 | int x, int dx) = ScaleCols_C; |
774 | | // Initial source x/y coordinate and step values as 16.16 fixed point. |
775 | 450 | int x = 0; |
776 | 450 | int y = 0; |
777 | 450 | int dx = 0; |
778 | 450 | int dy = 0; |
779 | 450 | ScaleSlope(src_width, src_height, dst_width, dst_height, kFilterNone, &x, &y, |
780 | 450 | &dx, &dy); |
781 | 450 | src_width = Abs(src_width); |
782 | | |
783 | 450 | if (src_width * 2 == dst_width && x < 0x8000) { |
784 | 67 | ScaleCols = ScaleColsUp2_C; |
785 | 67 | } |
786 | | |
787 | 282k | for (i = 0; i < dst_height; ++i) { |
788 | 282k | ScaleCols(dst_ptr, src_ptr + (y >> 16) * (int64_t)src_stride, dst_width, x, |
789 | 282k | dx); |
790 | 282k | dst_ptr += dst_stride; |
791 | 282k | y += dy; |
792 | 282k | } |
793 | 450 | } |
794 | | |
795 | | static void ScalePlaneSimple_16(int src_width, |
796 | | int src_height, |
797 | | int dst_width, |
798 | | int dst_height, |
799 | | int src_stride, |
800 | | int dst_stride, |
801 | | const uint16_t* src_ptr, |
802 | 275 | uint16_t* dst_ptr) { |
803 | 275 | int i; |
804 | 275 | void (*ScaleCols)(uint16_t* dst_ptr, const uint16_t* src_ptr, int dst_width, |
805 | 275 | int x, int dx) = ScaleCols_16_C; |
806 | | // Initial source x/y coordinate and step values as 16.16 fixed point. |
807 | 275 | int x = 0; |
808 | 275 | int y = 0; |
809 | 275 | int dx = 0; |
810 | 275 | int dy = 0; |
811 | 275 | ScaleSlope(src_width, src_height, dst_width, dst_height, kFilterNone, &x, &y, |
812 | 275 | &dx, &dy); |
813 | 275 | src_width = Abs(src_width); |
814 | | |
815 | 275 | if (src_width * 2 == dst_width && x < 0x8000) { |
816 | 74 | ScaleCols = ScaleColsUp2_16_C; |
817 | 74 | } |
818 | | |
819 | 291k | for (i = 0; i < dst_height; ++i) { |
820 | 291k | ScaleCols(dst_ptr, src_ptr + (y >> 16) * (int64_t)src_stride, dst_width, x, |
821 | 291k | dx); |
822 | 291k | dst_ptr += dst_stride; |
823 | 291k | y += dy; |
824 | 291k | } |
825 | 275 | } |
826 | | |
827 | | // Scale a plane. |
828 | | // This function dispatches to a specialized scaler based on scale factor. |
829 | | int ScalePlane(const uint8_t* src, |
830 | | int src_stride, |
831 | | int src_width, |
832 | | int src_height, |
833 | | uint8_t* dst, |
834 | | int dst_stride, |
835 | | int dst_width, |
836 | | int dst_height, |
837 | 1.89k | enum FilterMode filtering) { |
838 | | // Simplify filtering when possible. |
839 | 1.89k | filtering = ScaleFilterReduce(src_width, src_height, dst_width, dst_height, |
840 | 1.89k | filtering); |
841 | | |
842 | | // Negative height means invert the image. |
843 | 1.89k | if (src_height < 0) { |
844 | 0 | src_height = -src_height; |
845 | 0 | src = src + (src_height - 1) * (int64_t)src_stride; |
846 | 0 | src_stride = -src_stride; |
847 | 0 | } |
848 | | // Use specialized scales to improve performance for common resolutions. |
849 | | // For example, all the 1/2 scalings will use ScalePlaneDown2() |
850 | 1.89k | if (dst_width == src_width && dst_height == src_height) { |
851 | | // Straight copy. |
852 | 10 | CopyPlane(src, src_stride, dst, dst_stride, dst_width, dst_height); |
853 | 10 | return 0; |
854 | 10 | } |
855 | 1.88k | if (dst_width == src_width && filtering != kFilterBox) { |
856 | 320 | int dy = 0; |
857 | 320 | int y = 0; |
858 | | // When scaling down, use the center 2 rows to filter. |
859 | | // When scaling up, last row of destination uses the last 2 source rows. |
860 | 320 | if (dst_height <= src_height) { |
861 | 203 | dy = FixedDiv(src_height, dst_height); |
862 | 203 | y = CENTERSTART(dy, -32768); // Subtract 0.5 (32768) to center filter. |
863 | 203 | } else if (src_height > 1 && dst_height > 1) { |
864 | 52 | dy = FixedDiv1(src_height, dst_height); |
865 | 52 | } |
866 | | // Arbitrary scale vertically, but unscaled horizontally. |
867 | 320 | ScalePlaneVertical(src_height, dst_width, dst_height, src_stride, |
868 | 320 | dst_stride, src, dst, 0, y, dy, /*bpp=*/1, filtering); |
869 | 320 | return 0; |
870 | 320 | } |
871 | 1.56k | if (filtering == kFilterBox && dst_height * 2 < src_height) { |
872 | 93 | return ScalePlaneBox(src_width, src_height, dst_width, dst_height, |
873 | 93 | src_stride, dst_stride, src, dst); |
874 | 93 | } |
875 | 1.46k | if ((dst_width + 1) / 2 == src_width && filtering == kFilterLinear) { |
876 | 56 | ScalePlaneUp2_Linear(src_width, src_height, dst_width, dst_height, |
877 | 56 | src_stride, dst_stride, src, dst); |
878 | 56 | return 0; |
879 | 56 | } |
880 | 1.41k | if ((dst_height + 1) / 2 == src_height && (dst_width + 1) / 2 == src_width && |
881 | 63 | (filtering == kFilterBilinear || filtering == kFilterBox)) { |
882 | 36 | ScalePlaneUp2_Bilinear(src_width, src_height, dst_width, dst_height, |
883 | 36 | src_stride, dst_stride, src, dst); |
884 | 36 | return 0; |
885 | 36 | } |
886 | 1.37k | if (filtering && dst_height > src_height) { |
887 | 570 | return ScalePlaneBilinearUp(src_width, src_height, dst_width, dst_height, |
888 | 570 | src_stride, dst_stride, src, dst, filtering); |
889 | 570 | } |
890 | 806 | if (filtering) { |
891 | 356 | return ScalePlaneBilinearDown(src_width, src_height, dst_width, dst_height, |
892 | 356 | src_stride, dst_stride, src, dst, filtering); |
893 | 356 | } |
894 | 450 | ScalePlaneSimple(src_width, src_height, dst_width, dst_height, src_stride, |
895 | 450 | dst_stride, src, dst); |
896 | 450 | return 0; |
897 | 806 | } |
898 | | |
899 | | int ScalePlane_16(const uint16_t* src, |
900 | | int src_stride, |
901 | | int src_width, |
902 | | int src_height, |
903 | | uint16_t* dst, |
904 | | int dst_stride, |
905 | | int dst_width, |
906 | | int dst_height, |
907 | 1.85k | enum FilterMode filtering) { |
908 | | // Simplify filtering when possible. |
909 | 1.85k | filtering = ScaleFilterReduce(src_width, src_height, dst_width, dst_height, |
910 | 1.85k | filtering); |
911 | | |
912 | | // Negative height means invert the image. |
913 | 1.85k | if (src_height < 0) { |
914 | 0 | src_height = -src_height; |
915 | 0 | src = src + (src_height - 1) * (int64_t)src_stride; |
916 | 0 | src_stride = -src_stride; |
917 | 0 | } |
918 | | // Use specialized scales to improve performance for common resolutions. |
919 | | // For example, all the 1/2 scalings will use ScalePlaneDown2() |
920 | 1.85k | if (dst_width == src_width && dst_height == src_height) { |
921 | | // Straight copy. |
922 | 12 | CopyPlane_16(src, src_stride, dst, dst_stride, dst_width, dst_height); |
923 | 12 | return 0; |
924 | 12 | } |
925 | 1.84k | if (dst_width == src_width && filtering != kFilterBox) { |
926 | 137 | int dy = 0; |
927 | 137 | int y = 0; |
928 | | // When scaling down, use the center 2 rows to filter. |
929 | | // When scaling up, last row of destination uses the last 2 source rows. |
930 | 137 | if (dst_height <= src_height) { |
931 | 67 | dy = FixedDiv(src_height, dst_height); |
932 | 67 | y = CENTERSTART(dy, -32768); // Subtract 0.5 (32768) to center filter. |
933 | | // When scaling up, ensure the last row of destination uses the last |
934 | | // source. Avoid divide by zero for dst_height but will do no scaling |
935 | | // later. |
936 | 70 | } else if (src_height > 1 && dst_height > 1) { |
937 | 46 | dy = FixedDiv1(src_height, dst_height); |
938 | 46 | } |
939 | | // Arbitrary scale vertically, but unscaled horizontally. |
940 | 137 | ScalePlaneVertical_16(src_height, dst_width, dst_height, src_stride, |
941 | 137 | dst_stride, src, dst, 0, y, dy, /*bpp=*/1, filtering); |
942 | 137 | return 0; |
943 | 137 | } |
944 | 1.71k | if (filtering == kFilterBox && dst_height * 2 < src_height) { |
945 | 88 | return ScalePlaneBox_16(src_width, src_height, dst_width, dst_height, |
946 | 88 | src_stride, dst_stride, src, dst); |
947 | 88 | } |
948 | 1.62k | if ((dst_width + 1) / 2 == src_width && filtering == kFilterLinear) { |
949 | 0 | ScalePlaneUp2_16_Linear(src_width, src_height, dst_width, dst_height, |
950 | 0 | src_stride, dst_stride, src, dst); |
951 | 0 | return 0; |
952 | 0 | } |
953 | 1.62k | if ((dst_height + 1) / 2 == src_height && (dst_width + 1) / 2 == src_width && |
954 | 23 | (filtering == kFilterBilinear || filtering == kFilterBox)) { |
955 | 0 | ScalePlaneUp2_16_Bilinear(src_width, src_height, dst_width, dst_height, |
956 | 0 | src_stride, dst_stride, src, dst); |
957 | 0 | return 0; |
958 | 0 | } |
959 | 1.62k | if (filtering && dst_height > src_height) { |
960 | 864 | return ScalePlaneBilinearUp_16(src_width, src_height, dst_width, dst_height, |
961 | 864 | src_stride, dst_stride, src, dst, filtering); |
962 | 864 | } |
963 | 758 | if (filtering) { |
964 | 483 | return ScalePlaneBilinearDown_16(src_width, src_height, dst_width, |
965 | 483 | dst_height, src_stride, dst_stride, src, |
966 | 483 | dst, filtering); |
967 | 483 | } |
968 | 275 | ScalePlaneSimple_16(src_width, src_height, dst_width, dst_height, src_stride, |
969 | 275 | dst_stride, src, dst); |
970 | 275 | return 0; |
971 | 758 | } |
972 | | |
973 | | int ScalePlane_12(const uint16_t* src, |
974 | | int src_stride, |
975 | | int src_width, |
976 | | int src_height, |
977 | | uint16_t* dst, |
978 | | int dst_stride, |
979 | | int dst_width, |
980 | | int dst_height, |
981 | 1.91k | enum FilterMode filtering) { |
982 | | // Simplify filtering when possible. |
983 | 1.91k | filtering = ScaleFilterReduce(src_width, src_height, dst_width, dst_height, |
984 | 1.91k | filtering); |
985 | | |
986 | | // Negative height means invert the image. |
987 | 1.91k | if (src_height < 0) { |
988 | 0 | src_height = -src_height; |
989 | 0 | src = src + (src_height - 1) * (int64_t)src_stride; |
990 | 0 | src_stride = -src_stride; |
991 | 0 | } |
992 | | |
993 | 1.91k | if ((dst_width + 1) / 2 == src_width && filtering == kFilterLinear) { |
994 | 31 | ScalePlaneUp2_12_Linear(src_width, src_height, dst_width, dst_height, |
995 | 31 | src_stride, dst_stride, src, dst); |
996 | 31 | return 0; |
997 | 31 | } |
998 | 1.88k | if ((dst_height + 1) / 2 == src_height && (dst_width + 1) / 2 == src_width && |
999 | 62 | (filtering == kFilterBilinear || filtering == kFilterBox)) { |
1000 | 29 | ScalePlaneUp2_12_Bilinear(src_width, src_height, dst_width, dst_height, |
1001 | 29 | src_stride, dst_stride, src, dst); |
1002 | 29 | return 0; |
1003 | 29 | } |
1004 | | |
1005 | 1.85k | return ScalePlane_16(src, src_stride, src_width, src_height, dst, dst_stride, |
1006 | 1.85k | dst_width, dst_height, filtering); |
1007 | 1.88k | } |