blob: 73910de12159b248217797a551502c9a1f0a63dd [file] [log] [blame]
Yaowu Xuc27fc142016-08-22 16:08:15 -07001/*
Yaowu Xubde4ac82016-11-28 15:26:06 -08002 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
Yaowu Xuc27fc142016-08-22 16:08:15 -07003 *
Yaowu Xubde4ac82016-11-28 15:26:06 -08004 * This source code is subject to the terms of the BSD 2 Clause License and
5 * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
6 * was not distributed with this source code in the LICENSE file, you can
7 * obtain it at www.aomedia.org/license/software. If the Alliance for Open
8 * Media Patent License 1.0 was not distributed with this source code in the
9 * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
Yaowu Xuc27fc142016-08-22 16:08:15 -070010 */
11
12#include <stdio.h>
13#include <stdlib.h>
James Zern723bbf92022-04-28 12:54:06 -070014#include <stdbool.h>
Yaowu Xuc27fc142016-08-22 16:08:15 -070015#include <memory.h>
16#include <math.h>
17#include <assert.h>
18
Sarah Parker29267d32018-11-13 16:01:41 -080019#include "config/aom_dsp_rtcd.h"
20
emilkeyder@google.com30ba4b42017-02-22 21:07:55 -050021#include "av1/encoder/global_motion.h"
22
Sarah Parker0115e932018-10-22 14:14:22 -070023#include "av1/common/convolve.h"
Yaowu Xuc27fc142016-08-22 16:08:15 -070024#include "av1/common/warped_motion.h"
25
26#include "av1/encoder/segmentation.h"
Yaowu Xuc27fc142016-08-22 16:08:15 -070027
Sarah Parker68478602016-12-09 13:08:40 -080028#define MIN_TRANS_THRESH (1 * GM_TRANS_DECODE_FACTOR)
29
30// Border over which to compute the global motion
31#define ERRORADV_BORDER 0
32
Rachel Barkere59f4112023-06-19 22:43:28 +000033/* clang-format off */
Rachel Barker80477f42023-08-07 19:50:19 +000034// Error metric used for global motion evaluation.
35// For 8-bit input, the pixel error used to index this table will always
36// be between -255 and +255. But for 10- and 12-bit input, we use interpolation
37// which means that we need to support indices of -256 and +256 as well.
38// Therefore, the table is offset so that logical index 0 corresponds to
39// error_measure_lut[256].
40const int error_measure_lut[513] = {
Rachel Barkere59f4112023-06-19 22:43:28 +000041 // pow 0.7
Rachel Barker80477f42023-08-07 19:50:19 +000042 16384, 16384, 16339, 16294, 16249, 16204, 16158, 16113,
43 16068, 16022, 15977, 15932, 15886, 15840, 15795, 15749,
44 15703, 15657, 15612, 15566, 15520, 15474, 15427, 15381,
45 15335, 15289, 15242, 15196, 15149, 15103, 15056, 15010,
46 14963, 14916, 14869, 14822, 14775, 14728, 14681, 14634,
47 14587, 14539, 14492, 14445, 14397, 14350, 14302, 14254,
48 14206, 14159, 14111, 14063, 14015, 13967, 13918, 13870,
49 13822, 13773, 13725, 13676, 13628, 13579, 13530, 13481,
50 13432, 13383, 13334, 13285, 13236, 13187, 13137, 13088,
51 13038, 12988, 12939, 12889, 12839, 12789, 12739, 12689,
52 12639, 12588, 12538, 12487, 12437, 12386, 12335, 12285,
53 12234, 12183, 12132, 12080, 12029, 11978, 11926, 11875,
54 11823, 11771, 11719, 11667, 11615, 11563, 11511, 11458,
55 11406, 11353, 11301, 11248, 11195, 11142, 11089, 11036,
56 10982, 10929, 10875, 10822, 10768, 10714, 10660, 10606,
57 10552, 10497, 10443, 10388, 10333, 10279, 10224, 10168,
58 10113, 10058, 10002, 9947, 9891, 9835, 9779, 9723,
59 9666, 9610, 9553, 9497, 9440, 9383, 9326, 9268,
60 9211, 9153, 9095, 9037, 8979, 8921, 8862, 8804,
61 8745, 8686, 8627, 8568, 8508, 8449, 8389, 8329,
62 8269, 8208, 8148, 8087, 8026, 7965, 7903, 7842,
63 7780, 7718, 7656, 7593, 7531, 7468, 7405, 7341,
64 7278, 7214, 7150, 7086, 7021, 6956, 6891, 6826,
65 6760, 6695, 6628, 6562, 6495, 6428, 6361, 6293,
66 6225, 6157, 6089, 6020, 5950, 5881, 5811, 5741,
67 5670, 5599, 5527, 5456, 5383, 5311, 5237, 5164,
68 5090, 5015, 4941, 4865, 4789, 4713, 4636, 4558,
69 4480, 4401, 4322, 4242, 4162, 4080, 3998, 3916,
70 3832, 3748, 3663, 3577, 3490, 3402, 3314, 3224,
71 3133, 3041, 2948, 2854, 2758, 2661, 2562, 2461,
72 2359, 2255, 2148, 2040, 1929, 1815, 1698, 1577,
73 1452, 1323, 1187, 1045, 894, 731, 550, 339,
74 0, 339, 550, 731, 894, 1045, 1187, 1323,
75 1452, 1577, 1698, 1815, 1929, 2040, 2148, 2255,
76 2359, 2461, 2562, 2661, 2758, 2854, 2948, 3041,
77 3133, 3224, 3314, 3402, 3490, 3577, 3663, 3748,
78 3832, 3916, 3998, 4080, 4162, 4242, 4322, 4401,
79 4480, 4558, 4636, 4713, 4789, 4865, 4941, 5015,
80 5090, 5164, 5237, 5311, 5383, 5456, 5527, 5599,
81 5670, 5741, 5811, 5881, 5950, 6020, 6089, 6157,
82 6225, 6293, 6361, 6428, 6495, 6562, 6628, 6695,
83 6760, 6826, 6891, 6956, 7021, 7086, 7150, 7214,
84 7278, 7341, 7405, 7468, 7531, 7593, 7656, 7718,
85 7780, 7842, 7903, 7965, 8026, 8087, 8148, 8208,
86 8269, 8329, 8389, 8449, 8508, 8568, 8627, 8686,
87 8745, 8804, 8862, 8921, 8979, 9037, 9095, 9153,
88 9211, 9268, 9326, 9383, 9440, 9497, 9553, 9610,
89 9666, 9723, 9779, 9835, 9891, 9947, 10002, 10058,
90 10113, 10168, 10224, 10279, 10333, 10388, 10443, 10497,
91 10552, 10606, 10660, 10714, 10768, 10822, 10875, 10929,
92 10982, 11036, 11089, 11142, 11195, 11248, 11301, 11353,
93 11406, 11458, 11511, 11563, 11615, 11667, 11719, 11771,
94 11823, 11875, 11926, 11978, 12029, 12080, 12132, 12183,
95 12234, 12285, 12335, 12386, 12437, 12487, 12538, 12588,
96 12639, 12689, 12739, 12789, 12839, 12889, 12939, 12988,
97 13038, 13088, 13137, 13187, 13236, 13285, 13334, 13383,
98 13432, 13481, 13530, 13579, 13628, 13676, 13725, 13773,
99 13822, 13870, 13918, 13967, 14015, 14063, 14111, 14159,
100 14206, 14254, 14302, 14350, 14397, 14445, 14492, 14539,
101 14587, 14634, 14681, 14728, 14775, 14822, 14869, 14916,
102 14963, 15010, 15056, 15103, 15149, 15196, 15242, 15289,
103 15335, 15381, 15427, 15474, 15520, 15566, 15612, 15657,
104 15703, 15749, 15795, 15840, 15886, 15932, 15977, 16022,
105 16068, 16113, 16158, 16204, 16249, 16294, 16339, 16384,
106 16384,
Rachel Barkere59f4112023-06-19 22:43:28 +0000107};
108/* clang-format on */
109
chiyotsaia6545dd2020-07-06 14:20:50 -0700110int av1_is_enough_erroradvantage(double best_erroradvantage, int params_cost) {
111 return best_erroradvantage < erroradv_tr &&
112 best_erroradvantage * params_cost < erroradv_prod_tr;
Debargha Mukherjeee832d572017-04-07 14:40:43 -0700113}
emilkeyder@google.com30ba4b42017-02-22 21:07:55 -0500114
Alex Converse88b4e7d2017-04-20 12:33:28 -0700115static void convert_to_params(const double *params, int32_t *model) {
Sarah Parker68478602016-12-09 13:08:40 -0800116 int i;
Sarah Parker68478602016-12-09 13:08:40 -0800117 model[0] = (int32_t)floor(params[0] * (1 << GM_TRANS_PREC_BITS) + 0.5);
118 model[1] = (int32_t)floor(params[1] * (1 << GM_TRANS_PREC_BITS) + 0.5);
119 model[0] = (int32_t)clamp(model[0], GM_TRANS_MIN, GM_TRANS_MAX) *
120 GM_TRANS_DECODE_FACTOR;
121 model[1] = (int32_t)clamp(model[1], GM_TRANS_MIN, GM_TRANS_MAX) *
122 GM_TRANS_DECODE_FACTOR;
123
124 for (i = 2; i < 6; ++i) {
125 const int diag_value = ((i == 2 || i == 5) ? (1 << GM_ALPHA_PREC_BITS) : 0);
126 model[i] = (int32_t)floor(params[i] * (1 << GM_ALPHA_PREC_BITS) + 0.5);
127 model[i] =
128 (int32_t)clamp(model[i] - diag_value, GM_ALPHA_MIN, GM_ALPHA_MAX);
Sarah Parker68478602016-12-09 13:08:40 -0800129 model[i] = (model[i] + diag_value) * GM_ALPHA_DECODE_FACTOR;
130 }
Sarah Parker68478602016-12-09 13:08:40 -0800131}
132
sarahparkerc957b002018-11-02 16:15:22 -0700133void av1_convert_model_to_params(const double *params,
134 WarpedMotionParams *model) {
Sarah Parker68478602016-12-09 13:08:40 -0800135 convert_to_params(params, model->wmmat);
Venkatb18cdfc2018-12-17 12:36:17 +0530136 model->wmtype = get_wmtype(model);
Sebastien Alaiwan742f6462018-01-10 15:12:30 +0100137 model->invalid = 0;
Sarah Parker68478602016-12-09 13:08:40 -0800138}
139
140// Adds some offset to a global motion parameter and handles
141// all of the necessary precision shifts, clamping, and
142// zero-centering.
Alex Converse88b4e7d2017-04-20 12:33:28 -0700143static int32_t add_param_offset(int param_index, int32_t param_value,
144 int32_t offset) {
Rachel Barker0d9df422023-03-07 20:51:55 +0000145 const int scale_vals[2] = { GM_TRANS_PREC_DIFF, GM_ALPHA_PREC_DIFF };
146 const int clamp_vals[2] = { GM_TRANS_MAX, GM_ALPHA_MAX };
147 // type of param: 0 - translation, 1 - affine
148 const int param_type = (param_index < 2 ? 0 : 1);
Sarah Parker68478602016-12-09 13:08:40 -0800149 const int is_one_centered = (param_index == 2 || param_index == 5);
150
151 // Make parameter zero-centered and offset the shift that was done to make
152 // it compatible with the warped model
153 param_value = (param_value - (is_one_centered << WARPEDMODEL_PREC_BITS)) >>
154 scale_vals[param_type];
155 // Add desired offset to the rescaled/zero-centered parameter
156 param_value += offset;
157 // Clamp the parameter so it does not overflow the number of bits allotted
158 // to it in the bitstream
159 param_value = (int32_t)clamp(param_value, -clamp_vals[param_type],
160 clamp_vals[param_type]);
161 // Rescale the parameter to WARPEDMODEL_PRECISION_BITS so it is compatible
162 // with the warped motion library
163 param_value *= (1 << scale_vals[param_type]);
164
165 // Undo the zero-centering step if necessary
166 return param_value + (is_one_centered << WARPEDMODEL_PREC_BITS);
167}
168
Alex Converse88b4e7d2017-04-20 12:33:28 -0700169static void force_wmtype(WarpedMotionParams *wm, TransformationType wmtype) {
Sarah Parker68478602016-12-09 13:08:40 -0800170 switch (wmtype) {
Sebastien Alaiwan5c99f4e2017-11-02 14:31:33 +0100171 case IDENTITY:
172 wm->wmmat[0] = 0;
173 wm->wmmat[1] = 0;
174 AOM_FALLTHROUGH_INTENDED;
Sarah Parker68478602016-12-09 13:08:40 -0800175 case TRANSLATION:
176 wm->wmmat[2] = 1 << WARPEDMODEL_PREC_BITS;
177 wm->wmmat[3] = 0;
Sebastien Alaiwan5c99f4e2017-11-02 14:31:33 +0100178 AOM_FALLTHROUGH_INTENDED;
179 case ROTZOOM:
180 wm->wmmat[4] = -wm->wmmat[3];
181 wm->wmmat[5] = wm->wmmat[2];
182 AOM_FALLTHROUGH_INTENDED;
James Zern88879fa2021-12-02 12:25:37 -0800183 case AFFINE: break;
Sarah Parker68478602016-12-09 13:08:40 -0800184 default: assert(0);
185 }
186 wm->wmtype = wmtype;
187}
188
Jerome Jiang7683ed52019-09-17 15:10:25 -0700189#if CONFIG_AV1_HIGHBITDEPTH
Rachel Barker33b6de72023-11-03 04:09:59 +0000190static INLINE int generic_sad_highbd(const uint16_t *const ref, int ref_stride,
191 const uint16_t *const dst, int dst_stride,
192 int p_width, int p_height) {
193 // This function should only be called for patches smaller than
194 // WARP_ERROR_BLOCK x WARP_ERROR_BLOCK. This keeps the number of pixels
195 // small enough that we don't need a 64-bit accumulator
196 assert(p_width <= WARP_ERROR_BLOCK && p_height <= WARP_ERROR_BLOCK);
197
198 int sad = 0;
Rachel Barkere59f4112023-06-19 22:43:28 +0000199 for (int i = 0; i < p_height; ++i) {
200 for (int j = 0; j < p_width; ++j) {
Rachel Barker33b6de72023-11-03 04:09:59 +0000201 sad += abs(dst[j + i * dst_stride] - ref[j + i * ref_stride]);
Rachel Barkere59f4112023-06-19 22:43:28 +0000202 }
203 }
Rachel Barker33b6de72023-11-03 04:09:59 +0000204 return sad;
Rachel Barkere59f4112023-06-19 22:43:28 +0000205}
206
Rachel Barker33b6de72023-11-03 04:09:59 +0000207#if WARP_ERROR_BLOCK != 32
208#error "Need to change SAD call size in highbd_segmented_frame_error"
209#endif // WARP_ERROR_BLOCK != 32
Rachel Barkere59f4112023-06-19 22:43:28 +0000210static int64_t highbd_segmented_frame_error(
Rachel Barker867fb6a2023-08-07 19:04:22 +0000211 const uint16_t *const ref, int ref_stride, const uint16_t *const dst,
212 int dst_stride, int p_width, int p_height, int bd, uint8_t *segment_map,
Rachel Barkere59f4112023-06-19 22:43:28 +0000213 int segment_map_stride) {
Rachel Barker33b6de72023-11-03 04:09:59 +0000214 (void)bd;
Rachel Barkere59f4112023-06-19 22:43:28 +0000215 int patch_w, patch_h;
216 const int error_bsize_w = AOMMIN(p_width, WARP_ERROR_BLOCK);
217 const int error_bsize_h = AOMMIN(p_height, WARP_ERROR_BLOCK);
218 int64_t sum_error = 0;
219 for (int i = 0; i < p_height; i += WARP_ERROR_BLOCK) {
220 for (int j = 0; j < p_width; j += WARP_ERROR_BLOCK) {
221 int seg_x = j >> WARP_ERROR_BLOCK_LOG;
222 int seg_y = i >> WARP_ERROR_BLOCK_LOG;
223 // Only compute the error if this block contains inliers from the motion
224 // model
225 if (!segment_map[seg_y * segment_map_stride + seg_x]) continue;
226
227 // avoid computing error into the frame padding
228 patch_w = AOMMIN(error_bsize_w, p_width - j);
229 patch_h = AOMMIN(error_bsize_h, p_height - i);
Rachel Barker33b6de72023-11-03 04:09:59 +0000230
231 if (patch_w == WARP_ERROR_BLOCK && patch_h == WARP_ERROR_BLOCK) {
232 sum_error += aom_highbd_sad32x32(
233 CONVERT_TO_BYTEPTR(ref + j + i * ref_stride), ref_stride,
234 CONVERT_TO_BYTEPTR(dst + j + i * dst_stride), dst_stride);
235 } else {
236 sum_error += generic_sad_highbd(ref + j + i * ref_stride, ref_stride,
237 dst + j + i * dst_stride, dst_stride,
238 patch_w, patch_h);
239 }
Rachel Barkere59f4112023-06-19 22:43:28 +0000240 }
241 }
242 return sum_error;
243}
244
Rachel Barker33b6de72023-11-03 04:09:59 +0000245#if WARP_ERROR_BLOCK != 32
246#error "Need to change SAD call size in highbd_warp_error"
247#endif // WARP_ERROR_BLOCK != 32
Rachel Barker867fb6a2023-08-07 19:04:22 +0000248static int64_t highbd_warp_error(WarpedMotionParams *wm,
249 const uint16_t *const ref, int ref_width,
250 int ref_height, int ref_stride,
251 const uint16_t *const dst, int dst_stride,
252 int p_col, int p_row, int p_width,
253 int p_height, int subsampling_x,
254 int subsampling_y, int bd, int64_t best_error,
255 uint8_t *segment_map, int segment_map_stride) {
Remya3eb3fe72019-08-30 11:35:04 +0530256 int64_t gm_sumerr = 0;
257 const int error_bsize_w = AOMMIN(p_width, WARP_ERROR_BLOCK);
258 const int error_bsize_h = AOMMIN(p_height, WARP_ERROR_BLOCK);
Rachel Barkered77cff2023-08-31 21:27:29 +0000259 DECLARE_ALIGNED(32, uint16_t, tmp[WARP_ERROR_BLOCK * WARP_ERROR_BLOCK]);
Remya3eb3fe72019-08-30 11:35:04 +0530260
261 ConvolveParams conv_params = get_conv_params(0, 0, bd);
262 conv_params.use_dist_wtd_comp_avg = 0;
263 for (int i = p_row; i < p_row + p_height; i += WARP_ERROR_BLOCK) {
264 for (int j = p_col; j < p_col + p_width; j += WARP_ERROR_BLOCK) {
265 int seg_x = j >> WARP_ERROR_BLOCK_LOG;
266 int seg_y = i >> WARP_ERROR_BLOCK_LOG;
267 // Only compute the error if this block contains inliers from the motion
268 // model
269 if (!segment_map[seg_y * segment_map_stride + seg_x]) continue;
270 // avoid warping extra 8x8 blocks in the padded region of the frame
271 // when p_width and p_height are not multiples of WARP_ERROR_BLOCK
Rachel Barker867fb6a2023-08-07 19:04:22 +0000272 const int warp_w = AOMMIN(error_bsize_w, p_col + ref_width - j);
273 const int warp_h = AOMMIN(error_bsize_h, p_row + ref_height - i);
274 highbd_warp_plane(wm, ref, ref_width, ref_height, ref_stride, tmp, j, i,
275 warp_w, warp_h, WARP_ERROR_BLOCK, subsampling_x,
276 subsampling_y, bd, &conv_params);
Rachel Barker33b6de72023-11-03 04:09:59 +0000277
278 if (warp_w == WARP_ERROR_BLOCK && warp_h == WARP_ERROR_BLOCK) {
279 gm_sumerr += aom_highbd_sad32x32(
280 CONVERT_TO_BYTEPTR(tmp), WARP_ERROR_BLOCK,
281 CONVERT_TO_BYTEPTR(dst + j + i * dst_stride), dst_stride);
282 } else {
283 gm_sumerr +=
284 generic_sad_highbd(tmp, WARP_ERROR_BLOCK, dst + j + i * dst_stride,
285 dst_stride, warp_w, warp_h);
286 }
287
Remya4871f422019-09-04 14:45:50 +0530288 if (gm_sumerr > best_error) return INT64_MAX;
Remya3eb3fe72019-08-30 11:35:04 +0530289 }
290 }
291 return gm_sumerr;
292}
Jerome Jiang7683ed52019-09-17 15:10:25 -0700293#endif
Remya3eb3fe72019-08-30 11:35:04 +0530294
Rachel Barker33b6de72023-11-03 04:09:59 +0000295static INLINE int generic_sad(const uint8_t *const ref, int ref_stride,
296 const uint8_t *const dst, int dst_stride,
297 int p_width, int p_height) {
298 // This function should only be called for patches smaller than
299 // WARP_ERROR_BLOCK x WARP_ERROR_BLOCK. This keeps the number of pixels
300 // small enough that we don't need a 64-bit accumulator
301 assert(p_width <= WARP_ERROR_BLOCK && p_height <= WARP_ERROR_BLOCK);
302
303 int sad = 0;
Rachel Barkere59f4112023-06-19 22:43:28 +0000304 for (int i = 0; i < p_height; ++i) {
305 for (int j = 0; j < p_width; ++j) {
Rachel Barker33b6de72023-11-03 04:09:59 +0000306 sad += abs(dst[j + i * dst_stride] - ref[j + i * ref_stride]);
Rachel Barkere59f4112023-06-19 22:43:28 +0000307 }
308 }
Rachel Barker33b6de72023-11-03 04:09:59 +0000309 return sad;
Rachel Barkere59f4112023-06-19 22:43:28 +0000310}
311
Rachel Barker33b6de72023-11-03 04:09:59 +0000312#if WARP_ERROR_BLOCK != 32
313#error "Need to change SAD call size in segmented_warp_error"
314#endif // WARP_ERROR_BLOCK != 32
Rachel Barker867fb6a2023-08-07 19:04:22 +0000315static int64_t segmented_frame_error(const uint8_t *const ref, int ref_stride,
316 const uint8_t *const dst, int dst_stride,
317 int p_width, int p_height,
Rachel Barkere59f4112023-06-19 22:43:28 +0000318 uint8_t *segment_map,
319 int segment_map_stride) {
320 int patch_w, patch_h;
321 const int error_bsize_w = AOMMIN(p_width, WARP_ERROR_BLOCK);
322 const int error_bsize_h = AOMMIN(p_height, WARP_ERROR_BLOCK);
323 int64_t sum_error = 0;
324 for (int i = 0; i < p_height; i += WARP_ERROR_BLOCK) {
325 for (int j = 0; j < p_width; j += WARP_ERROR_BLOCK) {
326 int seg_x = j >> WARP_ERROR_BLOCK_LOG;
327 int seg_y = i >> WARP_ERROR_BLOCK_LOG;
328 // Only compute the error if this block contains inliers from the motion
329 // model
330 if (!segment_map[seg_y * segment_map_stride + seg_x]) continue;
331
332 // avoid computing error into the frame padding
333 patch_w = AOMMIN(error_bsize_w, p_width - j);
334 patch_h = AOMMIN(error_bsize_h, p_height - i);
Rachel Barker33b6de72023-11-03 04:09:59 +0000335
336 if (patch_w == WARP_ERROR_BLOCK && patch_h == WARP_ERROR_BLOCK) {
337 sum_error += aom_sad32x32(ref + j + i * ref_stride, ref_stride,
338 dst + j + i * dst_stride, dst_stride);
339 } else {
340 sum_error +=
341 generic_sad(ref + j + i * ref_stride, ref_stride,
342 dst + j + i * dst_stride, dst_stride, patch_w, patch_h);
343 }
Rachel Barkere59f4112023-06-19 22:43:28 +0000344 }
345 }
346 return sum_error;
347}
348
Rachel Barker33b6de72023-11-03 04:09:59 +0000349#if WARP_ERROR_BLOCK != 32
350#error "Need to change SAD call size in warp_error"
351#endif // WARP_ERROR_BLOCK != 32
Remya3eb3fe72019-08-30 11:35:04 +0530352static int64_t warp_error(WarpedMotionParams *wm, const uint8_t *const ref,
Rachel Barker867fb6a2023-08-07 19:04:22 +0000353 int ref_width, int ref_height, int ref_stride,
354 const uint8_t *const dst, int dst_stride, int p_col,
355 int p_row, int p_width, int p_height,
Remya3eb3fe72019-08-30 11:35:04 +0530356 int subsampling_x, int subsampling_y,
357 int64_t best_error, uint8_t *segment_map,
358 int segment_map_stride) {
359 int64_t gm_sumerr = 0;
360 int warp_w, warp_h;
361 const int error_bsize_w = AOMMIN(p_width, WARP_ERROR_BLOCK);
362 const int error_bsize_h = AOMMIN(p_height, WARP_ERROR_BLOCK);
363 DECLARE_ALIGNED(16, uint8_t, tmp[WARP_ERROR_BLOCK * WARP_ERROR_BLOCK]);
364 ConvolveParams conv_params = get_conv_params(0, 0, 8);
365 conv_params.use_dist_wtd_comp_avg = 0;
366
367 for (int i = p_row; i < p_row + p_height; i += WARP_ERROR_BLOCK) {
368 for (int j = p_col; j < p_col + p_width; j += WARP_ERROR_BLOCK) {
369 int seg_x = j >> WARP_ERROR_BLOCK_LOG;
370 int seg_y = i >> WARP_ERROR_BLOCK_LOG;
371 // Only compute the error if this block contains inliers from the motion
372 // model
373 if (!segment_map[seg_y * segment_map_stride + seg_x]) continue;
374 // avoid warping extra 8x8 blocks in the padded region of the frame
375 // when p_width and p_height are not multiples of WARP_ERROR_BLOCK
Rachel Barker867fb6a2023-08-07 19:04:22 +0000376 warp_w = AOMMIN(error_bsize_w, p_col + ref_width - j);
377 warp_h = AOMMIN(error_bsize_h, p_row + ref_height - i);
378 warp_plane(wm, ref, ref_width, ref_height, ref_stride, tmp, j, i, warp_w,
379 warp_h, WARP_ERROR_BLOCK, subsampling_x, subsampling_y,
380 &conv_params);
Remya3eb3fe72019-08-30 11:35:04 +0530381
Rachel Barker33b6de72023-11-03 04:09:59 +0000382 if (warp_w == WARP_ERROR_BLOCK && warp_h == WARP_ERROR_BLOCK) {
383 gm_sumerr += aom_sad32x32(tmp, WARP_ERROR_BLOCK,
384 dst + j + i * dst_stride, dst_stride);
385 } else {
386 gm_sumerr +=
387 generic_sad(tmp, WARP_ERROR_BLOCK, dst + j + i * dst_stride,
388 dst_stride, warp_w, warp_h);
389 }
390
Remya4871f422019-09-04 14:45:50 +0530391 if (gm_sumerr > best_error) return INT64_MAX;
Remya3eb3fe72019-08-30 11:35:04 +0530392 }
393 }
394 return gm_sumerr;
395}
396
Rachel Barkere59f4112023-06-19 22:43:28 +0000397int64_t av1_segmented_frame_error(int use_hbd, int bd, const uint8_t *ref,
Rachel Barker867fb6a2023-08-07 19:04:22 +0000398 int ref_stride, uint8_t *dst, int dst_stride,
399 int p_width, int p_height,
Rachel Barkere59f4112023-06-19 22:43:28 +0000400 uint8_t *segment_map,
401 int segment_map_stride) {
402#if CONFIG_AV1_HIGHBITDEPTH
403 if (use_hbd) {
404 return highbd_segmented_frame_error(
Rachel Barker867fb6a2023-08-07 19:04:22 +0000405 CONVERT_TO_SHORTPTR(ref), ref_stride, CONVERT_TO_SHORTPTR(dst),
406 dst_stride, p_width, p_height, bd, segment_map, segment_map_stride);
Rachel Barkere59f4112023-06-19 22:43:28 +0000407 }
408#endif
409 (void)use_hbd;
410 (void)bd;
Rachel Barker867fb6a2023-08-07 19:04:22 +0000411 return segmented_frame_error(ref, ref_stride, dst, dst_stride, p_width,
412 p_height, segment_map, segment_map_stride);
Rachel Barkere59f4112023-06-19 22:43:28 +0000413}
414
Remya3eb3fe72019-08-30 11:35:04 +0530415int64_t av1_warp_error(WarpedMotionParams *wm, int use_hbd, int bd,
Rachel Barker867fb6a2023-08-07 19:04:22 +0000416 const uint8_t *ref, int ref_width, int ref_height,
417 int ref_stride, uint8_t *dst, int dst_stride, int p_col,
418 int p_row, int p_width, int p_height, int subsampling_x,
Remya3eb3fe72019-08-30 11:35:04 +0530419 int subsampling_y, int64_t best_error,
420 uint8_t *segment_map, int segment_map_stride) {
Rachel Barker0d9df422023-03-07 20:51:55 +0000421 if (!av1_get_shear_params(wm)) return INT64_MAX;
Jerome Jiang7683ed52019-09-17 15:10:25 -0700422#if CONFIG_AV1_HIGHBITDEPTH
Remya3eb3fe72019-08-30 11:35:04 +0530423 if (use_hbd)
Rachel Barker867fb6a2023-08-07 19:04:22 +0000424 return highbd_warp_error(wm, CONVERT_TO_SHORTPTR(ref), ref_width,
425 ref_height, ref_stride, CONVERT_TO_SHORTPTR(dst),
426 dst_stride, p_col, p_row, p_width, p_height,
427 subsampling_x, subsampling_y, bd, best_error,
428 segment_map, segment_map_stride);
Jerome Jiang7683ed52019-09-17 15:10:25 -0700429#endif
430 (void)use_hbd;
431 (void)bd;
Rachel Barker867fb6a2023-08-07 19:04:22 +0000432 return warp_error(wm, ref, ref_width, ref_height, ref_stride, dst, dst_stride,
433 p_col, p_row, p_width, p_height, subsampling_x,
434 subsampling_y, best_error, segment_map, segment_map_stride);
Remya3eb3fe72019-08-30 11:35:04 +0530435}
436
Sarah Parker36b997b2019-05-09 16:06:53 -0700437int64_t av1_refine_integerized_param(
438 WarpedMotionParams *wm, TransformationType wmtype, int use_hbd, int bd,
439 uint8_t *ref, int r_width, int r_height, int r_stride, uint8_t *dst,
440 int d_width, int d_height, int d_stride, int n_refinements,
Rachel Barkere4e784e2023-08-04 19:58:27 +0000441 int64_t ref_frame_error, uint8_t *segment_map, int segment_map_stride) {
Johannb0ef6ff2018-02-08 14:32:21 -0800442 static const int max_trans_model_params[TRANS_TYPES] = { 0, 2, 4, 6 };
Sarah Parker68478602016-12-09 13:08:40 -0800443 const int border = ERRORADV_BORDER;
444 int i = 0, p;
Debargha Mukherjee5dfa9302017-02-10 05:00:08 -0800445 int n_params = max_trans_model_params[wmtype];
Sarah Parker68478602016-12-09 13:08:40 -0800446 int32_t *param_mat = wm->wmmat;
emilkeyder@google.com6e3557c2017-03-27 10:52:53 -0400447 int64_t step_error, best_error;
Sarah Parker68478602016-12-09 13:08:40 -0800448 int32_t step;
449 int32_t *param;
450 int32_t curr_param;
451 int32_t best_param;
Sarah Parker68478602016-12-09 13:08:40 -0800452
453 force_wmtype(wm, wmtype);
Rachel Barkere4e784e2023-08-04 19:58:27 +0000454 wm->wmtype = get_wmtype(wm);
455
456 if (n_refinements == 0) {
457 // Compute the maximum error value that will be accepted, so that
458 // av1_warp_error can terminate early if it proves the model will not
459 // be accepted.
460 int64_t selection_threshold = (int64_t)lrint(ref_frame_error * erroradv_tr);
461 return av1_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
Rachel Barker867fb6a2023-08-07 19:04:22 +0000462 dst + border * d_stride + border, d_stride, border,
463 border, d_width - 2 * border, d_height - 2 * border,
Rachel Barkere4e784e2023-08-04 19:58:27 +0000464 0, 0, selection_threshold, segment_map,
465 segment_map_stride);
466 }
467
468 // When refining, use a slightly higher threshold for the initial error
469 // calculation - see comment above erroradv_early_tr for why.
470 int64_t selection_threshold =
471 (int64_t)lrint(ref_frame_error * erroradv_early_tr);
Sarah Parker36b997b2019-05-09 16:06:53 -0700472 best_error =
473 av1_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
Rachel Barker867fb6a2023-08-07 19:04:22 +0000474 dst + border * d_stride + border, d_stride, border, border,
475 d_width - 2 * border, d_height - 2 * border, 0, 0,
476 selection_threshold, segment_map, segment_map_stride);
Rachel Barkera5b228f2023-01-16 20:09:45 +0000477
Rachel Barkere4e784e2023-08-04 19:58:27 +0000478 if (best_error > selection_threshold) {
479 return INT64_MAX;
Rachel Barkera5b228f2023-01-16 20:09:45 +0000480 }
481
Sarah Parker3e85f672017-06-15 09:04:32 -0700482 step = 1 << (n_refinements - 1);
Sarah Parker68478602016-12-09 13:08:40 -0800483 for (i = 0; i < n_refinements; i++, step >>= 1) {
484 for (p = 0; p < n_params; ++p) {
485 int step_dir = 0;
486 param = param_mat + p;
487 curr_param = *param;
488 best_param = curr_param;
489 // look to the left
Rachel Barkerea38c7d2023-06-19 22:03:09 +0000490 // Note: We have to use force_wmtype() to keep the proper symmetry for
491 // ROTZOOM type models
Sarah Parker68478602016-12-09 13:08:40 -0800492 *param = add_param_offset(p, curr_param, -step);
Rachel Barkerea38c7d2023-06-19 22:03:09 +0000493 force_wmtype(wm, wmtype);
Yaowu Xud3e7c682017-12-21 14:08:25 -0800494 step_error =
495 av1_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
Rachel Barker867fb6a2023-08-07 19:04:22 +0000496 dst + border * d_stride + border, d_stride, border,
497 border, d_width - 2 * border, d_height - 2 * border, 0,
498 0, best_error, segment_map, segment_map_stride);
Sarah Parker68478602016-12-09 13:08:40 -0800499 if (step_error < best_error) {
500 best_error = step_error;
501 best_param = *param;
502 step_dir = -1;
503 }
504
505 // look to the right
506 *param = add_param_offset(p, curr_param, step);
Rachel Barkerea38c7d2023-06-19 22:03:09 +0000507 force_wmtype(wm, wmtype);
Yaowu Xud3e7c682017-12-21 14:08:25 -0800508 step_error =
509 av1_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
Rachel Barker867fb6a2023-08-07 19:04:22 +0000510 dst + border * d_stride + border, d_stride, border,
511 border, d_width - 2 * border, d_height - 2 * border, 0,
512 0, best_error, segment_map, segment_map_stride);
Sarah Parker68478602016-12-09 13:08:40 -0800513 if (step_error < best_error) {
514 best_error = step_error;
515 best_param = *param;
516 step_dir = 1;
517 }
Sarah Parker68478602016-12-09 13:08:40 -0800518
519 // look to the direction chosen above repeatedly until error increases
520 // for the biggest step size
521 while (step_dir) {
522 *param = add_param_offset(p, best_param, step * step_dir);
Rachel Barkerea38c7d2023-06-19 22:03:09 +0000523 force_wmtype(wm, wmtype);
Rachel Barker867fb6a2023-08-07 19:04:22 +0000524 step_error =
525 av1_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
526 dst + border * d_stride + border, d_stride, border,
527 border, d_width - 2 * border, d_height - 2 * border,
528 0, 0, best_error, segment_map, segment_map_stride);
Sarah Parker68478602016-12-09 13:08:40 -0800529 if (step_error < best_error) {
530 best_error = step_error;
531 best_param = *param;
532 } else {
Sarah Parker68478602016-12-09 13:08:40 -0800533 step_dir = 0;
534 }
535 }
Rachel Barkerea38c7d2023-06-19 22:03:09 +0000536
537 // Restore best parameter value so far
538 *param = best_param;
539 force_wmtype(wm, wmtype);
Sarah Parker68478602016-12-09 13:08:40 -0800540 }
541 }
Rachel Barkerea38c7d2023-06-19 22:03:09 +0000542
Venkatb18cdfc2018-12-17 12:36:17 +0530543 wm->wmtype = get_wmtype(wm);
Sarah Parker68478602016-12-09 13:08:40 -0800544 return best_error;
545}
546
Sarah Parker36b997b2019-05-09 16:06:53 -0700547#define FEAT_COUNT_TR 3
Rachel Barkerb49c5912023-02-22 16:46:45 +0000548#define SEG_COUNT_TR 48
Sarah Parker36b997b2019-05-09 16:06:53 -0700549void av1_compute_feature_segmentation_map(uint8_t *segment_map, int width,
550 int height, int *inliers,
551 int num_inliers) {
552 int seg_count = 0;
553 memset(segment_map, 0, sizeof(*segment_map) * width * height);
554
555 for (int i = 0; i < num_inliers; i++) {
556 int x = inliers[i * 2];
557 int y = inliers[i * 2 + 1];
558 int seg_x = x >> WARP_ERROR_BLOCK_LOG;
559 int seg_y = y >> WARP_ERROR_BLOCK_LOG;
560 segment_map[seg_y * width + seg_x] += 1;
561 }
562
563 for (int i = 0; i < height; i++) {
564 for (int j = 0; j < width; j++) {
565 uint8_t feat_count = segment_map[i * width + j];
566 segment_map[i * width + j] = (feat_count >= FEAT_COUNT_TR);
567 seg_count += (segment_map[i * width + j]);
568 }
569 }
570
571 // If this motion does not make up a large enough portion of the frame,
572 // use the unsegmented version of the error metric
Rachel Barkerb49c5912023-02-22 16:46:45 +0000573 if (seg_count < SEG_COUNT_TR)
Sarah Parker36b997b2019-05-09 16:06:53 -0700574 memset(segment_map, 1, width * height * sizeof(*segment_map));
575}