]> granicus.if.org Git - libvpx/blob - vp9/encoder/vp9_resize.c
e5ae9594cf46c53905d134c4b29032ffeee25db7
[libvpx] / vp9 / encoder / vp9_resize.c
1 /*
2  *  Copyright (c) 2014 The WebM 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 <assert.h>
12 #include <limits.h>
13 #include <math.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17
18 #if CONFIG_VP9_HIGHBITDEPTH
19 #include "vpx_dsp/vpx_dsp_common.h"
20 #endif  // CONFIG_VP9_HIGHBITDEPTH
21 #include "vpx_ports/mem.h"
22 #include "vp9/common/vp9_common.h"
23 #include "vp9/encoder/vp9_resize.h"
24
25 #define FILTER_BITS               7
26
27 #define INTERP_TAPS               8
28 #define SUBPEL_BITS               5
29 #define SUBPEL_MASK               ((1 << SUBPEL_BITS) - 1)
30 #define INTERP_PRECISION_BITS     32
31
32 typedef int16_t interp_kernel[INTERP_TAPS];
33
34 // Filters for interpolation (0.5-band) - note this also filters integer pels.
35 static const interp_kernel filteredinterp_filters500[(1 << SUBPEL_BITS)] = {
36   {-3,  0, 35, 64, 35,  0, -3, 0},
37   {-3, -1, 34, 64, 36,  1, -3, 0},
38   {-3, -1, 32, 64, 38,  1, -3, 0},
39   {-2, -2, 31, 63, 39,  2, -3, 0},
40   {-2, -2, 29, 63, 41,  2, -3, 0},
41   {-2, -2, 28, 63, 42,  3, -4, 0},
42   {-2, -3, 27, 63, 43,  4, -4, 0},
43   {-2, -3, 25, 62, 45,  5, -4, 0},
44   {-2, -3, 24, 62, 46,  5, -4, 0},
45   {-2, -3, 23, 61, 47,  6, -4, 0},
46   {-2, -3, 21, 60, 49,  7, -4, 0},
47   {-1, -4, 20, 60, 50,  8, -4, -1},
48   {-1, -4, 19, 59, 51,  9, -4, -1},
49   {-1, -4, 17, 58, 52, 10, -4, 0},
50   {-1, -4, 16, 57, 53, 12, -4, -1},
51   {-1, -4, 15, 56, 54, 13, -4, -1},
52   {-1, -4, 14, 55, 55, 14, -4, -1},
53   {-1, -4, 13, 54, 56, 15, -4, -1},
54   {-1, -4, 12, 53, 57, 16, -4, -1},
55   {0, -4, 10, 52, 58, 17, -4, -1},
56   {-1, -4,  9, 51, 59, 19, -4, -1},
57   {-1, -4,  8, 50, 60, 20, -4, -1},
58   {0, -4,  7, 49, 60, 21, -3, -2},
59   {0, -4,  6, 47, 61, 23, -3, -2},
60   {0, -4,  5, 46, 62, 24, -3, -2},
61   {0, -4,  5, 45, 62, 25, -3, -2},
62   {0, -4,  4, 43, 63, 27, -3, -2},
63   {0, -4,  3, 42, 63, 28, -2, -2},
64   {0, -3,  2, 41, 63, 29, -2, -2},
65   {0, -3,  2, 39, 63, 31, -2, -2},
66   {0, -3,  1, 38, 64, 32, -1, -3},
67   {0, -3,  1, 36, 64, 34, -1, -3}
68 };
69
70 // Filters for interpolation (0.625-band) - note this also filters integer pels.
71 static const interp_kernel filteredinterp_filters625[(1 << SUBPEL_BITS)] = {
72   {-1, -8, 33, 80, 33, -8, -1, 0},
73   {-1, -8, 30, 80, 35, -8, -1, 1},
74   {-1, -8, 28, 80, 37, -7, -2, 1},
75   {0, -8, 26, 79, 39, -7, -2, 1},
76   {0, -8, 24, 79, 41, -7, -2, 1},
77   {0, -8, 22, 78, 43, -6, -2, 1},
78   {0, -8, 20, 78, 45, -5, -3, 1},
79   {0, -8, 18, 77, 48, -5, -3, 1},
80   {0, -8, 16, 76, 50, -4, -3, 1},
81   {0, -8, 15, 75, 52, -3, -4, 1},
82   {0, -7, 13, 74, 54, -3, -4, 1},
83   {0, -7, 11, 73, 56, -2, -4, 1},
84   {0, -7, 10, 71, 58, -1, -4, 1},
85   {1, -7,  8, 70, 60,  0, -5, 1},
86   {1, -6,  6, 68, 62,  1, -5, 1},
87   {1, -6,  5, 67, 63,  2, -5, 1},
88   {1, -6,  4, 65, 65,  4, -6, 1},
89   {1, -5,  2, 63, 67,  5, -6, 1},
90   {1, -5,  1, 62, 68,  6, -6, 1},
91   {1, -5,  0, 60, 70,  8, -7, 1},
92   {1, -4, -1, 58, 71, 10, -7, 0},
93   {1, -4, -2, 56, 73, 11, -7, 0},
94   {1, -4, -3, 54, 74, 13, -7, 0},
95   {1, -4, -3, 52, 75, 15, -8, 0},
96   {1, -3, -4, 50, 76, 16, -8, 0},
97   {1, -3, -5, 48, 77, 18, -8, 0},
98   {1, -3, -5, 45, 78, 20, -8, 0},
99   {1, -2, -6, 43, 78, 22, -8, 0},
100   {1, -2, -7, 41, 79, 24, -8, 0},
101   {1, -2, -7, 39, 79, 26, -8, 0},
102   {1, -2, -7, 37, 80, 28, -8, -1},
103   {1, -1, -8, 35, 80, 30, -8, -1},
104 };
105
106 // Filters for interpolation (0.75-band) - note this also filters integer pels.
107 static const interp_kernel filteredinterp_filters750[(1 << SUBPEL_BITS)] = {
108   {2, -11,  25,  96,  25, -11,   2, 0},
109   {2, -11,  22,  96,  28, -11,   2, 0},
110   {2, -10,  19,  95,  31, -11,   2, 0},
111   {2, -10,  17,  95,  34, -12,   2, 0},
112   {2,  -9,  14,  94,  37, -12,   2, 0},
113   {2,  -8,  12,  93,  40, -12,   1, 0},
114   {2,  -8,   9,  92,  43, -12,   1, 1},
115   {2,  -7,   7,  91,  46, -12,   1, 0},
116   {2,  -7,   5,  90,  49, -12,   1, 0},
117   {2,  -6,   3,  88,  52, -12,   0, 1},
118   {2,  -5,   1,  86,  55, -12,   0, 1},
119   {2,  -5,  -1,  84,  58, -11,   0, 1},
120   {2,  -4,  -2,  82,  61, -11,  -1, 1},
121   {2,  -4,  -4,  80,  64, -10,  -1, 1},
122   {1, -3, -5, 77, 67, -9, -1, 1},
123   {1, -3, -6, 75, 70, -8, -2, 1},
124   {1, -2, -7, 72, 72, -7, -2, 1},
125   {1, -2, -8, 70, 75, -6, -3, 1},
126   {1, -1, -9, 67, 77, -5, -3, 1},
127   {1,  -1, -10,  64,  80,  -4,  -4, 2},
128   {1,  -1, -11,  61,  82,  -2,  -4, 2},
129   {1,   0, -11,  58,  84,  -1,  -5, 2},
130   {1,   0, -12,  55,  86,   1,  -5, 2},
131   {1,   0, -12,  52,  88,   3,  -6, 2},
132   {0,   1, -12,  49,  90,   5,  -7, 2},
133   {0,   1, -12,  46,  91,   7,  -7, 2},
134   {1,   1, -12,  43,  92,   9,  -8, 2},
135   {0,   1, -12,  40,  93,  12,  -8, 2},
136   {0,   2, -12,  37,  94,  14,  -9, 2},
137   {0,   2, -12,  34,  95,  17, -10, 2},
138   {0,   2, -11,  31,  95,  19, -10, 2},
139   {0,   2, -11,  28,  96,  22, -11, 2}
140 };
141
142 // Filters for interpolation (0.875-band) - note this also filters integer pels.
143 static const interp_kernel filteredinterp_filters875[(1 << SUBPEL_BITS)] = {
144   {3,  -8,  13, 112,  13,  -8,   3, 0},
145   {3,  -7,  10, 112,  17,  -9,   3, -1},
146   {2,  -6,   7, 111,  21,  -9,   3, -1},
147   {2,  -5,   4, 111,  24, -10,   3, -1},
148   {2,  -4,   1, 110,  28, -11,   3, -1},
149   {1,  -3,  -1, 108,  32, -12,   4, -1},
150   {1,  -2,  -3, 106,  36, -13,   4, -1},
151   {1,  -1,  -6, 105,  40, -14,   4, -1},
152   {1,  -1,  -7, 102,  44, -14,   4, -1},
153   {1,   0,  -9, 100,  48, -15,   4, -1},
154   {1,   1, -11,  97,  53, -16,   4, -1},
155   {0,   1, -12,  95,  57, -16,   4, -1},
156   {0,   2, -13,  91,  61, -16,   4, -1},
157   {0,   2, -14,  88,  65, -16,   4, -1},
158   {0,   3, -15,  84,  69, -17,   4, 0},
159   {0,   3, -16,  81,  73, -16,   3, 0},
160   {0,   3, -16,  77,  77, -16,   3, 0},
161   {0,   3, -16,  73,  81, -16,   3, 0},
162   {0,   4, -17,  69,  84, -15,   3, 0},
163   {-1,   4, -16,  65,  88, -14,   2, 0},
164   {-1,   4, -16,  61,  91, -13,   2, 0},
165   {-1,   4, -16,  57,  95, -12,   1, 0},
166   {-1,   4, -16,  53,  97, -11,   1, 1},
167   {-1,   4, -15,  48, 100,  -9,   0, 1},
168   {-1,   4, -14,  44, 102,  -7,  -1, 1},
169   {-1,   4, -14,  40, 105,  -6,  -1, 1},
170   {-1,   4, -13,  36, 106,  -3,  -2, 1},
171   {-1,   4, -12,  32, 108,  -1,  -3, 1},
172   {-1,   3, -11,  28, 110,   1,  -4, 2},
173   {-1,   3, -10,  24, 111,   4,  -5, 2},
174   {-1,   3,  -9,  21, 111,   7,  -6, 2},
175   {-1,   3,  -9,  17, 112,  10,  -7, 3}
176 };
177
178 // Filters for interpolation (full-band) - no filtering for integer pixels
179 static const interp_kernel filteredinterp_filters1000[(1 << SUBPEL_BITS)] = {
180   {0,   0,   0, 128,   0,   0,   0, 0},
181   {0,   1,  -3, 128,   3,  -1,   0, 0},
182   {-1,   2,  -6, 127,   7,  -2,   1, 0},
183   {-1,   3,  -9, 126,  12,  -4,   1, 0},
184   {-1,   4, -12, 125,  16,  -5,   1, 0},
185   {-1,   4, -14, 123,  20,  -6,   2, 0},
186   {-1,   5, -15, 120,  25,  -8,   2, 0},
187   {-1,   5, -17, 118,  30,  -9,   3, -1},
188   {-1,   6, -18, 114,  35, -10,   3, -1},
189   {-1,   6, -19, 111,  41, -12,   3, -1},
190   {-1,   6, -20, 107,  46, -13,   4, -1},
191   {-1,   6, -21, 103,  52, -14,   4, -1},
192   {-1,   6, -21,  99,  57, -16,   5, -1},
193   {-1,   6, -21,  94,  63, -17,   5, -1},
194   {-1,   6, -20,  89,  68, -18,   5, -1},
195   {-1,   6, -20,  84,  73, -19,   6, -1},
196   {-1,   6, -20,  79,  79, -20,   6, -1},
197   {-1,   6, -19,  73,  84, -20,   6, -1},
198   {-1,   5, -18,  68,  89, -20,   6, -1},
199   {-1,   5, -17,  63,  94, -21,   6, -1},
200   {-1,   5, -16,  57,  99, -21,   6, -1},
201   {-1,   4, -14,  52, 103, -21,   6, -1},
202   {-1,   4, -13,  46, 107, -20,   6, -1},
203   {-1,   3, -12,  41, 111, -19,   6, -1},
204   {-1,   3, -10,  35, 114, -18,   6, -1},
205   {-1,   3,  -9,  30, 118, -17,   5, -1},
206   {0,   2,  -8,  25, 120, -15,   5, -1},
207   {0,   2,  -6,  20, 123, -14,   4, -1},
208   {0,   1,  -5,  16, 125, -12,   4, -1},
209   {0,   1,  -4,  12, 126,  -9,   3, -1},
210   {0,   1,  -2,   7, 127,  -6,   2, -1},
211   {0,   0,  -1,   3, 128,  -3,   1, 0}
212 };
213
214 // Filters for factor of 2 downsampling.
215 static const int16_t vp9_down2_symeven_half_filter[] = {56, 12, -3, -1};
216 static const int16_t vp9_down2_symodd_half_filter[] = {64, 35, 0, -3};
217
218 static const interp_kernel *choose_interp_filter(int inlength, int outlength) {
219   int outlength16 = outlength * 16;
220   if (outlength16 >= inlength * 16)
221     return filteredinterp_filters1000;
222   else if (outlength16 >= inlength * 13)
223     return filteredinterp_filters875;
224   else if (outlength16 >= inlength * 11)
225     return filteredinterp_filters750;
226   else if (outlength16 >= inlength * 9)
227     return filteredinterp_filters625;
228   else
229     return filteredinterp_filters500;
230 }
231
232 static void interpolate(const uint8_t *const input, int inlength,
233                         uint8_t *output, int outlength) {
234   const int64_t delta = (((uint64_t)inlength << 32) + outlength / 2) /
235       outlength;
236   const int64_t offset = inlength > outlength ?
237       (((int64_t)(inlength - outlength) << 31) + outlength / 2) / outlength :
238       -(((int64_t)(outlength - inlength) << 31) + outlength / 2) / outlength;
239   uint8_t *optr = output;
240   int x, x1, x2, sum, k, int_pel, sub_pel;
241   int64_t y;
242
243   const interp_kernel *interp_filters =
244       choose_interp_filter(inlength, outlength);
245
246   x = 0;
247   y = offset;
248   while ((y >> INTERP_PRECISION_BITS) < (INTERP_TAPS / 2 - 1)) {
249     x++;
250     y += delta;
251   }
252   x1 = x;
253   x = outlength - 1;
254   y = delta * x + offset;
255   while ((y >> INTERP_PRECISION_BITS) +
256          (int64_t)(INTERP_TAPS / 2) >= inlength) {
257     x--;
258     y -= delta;
259   }
260   x2 = x;
261   if (x1 > x2) {
262     for (x = 0, y = offset; x < outlength; ++x, y += delta) {
263       const int16_t *filter;
264       int_pel = y >> INTERP_PRECISION_BITS;
265       sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
266       filter = interp_filters[sub_pel];
267       sum = 0;
268       for (k = 0; k < INTERP_TAPS; ++k) {
269         const int pk = int_pel - INTERP_TAPS / 2 + 1 + k;
270         sum += filter[k] * input[(pk < 0 ? 0 :
271                                   (pk >= inlength ? inlength - 1 : pk))];
272       }
273       *optr++ = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
274     }
275   } else {
276     // Initial part.
277     for (x = 0, y = offset; x < x1; ++x, y += delta) {
278       const int16_t *filter;
279       int_pel = y >> INTERP_PRECISION_BITS;
280       sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
281       filter = interp_filters[sub_pel];
282       sum = 0;
283       for (k = 0; k < INTERP_TAPS; ++k)
284         sum += filter[k] * input[(int_pel - INTERP_TAPS / 2 + 1 + k < 0 ?
285                                   0 :
286                                   int_pel - INTERP_TAPS / 2 + 1 + k)];
287       *optr++ = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
288     }
289     // Middle part.
290     for (; x <= x2; ++x, y += delta) {
291       const int16_t *filter;
292       int_pel = y >> INTERP_PRECISION_BITS;
293       sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
294       filter = interp_filters[sub_pel];
295       sum = 0;
296       for (k = 0; k < INTERP_TAPS; ++k)
297         sum += filter[k] * input[int_pel - INTERP_TAPS / 2 + 1 + k];
298       *optr++ = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
299     }
300     // End part.
301     for (; x < outlength; ++x, y += delta) {
302       const int16_t *filter;
303       int_pel = y >> INTERP_PRECISION_BITS;
304       sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
305       filter = interp_filters[sub_pel];
306       sum = 0;
307       for (k = 0; k < INTERP_TAPS; ++k)
308         sum += filter[k] * input[(int_pel - INTERP_TAPS / 2 + 1 + k >=
309                                   inlength ?  inlength - 1 :
310                                   int_pel - INTERP_TAPS / 2 + 1 + k)];
311       *optr++ = clip_pixel(ROUND_POWER_OF_TWO(sum, FILTER_BITS));
312     }
313   }
314 }
315
316 static void down2_symeven(const uint8_t *const input, int length,
317                           uint8_t *output) {
318   // Actual filter len = 2 * filter_len_half.
319   const int16_t *filter = vp9_down2_symeven_half_filter;
320   const int filter_len_half = sizeof(vp9_down2_symeven_half_filter) / 2;
321   int i, j;
322   uint8_t *optr = output;
323   int l1 = filter_len_half;
324   int l2 = (length - filter_len_half);
325   l1 += (l1 & 1);
326   l2 += (l2 & 1);
327   if (l1 > l2) {
328     // Short input length.
329     for (i = 0; i < length; i += 2) {
330       int sum = (1 << (FILTER_BITS - 1));
331       for (j = 0; j < filter_len_half; ++j) {
332         sum += (input[(i - j < 0 ? 0 : i - j)] +
333                 input[(i + 1 + j >= length ? length - 1 : i + 1 + j)]) *
334             filter[j];
335       }
336       sum >>= FILTER_BITS;
337       *optr++ = clip_pixel(sum);
338     }
339   } else {
340     // Initial part.
341     for (i = 0; i < l1; i += 2) {
342       int sum = (1 << (FILTER_BITS - 1));
343       for (j = 0; j < filter_len_half; ++j) {
344         sum += (input[(i - j < 0 ? 0 : i - j)] + input[i + 1 + j]) * filter[j];
345       }
346       sum >>= FILTER_BITS;
347       *optr++ = clip_pixel(sum);
348     }
349     // Middle part.
350     for (; i < l2; i += 2) {
351       int sum = (1 << (FILTER_BITS - 1));
352       for (j = 0; j < filter_len_half; ++j) {
353         sum += (input[i - j] + input[i + 1 + j]) * filter[j];
354       }
355       sum >>= FILTER_BITS;
356       *optr++ = clip_pixel(sum);
357     }
358     // End part.
359     for (; i < length; i += 2) {
360       int sum = (1 << (FILTER_BITS - 1));
361       for (j = 0; j < filter_len_half; ++j) {
362         sum += (input[i - j] +
363                 input[(i + 1 + j >= length ? length - 1 : i + 1 + j)]) *
364             filter[j];
365       }
366       sum >>= FILTER_BITS;
367       *optr++ = clip_pixel(sum);
368     }
369   }
370 }
371
372 static void down2_symodd(const uint8_t *const input, int length,
373                          uint8_t *output) {
374   // Actual filter len = 2 * filter_len_half - 1.
375   const int16_t *filter = vp9_down2_symodd_half_filter;
376   const int filter_len_half = sizeof(vp9_down2_symodd_half_filter) / 2;
377   int i, j;
378   uint8_t *optr = output;
379   int l1 = filter_len_half - 1;
380   int l2 = (length - filter_len_half + 1);
381   l1 += (l1 & 1);
382   l2 += (l2 & 1);
383   if (l1 > l2) {
384     // Short input length.
385     for (i = 0; i < length; i += 2) {
386       int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
387       for (j = 1; j < filter_len_half; ++j) {
388         sum += (input[(i - j < 0 ? 0 : i - j)] +
389                 input[(i + j >= length ? length - 1 : i + j)]) *
390             filter[j];
391       }
392       sum >>= FILTER_BITS;
393       *optr++ = clip_pixel(sum);
394     }
395   } else {
396     // Initial part.
397     for (i = 0; i < l1; i += 2) {
398       int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
399       for (j = 1; j < filter_len_half; ++j) {
400         sum += (input[(i - j < 0 ? 0 : i - j)] + input[i + j]) * filter[j];
401       }
402       sum >>= FILTER_BITS;
403       *optr++ = clip_pixel(sum);
404     }
405     // Middle part.
406     for (; i < l2; i += 2) {
407       int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
408       for (j = 1; j < filter_len_half; ++j) {
409         sum += (input[i - j] + input[i + j]) * filter[j];
410       }
411       sum >>= FILTER_BITS;
412       *optr++ = clip_pixel(sum);
413     }
414     // End part.
415     for (; i < length; i += 2) {
416       int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
417       for (j = 1; j < filter_len_half; ++j) {
418         sum += (input[i - j] + input[(i + j >= length ? length - 1 : i + j)]) *
419             filter[j];
420       }
421       sum >>= FILTER_BITS;
422       *optr++ = clip_pixel(sum);
423     }
424   }
425 }
426
427 static int get_down2_length(int length, int steps) {
428   int s;
429   for (s = 0; s < steps; ++s)
430     length = (length + 1) >> 1;
431   return length;
432 }
433
434 static int get_down2_steps(int in_length, int out_length) {
435   int steps = 0;
436   int proj_in_length;
437   while ((proj_in_length = get_down2_length(in_length, 1)) >= out_length) {
438     ++steps;
439     in_length = proj_in_length;
440   }
441   return steps;
442 }
443
444 static void resize_multistep(const uint8_t *const input,
445                              int length,
446                              uint8_t *output,
447                              int olength,
448                              uint8_t *buf) {
449   int steps;
450   if (length == olength) {
451     memcpy(output, input, sizeof(uint8_t) * length);
452     return;
453   }
454   steps = get_down2_steps(length, olength);
455
456   if (steps > 0) {
457     int s;
458     uint8_t *out = NULL;
459     uint8_t *tmpbuf = NULL;
460     uint8_t *otmp, *otmp2;
461     int filteredlength = length;
462     if (!tmpbuf) {
463       tmpbuf = (uint8_t *)malloc(sizeof(uint8_t) * length);
464       otmp = tmpbuf;
465     } else {
466       otmp = buf;
467     }
468     otmp2 = otmp + get_down2_length(length, 1);
469     for (s = 0; s < steps; ++s) {
470       const int proj_filteredlength = get_down2_length(filteredlength, 1);
471       const uint8_t *const in = (s == 0 ? input : out);
472       if (s == steps - 1 && proj_filteredlength == olength)
473         out = output;
474       else
475         out = (s & 1 ? otmp2 : otmp);
476       if (filteredlength & 1)
477         down2_symodd(in, filteredlength, out);
478       else
479         down2_symeven(in, filteredlength, out);
480       filteredlength = proj_filteredlength;
481     }
482     if (filteredlength != olength) {
483       interpolate(out, filteredlength, output, olength);
484     }
485     if (tmpbuf)
486       free(tmpbuf);
487   } else {
488     interpolate(input, length, output, olength);
489   }
490 }
491
492 static void fill_col_to_arr(uint8_t *img, int stride, int len, uint8_t *arr) {
493   int i;
494   uint8_t *iptr = img;
495   uint8_t *aptr = arr;
496   for (i = 0; i < len; ++i, iptr += stride) {
497     *aptr++ = *iptr;
498   }
499 }
500
501 static void fill_arr_to_col(uint8_t *img, int stride, int len, uint8_t *arr) {
502   int i;
503   uint8_t *iptr = img;
504   uint8_t *aptr = arr;
505   for (i = 0; i < len; ++i, iptr += stride) {
506     *iptr = *aptr++;
507   }
508 }
509
510 void vp9_resize_plane(const uint8_t *const input,
511                       int height,
512                       int width,
513                       int in_stride,
514                       uint8_t *output,
515                       int height2,
516                       int width2,
517                       int out_stride) {
518   int i;
519   uint8_t *intbuf = (uint8_t *)malloc(sizeof(uint8_t) * width2 * height);
520   uint8_t *tmpbuf = (uint8_t *)malloc(sizeof(uint8_t) *
521                                       (width < height ? height : width));
522   uint8_t *arrbuf = (uint8_t *)malloc(sizeof(uint8_t) * (height + height2));
523   assert(width > 0);
524   assert(height > 0);
525   assert(width2 > 0);
526   assert(height2 > 0);
527   for (i = 0; i < height; ++i)
528     resize_multistep(input + in_stride * i, width,
529                         intbuf + width2 * i, width2, tmpbuf);
530   for (i = 0; i < width2; ++i) {
531     fill_col_to_arr(intbuf + i, width2, height, arrbuf);
532     resize_multistep(arrbuf, height, arrbuf + height, height2, tmpbuf);
533     fill_arr_to_col(output + i, out_stride, height2, arrbuf + height);
534   }
535   free(intbuf);
536   free(tmpbuf);
537   free(arrbuf);
538 }
539
540 #if CONFIG_VP9_HIGHBITDEPTH
541 static void highbd_interpolate(const uint16_t *const input, int inlength,
542                                uint16_t *output, int outlength, int bd) {
543   const int64_t delta =
544       (((uint64_t)inlength << 32) + outlength / 2) / outlength;
545   const int64_t offset = inlength > outlength ?
546       (((int64_t)(inlength - outlength) << 31) + outlength / 2) / outlength :
547       -(((int64_t)(outlength - inlength) << 31) + outlength / 2) / outlength;
548   uint16_t *optr = output;
549   int x, x1, x2, sum, k, int_pel, sub_pel;
550   int64_t y;
551
552   const interp_kernel *interp_filters =
553       choose_interp_filter(inlength, outlength);
554
555   x = 0;
556   y = offset;
557   while ((y >> INTERP_PRECISION_BITS) < (INTERP_TAPS / 2 - 1)) {
558     x++;
559     y += delta;
560   }
561   x1 = x;
562   x = outlength - 1;
563   y = delta * x + offset;
564   while ((y >> INTERP_PRECISION_BITS) +
565          (int64_t)(INTERP_TAPS / 2) >= inlength) {
566     x--;
567     y -= delta;
568   }
569   x2 = x;
570   if (x1 > x2) {
571     for (x = 0, y = offset; x < outlength; ++x, y += delta) {
572       const int16_t *filter;
573       int_pel = y >> INTERP_PRECISION_BITS;
574       sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
575       filter = interp_filters[sub_pel];
576       sum = 0;
577       for (k = 0; k < INTERP_TAPS; ++k) {
578         const int pk = int_pel - INTERP_TAPS / 2 + 1 + k;
579         sum += filter[k] *
580             input[(pk < 0 ? 0 : (pk >= inlength ? inlength - 1 : pk))];
581       }
582       *optr++ = clip_pixel_highbd(ROUND_POWER_OF_TWO(sum, FILTER_BITS), bd);
583     }
584   } else {
585     // Initial part.
586     for (x = 0, y = offset; x < x1; ++x, y += delta) {
587       const int16_t *filter;
588       int_pel = y >> INTERP_PRECISION_BITS;
589       sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
590       filter = interp_filters[sub_pel];
591       sum = 0;
592       for (k = 0; k < INTERP_TAPS; ++k)
593         sum += filter[k] *
594             input[(int_pel - INTERP_TAPS / 2 + 1 + k < 0 ?
595                    0 : int_pel - INTERP_TAPS / 2 + 1 + k)];
596       *optr++ = clip_pixel_highbd(ROUND_POWER_OF_TWO(sum, FILTER_BITS), bd);
597     }
598     // Middle part.
599     for (; x <= x2; ++x, y += delta) {
600       const int16_t *filter;
601       int_pel = y >> INTERP_PRECISION_BITS;
602       sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
603       filter = interp_filters[sub_pel];
604       sum = 0;
605       for (k = 0; k < INTERP_TAPS; ++k)
606         sum += filter[k] * input[int_pel - INTERP_TAPS / 2 + 1 + k];
607       *optr++ = clip_pixel_highbd(ROUND_POWER_OF_TWO(sum, FILTER_BITS), bd);
608     }
609     // End part.
610     for (; x < outlength; ++x, y += delta) {
611       const int16_t *filter;
612       int_pel = y >> INTERP_PRECISION_BITS;
613       sub_pel = (y >> (INTERP_PRECISION_BITS - SUBPEL_BITS)) & SUBPEL_MASK;
614       filter = interp_filters[sub_pel];
615       sum = 0;
616       for (k = 0; k < INTERP_TAPS; ++k)
617         sum += filter[k] * input[(int_pel - INTERP_TAPS / 2 + 1 + k >=
618                                   inlength ?  inlength - 1 :
619                                   int_pel - INTERP_TAPS / 2 + 1 + k)];
620       *optr++ = clip_pixel_highbd(ROUND_POWER_OF_TWO(sum, FILTER_BITS), bd);
621     }
622   }
623 }
624
625 static void highbd_down2_symeven(const uint16_t *const input, int length,
626                                  uint16_t *output, int bd) {
627   // Actual filter len = 2 * filter_len_half.
628   static const int16_t *filter = vp9_down2_symeven_half_filter;
629   const int filter_len_half = sizeof(vp9_down2_symeven_half_filter) / 2;
630   int i, j;
631   uint16_t *optr = output;
632   int l1 = filter_len_half;
633   int l2 = (length - filter_len_half);
634   l1 += (l1 & 1);
635   l2 += (l2 & 1);
636   if (l1 > l2) {
637     // Short input length.
638     for (i = 0; i < length; i += 2) {
639       int sum = (1 << (FILTER_BITS - 1));
640       for (j = 0; j < filter_len_half; ++j) {
641         sum += (input[(i - j < 0 ? 0 : i - j)] +
642                 input[(i + 1 + j >= length ? length - 1 : i + 1 + j)]) *
643             filter[j];
644       }
645       sum >>= FILTER_BITS;
646       *optr++ = clip_pixel_highbd(sum, bd);
647     }
648   } else {
649     // Initial part.
650     for (i = 0; i < l1; i += 2) {
651       int sum = (1 << (FILTER_BITS - 1));
652       for (j = 0; j < filter_len_half; ++j) {
653         sum += (input[(i - j < 0 ? 0 : i - j)] + input[i + 1 + j]) * filter[j];
654       }
655       sum >>= FILTER_BITS;
656       *optr++ = clip_pixel_highbd(sum, bd);
657     }
658     // Middle part.
659     for (; i < l2; i += 2) {
660       int sum = (1 << (FILTER_BITS - 1));
661       for (j = 0; j < filter_len_half; ++j) {
662         sum += (input[i - j] + input[i + 1 + j]) * filter[j];
663       }
664       sum >>= FILTER_BITS;
665       *optr++ = clip_pixel_highbd(sum, bd);
666     }
667     // End part.
668     for (; i < length; i += 2) {
669       int sum = (1 << (FILTER_BITS - 1));
670       for (j = 0; j < filter_len_half; ++j) {
671         sum += (input[i - j] +
672                 input[(i + 1 + j >= length ? length - 1 : i + 1 + j)]) *
673             filter[j];
674       }
675       sum >>= FILTER_BITS;
676       *optr++ = clip_pixel_highbd(sum, bd);
677     }
678   }
679 }
680
681 static void highbd_down2_symodd(const uint16_t *const input, int length,
682                               uint16_t *output, int bd) {
683   // Actual filter len = 2 * filter_len_half - 1.
684   static const int16_t *filter = vp9_down2_symodd_half_filter;
685   const int filter_len_half = sizeof(vp9_down2_symodd_half_filter) / 2;
686   int i, j;
687   uint16_t *optr = output;
688   int l1 = filter_len_half - 1;
689   int l2 = (length - filter_len_half + 1);
690   l1 += (l1 & 1);
691   l2 += (l2 & 1);
692   if (l1 > l2) {
693     // Short input length.
694     for (i = 0; i < length; i += 2) {
695       int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
696       for (j = 1; j < filter_len_half; ++j) {
697         sum += (input[(i - j < 0 ? 0 : i - j)] +
698                 input[(i + j >= length ? length - 1 : i + j)]) *
699             filter[j];
700       }
701       sum >>= FILTER_BITS;
702       *optr++ = clip_pixel_highbd(sum, bd);
703     }
704   } else {
705     // Initial part.
706     for (i = 0; i < l1; i += 2) {
707       int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
708       for (j = 1; j < filter_len_half; ++j) {
709         sum += (input[(i - j < 0 ? 0 : i - j)] + input[i + j]) * filter[j];
710       }
711       sum >>= FILTER_BITS;
712       *optr++ = clip_pixel_highbd(sum, bd);
713     }
714     // Middle part.
715     for (; i < l2; i += 2) {
716       int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
717       for (j = 1; j < filter_len_half; ++j) {
718         sum += (input[i - j] + input[i + j]) * filter[j];
719       }
720       sum >>= FILTER_BITS;
721       *optr++ = clip_pixel_highbd(sum, bd);
722     }
723     // End part.
724     for (; i < length; i += 2) {
725       int sum = (1 << (FILTER_BITS - 1)) + input[i] * filter[0];
726       for (j = 1; j < filter_len_half; ++j) {
727         sum += (input[i - j] + input[(i + j >= length ? length - 1 : i + j)]) *
728             filter[j];
729       }
730       sum >>= FILTER_BITS;
731       *optr++ = clip_pixel_highbd(sum, bd);
732     }
733   }
734 }
735
736 static void highbd_resize_multistep(const uint16_t *const input,
737                                     int length,
738                                     uint16_t *output,
739                                     int olength,
740                                     uint16_t *buf,
741                                     int bd) {
742   int steps;
743   if (length == olength) {
744     memcpy(output, input, sizeof(uint16_t) * length);
745     return;
746   }
747   steps = get_down2_steps(length, olength);
748
749   if (steps > 0) {
750     int s;
751     uint16_t *out = NULL;
752     uint16_t *tmpbuf = NULL;
753     uint16_t *otmp, *otmp2;
754     int filteredlength = length;
755     if (!tmpbuf) {
756       tmpbuf = (uint16_t *)malloc(sizeof(uint16_t) * length);
757       otmp = tmpbuf;
758     } else {
759       otmp = buf;
760     }
761     otmp2 = otmp + get_down2_length(length, 1);
762     for (s = 0; s < steps; ++s) {
763       const int proj_filteredlength = get_down2_length(filteredlength, 1);
764       const uint16_t *const in = (s == 0 ? input : out);
765       if (s == steps - 1 && proj_filteredlength == olength)
766         out = output;
767       else
768         out = (s & 1 ? otmp2 : otmp);
769       if (filteredlength & 1)
770         highbd_down2_symodd(in, filteredlength, out, bd);
771       else
772         highbd_down2_symeven(in, filteredlength, out, bd);
773       filteredlength = proj_filteredlength;
774     }
775     if (filteredlength != olength) {
776       highbd_interpolate(out, filteredlength, output, olength, bd);
777     }
778     if (tmpbuf)
779       free(tmpbuf);
780   } else {
781     highbd_interpolate(input, length, output, olength, bd);
782   }
783 }
784
785 static void highbd_fill_col_to_arr(uint16_t *img, int stride, int len,
786                                    uint16_t *arr) {
787   int i;
788   uint16_t *iptr = img;
789   uint16_t *aptr = arr;
790   for (i = 0; i < len; ++i, iptr += stride) {
791     *aptr++ = *iptr;
792   }
793 }
794
795 static void highbd_fill_arr_to_col(uint16_t *img, int stride, int len,
796                                    uint16_t *arr) {
797   int i;
798   uint16_t *iptr = img;
799   uint16_t *aptr = arr;
800   for (i = 0; i < len; ++i, iptr += stride) {
801     *iptr = *aptr++;
802   }
803 }
804
805 void vp9_highbd_resize_plane(const uint8_t *const input,
806                              int height,
807                              int width,
808                              int in_stride,
809                              uint8_t *output,
810                              int height2,
811                              int width2,
812                              int out_stride,
813                              int bd) {
814   int i;
815   uint16_t *intbuf = (uint16_t *)malloc(sizeof(uint16_t) * width2 * height);
816   uint16_t *tmpbuf = (uint16_t *)malloc(sizeof(uint16_t) *
817                                         (width < height ? height : width));
818   uint16_t *arrbuf = (uint16_t *)malloc(sizeof(uint16_t) * (height + height2));
819   for (i = 0; i < height; ++i) {
820     highbd_resize_multistep(CONVERT_TO_SHORTPTR(input + in_stride * i), width,
821                             intbuf + width2 * i, width2, tmpbuf, bd);
822   }
823   for (i = 0; i < width2; ++i) {
824     highbd_fill_col_to_arr(intbuf + i, width2, height, arrbuf);
825     highbd_resize_multistep(arrbuf, height, arrbuf + height, height2, tmpbuf,
826                             bd);
827     highbd_fill_arr_to_col(CONVERT_TO_SHORTPTR(output + i), out_stride, height2,
828                            arrbuf + height);
829   }
830   free(intbuf);
831   free(tmpbuf);
832   free(arrbuf);
833 }
834 #endif  // CONFIG_VP9_HIGHBITDEPTH
835
836 void vp9_resize_frame420(const uint8_t *const y,
837                          int y_stride,
838                          const uint8_t *const u, const uint8_t *const v,
839                          int uv_stride,
840                          int height, int width,
841                          uint8_t *oy, int oy_stride,
842                          uint8_t *ou, uint8_t *ov, int ouv_stride,
843                          int oheight, int owidth) {
844   vp9_resize_plane(y, height, width, y_stride,
845                    oy, oheight, owidth, oy_stride);
846   vp9_resize_plane(u, height / 2, width / 2, uv_stride,
847                    ou, oheight / 2, owidth / 2, ouv_stride);
848   vp9_resize_plane(v, height / 2, width / 2, uv_stride,
849                    ov, oheight / 2, owidth / 2, ouv_stride);
850 }
851
852 void vp9_resize_frame422(const uint8_t *const y, int y_stride,
853                          const uint8_t *const u, const uint8_t *const v,
854                          int uv_stride,
855                          int height, int width,
856                          uint8_t *oy, int oy_stride,
857                          uint8_t *ou, uint8_t *ov, int ouv_stride,
858                          int oheight, int owidth) {
859   vp9_resize_plane(y, height, width, y_stride,
860                    oy, oheight, owidth, oy_stride);
861   vp9_resize_plane(u, height, width / 2, uv_stride,
862                    ou, oheight, owidth / 2, ouv_stride);
863   vp9_resize_plane(v, height, width / 2, uv_stride,
864                    ov, oheight, owidth / 2, ouv_stride);
865 }
866
867 void vp9_resize_frame444(const uint8_t *const y, int y_stride,
868                          const uint8_t *const u, const uint8_t *const v,
869                          int uv_stride,
870                          int height, int width,
871                          uint8_t *oy, int oy_stride,
872                          uint8_t *ou, uint8_t *ov, int ouv_stride,
873                          int oheight, int owidth) {
874   vp9_resize_plane(y, height, width, y_stride,
875                    oy, oheight, owidth, oy_stride);
876   vp9_resize_plane(u, height, width, uv_stride,
877                    ou, oheight, owidth, ouv_stride);
878   vp9_resize_plane(v, height, width, uv_stride,
879                    ov, oheight, owidth, ouv_stride);
880 }
881
882 #if CONFIG_VP9_HIGHBITDEPTH
883 void vp9_highbd_resize_frame420(const uint8_t *const y,
884                                 int y_stride,
885                                 const uint8_t *const u, const uint8_t *const v,
886                                 int uv_stride,
887                                 int height, int width,
888                                 uint8_t *oy, int oy_stride,
889                                 uint8_t *ou, uint8_t *ov, int ouv_stride,
890                                 int oheight, int owidth, int bd) {
891   vp9_highbd_resize_plane(y, height, width, y_stride,
892                           oy, oheight, owidth, oy_stride, bd);
893   vp9_highbd_resize_plane(u, height / 2, width / 2, uv_stride,
894                           ou, oheight / 2, owidth / 2, ouv_stride, bd);
895   vp9_highbd_resize_plane(v, height / 2, width / 2, uv_stride,
896                           ov, oheight / 2, owidth / 2, ouv_stride, bd);
897 }
898
899 void vp9_highbd_resize_frame422(const uint8_t *const y, int y_stride,
900                                 const uint8_t *const u, const uint8_t *const v,
901                                 int uv_stride,
902                                 int height, int width,
903                                 uint8_t *oy, int oy_stride,
904                                 uint8_t *ou, uint8_t *ov, int ouv_stride,
905                                 int oheight, int owidth, int bd) {
906   vp9_highbd_resize_plane(y, height, width, y_stride,
907                           oy, oheight, owidth, oy_stride, bd);
908   vp9_highbd_resize_plane(u, height, width / 2, uv_stride,
909                           ou, oheight, owidth / 2, ouv_stride, bd);
910   vp9_highbd_resize_plane(v, height, width / 2, uv_stride,
911                           ov, oheight, owidth / 2, ouv_stride, bd);
912 }
913
914 void vp9_highbd_resize_frame444(const uint8_t *const y, int y_stride,
915                                 const uint8_t *const u, const uint8_t *const v,
916                                 int uv_stride,
917                                 int height, int width,
918                                 uint8_t *oy, int oy_stride,
919                                 uint8_t *ou, uint8_t *ov, int ouv_stride,
920                                 int oheight, int owidth, int bd) {
921   vp9_highbd_resize_plane(y, height, width, y_stride,
922                           oy, oheight, owidth, oy_stride, bd);
923   vp9_highbd_resize_plane(u, height, width, uv_stride,
924                           ou, oheight, owidth, ouv_stride, bd);
925   vp9_highbd_resize_plane(v, height, width, uv_stride,
926                           ov, oheight, owidth, ouv_stride, bd);
927 }
928 #endif  // CONFIG_VP9_HIGHBITDEPTH