1 /*
2 * Copyright (c) 2016, Alliance for Open Media. All rights reserved
3 *
4 * 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.
10 */
11
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <stdbool.h>
15 #include <memory.h>
16 #include <math.h>
17 #include <assert.h>
18
19 #include "config/aom_dsp_rtcd.h"
20
21 #include "av1/encoder/global_motion.h"
22
23 #include "av1/common/convolve.h"
24 #include "av1/common/warped_motion.h"
25
26 #include "av1/encoder/segmentation.h"
27
28 #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
av1_is_enough_erroradvantage(double best_erroradvantage,int params_cost)33 int av1_is_enough_erroradvantage(double best_erroradvantage, int params_cost) {
34 return best_erroradvantage < erroradv_tr &&
35 best_erroradvantage * params_cost < erroradv_prod_tr;
36 }
37
convert_to_params(const double * params,int32_t * model)38 static void convert_to_params(const double *params, int32_t *model) {
39 int i;
40 int alpha_present = 0;
41 model[0] = (int32_t)floor(params[0] * (1 << GM_TRANS_PREC_BITS) + 0.5);
42 model[1] = (int32_t)floor(params[1] * (1 << GM_TRANS_PREC_BITS) + 0.5);
43 model[0] = (int32_t)clamp(model[0], GM_TRANS_MIN, GM_TRANS_MAX) *
44 GM_TRANS_DECODE_FACTOR;
45 model[1] = (int32_t)clamp(model[1], GM_TRANS_MIN, GM_TRANS_MAX) *
46 GM_TRANS_DECODE_FACTOR;
47
48 for (i = 2; i < 6; ++i) {
49 const int diag_value = ((i == 2 || i == 5) ? (1 << GM_ALPHA_PREC_BITS) : 0);
50 model[i] = (int32_t)floor(params[i] * (1 << GM_ALPHA_PREC_BITS) + 0.5);
51 model[i] =
52 (int32_t)clamp(model[i] - diag_value, GM_ALPHA_MIN, GM_ALPHA_MAX);
53 alpha_present |= (model[i] != 0);
54 model[i] = (model[i] + diag_value) * GM_ALPHA_DECODE_FACTOR;
55 }
56 for (; i < 8; ++i) {
57 model[i] = (int32_t)floor(params[i] * (1 << GM_ROW3HOMO_PREC_BITS) + 0.5);
58 model[i] = (int32_t)clamp(model[i], GM_ROW3HOMO_MIN, GM_ROW3HOMO_MAX) *
59 GM_ROW3HOMO_DECODE_FACTOR;
60 alpha_present |= (model[i] != 0);
61 }
62
63 if (!alpha_present) {
64 if (abs(model[0]) < MIN_TRANS_THRESH && abs(model[1]) < MIN_TRANS_THRESH) {
65 model[0] = 0;
66 model[1] = 0;
67 }
68 }
69 }
70
av1_convert_model_to_params(const double * params,WarpedMotionParams * model)71 void av1_convert_model_to_params(const double *params,
72 WarpedMotionParams *model) {
73 convert_to_params(params, model->wmmat);
74 model->wmtype = get_wmtype(model);
75 model->invalid = 0;
76 }
77
78 // Adds some offset to a global motion parameter and handles
79 // all of the necessary precision shifts, clamping, and
80 // zero-centering.
add_param_offset(int param_index,int32_t param_value,int32_t offset)81 static int32_t add_param_offset(int param_index, int32_t param_value,
82 int32_t offset) {
83 const int scale_vals[3] = { GM_TRANS_PREC_DIFF, GM_ALPHA_PREC_DIFF,
84 GM_ROW3HOMO_PREC_DIFF };
85 const int clamp_vals[3] = { GM_TRANS_MAX, GM_ALPHA_MAX, GM_ROW3HOMO_MAX };
86 // type of param: 0 - translation, 1 - affine, 2 - homography
87 const int param_type = (param_index < 2 ? 0 : (param_index < 6 ? 1 : 2));
88 const int is_one_centered = (param_index == 2 || param_index == 5);
89
90 // Make parameter zero-centered and offset the shift that was done to make
91 // it compatible with the warped model
92 param_value = (param_value - (is_one_centered << WARPEDMODEL_PREC_BITS)) >>
93 scale_vals[param_type];
94 // Add desired offset to the rescaled/zero-centered parameter
95 param_value += offset;
96 // Clamp the parameter so it does not overflow the number of bits allotted
97 // to it in the bitstream
98 param_value = (int32_t)clamp(param_value, -clamp_vals[param_type],
99 clamp_vals[param_type]);
100 // Rescale the parameter to WARPEDMODEL_PRECISION_BITS so it is compatible
101 // with the warped motion library
102 param_value *= (1 << scale_vals[param_type]);
103
104 // Undo the zero-centering step if necessary
105 return param_value + (is_one_centered << WARPEDMODEL_PREC_BITS);
106 }
107
force_wmtype(WarpedMotionParams * wm,TransformationType wmtype)108 static void force_wmtype(WarpedMotionParams *wm, TransformationType wmtype) {
109 switch (wmtype) {
110 case IDENTITY:
111 wm->wmmat[0] = 0;
112 wm->wmmat[1] = 0;
113 AOM_FALLTHROUGH_INTENDED;
114 case TRANSLATION:
115 wm->wmmat[2] = 1 << WARPEDMODEL_PREC_BITS;
116 wm->wmmat[3] = 0;
117 AOM_FALLTHROUGH_INTENDED;
118 case ROTZOOM:
119 wm->wmmat[4] = -wm->wmmat[3];
120 wm->wmmat[5] = wm->wmmat[2];
121 AOM_FALLTHROUGH_INTENDED;
122 case AFFINE: break;
123 default: assert(0);
124 }
125 wm->wmtype = wmtype;
126 }
127
128 #if CONFIG_AV1_HIGHBITDEPTH
highbd_warp_error(WarpedMotionParams * wm,const uint16_t * const ref,int width,int height,int stride,const uint16_t * const dst,int p_col,int p_row,int p_width,int p_height,int p_stride,int subsampling_x,int subsampling_y,int bd,int64_t best_error,uint8_t * segment_map,int segment_map_stride)129 static int64_t highbd_warp_error(
130 WarpedMotionParams *wm, const uint16_t *const ref, int width, int height,
131 int stride, const uint16_t *const dst, int p_col, int p_row, int p_width,
132 int p_height, int p_stride, int subsampling_x, int subsampling_y, int bd,
133 int64_t best_error, uint8_t *segment_map, int segment_map_stride) {
134 int64_t gm_sumerr = 0;
135 const int error_bsize_w = AOMMIN(p_width, WARP_ERROR_BLOCK);
136 const int error_bsize_h = AOMMIN(p_height, WARP_ERROR_BLOCK);
137 uint16_t tmp[WARP_ERROR_BLOCK * WARP_ERROR_BLOCK];
138
139 ConvolveParams conv_params = get_conv_params(0, 0, bd);
140 conv_params.use_dist_wtd_comp_avg = 0;
141 for (int i = p_row; i < p_row + p_height; i += WARP_ERROR_BLOCK) {
142 for (int j = p_col; j < p_col + p_width; j += WARP_ERROR_BLOCK) {
143 int seg_x = j >> WARP_ERROR_BLOCK_LOG;
144 int seg_y = i >> WARP_ERROR_BLOCK_LOG;
145 // Only compute the error if this block contains inliers from the motion
146 // model
147 if (!segment_map[seg_y * segment_map_stride + seg_x]) continue;
148 // avoid warping extra 8x8 blocks in the padded region of the frame
149 // when p_width and p_height are not multiples of WARP_ERROR_BLOCK
150 const int warp_w = AOMMIN(error_bsize_w, p_col + p_width - j);
151 const int warp_h = AOMMIN(error_bsize_h, p_row + p_height - i);
152 highbd_warp_plane(wm, ref, width, height, stride, tmp, j, i, warp_w,
153 warp_h, WARP_ERROR_BLOCK, subsampling_x, subsampling_y,
154 bd, &conv_params);
155 gm_sumerr += av1_calc_highbd_frame_error(tmp, WARP_ERROR_BLOCK,
156 dst + j + i * p_stride, warp_w,
157 warp_h, p_stride, bd);
158 if (gm_sumerr > best_error) return INT64_MAX;
159 }
160 }
161 return gm_sumerr;
162 }
163 #endif
164
warp_error(WarpedMotionParams * wm,const uint8_t * const ref,int width,int height,int stride,const uint8_t * const dst,int p_col,int p_row,int p_width,int p_height,int p_stride,int subsampling_x,int subsampling_y,int64_t best_error,uint8_t * segment_map,int segment_map_stride)165 static int64_t warp_error(WarpedMotionParams *wm, const uint8_t *const ref,
166 int width, int height, int stride,
167 const uint8_t *const dst, int p_col, int p_row,
168 int p_width, int p_height, int p_stride,
169 int subsampling_x, int subsampling_y,
170 int64_t best_error, uint8_t *segment_map,
171 int segment_map_stride) {
172 int64_t gm_sumerr = 0;
173 int warp_w, warp_h;
174 const int error_bsize_w = AOMMIN(p_width, WARP_ERROR_BLOCK);
175 const int error_bsize_h = AOMMIN(p_height, WARP_ERROR_BLOCK);
176 DECLARE_ALIGNED(16, uint8_t, tmp[WARP_ERROR_BLOCK * WARP_ERROR_BLOCK]);
177 ConvolveParams conv_params = get_conv_params(0, 0, 8);
178 conv_params.use_dist_wtd_comp_avg = 0;
179
180 for (int i = p_row; i < p_row + p_height; i += WARP_ERROR_BLOCK) {
181 for (int j = p_col; j < p_col + p_width; j += WARP_ERROR_BLOCK) {
182 int seg_x = j >> WARP_ERROR_BLOCK_LOG;
183 int seg_y = i >> WARP_ERROR_BLOCK_LOG;
184 // Only compute the error if this block contains inliers from the motion
185 // model
186 if (!segment_map[seg_y * segment_map_stride + seg_x]) continue;
187 // avoid warping extra 8x8 blocks in the padded region of the frame
188 // when p_width and p_height are not multiples of WARP_ERROR_BLOCK
189 warp_w = AOMMIN(error_bsize_w, p_col + p_width - j);
190 warp_h = AOMMIN(error_bsize_h, p_row + p_height - i);
191 warp_plane(wm, ref, width, height, stride, tmp, j, i, warp_w, warp_h,
192 WARP_ERROR_BLOCK, subsampling_x, subsampling_y, &conv_params);
193
194 gm_sumerr +=
195 av1_calc_frame_error(tmp, WARP_ERROR_BLOCK, dst + j + i * p_stride,
196 warp_w, warp_h, p_stride);
197 if (gm_sumerr > best_error) return INT64_MAX;
198 }
199 }
200 return gm_sumerr;
201 }
202
av1_warp_error(WarpedMotionParams * wm,int use_hbd,int bd,const 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,int64_t best_error,uint8_t * segment_map,int segment_map_stride)203 int64_t av1_warp_error(WarpedMotionParams *wm, int use_hbd, int bd,
204 const uint8_t *ref, int width, int height, int stride,
205 uint8_t *dst, int p_col, int p_row, int p_width,
206 int p_height, int p_stride, int subsampling_x,
207 int subsampling_y, int64_t best_error,
208 uint8_t *segment_map, int segment_map_stride) {
209 if (wm->wmtype <= AFFINE)
210 if (!av1_get_shear_params(wm)) return INT64_MAX;
211 #if CONFIG_AV1_HIGHBITDEPTH
212 if (use_hbd)
213 return highbd_warp_error(wm, CONVERT_TO_SHORTPTR(ref), width, height,
214 stride, CONVERT_TO_SHORTPTR(dst), p_col, p_row,
215 p_width, p_height, p_stride, subsampling_x,
216 subsampling_y, bd, best_error, segment_map,
217 segment_map_stride);
218 #endif
219 (void)use_hbd;
220 (void)bd;
221 return warp_error(wm, ref, width, height, stride, dst, p_col, p_row, p_width,
222 p_height, p_stride, subsampling_x, subsampling_y,
223 best_error, segment_map, segment_map_stride);
224 }
225
226 // Factors used to calculate the thresholds for av1_warp_error
227 static double thresh_factors[GM_REFINEMENT_COUNT] = { 1.25, 1.20, 1.15, 1.10,
228 1.05 };
229
calc_approx_erroradv_threshold(double scaling_factor,int64_t erroradv_threshold)230 static INLINE int64_t calc_approx_erroradv_threshold(
231 double scaling_factor, int64_t erroradv_threshold) {
232 return erroradv_threshold <
233 (int64_t)(((double)INT64_MAX / scaling_factor) + 0.5)
234 ? (int64_t)(scaling_factor * erroradv_threshold + 0.5)
235 : INT64_MAX;
236 }
237
av1_refine_integerized_param(WarpedMotionParams * wm,TransformationType wmtype,int use_hbd,int bd,uint8_t * ref,int r_width,int r_height,int r_stride,uint8_t * dst,int d_width,int d_height,int d_stride,int n_refinements,int64_t best_frame_error,uint8_t * segment_map,int segment_map_stride,int64_t erroradv_threshold)238 int64_t av1_refine_integerized_param(
239 WarpedMotionParams *wm, TransformationType wmtype, int use_hbd, int bd,
240 uint8_t *ref, int r_width, int r_height, int r_stride, uint8_t *dst,
241 int d_width, int d_height, int d_stride, int n_refinements,
242 int64_t best_frame_error, uint8_t *segment_map, int segment_map_stride,
243 int64_t erroradv_threshold) {
244 static const int max_trans_model_params[TRANS_TYPES] = { 0, 2, 4, 6 };
245 const int border = ERRORADV_BORDER;
246 int i = 0, p;
247 int n_params = max_trans_model_params[wmtype];
248 int32_t *param_mat = wm->wmmat;
249 int64_t step_error, best_error;
250 int32_t step;
251 int32_t *param;
252 int32_t curr_param;
253 int32_t best_param;
254
255 force_wmtype(wm, wmtype);
256 best_error =
257 av1_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
258 dst + border * d_stride + border, border, border,
259 d_width - 2 * border, d_height - 2 * border, d_stride, 0,
260 0, best_frame_error, segment_map, segment_map_stride);
261 best_error = AOMMIN(best_error, best_frame_error);
262 step = 1 << (n_refinements - 1);
263 for (i = 0; i < n_refinements; i++, step >>= 1) {
264 int64_t error_adv_thresh =
265 calc_approx_erroradv_threshold(thresh_factors[i], erroradv_threshold);
266 for (p = 0; p < n_params; ++p) {
267 int step_dir = 0;
268 // Skip searches for parameters that are forced to be 0
269 param = param_mat + p;
270 curr_param = *param;
271 best_param = curr_param;
272 // look to the left
273 *param = add_param_offset(p, curr_param, -step);
274 step_error =
275 av1_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
276 dst + border * d_stride + border, border, border,
277 d_width - 2 * border, d_height - 2 * border, d_stride,
278 0, 0, AOMMIN(best_error, error_adv_thresh),
279 segment_map, segment_map_stride);
280 if (step_error < best_error) {
281 best_error = step_error;
282 best_param = *param;
283 step_dir = -1;
284 }
285
286 // look to the right
287 *param = add_param_offset(p, curr_param, step);
288 step_error =
289 av1_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
290 dst + border * d_stride + border, border, border,
291 d_width - 2 * border, d_height - 2 * border, d_stride,
292 0, 0, AOMMIN(best_error, error_adv_thresh),
293 segment_map, segment_map_stride);
294 if (step_error < best_error) {
295 best_error = step_error;
296 best_param = *param;
297 step_dir = 1;
298 }
299 *param = best_param;
300
301 // look to the direction chosen above repeatedly until error increases
302 // for the biggest step size
303 while (step_dir) {
304 *param = add_param_offset(p, best_param, step * step_dir);
305 step_error =
306 av1_warp_error(wm, use_hbd, bd, ref, r_width, r_height, r_stride,
307 dst + border * d_stride + border, border, border,
308 d_width - 2 * border, d_height - 2 * border,
309 d_stride, 0, 0, AOMMIN(best_error, error_adv_thresh),
310 segment_map, segment_map_stride);
311 if (step_error < best_error) {
312 best_error = step_error;
313 best_param = *param;
314 } else {
315 *param = best_param;
316 step_dir = 0;
317 }
318 }
319 }
320 }
321 force_wmtype(wm, wmtype);
322 wm->wmtype = get_wmtype(wm);
323 return best_error;
324 }
325
326 #define FEAT_COUNT_TR 3
327 #define SEG_COUNT_TR 0.40
av1_compute_feature_segmentation_map(uint8_t * segment_map,int width,int height,int * inliers,int num_inliers)328 void av1_compute_feature_segmentation_map(uint8_t *segment_map, int width,
329 int height, int *inliers,
330 int num_inliers) {
331 int seg_count = 0;
332 memset(segment_map, 0, sizeof(*segment_map) * width * height);
333
334 for (int i = 0; i < num_inliers; i++) {
335 int x = inliers[i * 2];
336 int y = inliers[i * 2 + 1];
337 int seg_x = x >> WARP_ERROR_BLOCK_LOG;
338 int seg_y = y >> WARP_ERROR_BLOCK_LOG;
339 segment_map[seg_y * width + seg_x] += 1;
340 }
341
342 for (int i = 0; i < height; i++) {
343 for (int j = 0; j < width; j++) {
344 uint8_t feat_count = segment_map[i * width + j];
345 segment_map[i * width + j] = (feat_count >= FEAT_COUNT_TR);
346 seg_count += (segment_map[i * width + j]);
347 }
348 }
349
350 // If this motion does not make up a large enough portion of the frame,
351 // use the unsegmented version of the error metric
352 if (seg_count < (width * height * SEG_COUNT_TR))
353 memset(segment_map, 1, width * height * sizeof(*segment_map));
354 }
355