Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 1 | /* |
| 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" |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 13 | |
Rachel Barker | 53e3a69 | 2022-11-30 15:45:11 +0000 | [diff] [blame] | 14 | #include "aom_dsp/flow_estimation/corner_detect.h" |
| 15 | #include "aom_dsp/flow_estimation/flow_estimation.h" |
Rachel Barker | 674eaa0 | 2022-12-22 16:03:44 +0000 | [diff] [blame] | 16 | #include "aom_dsp/pyramid.h" |
Rachel Barker | 53e3a69 | 2022-11-30 15:45:11 +0000 | [diff] [blame] | 17 | #include "av1/common/warped_motion.h" |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 18 | #include "av1/encoder/encoder.h" |
| 19 | #include "av1/encoder/ethread.h" |
| 20 | #include "av1/encoder/rdopt.h" |
Rachel Barker | 674eaa0 | 2022-12-22 16:03:44 +0000 | [diff] [blame] | 21 | #include "av1/encoder/global_motion_facade.h" |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 22 | |
| 23 | // Highest motion model to search. |
| 24 | #define GLOBAL_TRANS_TYPES_ENC 3 |
| 25 | |
| 26 | // Computes the cost for the warp parameters. |
| 27 | static 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. |
chiyotsai | a6545dd | 2020-07-06 14:20:50 -0700 | [diff] [blame] | 77 | static AOM_INLINE int64_t calc_erroradv_threshold(int64_t ref_frame_error) { |
| 78 | return (int64_t)(ref_frame_error * erroradv_tr + 0.5); |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 79 | } |
| 80 | |
| 81 | // For the given reference frame, computes the global motion parameters for |
| 82 | // different motion models and finds the best. |
| 83 | static AOM_INLINE void compute_global_motion_for_ref_frame( |
| 84 | AV1_COMP *cpi, YV12_BUFFER_CONFIG *ref_buf[REF_FRAMES], int frame, |
Rachel Barker | 738c4f4 | 2023-01-11 17:36:18 +0000 | [diff] [blame] | 85 | MotionModel *motion_models, uint8_t *segment_map, const int segment_map_w, |
| 86 | const int segment_map_h, const WarpedMotionParams *ref_params) { |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 87 | 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 Barker | 5ed9ce5 | 2022-12-15 17:19:18 +0000 | [diff] [blame] | 92 | int src_width = cpi->source->y_crop_width; |
| 93 | int src_height = cpi->source->y_crop_height; |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 94 | int src_stride = cpi->source->y_stride; |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 95 | WarpedMotionParams tmp_wm_params; |
| 96 | const double *params_this_motion; |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 97 | assert(ref_buf[frame] != NULL); |
| 98 | TransformationType model; |
Rachel Barker | 674eaa0 | 2022-12-22 16:03:44 +0000 | [diff] [blame] | 99 | int bit_depth = cpi->common.seq_params->bit_depth; |
Rachel Barker | 6ebcbc1 | 2022-12-20 19:13:26 +0000 | [diff] [blame] | 100 | GlobalMotionMethod global_motion_method = cpi->oxcf.global_motion_method; |
Rachel Barker | a5b228f | 2023-01-16 20:09:45 +0000 | [diff] [blame] | 101 | int num_refinements = cpi->sf.gm_sf.num_refinement_steps; |
Rachel Barker | 674eaa0 | 2022-12-22 16:03:44 +0000 | [diff] [blame] | 102 | |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 103 | for (model = ROTZOOM; model < GLOBAL_TRANS_TYPES_ENC; ++model) { |
Rachel Barker | a02796a | 2023-03-02 20:06:47 +0000 | [diff] [blame] | 104 | 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; |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 108 | } |
| 109 | |
Rachel Barker | 8892c51 | 2023-03-13 22:41:24 +0000 | [diff] [blame] | 110 | int64_t best_ref_frame_error = 0; |
| 111 | int64_t best_warp_error = INT64_MAX; |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 112 | for (i = 0; i < RANSAC_NUM_MOTIONS; ++i) { |
Rachel Barker | 738c4f4 | 2023-01-11 17:36:18 +0000 | [diff] [blame] | 113 | if (motion_models[i].num_inliers == 0) continue; |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 114 | |
Rachel Barker | 738c4f4 | 2023-01-11 17:36:18 +0000 | [diff] [blame] | 115 | params_this_motion = motion_models[i].params; |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 116 | av1_convert_model_to_params(params_this_motion, &tmp_wm_params); |
| 117 | |
Rachel Barker | 8892c51 | 2023-03-13 22:41:24 +0000 | [diff] [blame] | 118 | // 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 Barker | 6496e8d | 2022-09-23 09:40:02 +0000 | [diff] [blame] | 123 | // |
| 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 Barker | 8892c51 | 2023-03-13 22:41:24 +0000 | [diff] [blame] | 128 | if (tmp_wm_params.wmtype <= TRANSLATION) continue; |
Rachel Barker | 6496e8d | 2022-09-23 09:40:02 +0000 | [diff] [blame] | 129 | |
Rachel Barker | 8892c51 | 2023-03-13 22:41:24 +0000 | [diff] [blame] | 130 | av1_compute_feature_segmentation_map( |
| 131 | segment_map, segment_map_w, segment_map_h, motion_models[i].inliers, |
| 132 | motion_models[i].num_inliers); |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 133 | |
Rachel Barker | 8892c51 | 2023-03-13 22:41:24 +0000 | [diff] [blame] | 134 | 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); |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 138 | |
Rachel Barker | 8892c51 | 2023-03-13 22:41:24 +0000 | [diff] [blame] | 139 | if (ref_frame_error == 0) continue; |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 140 | |
Rachel Barker | 8892c51 | 2023-03-13 22:41:24 +0000 | [diff] [blame] | 141 | const int64_t erroradv_threshold = |
| 142 | calc_erroradv_threshold(ref_frame_error); |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 143 | |
Rachel Barker | 8892c51 | 2023-03-13 22:41:24 +0000 | [diff] [blame] | 144 | 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 Barker | 6496e8d | 2022-09-23 09:40:02 +0000 | [diff] [blame] | 151 | |
Rachel Barker | 8892c51 | 2023-03-13 22:41:24 +0000 | [diff] [blame] | 152 | // 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)); |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 164 | } |
| 165 | } |
Rachel Barker | 0d9df42 | 2023-03-07 20:51:55 +0000 | [diff] [blame] | 166 | 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; |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 169 | |
Rachel Barker | 6496e8d | 2022-09-23 09:40:02 +0000 | [diff] [blame] | 170 | #if 0 |
| 171 | // We never choose translational models, so this code is disabled |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 172 | 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 Barker | 6496e8d | 2022-09-23 09:40:02 +0000 | [diff] [blame] | 182 | #endif |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 183 | |
| 184 | if (cm->global_motion[frame].wmtype == IDENTITY) continue; |
| 185 | |
Rachel Barker | 8892c51 | 2023-03-13 22:41:24 +0000 | [diff] [blame] | 186 | // 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); |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 190 | |
| 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 Barker | 8892c51 | 2023-03-13 22:41:24 +0000 | [diff] [blame] | 194 | (double)best_warp_error / best_ref_frame_error, |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 195 | gm_get_params_cost(&cm->global_motion[frame], ref_params, |
chiyotsai | a6545dd | 2020-07-06 14:20:50 -0700 | [diff] [blame] | 196 | cm->features.allow_high_precision_mv))) { |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 197 | cm->global_motion[frame] = default_warp_params; |
| 198 | } |
| 199 | |
| 200 | if (cm->global_motion[frame].wmtype != IDENTITY) break; |
| 201 | } |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 202 | } |
| 203 | |
| 204 | // Computes global motion for the given reference frame. |
| 205 | void av1_compute_gm_for_valid_ref_frames( |
| 206 | AV1_COMP *cpi, YV12_BUFFER_CONFIG *ref_buf[REF_FRAMES], int frame, |
Rachel Barker | 738c4f4 | 2023-01-11 17:36:18 +0000 | [diff] [blame] | 207 | MotionModel *motion_models, uint8_t *segment_map, int segment_map_w, |
Rachel Barker | 2722ce6 | 2022-12-19 15:38:55 +0000 | [diff] [blame] | 208 | int segment_map_h) { |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 209 | AV1_COMMON *const cm = &cpi->common; |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 210 | const WarpedMotionParams *ref_params = |
| 211 | cm->prev_frame ? &cm->prev_frame->global_motion[frame] |
| 212 | : &default_warp_params; |
| 213 | |
Rachel Barker | 738c4f4 | 2023-01-11 17:36:18 +0000 | [diff] [blame] | 214 | compute_global_motion_for_ref_frame(cpi, ref_buf, frame, motion_models, |
Rachel Barker | 2722ce6 | 2022-12-19 15:38:55 +0000 | [diff] [blame] | 215 | segment_map, segment_map_w, segment_map_h, |
| 216 | ref_params); |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 217 | } |
| 218 | |
| 219 | // Loops over valid reference frames and computes global motion estimation. |
| 220 | static 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 Barker | 738c4f4 | 2023-01-11 17:36:18 +0000 | [diff] [blame] | 223 | MotionModel *motion_models, uint8_t *segment_map, const int segment_map_w, |
| 224 | const int segment_map_h) { |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 225 | 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 Barker | 738c4f4 | 2023-01-11 17:36:18 +0000 | [diff] [blame] | 230 | av1_compute_gm_for_valid_ref_frames(cpi, ref_buf, ref_frame, motion_models, |
| 231 | segment_map, segment_map_w, |
| 232 | segment_map_h); |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 233 | // If global motion w.r.t. current ref frame is |
| 234 | // INVALID/TRANSLATION/IDENTITY, skip the evaluation of global motion w.r.t |
Rachel Barker | 277c8ce | 2023-01-25 16:11:07 +0000 | [diff] [blame] | 235 | // the remaining ref frames in that direction. |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 236 | if (cpi->sf.gm_sf.prune_ref_frame_for_gm_search && |
Rachel Barker | 8892c51 | 2023-03-13 22:41:24 +0000 | [diff] [blame] | 237 | cm->global_motion[ref_frame].wmtype <= TRANSLATION) |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 238 | 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. |
| 244 | static 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 Hamsalekha | 7e640e3 | 2021-10-14 18:57:11 +0530 | [diff] [blame] | 254 | static 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 Chang | 50f9377 | 2022-03-30 18:23:50 -0700 | [diff] [blame] | 264 | // at least 1 frame each of ARF_UPDATE, INTNL_ARF_UPDATE and LF_UPDATE are |
S Hamsalekha | 7e640e3 | 2021-10-14 18:57:11 +0530 | [diff] [blame] | 265 | // 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 | |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 275 | // Prunes reference frames for global motion estimation based on the speed |
| 276 | // feature 'gm_search_type'. |
| 277 | static 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'. |
| 294 | static 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; |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 299 | int *num_past_ref_frames = &num_ref_frames[0]; |
| 300 | int *num_future_ref_frames = &num_ref_frames[1]; |
Mufaddal Chakera | 8ee04fa | 2021-03-17 13:33:18 +0530 | [diff] [blame] | 301 | const GF_GROUP *gf_group = &cpi->ppi->gf_group; |
Deepa K G | 39141dd | 2020-07-31 18:53:08 +0530 | [diff] [blame] | 302 | int ref_pruning_enabled = is_frame_eligible_for_ref_pruning( |
Mufaddal Chakera | ab20d37 | 2021-03-17 12:18:34 +0530 | [diff] [blame] | 303 | gf_group, cpi->sf.inter_sf.selective_ref_frame, 1, cpi->gf_frame_index); |
S Hamsalekha | 7e640e3 | 2021-10-14 18:57:11 +0530 | [diff] [blame] | 304 | 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 G | 39141dd | 2020-07-31 18:53:08 +0530 | [diff] [blame] | 309 | |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 310 | 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)) { |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 320 | continue; |
| 321 | } else { |
| 322 | ref_buf[frame] = &buf->buf; |
| 323 | } |
| 324 | |
Deepa K G | 39141dd | 2020-07-31 18:53:08 +0530 | [diff] [blame] | 325 | 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 | |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 330 | 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 Hamsalekha | 7e640e3 | 2021-10-14 18:57:11 +0530 | [diff] [blame] | 332 | do_gm_search_logic(&cpi->sf, frame) && !prune_ref_frames && |
| 333 | !cur_frame_gm_disabled) { |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 334 | assert(ref_buf[frame] != NULL); |
Hui Su | 8438c69 | 2020-10-09 13:54:56 -0700 | [diff] [blame] | 335 | const int relative_frame_dist = av1_encoder_get_relative_dist( |
| 336 | buf->display_order_hint, cm->cur_frame->display_order_hint); |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 337 | // Populate past and future ref frames. |
| 338 | // reference_frames[0][] indicates past direction and |
| 339 | // reference_frames[1][] indicates future direction. |
Rachel Barker | 277c8ce | 2023-01-25 16:11:07 +0000 | [diff] [blame] | 340 | 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) { |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 347 | 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 | |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 361 | // Deallocates segment_map and inliers. |
Rachel Barker | 738c4f4 | 2023-01-11 17:36:18 +0000 | [diff] [blame] | 362 | static AOM_INLINE void dealloc_global_motion_data(MotionModel *motion_models, |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 363 | uint8_t *segment_map) { |
| 364 | aom_free(segment_map); |
| 365 | |
| 366 | for (int m = 0; m < RANSAC_NUM_MOTIONS; m++) { |
Rachel Barker | 738c4f4 | 2023-01-11 17:36:18 +0000 | [diff] [blame] | 367 | aom_free(motion_models[m].inliers); |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 368 | } |
| 369 | } |
| 370 | |
James Zern | 723bbf9 | 2022-04-28 12:54:06 -0700 | [diff] [blame] | 371 | // Allocates and initializes memory for segment_map and MotionModel. |
Rachel Barker | 738c4f4 | 2023-01-11 17:36:18 +0000 | [diff] [blame] | 372 | static AOM_INLINE bool alloc_global_motion_data(MotionModel *motion_models, |
James Zern | 723bbf9 | 2022-04-28 12:54:06 -0700 | [diff] [blame] | 373 | uint8_t **segment_map, |
| 374 | const int segment_map_w, |
| 375 | const int segment_map_h) { |
Rachel Barker | 738c4f4 | 2023-01-11 17:36:18 +0000 | [diff] [blame] | 376 | av1_zero_array(motion_models, RANSAC_NUM_MOTIONS); |
James Zern | 723bbf9 | 2022-04-28 12:54:06 -0700 | [diff] [blame] | 377 | for (int m = 0; m < RANSAC_NUM_MOTIONS; m++) { |
Rachel Barker | 738c4f4 | 2023-01-11 17:36:18 +0000 | [diff] [blame] | 378 | 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 Zern | 723bbf9 | 2022-04-28 12:54:06 -0700 | [diff] [blame] | 382 | 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 Barker | 738c4f4 | 2023-01-11 17:36:18 +0000 | [diff] [blame] | 389 | dealloc_global_motion_data(motion_models, NULL); |
James Zern | 723bbf9 | 2022-04-28 12:54:06 -0700 | [diff] [blame] | 390 | return false; |
| 391 | } |
| 392 | return true; |
| 393 | } |
| 394 | |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 395 | // Initializes parameters used for computing global motion. |
| 396 | static 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 | |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 400 | gm_info->segment_map_w = |
Rachel Barker | 5ed9ce5 | 2022-12-15 17:19:18 +0000 | [diff] [blame] | 401 | (source->y_crop_width + WARP_ERROR_BLOCK - 1) >> WARP_ERROR_BLOCK_LOG; |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 402 | gm_info->segment_map_h = |
Rachel Barker | 5ed9ce5 | 2022-12-15 17:19:18 +0000 | [diff] [blame] | 403 | (source->y_crop_height + WARP_ERROR_BLOCK - 1) >> WARP_ERROR_BLOCK_LOG; |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 404 | |
| 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); |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 422 | } |
| 423 | |
| 424 | // Computes global motion w.r.t. valid reference frames. |
| 425 | static AOM_INLINE void global_motion_estimation(AV1_COMP *cpi) { |
| 426 | GlobalMotionInfo *const gm_info = &cpi->gm_info; |
Rachel Barker | 738c4f4 | 2023-01-11 17:36:18 +0000 | [diff] [blame] | 427 | MotionModel motion_models[RANSAC_NUM_MOTIONS]; |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 428 | uint8_t *segment_map = NULL; |
| 429 | |
Rachel Barker | 738c4f4 | 2023-01-11 17:36:18 +0000 | [diff] [blame] | 430 | alloc_global_motion_data(motion_models, &segment_map, gm_info->segment_map_w, |
| 431 | gm_info->segment_map_h); |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 432 | |
| 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 Barker | 738c4f4 | 2023-01-11 17:36:18 +0000 | [diff] [blame] | 439 | gm_info->num_ref_frames[dir], motion_models, segment_map, |
Rachel Barker | 674eaa0 | 2022-12-22 16:03:44 +0000 | [diff] [blame] | 440 | gm_info->segment_map_w, gm_info->segment_map_h); |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 441 | } |
| 442 | |
Rachel Barker | 738c4f4 | 2023-01-11 17:36:18 +0000 | [diff] [blame] | 443 | dealloc_global_motion_data(motion_models, segment_map); |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 444 | } |
| 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. |
| 449 | void 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 Hamsalekha | 7e640e3 | 2021-10-14 18:57:11 +0530 | [diff] [blame] | 453 | if (cpi->oxcf.tool_cfg.enable_global_motion) { |
| 454 | if (cpi->gf_frame_index == 0) { |
Remya Prakasan | 6566bc8 | 2021-11-05 23:21:12 +0530 | [diff] [blame] | 455 | for (int i = 0; i < FRAME_UPDATE_TYPES; i++) { |
S Hamsalekha | 7e640e3 | 2021-10-14 18:57:11 +0530 | [diff] [blame] | 456 | cpi->ppi->valid_gm_model_found[i] = INT32_MAX; |
Remya Prakasan | ffeb497 | 2022-06-21 20:00:28 +0530 | [diff] [blame] | 457 | #if CONFIG_FPMT_TEST |
Remya Prakasan | 6566bc8 | 2021-11-05 23:21:12 +0530 | [diff] [blame] | 458 | 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 Hamsalekha | 7e640e3 | 2021-10-14 18:57:11 +0530 | [diff] [blame] | 462 | } |
| 463 | } |
| 464 | |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 465 | if (cpi->common.current_frame.frame_type == INTER_FRAME && cpi->source && |
Vishesh | aa6a170 | 2020-06-30 19:27:22 +0530 | [diff] [blame] | 466 | cpi->oxcf.tool_cfg.enable_global_motion && !gm_info->search_done) { |
Remya | efd09fa | 2020-05-07 15:05:34 +0530 | [diff] [blame] | 467 | 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 | } |