blob: 448215a63823cc5fb2f27e099d33d7b61a721aec [file] [log] [blame]
Remyaefd09fa2020-05-07 15:05:34 +05301/*
2 * Copyright (c) 2020, 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 "aom_dsp/binary_codes_writer.h"
Remyaefd09fa2020-05-07 15:05:34 +053013
Rachel Barker53e3a692022-11-30 15:45:11 +000014#include "aom_dsp/flow_estimation/corner_detect.h"
15#include "aom_dsp/flow_estimation/flow_estimation.h"
Rachel Barker674eaa02022-12-22 16:03:44 +000016#include "aom_dsp/pyramid.h"
Rachel Barker53e3a692022-11-30 15:45:11 +000017#include "av1/common/warped_motion.h"
Remyaefd09fa2020-05-07 15:05:34 +053018#include "av1/encoder/encoder.h"
19#include "av1/encoder/ethread.h"
20#include "av1/encoder/rdopt.h"
Rachel Barker674eaa02022-12-22 16:03:44 +000021#include "av1/encoder/global_motion_facade.h"
Remyaefd09fa2020-05-07 15:05:34 +053022
23// Highest motion model to search.
24#define GLOBAL_TRANS_TYPES_ENC 3
25
26// Computes the cost for the warp parameters.
27static int gm_get_params_cost(const WarpedMotionParams *gm,
28 const WarpedMotionParams *ref_gm, int allow_hp) {
29 int params_cost = 0;
30 int trans_bits, trans_prec_diff;
31 switch (gm->wmtype) {
32 case AFFINE:
33 case ROTZOOM:
34 params_cost += aom_count_signed_primitive_refsubexpfin(
35 GM_ALPHA_MAX + 1, SUBEXPFIN_K,
36 (ref_gm->wmmat[2] >> GM_ALPHA_PREC_DIFF) - (1 << GM_ALPHA_PREC_BITS),
37 (gm->wmmat[2] >> GM_ALPHA_PREC_DIFF) - (1 << GM_ALPHA_PREC_BITS));
38 params_cost += aom_count_signed_primitive_refsubexpfin(
39 GM_ALPHA_MAX + 1, SUBEXPFIN_K,
40 (ref_gm->wmmat[3] >> GM_ALPHA_PREC_DIFF),
41 (gm->wmmat[3] >> GM_ALPHA_PREC_DIFF));
42 if (gm->wmtype >= AFFINE) {
43 params_cost += aom_count_signed_primitive_refsubexpfin(
44 GM_ALPHA_MAX + 1, SUBEXPFIN_K,
45 (ref_gm->wmmat[4] >> GM_ALPHA_PREC_DIFF),
46 (gm->wmmat[4] >> GM_ALPHA_PREC_DIFF));
47 params_cost += aom_count_signed_primitive_refsubexpfin(
48 GM_ALPHA_MAX + 1, SUBEXPFIN_K,
49 (ref_gm->wmmat[5] >> GM_ALPHA_PREC_DIFF) -
50 (1 << GM_ALPHA_PREC_BITS),
51 (gm->wmmat[5] >> GM_ALPHA_PREC_DIFF) - (1 << GM_ALPHA_PREC_BITS));
52 }
53 AOM_FALLTHROUGH_INTENDED;
54 case TRANSLATION:
55 trans_bits = (gm->wmtype == TRANSLATION)
56 ? GM_ABS_TRANS_ONLY_BITS - !allow_hp
57 : GM_ABS_TRANS_BITS;
58 trans_prec_diff = (gm->wmtype == TRANSLATION)
59 ? GM_TRANS_ONLY_PREC_DIFF + !allow_hp
60 : GM_TRANS_PREC_DIFF;
61 params_cost += aom_count_signed_primitive_refsubexpfin(
62 (1 << trans_bits) + 1, SUBEXPFIN_K,
63 (ref_gm->wmmat[0] >> trans_prec_diff),
64 (gm->wmmat[0] >> trans_prec_diff));
65 params_cost += aom_count_signed_primitive_refsubexpfin(
66 (1 << trans_bits) + 1, SUBEXPFIN_K,
67 (ref_gm->wmmat[1] >> trans_prec_diff),
68 (gm->wmmat[1] >> trans_prec_diff));
69 AOM_FALLTHROUGH_INTENDED;
70 case IDENTITY: break;
71 default: assert(0);
72 }
73 return (params_cost << AV1_PROB_COST_SHIFT);
74}
75
76// Calculates the threshold to be used for warp error computation.
chiyotsaia6545dd2020-07-06 14:20:50 -070077static AOM_INLINE int64_t calc_erroradv_threshold(int64_t ref_frame_error) {
78 return (int64_t)(ref_frame_error * erroradv_tr + 0.5);
Remyaefd09fa2020-05-07 15:05:34 +053079}
80
81// For the given reference frame, computes the global motion parameters for
82// different motion models and finds the best.
83static AOM_INLINE void compute_global_motion_for_ref_frame(
84 AV1_COMP *cpi, YV12_BUFFER_CONFIG *ref_buf[REF_FRAMES], int frame,
Rachel Barker738c4f42023-01-11 17:36:18 +000085 MotionModel *motion_models, uint8_t *segment_map, const int segment_map_w,
86 const int segment_map_h, const WarpedMotionParams *ref_params) {
Remyaefd09fa2020-05-07 15:05:34 +053087 ThreadData *const td = &cpi->td;
88 MACROBLOCK *const x = &td->mb;
89 AV1_COMMON *const cm = &cpi->common;
90 MACROBLOCKD *const xd = &x->e_mbd;
91 int i;
Rachel Barker5ed9ce52022-12-15 17:19:18 +000092 int src_width = cpi->source->y_crop_width;
93 int src_height = cpi->source->y_crop_height;
Remyaefd09fa2020-05-07 15:05:34 +053094 int src_stride = cpi->source->y_stride;
Remyaefd09fa2020-05-07 15:05:34 +053095 WarpedMotionParams tmp_wm_params;
96 const double *params_this_motion;
Remyaefd09fa2020-05-07 15:05:34 +053097 assert(ref_buf[frame] != NULL);
98 TransformationType model;
Rachel Barker674eaa02022-12-22 16:03:44 +000099 int bit_depth = cpi->common.seq_params->bit_depth;
Rachel Barker6ebcbc12022-12-20 19:13:26 +0000100 GlobalMotionMethod global_motion_method = cpi->oxcf.global_motion_method;
Rachel Barkera5b228f2023-01-16 20:09:45 +0000101 int num_refinements = cpi->sf.gm_sf.num_refinement_steps;
Rachel Barker674eaa02022-12-22 16:03:44 +0000102
Remyaefd09fa2020-05-07 15:05:34 +0530103 for (model = ROTZOOM; model < GLOBAL_TRANS_TYPES_ENC; ++model) {
Rachel Barkera02796a2023-03-02 20:06:47 +0000104 if (!aom_compute_global_motion(model, cpi->source, ref_buf[frame],
105 bit_depth, global_motion_method,
106 motion_models, RANSAC_NUM_MOTIONS)) {
107 continue;
Remyaefd09fa2020-05-07 15:05:34 +0530108 }
109
Rachel Barker8892c512023-03-13 22:41:24 +0000110 int64_t best_ref_frame_error = 0;
111 int64_t best_warp_error = INT64_MAX;
Remyaefd09fa2020-05-07 15:05:34 +0530112 for (i = 0; i < RANSAC_NUM_MOTIONS; ++i) {
Rachel Barker738c4f42023-01-11 17:36:18 +0000113 if (motion_models[i].num_inliers == 0) continue;
Remyaefd09fa2020-05-07 15:05:34 +0530114
Rachel Barker738c4f42023-01-11 17:36:18 +0000115 params_this_motion = motion_models[i].params;
Remyaefd09fa2020-05-07 15:05:34 +0530116 av1_convert_model_to_params(params_this_motion, &tmp_wm_params);
117
Rachel Barker8892c512023-03-13 22:41:24 +0000118 // Skip models that we won't use (IDENTITY or TRANSLATION)
119 //
120 // For IDENTITY type models, we don't need to evaluate anything because
121 // all the following logic is effectively comparing the estimated model
122 // to an identity model.
Rachel Barker6496e8d2022-09-23 09:40:02 +0000123 //
124 // For TRANSLATION type global motion models, gm_get_motion_vector() gives
125 // the wrong motion vector (see comments in that function for details).
126 // As translation-type models do not give much gain, we can avoid this bug
127 // by never choosing a TRANSLATION type model
Rachel Barker8892c512023-03-13 22:41:24 +0000128 if (tmp_wm_params.wmtype <= TRANSLATION) continue;
Rachel Barker6496e8d2022-09-23 09:40:02 +0000129
Rachel Barker8892c512023-03-13 22:41:24 +0000130 av1_compute_feature_segmentation_map(
131 segment_map, segment_map_w, segment_map_h, motion_models[i].inliers,
132 motion_models[i].num_inliers);
Remyaefd09fa2020-05-07 15:05:34 +0530133
Rachel Barker8892c512023-03-13 22:41:24 +0000134 int64_t ref_frame_error = av1_segmented_frame_error(
135 is_cur_buf_hbd(xd), xd->bd, ref_buf[frame]->y_buffer,
136 ref_buf[frame]->y_stride, cpi->source->y_buffer, src_width,
137 src_height, src_stride, segment_map, segment_map_w);
Remyaefd09fa2020-05-07 15:05:34 +0530138
Rachel Barker8892c512023-03-13 22:41:24 +0000139 if (ref_frame_error == 0) continue;
Remyaefd09fa2020-05-07 15:05:34 +0530140
Rachel Barker8892c512023-03-13 22:41:24 +0000141 const int64_t erroradv_threshold =
142 calc_erroradv_threshold(ref_frame_error);
Remyaefd09fa2020-05-07 15:05:34 +0530143
Rachel Barker8892c512023-03-13 22:41:24 +0000144 const int64_t warp_error = av1_refine_integerized_param(
145 &tmp_wm_params, tmp_wm_params.wmtype, is_cur_buf_hbd(xd), xd->bd,
146 ref_buf[frame]->y_buffer, ref_buf[frame]->y_crop_width,
147 ref_buf[frame]->y_crop_height, ref_buf[frame]->y_stride,
148 cpi->source->y_buffer, src_width, src_height, src_stride,
149 num_refinements, best_warp_error, segment_map, segment_map_w,
150 erroradv_threshold);
Rachel Barker6496e8d2022-09-23 09:40:02 +0000151
Rachel Barker8892c512023-03-13 22:41:24 +0000152 // av1_refine_integerized_param() can return a simpler model type than
153 // its input, so re-check model type here
154 if (tmp_wm_params.wmtype <= TRANSLATION) continue;
155
156 if (warp_error < best_warp_error) {
157 best_ref_frame_error = ref_frame_error;
158 best_warp_error = warp_error;
159 // Save the wm_params modified by
160 // av1_refine_integerized_param() rather than motion index to
161 // avoid rerunning refine() below.
162 memcpy(&(cm->global_motion[frame]), &tmp_wm_params,
163 sizeof(WarpedMotionParams));
Remyaefd09fa2020-05-07 15:05:34 +0530164 }
165 }
Rachel Barker0d9df422023-03-07 20:51:55 +0000166 assert(cm->global_motion[frame].wmtype <= AFFINE);
167 if (!av1_get_shear_params(&cm->global_motion[frame]))
168 cm->global_motion[frame] = default_warp_params;
Remyaefd09fa2020-05-07 15:05:34 +0530169
Rachel Barker6496e8d2022-09-23 09:40:02 +0000170#if 0
171 // We never choose translational models, so this code is disabled
Remyaefd09fa2020-05-07 15:05:34 +0530172 if (cm->global_motion[frame].wmtype == TRANSLATION) {
173 cm->global_motion[frame].wmmat[0] =
174 convert_to_trans_prec(cm->features.allow_high_precision_mv,
175 cm->global_motion[frame].wmmat[0]) *
176 GM_TRANS_ONLY_DECODE_FACTOR;
177 cm->global_motion[frame].wmmat[1] =
178 convert_to_trans_prec(cm->features.allow_high_precision_mv,
179 cm->global_motion[frame].wmmat[1]) *
180 GM_TRANS_ONLY_DECODE_FACTOR;
181 }
Rachel Barker6496e8d2022-09-23 09:40:02 +0000182#endif
Remyaefd09fa2020-05-07 15:05:34 +0530183
184 if (cm->global_motion[frame].wmtype == IDENTITY) continue;
185
Rachel Barker8892c512023-03-13 22:41:24 +0000186 // Once we get here, best_ref_frame_error must be > 0. This is because
187 // of the logic above, which skips over any models which have
188 // ref_frame_error == 0
189 assert(best_ref_frame_error > 0);
Remyaefd09fa2020-05-07 15:05:34 +0530190
191 // If the best error advantage found doesn't meet the threshold for
192 // this motion type, revert to IDENTITY.
193 if (!av1_is_enough_erroradvantage(
Rachel Barker8892c512023-03-13 22:41:24 +0000194 (double)best_warp_error / best_ref_frame_error,
Remyaefd09fa2020-05-07 15:05:34 +0530195 gm_get_params_cost(&cm->global_motion[frame], ref_params,
chiyotsaia6545dd2020-07-06 14:20:50 -0700196 cm->features.allow_high_precision_mv))) {
Remyaefd09fa2020-05-07 15:05:34 +0530197 cm->global_motion[frame] = default_warp_params;
198 }
199
200 if (cm->global_motion[frame].wmtype != IDENTITY) break;
201 }
Remyaefd09fa2020-05-07 15:05:34 +0530202}
203
204// Computes global motion for the given reference frame.
205void av1_compute_gm_for_valid_ref_frames(
206 AV1_COMP *cpi, YV12_BUFFER_CONFIG *ref_buf[REF_FRAMES], int frame,
Rachel Barker738c4f42023-01-11 17:36:18 +0000207 MotionModel *motion_models, uint8_t *segment_map, int segment_map_w,
Rachel Barker2722ce62022-12-19 15:38:55 +0000208 int segment_map_h) {
Remyaefd09fa2020-05-07 15:05:34 +0530209 AV1_COMMON *const cm = &cpi->common;
Remyaefd09fa2020-05-07 15:05:34 +0530210 const WarpedMotionParams *ref_params =
211 cm->prev_frame ? &cm->prev_frame->global_motion[frame]
212 : &default_warp_params;
213
Rachel Barker738c4f42023-01-11 17:36:18 +0000214 compute_global_motion_for_ref_frame(cpi, ref_buf, frame, motion_models,
Rachel Barker2722ce62022-12-19 15:38:55 +0000215 segment_map, segment_map_w, segment_map_h,
216 ref_params);
Remyaefd09fa2020-05-07 15:05:34 +0530217}
218
219// Loops over valid reference frames and computes global motion estimation.
220static AOM_INLINE void compute_global_motion_for_references(
221 AV1_COMP *cpi, YV12_BUFFER_CONFIG *ref_buf[REF_FRAMES],
222 FrameDistPair reference_frame[REF_FRAMES - 1], int num_ref_frames,
Rachel Barker738c4f42023-01-11 17:36:18 +0000223 MotionModel *motion_models, uint8_t *segment_map, const int segment_map_w,
224 const int segment_map_h) {
Remyaefd09fa2020-05-07 15:05:34 +0530225 AV1_COMMON *const cm = &cpi->common;
226 // Compute global motion w.r.t. reference frames starting from the nearest ref
227 // frame in a given direction.
228 for (int frame = 0; frame < num_ref_frames; frame++) {
229 int ref_frame = reference_frame[frame].frame;
Rachel Barker738c4f42023-01-11 17:36:18 +0000230 av1_compute_gm_for_valid_ref_frames(cpi, ref_buf, ref_frame, motion_models,
231 segment_map, segment_map_w,
232 segment_map_h);
Remyaefd09fa2020-05-07 15:05:34 +0530233 // If global motion w.r.t. current ref frame is
234 // INVALID/TRANSLATION/IDENTITY, skip the evaluation of global motion w.r.t
Rachel Barker277c8ce2023-01-25 16:11:07 +0000235 // the remaining ref frames in that direction.
Remyaefd09fa2020-05-07 15:05:34 +0530236 if (cpi->sf.gm_sf.prune_ref_frame_for_gm_search &&
Rachel Barker8892c512023-03-13 22:41:24 +0000237 cm->global_motion[ref_frame].wmtype <= TRANSLATION)
Remyaefd09fa2020-05-07 15:05:34 +0530238 break;
239 }
240}
241
242// Compares the distance in 'a' and 'b'. Returns 1 if the frame corresponding to
243// 'a' is farther, -1 if the frame corresponding to 'b' is farther, 0 otherwise.
244static int compare_distance(const void *a, const void *b) {
245 const int diff =
246 ((FrameDistPair *)a)->distance - ((FrameDistPair *)b)->distance;
247 if (diff > 0)
248 return 1;
249 else if (diff < 0)
250 return -1;
251 return 0;
252}
253
S Hamsalekha7e640e32021-10-14 18:57:11 +0530254static int disable_gm_search_based_on_stats(const AV1_COMP *const cpi) {
255 int is_gm_present = 1;
256
257 // Check number of GM models only in GF groups with ARF frames. GM param
258 // estimation is always done in the case of GF groups with no ARF frames (flat
259 // gops)
260 if (cpi->ppi->gf_group.arf_index > -1) {
261 // valid_gm_model_found is initialized to INT32_MAX in the beginning of
262 // every GF group.
263 // Therefore, GM param estimation is always done for all frames until
Wan-Teh Chang50f93772022-03-30 18:23:50 -0700264 // at least 1 frame each of ARF_UPDATE, INTNL_ARF_UPDATE and LF_UPDATE are
S Hamsalekha7e640e32021-10-14 18:57:11 +0530265 // encoded in a GF group For subsequent frames, GM param estimation is
266 // disabled, if no valid models have been found in all the three update
267 // types.
268 is_gm_present = (cpi->ppi->valid_gm_model_found[ARF_UPDATE] != 0) ||
269 (cpi->ppi->valid_gm_model_found[INTNL_ARF_UPDATE] != 0) ||
270 (cpi->ppi->valid_gm_model_found[LF_UPDATE] != 0);
271 }
272 return !is_gm_present;
273}
274
Remyaefd09fa2020-05-07 15:05:34 +0530275// Prunes reference frames for global motion estimation based on the speed
276// feature 'gm_search_type'.
277static int do_gm_search_logic(SPEED_FEATURES *const sf, int frame) {
278 (void)frame;
279 switch (sf->gm_sf.gm_search_type) {
280 case GM_FULL_SEARCH: return 1;
281 case GM_REDUCED_REF_SEARCH_SKIP_L2_L3:
282 return !(frame == LAST2_FRAME || frame == LAST3_FRAME);
283 case GM_REDUCED_REF_SEARCH_SKIP_L2_L3_ARF2:
284 return !(frame == LAST2_FRAME || frame == LAST3_FRAME ||
285 (frame == ALTREF2_FRAME));
286 case GM_DISABLE_SEARCH: return 0;
287 default: assert(0);
288 }
289 return 1;
290}
291
292// Populates valid reference frames in past/future directions in
293// 'reference_frames' and their count in 'num_ref_frames'.
294static AOM_INLINE void update_valid_ref_frames_for_gm(
295 AV1_COMP *cpi, YV12_BUFFER_CONFIG *ref_buf[REF_FRAMES],
296 FrameDistPair reference_frames[MAX_DIRECTIONS][REF_FRAMES - 1],
297 int *num_ref_frames) {
298 AV1_COMMON *const cm = &cpi->common;
Remyaefd09fa2020-05-07 15:05:34 +0530299 int *num_past_ref_frames = &num_ref_frames[0];
300 int *num_future_ref_frames = &num_ref_frames[1];
Mufaddal Chakera8ee04fa2021-03-17 13:33:18 +0530301 const GF_GROUP *gf_group = &cpi->ppi->gf_group;
Deepa K G39141dd2020-07-31 18:53:08 +0530302 int ref_pruning_enabled = is_frame_eligible_for_ref_pruning(
Mufaddal Chakeraab20d372021-03-17 12:18:34 +0530303 gf_group, cpi->sf.inter_sf.selective_ref_frame, 1, cpi->gf_frame_index);
S Hamsalekha7e640e32021-10-14 18:57:11 +0530304 int cur_frame_gm_disabled = 0;
305
306 if (cpi->sf.gm_sf.disable_gm_search_based_on_stats) {
307 cur_frame_gm_disabled = disable_gm_search_based_on_stats(cpi);
308 }
Deepa K G39141dd2020-07-31 18:53:08 +0530309
Remyaefd09fa2020-05-07 15:05:34 +0530310 for (int frame = ALTREF_FRAME; frame >= LAST_FRAME; --frame) {
311 const MV_REFERENCE_FRAME ref_frame[2] = { frame, NONE_FRAME };
312 RefCntBuffer *buf = get_ref_frame_buf(cm, frame);
313 const int ref_disabled =
314 !(cpi->ref_frame_flags & av1_ref_frame_flag_list[frame]);
315 ref_buf[frame] = NULL;
316 cm->global_motion[frame] = default_warp_params;
317 // Skip global motion estimation for invalid ref frames
318 if (buf == NULL ||
319 (ref_disabled && cpi->sf.hl_sf.recode_loop != DISALLOW_RECODE)) {
Remyaefd09fa2020-05-07 15:05:34 +0530320 continue;
321 } else {
322 ref_buf[frame] = &buf->buf;
323 }
324
Deepa K G39141dd2020-07-31 18:53:08 +0530325 int prune_ref_frames =
326 ref_pruning_enabled &&
327 prune_ref_by_selective_ref_frame(cpi, NULL, ref_frame,
328 cm->cur_frame->ref_display_order_hint);
329
Remyaefd09fa2020-05-07 15:05:34 +0530330 if (ref_buf[frame]->y_crop_width == cpi->source->y_crop_width &&
331 ref_buf[frame]->y_crop_height == cpi->source->y_crop_height &&
S Hamsalekha7e640e32021-10-14 18:57:11 +0530332 do_gm_search_logic(&cpi->sf, frame) && !prune_ref_frames &&
333 !cur_frame_gm_disabled) {
Remyaefd09fa2020-05-07 15:05:34 +0530334 assert(ref_buf[frame] != NULL);
Hui Su8438c692020-10-09 13:54:56 -0700335 const int relative_frame_dist = av1_encoder_get_relative_dist(
336 buf->display_order_hint, cm->cur_frame->display_order_hint);
Remyaefd09fa2020-05-07 15:05:34 +0530337 // Populate past and future ref frames.
338 // reference_frames[0][] indicates past direction and
339 // reference_frames[1][] indicates future direction.
Rachel Barker277c8ce2023-01-25 16:11:07 +0000340 if (relative_frame_dist == 0) {
341 // Skip global motion estimation for frames at the same nominal instant.
342 // This will generally be either a "real" frame coded against a
343 // temporal filtered version, or a higher spatial layer coded against
344 // a lower spatial layer. In either case, the optimal motion model will
345 // be IDENTITY, so we don't need to search explicitly.
346 } else if (relative_frame_dist < 0) {
Remyaefd09fa2020-05-07 15:05:34 +0530347 reference_frames[0][*num_past_ref_frames].distance =
348 abs(relative_frame_dist);
349 reference_frames[0][*num_past_ref_frames].frame = frame;
350 (*num_past_ref_frames)++;
351 } else {
352 reference_frames[1][*num_future_ref_frames].distance =
353 abs(relative_frame_dist);
354 reference_frames[1][*num_future_ref_frames].frame = frame;
355 (*num_future_ref_frames)++;
356 }
357 }
358 }
359}
360
Remyaefd09fa2020-05-07 15:05:34 +0530361// Deallocates segment_map and inliers.
Rachel Barker738c4f42023-01-11 17:36:18 +0000362static AOM_INLINE void dealloc_global_motion_data(MotionModel *motion_models,
Remyaefd09fa2020-05-07 15:05:34 +0530363 uint8_t *segment_map) {
364 aom_free(segment_map);
365
366 for (int m = 0; m < RANSAC_NUM_MOTIONS; m++) {
Rachel Barker738c4f42023-01-11 17:36:18 +0000367 aom_free(motion_models[m].inliers);
Remyaefd09fa2020-05-07 15:05:34 +0530368 }
369}
370
James Zern723bbf92022-04-28 12:54:06 -0700371// Allocates and initializes memory for segment_map and MotionModel.
Rachel Barker738c4f42023-01-11 17:36:18 +0000372static AOM_INLINE bool alloc_global_motion_data(MotionModel *motion_models,
James Zern723bbf92022-04-28 12:54:06 -0700373 uint8_t **segment_map,
374 const int segment_map_w,
375 const int segment_map_h) {
Rachel Barker738c4f42023-01-11 17:36:18 +0000376 av1_zero_array(motion_models, RANSAC_NUM_MOTIONS);
James Zern723bbf92022-04-28 12:54:06 -0700377 for (int m = 0; m < RANSAC_NUM_MOTIONS; m++) {
Rachel Barker738c4f42023-01-11 17:36:18 +0000378 motion_models[m].inliers =
379 aom_malloc(sizeof(*(motion_models[m].inliers)) * 2 * MAX_CORNERS);
380 if (!motion_models[m].inliers) {
381 dealloc_global_motion_data(motion_models, NULL);
James Zern723bbf92022-04-28 12:54:06 -0700382 return false;
383 }
384 }
385
386 *segment_map = (uint8_t *)aom_calloc(segment_map_w * segment_map_h,
387 sizeof(*segment_map));
388 if (!*segment_map) {
Rachel Barker738c4f42023-01-11 17:36:18 +0000389 dealloc_global_motion_data(motion_models, NULL);
James Zern723bbf92022-04-28 12:54:06 -0700390 return false;
391 }
392 return true;
393}
394
Remyaefd09fa2020-05-07 15:05:34 +0530395// Initializes parameters used for computing global motion.
396static AOM_INLINE void setup_global_motion_info_params(AV1_COMP *cpi) {
397 GlobalMotionInfo *const gm_info = &cpi->gm_info;
398 YV12_BUFFER_CONFIG *source = cpi->source;
399
Remyaefd09fa2020-05-07 15:05:34 +0530400 gm_info->segment_map_w =
Rachel Barker5ed9ce52022-12-15 17:19:18 +0000401 (source->y_crop_width + WARP_ERROR_BLOCK - 1) >> WARP_ERROR_BLOCK_LOG;
Remyaefd09fa2020-05-07 15:05:34 +0530402 gm_info->segment_map_h =
Rachel Barker5ed9ce52022-12-15 17:19:18 +0000403 (source->y_crop_height + WARP_ERROR_BLOCK - 1) >> WARP_ERROR_BLOCK_LOG;
Remyaefd09fa2020-05-07 15:05:34 +0530404
405 memset(gm_info->reference_frames, -1,
406 sizeof(gm_info->reference_frames[0][0]) * MAX_DIRECTIONS *
407 (REF_FRAMES - 1));
408 av1_zero(gm_info->num_ref_frames);
409
410 // Populate ref_buf for valid ref frames in global motion
411 update_valid_ref_frames_for_gm(cpi, gm_info->ref_buf,
412 gm_info->reference_frames,
413 gm_info->num_ref_frames);
414
415 // Sort the past and future ref frames in the ascending order of their
416 // distance from the current frame. reference_frames[0] => past direction
417 // and reference_frames[1] => future direction.
418 qsort(gm_info->reference_frames[0], gm_info->num_ref_frames[0],
419 sizeof(gm_info->reference_frames[0][0]), compare_distance);
420 qsort(gm_info->reference_frames[1], gm_info->num_ref_frames[1],
421 sizeof(gm_info->reference_frames[1][0]), compare_distance);
Remyaefd09fa2020-05-07 15:05:34 +0530422}
423
424// Computes global motion w.r.t. valid reference frames.
425static AOM_INLINE void global_motion_estimation(AV1_COMP *cpi) {
426 GlobalMotionInfo *const gm_info = &cpi->gm_info;
Rachel Barker738c4f42023-01-11 17:36:18 +0000427 MotionModel motion_models[RANSAC_NUM_MOTIONS];
Remyaefd09fa2020-05-07 15:05:34 +0530428 uint8_t *segment_map = NULL;
429
Rachel Barker738c4f42023-01-11 17:36:18 +0000430 alloc_global_motion_data(motion_models, &segment_map, gm_info->segment_map_w,
431 gm_info->segment_map_h);
Remyaefd09fa2020-05-07 15:05:34 +0530432
433 // Compute global motion w.r.t. past reference frames and future reference
434 // frames
435 for (int dir = 0; dir < MAX_DIRECTIONS; dir++) {
436 if (gm_info->num_ref_frames[dir] > 0)
437 compute_global_motion_for_references(
438 cpi, gm_info->ref_buf, gm_info->reference_frames[dir],
Rachel Barker738c4f42023-01-11 17:36:18 +0000439 gm_info->num_ref_frames[dir], motion_models, segment_map,
Rachel Barker674eaa02022-12-22 16:03:44 +0000440 gm_info->segment_map_w, gm_info->segment_map_h);
Remyaefd09fa2020-05-07 15:05:34 +0530441 }
442
Rachel Barker738c4f42023-01-11 17:36:18 +0000443 dealloc_global_motion_data(motion_models, segment_map);
Remyaefd09fa2020-05-07 15:05:34 +0530444}
445
446// Global motion estimation for the current frame is computed.This computation
447// happens once per frame and the winner motion model parameters are stored in
448// cm->cur_frame->global_motion.
449void av1_compute_global_motion_facade(AV1_COMP *cpi) {
450 AV1_COMMON *const cm = &cpi->common;
451 GlobalMotionInfo *const gm_info = &cpi->gm_info;
452
S Hamsalekha7e640e32021-10-14 18:57:11 +0530453 if (cpi->oxcf.tool_cfg.enable_global_motion) {
454 if (cpi->gf_frame_index == 0) {
Remya Prakasan6566bc82021-11-05 23:21:12 +0530455 for (int i = 0; i < FRAME_UPDATE_TYPES; i++) {
S Hamsalekha7e640e32021-10-14 18:57:11 +0530456 cpi->ppi->valid_gm_model_found[i] = INT32_MAX;
Remya Prakasanffeb4972022-06-21 20:00:28 +0530457#if CONFIG_FPMT_TEST
Remya Prakasan6566bc82021-11-05 23:21:12 +0530458 if (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE)
459 cpi->ppi->temp_valid_gm_model_found[i] = INT32_MAX;
460#endif
461 }
S Hamsalekha7e640e32021-10-14 18:57:11 +0530462 }
463 }
464
Remyaefd09fa2020-05-07 15:05:34 +0530465 if (cpi->common.current_frame.frame_type == INTER_FRAME && cpi->source &&
Visheshaa6a1702020-06-30 19:27:22 +0530466 cpi->oxcf.tool_cfg.enable_global_motion && !gm_info->search_done) {
Remyaefd09fa2020-05-07 15:05:34 +0530467 setup_global_motion_info_params(cpi);
468 if (cpi->mt_info.num_workers > 1)
469 av1_global_motion_estimation_mt(cpi);
470 else
471 global_motion_estimation(cpi);
472 gm_info->search_done = 1;
473 }
474 memcpy(cm->cur_frame->global_motion, cm->global_motion,
475 sizeof(cm->cur_frame->global_motion));
476}