warped_motion.c 26.7 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
 *  Copyright (c) 2015 The WebM project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be
 *  found  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <math.h>
#include <assert.h>

17
#include "av1/common/warped_motion.h"
18

19
static ProjectPointsType get_project_points_type(TransformationType type) {
20
  switch (type) {
clang-format's avatar
clang-format committed
21
22
23
24
25
    case HOMOGRAPHY: return projectPointsHomography;
    case AFFINE: return projectPointsAffine;
    case ROTZOOM: return projectPointsRotZoom;
    case TRANSLATION: return projectPointsTranslation;
    default: assert(0); return NULL;
26
27
28
  }
}

29
void projectPointsTranslation(int16_t *mat, int *points, int *proj, const int n,
30
31
32
                              const int stride_points, const int stride_proj,
                              const int subsampling_x,
                              const int subsampling_y) {
33
34
35
36
  int i;
  for (i = 0; i < n; ++i) {
    const int x = *(points++), y = *(points++);
    if (subsampling_x)
37
      *(proj++) = ROUND_POWER_OF_TWO_SIGNED(
38
          ((x << (WARPEDMODEL_PREC_BITS + 1)) + mat[1]),
39
          WARPEDDIFF_PREC_BITS + 1);
40
    else
41
      *(proj++) = ROUND_POWER_OF_TWO_SIGNED(
42
          ((x << WARPEDMODEL_PREC_BITS) + mat[1]), WARPEDDIFF_PREC_BITS);
43
    if (subsampling_y)
44
      *(proj++) = ROUND_POWER_OF_TWO_SIGNED(
45
          ((y << (WARPEDMODEL_PREC_BITS + 1)) + mat[0]),
46
          WARPEDDIFF_PREC_BITS + 1);
47
    else
48
      *(proj++) = ROUND_POWER_OF_TWO_SIGNED(
49
          ((y << WARPEDMODEL_PREC_BITS)) + mat[0], WARPEDDIFF_PREC_BITS);
50
51
52
53
54
    points += stride_points - 2;
    proj += stride_proj - 2;
  }
}

55
void projectPointsRotZoom(int16_t *mat, int *points, int *proj, const int n,
clang-format's avatar
clang-format committed
56
57
                          const int stride_points, const int stride_proj,
                          const int subsampling_x, const int subsampling_y) {
58
59
60
61
  int i;
  for (i = 0; i < n; ++i) {
    const int x = *(points++), y = *(points++);
    if (subsampling_x)
62
      *(proj++) = ROUND_POWER_OF_TWO_SIGNED(
63
64
          mat[3] * 2 * x + mat[2] * 2 * y + mat[1] +
              (mat[3] + mat[2] - (1 << WARPEDMODEL_PREC_BITS)) / 2,
65
66
          WARPEDDIFF_PREC_BITS + 1);
    else
67
      *(proj++) = ROUND_POWER_OF_TWO_SIGNED(mat[3] * x + mat[2] * y + mat[1],
68
                                            WARPEDDIFF_PREC_BITS);
69
    if (subsampling_y)
70
      *(proj++) = ROUND_POWER_OF_TWO_SIGNED(
71
72
          -mat[2] * 2 * x + mat[3] * 2 * y + mat[0] +
              (-mat[2] + mat[3] - (1 << WARPEDMODEL_PREC_BITS)) / 2,
73
74
          WARPEDDIFF_PREC_BITS + 1);
    else
75
      *(proj++) = ROUND_POWER_OF_TWO_SIGNED(-mat[2] * x + mat[3] * y + mat[0],
76
                                            WARPEDDIFF_PREC_BITS);
77
78
79
80
81
    points += stride_points - 2;
    proj += stride_proj - 2;
  }
}

82
void projectPointsAffine(int16_t *mat, int *points, int *proj, const int n,
83
84
                         const int stride_points, const int stride_proj,
                         const int subsampling_x, const int subsampling_y) {
85
86
87
88
  int i;
  for (i = 0; i < n; ++i) {
    const int x = *(points++), y = *(points++);
    if (subsampling_x)
89
      *(proj++) = ROUND_POWER_OF_TWO_SIGNED(
90
91
          mat[3] * 2 * x + mat[2] * 2 * y + mat[1] +
              (mat[3] + mat[2] - (1 << WARPEDMODEL_PREC_BITS)) / 2,
92
93
          WARPEDDIFF_PREC_BITS + 1);
    else
94
      *(proj++) = ROUND_POWER_OF_TWO_SIGNED(mat[3] * x + mat[2] * y + mat[1],
95
                                            WARPEDDIFF_PREC_BITS);
96
    if (subsampling_y)
97
      *(proj++) = ROUND_POWER_OF_TWO_SIGNED(
Sarah Parker's avatar
Sarah Parker committed
98
99
          mat[4] * 2 * x + mat[5] * 2 * y + mat[0] +
              (mat[4] + mat[5] - (1 << WARPEDMODEL_PREC_BITS)) / 2,
100
101
          WARPEDDIFF_PREC_BITS + 1);
    else
Sarah Parker's avatar
Sarah Parker committed
102
      *(proj++) = ROUND_POWER_OF_TWO_SIGNED(mat[4] * x + mat[5] * y + mat[0],
103
                                            WARPEDDIFF_PREC_BITS);
104
105
106
107
108
    points += stride_points - 2;
    proj += stride_proj - 2;
  }
}

109
void projectPointsHomography(int16_t *mat, int *points, int *proj, const int n,
110
111
                             const int stride_points, const int stride_proj,
                             const int subsampling_x, const int subsampling_y) {
112
  int i;
113
114
  int64_t x, y, Z;
  int64_t xp, yp;
115
116
117
118
119
  for (i = 0; i < n; ++i) {
    x = *(points++), y = *(points++);
    x = (subsampling_x ? 4 * x + 1 : 2 * x);
    y = (subsampling_y ? 4 * y + 1 : 2 * y);

120
121
    Z = (mat[7] * x + mat[6] * y + (1 << (WARPEDMODEL_ROW3HOMO_PREC_BITS + 1)));
    xp = (mat[1] * x + mat[0] * y + 2 * mat[3])
clang-format's avatar
clang-format committed
122
123
         << (WARPEDPIXEL_PREC_BITS + WARPEDMODEL_ROW3HOMO_PREC_BITS -
             WARPEDMODEL_PREC_BITS);
124
    yp = (mat[2] * x + mat[5] * y + 2 * mat[4])
clang-format's avatar
clang-format committed
125
126
         << (WARPEDPIXEL_PREC_BITS + WARPEDMODEL_ROW3HOMO_PREC_BITS -
             WARPEDMODEL_PREC_BITS);
127
128
129
130

    xp = xp > 0 ? (xp + Z / 2) / Z : (xp - Z / 2) / Z;
    yp = yp > 0 ? (yp + Z / 2) / Z : (yp - Z / 2) / Z;

clang-format's avatar
clang-format committed
131
132
    if (subsampling_x) xp = (xp - (1 << (WARPEDPIXEL_PREC_BITS - 1))) / 2;
    if (subsampling_y) yp = (yp - (1 << (WARPEDPIXEL_PREC_BITS - 1))) / 2;
133
134
135
136
137
138
139
140
    *(proj++) = xp;
    *(proj++) = yp;

    points += stride_points - 2;
    proj += stride_proj - 2;
  }
}

clang-format's avatar
clang-format committed
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
static const int16_t filter_4tap[WARPEDPIXEL_PREC_SHIFTS][4] = {
  { 0, 128, 0, 0 },     { -1, 127, 2, 0 },    { -2, 127, 4, -1 },
  { -3, 126, 6, -1 },   { -3, 125, 8, -2 },   { -4, 124, 11, -3 },
  { -5, 123, 13, -3 },  { -5, 121, 15, -3 },  { -6, 120, 18, -4 },
  { -7, 119, 20, -4 },  { -7, 118, 22, -5 },  { -8, 116, 25, -5 },
  { -8, 115, 27, -6 },  { -9, 113, 30, -6 },  { -9, 112, 32, -7 },
  { -9, 110, 34, -7 },  { -10, 108, 37, -7 }, { -10, 107, 39, -8 },
  { -10, 105, 41, -8 }, { -11, 103, 44, -8 }, { -11, 101, 47, -9 },
  { -11, 99, 49, -9 },  { -11, 97, 51, -9 },  { -11, 95, 54, -10 },
  { -11, 93, 56, -10 }, { -12, 91, 59, -10 }, { -12, 89, 61, -10 },
  { -12, 87, 64, -11 }, { -12, 85, 66, -11 }, { -12, 82, 69, -11 },
  { -12, 80, 71, -11 }, { -12, 78, 73, -11 }, { -11, 75, 75, -11 },
  { -11, 73, 78, -12 }, { -11, 71, 80, -12 }, { -11, 69, 82, -12 },
  { -11, 66, 85, -12 }, { -11, 64, 87, -12 }, { -10, 61, 89, -12 },
  { -10, 59, 91, -12 }, { -10, 56, 93, -11 }, { -10, 54, 95, -11 },
  { -9, 51, 97, -11 },  { -9, 49, 99, -11 },  { -9, 47, 101, -11 },
  { -8, 44, 103, -11 }, { -8, 41, 105, -10 }, { -8, 39, 107, -10 },
  { -7, 37, 108, -10 }, { -7, 34, 110, -9 },  { -7, 32, 112, -9 },
  { -6, 30, 113, -9 },  { -6, 27, 115, -8 },  { -5, 25, 116, -8 },
  { -5, 22, 118, -7 },  { -4, 20, 119, -7 },  { -4, 18, 120, -6 },
  { -3, 15, 121, -5 },  { -3, 13, 123, -5 },  { -3, 11, 124, -4 },
  { -2, 8, 125, -3 },   { -1, 6, 126, -3 },   { -1, 4, 127, -2 },
  { 0, 2, 127, -1 },
164
165
166
};

static const int16_t
clang-format's avatar
clang-format committed
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
    filter_ntap[WARPEDPIXEL_PREC_SHIFTS][WARPEDPIXEL_FILTER_TAPS] = {
      { 0, 0, 128, 0, 0, 0 },      { 0, -1, 128, 2, -1, 0 },
      { 1, -3, 127, 4, -1, 0 },    { 1, -4, 126, 6, -2, 1 },
      { 1, -5, 126, 8, -3, 1 },    { 1, -6, 125, 11, -4, 1 },
      { 1, -7, 124, 13, -4, 1 },   { 2, -8, 123, 15, -5, 1 },
      { 2, -9, 122, 18, -6, 1 },   { 2, -10, 121, 20, -6, 1 },
      { 2, -11, 120, 22, -7, 2 },  { 2, -12, 119, 25, -8, 2 },
      { 3, -13, 117, 27, -8, 2 },  { 3, -13, 116, 29, -9, 2 },
      { 3, -14, 114, 32, -10, 3 }, { 3, -15, 113, 35, -10, 2 },
      { 3, -15, 111, 37, -11, 3 }, { 3, -16, 109, 40, -11, 3 },
      { 3, -16, 108, 42, -12, 3 }, { 4, -17, 106, 45, -13, 3 },
      { 4, -17, 104, 47, -13, 3 }, { 4, -17, 102, 50, -14, 3 },
      { 4, -17, 100, 52, -14, 3 }, { 4, -18, 98, 55, -15, 4 },
      { 4, -18, 96, 58, -15, 3 },  { 4, -18, 94, 60, -16, 4 },
      { 4, -18, 91, 63, -16, 4 },  { 4, -18, 89, 65, -16, 4 },
      { 4, -18, 87, 68, -17, 4 },  { 4, -18, 85, 70, -17, 4 },
      { 4, -18, 82, 73, -17, 4 },  { 4, -18, 80, 75, -17, 4 },
      { 4, -18, 78, 78, -18, 4 },  { 4, -17, 75, 80, -18, 4 },
      { 4, -17, 73, 82, -18, 4 },  { 4, -17, 70, 85, -18, 4 },
      { 4, -17, 68, 87, -18, 4 },  { 4, -16, 65, 89, -18, 4 },
      { 4, -16, 63, 91, -18, 4 },  { 4, -16, 60, 94, -18, 4 },
      { 3, -15, 58, 96, -18, 4 },  { 4, -15, 55, 98, -18, 4 },
      { 3, -14, 52, 100, -17, 4 }, { 3, -14, 50, 102, -17, 4 },
      { 3, -13, 47, 104, -17, 4 }, { 3, -13, 45, 106, -17, 4 },
      { 3, -12, 42, 108, -16, 3 }, { 3, -11, 40, 109, -16, 3 },
      { 3, -11, 37, 111, -15, 3 }, { 2, -10, 35, 113, -15, 3 },
      { 3, -10, 32, 114, -14, 3 }, { 2, -9, 29, 116, -13, 3 },
      { 2, -8, 27, 117, -13, 3 },  { 2, -8, 25, 119, -12, 2 },
      { 2, -7, 22, 120, -11, 2 },  { 1, -6, 20, 121, -10, 2 },
      { 1, -6, 18, 122, -9, 2 },   { 1, -5, 15, 123, -8, 2 },
      { 1, -4, 13, 124, -7, 1 },   { 1, -4, 11, 125, -6, 1 },
      { 1, -3, 8, 126, -5, 1 },    { 1, -2, 6, 126, -4, 1 },
      { 0, -1, 4, 127, -3, 1 },    { 0, -1, 2, 128, -1, 0 },
    };
201
202
203
204
205
206
207
208
209
210
211

static int32_t do_ntap_filter(int32_t *p, int x) {
  int i;
  int32_t sum = 0;
  for (i = 0; i < WARPEDPIXEL_FILTER_TAPS; ++i) {
    sum += p[i - WARPEDPIXEL_FILTER_TAPS / 2 + 1] * filter_ntap[x][i];
  }
  return sum;
}

static int32_t do_cubic_filter(int32_t *p, int x) {
clang-format's avatar
clang-format committed
212
  if (x == 0) {
213
214
215
216
217
218
219
220
    return p[0];
  } else if (x == (1 << WARPEDPIXEL_PREC_BITS)) {
    return p[1];
  } else {
    const int64_t v1 = x * x * x * (3 * (p[0] - p[1]) + p[2] - p[-1]);
    const int64_t v2 = x * x * (2 * p[-1] - 5 * p[0] + 4 * p[1] - p[2]);
    const int64_t v3 = x * (p[1] - p[-1]);
    const int64_t v4 = 2 * p[0];
221
    return (int32_t)ROUND_POWER_OF_TWO_SIGNED(
222
        (v4 << (3 * WARPEDPIXEL_PREC_BITS)) +
clang-format's avatar
clang-format committed
223
224
            (v3 << (2 * WARPEDPIXEL_PREC_BITS)) +
            (v2 << WARPEDPIXEL_PREC_BITS) + v1,
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
        3 * WARPEDPIXEL_PREC_BITS + 1 - WARPEDPIXEL_FILTER_BITS);
  }
}

/*
static int32_t do_linear_filter(int32_t *p, int x) {
  int32_t sum = 0;
  sum = p[0] * (WARPEDPIXEL_PREC_SHIFTS - x) + p[1] * x;
  sum <<= (WARPEDPIXEL_FILTER_BITS - WARPEDPIXEL_PREC_BITS);
  return sum;
}

static int32_t do_4tap_filter(int32_t *p, int x) {
  int i;
  int32_t sum = 0;
  for (i = 0; i < 4; ++i) {
    sum += p[i - 1] * filter_4tap[x][i];
  }
  return sum;
}
*/

static INLINE void get_subcolumn(int taps, uint8_t *ref, int32_t *col,
                                 int stride, int x, int y_start) {
  int i;
  for (i = 0; i < taps; ++i) {
    col[i] = ref[(i + y_start) * stride + x];
  }
}

static uint8_t bi_ntap_filter(uint8_t *ref, int x, int y, int stride) {
  int32_t val, arr[WARPEDPIXEL_FILTER_TAPS];
  int k;
clang-format's avatar
clang-format committed
258
259
  int i = (int)x >> WARPEDPIXEL_PREC_BITS;
  int j = (int)y >> WARPEDPIXEL_PREC_BITS;
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
  for (k = 0; k < WARPEDPIXEL_FILTER_TAPS; ++k) {
    int32_t arr_temp[WARPEDPIXEL_FILTER_TAPS];
    get_subcolumn(WARPEDPIXEL_FILTER_TAPS, ref, arr_temp, stride,
                  i + k + 1 - WARPEDPIXEL_FILTER_TAPS / 2,
                  j + 1 - WARPEDPIXEL_FILTER_TAPS / 2);
    arr[k] = do_ntap_filter(arr_temp + WARPEDPIXEL_FILTER_TAPS / 2 - 1,
                            y - (j << WARPEDPIXEL_PREC_BITS));
  }
  val = do_ntap_filter(arr + WARPEDPIXEL_FILTER_TAPS / 2 - 1,
                       x - (i << WARPEDPIXEL_PREC_BITS));
  val = ROUND_POWER_OF_TWO_SIGNED(val, WARPEDPIXEL_FILTER_BITS * 2);
  return (uint8_t)clip_pixel(val);
}

static uint8_t bi_cubic_filter(uint8_t *ref, int x, int y, int stride) {
  int32_t val, arr[4];
  int k;
clang-format's avatar
clang-format committed
277
278
  int i = (int)x >> WARPEDPIXEL_PREC_BITS;
  int j = (int)y >> WARPEDPIXEL_PREC_BITS;
279
280
  for (k = 0; k < 4; ++k) {
    int32_t arr_temp[4];
clang-format's avatar
clang-format committed
281
    get_subcolumn(4, ref, arr_temp, stride, i + k - 1, j - 1);
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
    arr[k] = do_cubic_filter(arr_temp + 1, y - (j << WARPEDPIXEL_PREC_BITS));
  }
  val = do_cubic_filter(arr + 1, x - (i << WARPEDPIXEL_PREC_BITS));
  val = ROUND_POWER_OF_TWO_SIGNED(val, WARPEDPIXEL_FILTER_BITS * 2);
  return (uint8_t)clip_pixel(val);
}

static uint8_t bi_linear_filter(uint8_t *ref, int x, int y, int stride) {
  const int ix = x >> WARPEDPIXEL_PREC_BITS;
  const int iy = y >> WARPEDPIXEL_PREC_BITS;
  const int sx = x - (ix << WARPEDPIXEL_PREC_BITS);
  const int sy = y - (iy << WARPEDPIXEL_PREC_BITS);
  int32_t val;
  val = ROUND_POWER_OF_TWO_SIGNED(
      ref[iy * stride + ix] * (WARPEDPIXEL_PREC_SHIFTS - sy) *
clang-format's avatar
clang-format committed
297
298
299
300
              (WARPEDPIXEL_PREC_SHIFTS - sx) +
          ref[iy * stride + ix + 1] * (WARPEDPIXEL_PREC_SHIFTS - sy) * sx +
          ref[(iy + 1) * stride + ix] * sy * (WARPEDPIXEL_PREC_SHIFTS - sx) +
          ref[(iy + 1) * stride + ix + 1] * sy * sx,
301
302
303
304
      WARPEDPIXEL_PREC_BITS * 2);
  return (uint8_t)clip_pixel(val);
}

clang-format's avatar
clang-format committed
305
306
static uint8_t warp_interpolate(uint8_t *ref, int x, int y, int width,
                                int height, int stride) {
307
308
309
310
311
312
  int ix = x >> WARPEDPIXEL_PREC_BITS;
  int iy = y >> WARPEDPIXEL_PREC_BITS;
  int sx = x - (ix << WARPEDPIXEL_PREC_BITS);
  int sy = y - (iy << WARPEDPIXEL_PREC_BITS);
  int32_t v;

clang-format's avatar
clang-format committed
313
314
  if (ix < 0 && iy < 0)
    return ref[0];
315
316
317
318
319
320
321
322
323
  else if (ix < 0 && iy > height - 1)
    return ref[(height - 1) * stride];
  else if (ix > width - 1 && iy < 0)
    return ref[width - 1];
  else if (ix > width - 1 && iy > height - 1)
    return ref[(height - 1) * stride + (width - 1)];
  else if (ix < 0) {
    v = ROUND_POWER_OF_TWO_SIGNED(
        ref[iy * stride] * (WARPEDPIXEL_PREC_SHIFTS - sy) +
clang-format's avatar
clang-format committed
324
            ref[(iy + 1) * stride] * sy,
325
326
327
328
        WARPEDPIXEL_PREC_BITS);
    return clip_pixel(v);
  } else if (iy < 0) {
    v = ROUND_POWER_OF_TWO_SIGNED(
clang-format's avatar
clang-format committed
329
        ref[ix] * (WARPEDPIXEL_PREC_SHIFTS - sx) + ref[ix + 1] * sx,
330
331
332
333
334
        WARPEDPIXEL_PREC_BITS);
    return clip_pixel(v);
  } else if (ix > width - 1) {
    v = ROUND_POWER_OF_TWO_SIGNED(
        ref[iy * stride + width - 1] * (WARPEDPIXEL_PREC_SHIFTS - sy) +
clang-format's avatar
clang-format committed
335
            ref[(iy + 1) * stride + width - 1] * sy,
336
337
338
339
340
        WARPEDPIXEL_PREC_BITS);
    return clip_pixel(v);
  } else if (iy > height - 1) {
    v = ROUND_POWER_OF_TWO_SIGNED(
        ref[(height - 1) * stride + ix] * (WARPEDPIXEL_PREC_SHIFTS - sx) +
clang-format's avatar
clang-format committed
341
            ref[(height - 1) * stride + ix + 1] * sx,
342
343
344
345
346
347
348
        WARPEDPIXEL_PREC_BITS);
    return clip_pixel(v);
  } else if (ix >= WARPEDPIXEL_FILTER_TAPS / 2 - 1 &&
             iy >= WARPEDPIXEL_FILTER_TAPS / 2 - 1 &&
             ix < width - WARPEDPIXEL_FILTER_TAPS / 2 &&
             iy < height - WARPEDPIXEL_FILTER_TAPS / 2) {
    return bi_ntap_filter(ref, x, y, stride);
clang-format's avatar
clang-format committed
349
  } else if (ix >= 1 && iy >= 1 && ix < width - 2 && iy < height - 2) {
350
351
352
353
354
355
    return bi_cubic_filter(ref, x, y, stride);
  } else {
    return bi_linear_filter(ref, x, y, stride);
  }
}

Yaowu Xu's avatar
Yaowu Xu committed
356
#if CONFIG_AOM_HIGHBITDEPTH
357
358
359
360
361
362
363
364
static INLINE void highbd_get_subcolumn(int taps, uint16_t *ref, int32_t *col,
                                        int stride, int x, int y_start) {
  int i;
  for (i = 0; i < taps; ++i) {
    col[i] = ref[(i + y_start) * stride + x];
  }
}

clang-format's avatar
clang-format committed
365
static uint16_t highbd_bi_ntap_filter(uint16_t *ref, int x, int y, int stride,
366
367
368
                                      int bd) {
  int32_t val, arr[WARPEDPIXEL_FILTER_TAPS];
  int k;
clang-format's avatar
clang-format committed
369
370
  int i = (int)x >> WARPEDPIXEL_PREC_BITS;
  int j = (int)y >> WARPEDPIXEL_PREC_BITS;
371
372
373
374
375
376
377
378
379
380
381
  for (k = 0; k < WARPEDPIXEL_FILTER_TAPS; ++k) {
    int32_t arr_temp[WARPEDPIXEL_FILTER_TAPS];
    highbd_get_subcolumn(WARPEDPIXEL_FILTER_TAPS, ref, arr_temp, stride,
                         i + k + 1 - WARPEDPIXEL_FILTER_TAPS / 2,
                         j + 1 - WARPEDPIXEL_FILTER_TAPS / 2);
    arr[k] = do_ntap_filter(arr_temp + WARPEDPIXEL_FILTER_TAPS / 2 - 1,
                            y - (j << WARPEDPIXEL_PREC_BITS));
  }
  val = do_ntap_filter(arr + WARPEDPIXEL_FILTER_TAPS / 2 - 1,
                       x - (i << WARPEDPIXEL_PREC_BITS));
  val = ROUND_POWER_OF_TWO_SIGNED(val, WARPEDPIXEL_FILTER_BITS * 2);
382
  return (uint16_t)clip_pixel_highbd(val, bd);
383
384
}

clang-format's avatar
clang-format committed
385
static uint16_t highbd_bi_cubic_filter(uint16_t *ref, int x, int y, int stride,
386
387
388
                                       int bd) {
  int32_t val, arr[4];
  int k;
clang-format's avatar
clang-format committed
389
390
  int i = (int)x >> WARPEDPIXEL_PREC_BITS;
  int j = (int)y >> WARPEDPIXEL_PREC_BITS;
391
392
  for (k = 0; k < 4; ++k) {
    int32_t arr_temp[4];
clang-format's avatar
clang-format committed
393
    highbd_get_subcolumn(4, ref, arr_temp, stride, i + k - 1, j - 1);
394
395
396
397
    arr[k] = do_cubic_filter(arr_temp + 1, y - (j << WARPEDPIXEL_PREC_BITS));
  }
  val = do_cubic_filter(arr + 1, x - (i << WARPEDPIXEL_PREC_BITS));
  val = ROUND_POWER_OF_TWO_SIGNED(val, WARPEDPIXEL_FILTER_BITS * 2);
398
  return (uint16_t)clip_pixel_highbd(val, bd);
399
400
}

clang-format's avatar
clang-format committed
401
static uint16_t highbd_bi_linear_filter(uint16_t *ref, int x, int y, int stride,
402
403
404
405
406
407
408
409
                                        int bd) {
  const int ix = x >> WARPEDPIXEL_PREC_BITS;
  const int iy = y >> WARPEDPIXEL_PREC_BITS;
  const int sx = x - (ix << WARPEDPIXEL_PREC_BITS);
  const int sy = y - (iy << WARPEDPIXEL_PREC_BITS);
  int32_t val;
  val = ROUND_POWER_OF_TWO_SIGNED(
      ref[iy * stride + ix] * (WARPEDPIXEL_PREC_SHIFTS - sy) *
clang-format's avatar
clang-format committed
410
411
412
413
              (WARPEDPIXEL_PREC_SHIFTS - sx) +
          ref[iy * stride + ix + 1] * (WARPEDPIXEL_PREC_SHIFTS - sy) * sx +
          ref[(iy + 1) * stride + ix] * sy * (WARPEDPIXEL_PREC_SHIFTS - sx) +
          ref[(iy + 1) * stride + ix + 1] * sy * sx,
414
      WARPEDPIXEL_PREC_BITS * 2);
415
  return (uint16_t)clip_pixel_highbd(val, bd);
416
417
}

clang-format's avatar
clang-format committed
418
419
static uint16_t highbd_warp_interpolate(uint16_t *ref, int x, int y, int width,
                                        int height, int stride, int bd) {
420
421
422
423
424
425
  int ix = x >> WARPEDPIXEL_PREC_BITS;
  int iy = y >> WARPEDPIXEL_PREC_BITS;
  int sx = x - (ix << WARPEDPIXEL_PREC_BITS);
  int sy = y - (iy << WARPEDPIXEL_PREC_BITS);
  int32_t v;

clang-format's avatar
clang-format committed
426
427
  if (ix < 0 && iy < 0)
    return ref[0];
428
429
430
431
432
433
434
435
436
  else if (ix < 0 && iy > height - 1)
    return ref[(height - 1) * stride];
  else if (ix > width - 1 && iy < 0)
    return ref[width - 1];
  else if (ix > width - 1 && iy > height - 1)
    return ref[(height - 1) * stride + (width - 1)];
  else if (ix < 0) {
    v = ROUND_POWER_OF_TWO_SIGNED(
        ref[iy * stride] * (WARPEDPIXEL_PREC_SHIFTS - sy) +
clang-format's avatar
clang-format committed
437
            ref[(iy + 1) * stride] * sy,
438
        WARPEDPIXEL_PREC_BITS);
439
    return clip_pixel_highbd(v, bd);
440
441
  } else if (iy < 0) {
    v = ROUND_POWER_OF_TWO_SIGNED(
clang-format's avatar
clang-format committed
442
        ref[ix] * (WARPEDPIXEL_PREC_SHIFTS - sx) + ref[ix + 1] * sx,
443
        WARPEDPIXEL_PREC_BITS);
444
    return clip_pixel_highbd(v, bd);
445
446
447
  } else if (ix > width - 1) {
    v = ROUND_POWER_OF_TWO_SIGNED(
        ref[iy * stride + width - 1] * (WARPEDPIXEL_PREC_SHIFTS - sy) +
clang-format's avatar
clang-format committed
448
            ref[(iy + 1) * stride + width - 1] * sy,
449
        WARPEDPIXEL_PREC_BITS);
450
    return clip_pixel_highbd(v, bd);
451
452
453
  } else if (iy > height - 1) {
    v = ROUND_POWER_OF_TWO_SIGNED(
        ref[(height - 1) * stride + ix] * (WARPEDPIXEL_PREC_SHIFTS - sx) +
clang-format's avatar
clang-format committed
454
            ref[(height - 1) * stride + ix + 1] * sx,
455
        WARPEDPIXEL_PREC_BITS);
456
    return clip_pixel_highbd(v, bd);
457
458
459
460
461
  } else if (ix >= WARPEDPIXEL_FILTER_TAPS / 2 - 1 &&
             iy >= WARPEDPIXEL_FILTER_TAPS / 2 - 1 &&
             ix < width - WARPEDPIXEL_FILTER_TAPS / 2 &&
             iy < height - WARPEDPIXEL_FILTER_TAPS / 2) {
    return highbd_bi_ntap_filter(ref, x, y, stride, bd);
clang-format's avatar
clang-format committed
462
  } else if (ix >= 1 && iy >= 1 && ix < width - 2 && iy < height - 2) {
463
464
465
466
467
468
    return highbd_bi_cubic_filter(ref, x, y, stride, bd);
  } else {
    return highbd_bi_linear_filter(ref, x, y, stride, bd);
  }
}

469
470
471
472
473
474
475
476
477
478
479
static double highbd_warp_erroradv(WarpedMotionParams *wm, uint8_t *ref8,
                                   int width, int height, int stride,
                                   uint8_t *dst8, int p_col, int p_row,
                                   int p_width, int p_height, int p_stride,
                                   int subsampling_x, int subsampling_y,
                                   int x_scale, int y_scale, int bd) {
  int i, j;
  ProjectPointsType projectpoints = get_project_points_type(wm->wmtype);
  uint16_t *dst = CONVERT_TO_SHORTPTR(dst8);
  uint16_t *ref = CONVERT_TO_SHORTPTR(ref8);
  int gm_err = 0, no_gm_err = 0;
480
  int64_t gm_sumerr = 0, no_gm_sumerr = 0;
481
482
483
484
485
  for (i = p_row; i < p_row + p_height; ++i) {
    for (j = p_col; j < p_col + p_width; ++j) {
      int in[2], out[2];
      in[0] = j;
      in[1] = i;
486
487
      projectpoints((int16_t *)wm->wmmat, in, out, 1, 2, 2, subsampling_x,
                    subsampling_y);
488
489
490
491
492
493
494
      out[0] = ROUND_POWER_OF_TWO_SIGNED(out[0] * x_scale, 4);
      out[1] = ROUND_POWER_OF_TWO_SIGNED(out[1] * y_scale, 4);
      gm_err = dst[(j - p_col) + (i - p_row) * p_stride] -
               highbd_warp_interpolate(ref, out[0], out[1], width, height,
                                       stride, bd);
      no_gm_err = dst[(j - p_col) + (i - p_row) * p_stride] -
                  ref[(j - p_col) + (i - p_row) * stride];
495
496
      gm_sumerr += (int64_t)gm_err * gm_err;
      no_gm_sumerr += (int64_t)no_gm_err * no_gm_err;
497
498
499
500
501
    }
  }
  return (double)gm_sumerr / no_gm_sumerr;
}

clang-format's avatar
clang-format committed
502
503
504
505
506
static void highbd_warp_plane(WarpedMotionParams *wm, uint8_t *ref8, int width,
                              int height, int stride, uint8_t *pred8, int p_col,
                              int p_row, int p_width, int p_height,
                              int p_stride, int subsampling_x,
                              int subsampling_y, int x_scale, int y_scale,
507
                              int bd) {
508
  int i, j;
509
  ProjectPointsType projectpoints = get_project_points_type(wm->wmtype);
510
511
  uint16_t *pred = CONVERT_TO_SHORTPTR(pred8);
  uint16_t *ref = CONVERT_TO_SHORTPTR(ref8);
512
  if (projectpoints == NULL) return;
513
514
515
  for (i = p_row; i < p_row + p_height; ++i) {
    for (j = p_col; j < p_col + p_width; ++j) {
      int in[2], out[2];
516
517
      in[0] = j;
      in[1] = i;
518
519
      projectpoints((int16_t *)wm->wmmat, in, out, 1, 2, 2, subsampling_x,
                    subsampling_y);
520
521
      out[0] = ROUND_POWER_OF_TWO_SIGNED(out[0] * x_scale, 4);
      out[1] = ROUND_POWER_OF_TWO_SIGNED(out[1] * y_scale, 4);
clang-format's avatar
clang-format committed
522
523
      pred[(j - p_col) + (i - p_row) * p_stride] = highbd_warp_interpolate(
          ref, out[0], out[1], width, height, stride, bd);
524
525
526
    }
  }
}
Yaowu Xu's avatar
Yaowu Xu committed
527
#endif  // CONFIG_AOM_HIGHBITDEPTH
528

529
530
531
532
533
534
535
536
537
538
539
540
541
542
static double warp_erroradv(WarpedMotionParams *wm, uint8_t *ref, int width,
                            int height, int stride, uint8_t *dst, int p_col,
                            int p_row, int p_width, int p_height, int p_stride,
                            int subsampling_x, int subsampling_y, int x_scale,
                            int y_scale) {
  int gm_err = 0, no_gm_err = 0;
  int gm_sumerr = 0, no_gm_sumerr = 0;
  int i, j;
  ProjectPointsType projectpoints = get_project_points_type(wm->wmtype);
  for (i = p_row; i < p_row + p_height; ++i) {
    for (j = p_col; j < p_col + p_width; ++j) {
      int in[2], out[2];
      in[0] = j;
      in[1] = i;
543
544
      projectpoints((int16_t *)wm->wmmat, in, out, 1, 2, 2, subsampling_x,
                    subsampling_y);
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
      out[0] = ROUND_POWER_OF_TWO_SIGNED(out[0] * x_scale, 4);
      out[1] = ROUND_POWER_OF_TWO_SIGNED(out[1] * y_scale, 4);
      gm_err = dst[(j - p_col) + (i - p_row) * p_stride] -
               warp_interpolate(ref, out[0], out[1], width, height, stride);
      no_gm_err = dst[(j - p_col) + (i - p_row) * p_stride] -
                  ref[(j - p_col) + (i - p_row) * stride];
      gm_sumerr += gm_err * gm_err;
      no_gm_sumerr += no_gm_err * no_gm_err;
    }
  }
  return (double)gm_sumerr / no_gm_sumerr;
}

static void warp_plane(WarpedMotionParams *wm, uint8_t *ref, int width,
                       int height, int stride, uint8_t *pred, int p_col,
                       int p_row, int p_width, int p_height, int p_stride,
                       int subsampling_x, int subsampling_y, int x_scale,
                       int y_scale) {
  int i, j;
  ProjectPointsType projectpoints = get_project_points_type(wm->wmtype);
  if (projectpoints == NULL) return;
  for (i = p_row; i < p_row + p_height; ++i) {
    for (j = p_col; j < p_col + p_width; ++j) {
      int in[2], out[2];
      in[0] = j;
      in[1] = i;
571
572
      projectpoints((int16_t *)wm->wmmat, in, out, 1, 2, 2, subsampling_x,
                    subsampling_y);
573
574
575
576
577
578
579
580
      out[0] = ROUND_POWER_OF_TWO_SIGNED(out[0] * x_scale, 4);
      out[1] = ROUND_POWER_OF_TWO_SIGNED(out[1] * y_scale, 4);
      pred[(j - p_col) + (i - p_row) * p_stride] =
          warp_interpolate(ref, out[0], out[1], width, height, stride);
    }
  }
}

Yaowu Xu's avatar
Yaowu Xu committed
581
582
583
584
585
586
587
588
589
double av1_warp_erroradv(WarpedMotionParams *wm,
#if CONFIG_AOM_HIGHBITDEPTH
                         int use_hbd, int bd,
#endif  // CONFIG_AOM_HIGHBITDEPTH
                         uint8_t *ref, int width, int height, int stride,
                         uint8_t *dst, int p_col, int p_row, int p_width,
                         int p_height, int p_stride, int subsampling_x,
                         int subsampling_y, int x_scale, int y_scale) {
#if CONFIG_AOM_HIGHBITDEPTH
590
591
592
593
594
  if (use_hbd)
    return highbd_warp_erroradv(
        wm, ref, width, height, stride, dst, p_col, p_row, p_width, p_height,
        p_stride, subsampling_x, subsampling_y, x_scale, y_scale, bd);
  else
Yaowu Xu's avatar
Yaowu Xu committed
595
#endif  // CONFIG_AOM_HIGHBITDEPTH
596
597
598
599
600
    return warp_erroradv(wm, ref, width, height, stride, dst, p_col, p_row,
                         p_width, p_height, p_stride, subsampling_x,
                         subsampling_y, x_scale, y_scale);
}

Yaowu Xu's avatar
Yaowu Xu committed
601
602
603
604
605
606
607
608
609
void av1_warp_plane(WarpedMotionParams *wm,
#if CONFIG_AOM_HIGHBITDEPTH
                    int use_hbd, int bd,
#endif  // CONFIG_AOM_HIGHBITDEPTH
                    uint8_t *ref, int width, int height, int stride,
                    uint8_t *pred, int p_col, int p_row, int p_width,
                    int p_height, int p_stride, int subsampling_x,
                    int subsampling_y, int x_scale, int y_scale) {
#if CONFIG_AOM_HIGHBITDEPTH
610
  if (use_hbd)
clang-format's avatar
clang-format committed
611
612
    highbd_warp_plane(wm, ref, width, height, stride, pred, p_col, p_row,
                      p_width, p_height, p_stride, subsampling_x, subsampling_y,
613
614
                      x_scale, y_scale, bd);
  else
Yaowu Xu's avatar
Yaowu Xu committed
615
#endif  // CONFIG_AOM_HIGHBITDEPTH
clang-format's avatar
clang-format committed
616
617
618
    warp_plane(wm, ref, width, height, stride, pred, p_col, p_row, p_width,
               p_height, p_stride, subsampling_x, subsampling_y, x_scale,
               y_scale);
619
}
620

Yaowu Xu's avatar
Yaowu Xu committed
621
622
void av1_integerize_model(const double *model, TransformationType wmtype,
                          WarpedMotionParams *wm) {
623
624
625
626
  wm->wmtype = wmtype;
  switch (wmtype) {
    case HOMOGRAPHY:
      assert(fabs(model[8] - 1.0) < 1e-12);
627
628
629
630
      wm->wmmat[3].as_mv.row =
          (int16_t)lrint(model[6] * (1 << WARPEDMODEL_ROW3HOMO_PREC_BITS));
      wm->wmmat[3].as_mv.col =
          (int16_t)lrint(model[7] * (1 << WARPEDMODEL_ROW3HOMO_PREC_BITS));
631
632
    /* fallthrough intended */
    case AFFINE:
633
634
635
636
      wm->wmmat[2].as_mv.row =
          (int16_t)lrint(model[4] * (1 << WARPEDMODEL_PREC_BITS));
      wm->wmmat[2].as_mv.col =
          (int16_t)lrint(model[5] * (1 << WARPEDMODEL_PREC_BITS));
637
638
    /* fallthrough intended */
    case ROTZOOM:
639
640
641
642
      wm->wmmat[1].as_mv.row =
          (int16_t)lrint(model[2] * (1 << WARPEDMODEL_PREC_BITS));
      wm->wmmat[1].as_mv.col =
          (int16_t)lrint(model[3] * (1 << WARPEDMODEL_PREC_BITS));
643
644
    /* fallthrough intended */
    case TRANSLATION:
645
646
647
648
      wm->wmmat[0].as_mv.row =
          (int16_t)lrint(model[0] * (1 << WARPEDMODEL_PREC_BITS));
      wm->wmmat[0].as_mv.col =
          (int16_t)lrint(model[1] * (1 << WARPEDMODEL_PREC_BITS));
649
650
651
652
      break;
    default: assert(0 && "Invalid TransformationType");
  }
}