• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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