/src/aom/av1/encoder/global_motion_facade.c
Line | Count | Source (jump to first uncovered line) |
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" |
13 | | |
14 | | #include "av1/encoder/corner_detect.h" |
15 | | #include "av1/encoder/encoder.h" |
16 | | #include "av1/encoder/ethread.h" |
17 | | #include "av1/encoder/rdopt.h" |
18 | | |
19 | | // Highest motion model to search. |
20 | 0 | #define GLOBAL_TRANS_TYPES_ENC 3 |
21 | | |
22 | | // Computes the cost for the warp parameters. |
23 | | static int gm_get_params_cost(const WarpedMotionParams *gm, |
24 | 0 | const WarpedMotionParams *ref_gm, int allow_hp) { |
25 | 0 | int params_cost = 0; |
26 | 0 | int trans_bits, trans_prec_diff; |
27 | 0 | switch (gm->wmtype) { |
28 | 0 | case AFFINE: |
29 | 0 | case ROTZOOM: |
30 | 0 | params_cost += aom_count_signed_primitive_refsubexpfin( |
31 | 0 | GM_ALPHA_MAX + 1, SUBEXPFIN_K, |
32 | 0 | (ref_gm->wmmat[2] >> GM_ALPHA_PREC_DIFF) - (1 << GM_ALPHA_PREC_BITS), |
33 | 0 | (gm->wmmat[2] >> GM_ALPHA_PREC_DIFF) - (1 << GM_ALPHA_PREC_BITS)); |
34 | 0 | params_cost += aom_count_signed_primitive_refsubexpfin( |
35 | 0 | GM_ALPHA_MAX + 1, SUBEXPFIN_K, |
36 | 0 | (ref_gm->wmmat[3] >> GM_ALPHA_PREC_DIFF), |
37 | 0 | (gm->wmmat[3] >> GM_ALPHA_PREC_DIFF)); |
38 | 0 | if (gm->wmtype >= AFFINE) { |
39 | 0 | params_cost += aom_count_signed_primitive_refsubexpfin( |
40 | 0 | GM_ALPHA_MAX + 1, SUBEXPFIN_K, |
41 | 0 | (ref_gm->wmmat[4] >> GM_ALPHA_PREC_DIFF), |
42 | 0 | (gm->wmmat[4] >> GM_ALPHA_PREC_DIFF)); |
43 | 0 | params_cost += aom_count_signed_primitive_refsubexpfin( |
44 | 0 | GM_ALPHA_MAX + 1, SUBEXPFIN_K, |
45 | 0 | (ref_gm->wmmat[5] >> GM_ALPHA_PREC_DIFF) - |
46 | 0 | (1 << GM_ALPHA_PREC_BITS), |
47 | 0 | (gm->wmmat[5] >> GM_ALPHA_PREC_DIFF) - (1 << GM_ALPHA_PREC_BITS)); |
48 | 0 | } |
49 | 0 | AOM_FALLTHROUGH_INTENDED; |
50 | 0 | case TRANSLATION: |
51 | 0 | trans_bits = (gm->wmtype == TRANSLATION) |
52 | 0 | ? GM_ABS_TRANS_ONLY_BITS - !allow_hp |
53 | 0 | : GM_ABS_TRANS_BITS; |
54 | 0 | trans_prec_diff = (gm->wmtype == TRANSLATION) |
55 | 0 | ? GM_TRANS_ONLY_PREC_DIFF + !allow_hp |
56 | 0 | : GM_TRANS_PREC_DIFF; |
57 | 0 | params_cost += aom_count_signed_primitive_refsubexpfin( |
58 | 0 | (1 << trans_bits) + 1, SUBEXPFIN_K, |
59 | 0 | (ref_gm->wmmat[0] >> trans_prec_diff), |
60 | 0 | (gm->wmmat[0] >> trans_prec_diff)); |
61 | 0 | params_cost += aom_count_signed_primitive_refsubexpfin( |
62 | 0 | (1 << trans_bits) + 1, SUBEXPFIN_K, |
63 | 0 | (ref_gm->wmmat[1] >> trans_prec_diff), |
64 | 0 | (gm->wmmat[1] >> trans_prec_diff)); |
65 | 0 | AOM_FALLTHROUGH_INTENDED; |
66 | 0 | case IDENTITY: break; |
67 | 0 | default: assert(0); |
68 | 0 | } |
69 | 0 | return (params_cost << AV1_PROB_COST_SHIFT); |
70 | 0 | } |
71 | | |
72 | | // Calculates the threshold to be used for warp error computation. |
73 | 0 | static AOM_INLINE int64_t calc_erroradv_threshold(int64_t ref_frame_error) { |
74 | 0 | return (int64_t)(ref_frame_error * erroradv_tr + 0.5); |
75 | 0 | } |
76 | | |
77 | | // For the given reference frame, computes the global motion parameters for |
78 | | // different motion models and finds the best. |
79 | | static AOM_INLINE void compute_global_motion_for_ref_frame( |
80 | | AV1_COMP *cpi, YV12_BUFFER_CONFIG *ref_buf[REF_FRAMES], int frame, |
81 | | int num_src_corners, int *src_corners, unsigned char *src_buffer, |
82 | | MotionModel *params_by_motion, uint8_t *segment_map, |
83 | | const int segment_map_w, const int segment_map_h, |
84 | 0 | const WarpedMotionParams *ref_params) { |
85 | 0 | ThreadData *const td = &cpi->td; |
86 | 0 | MACROBLOCK *const x = &td->mb; |
87 | 0 | AV1_COMMON *const cm = &cpi->common; |
88 | 0 | MACROBLOCKD *const xd = &x->e_mbd; |
89 | 0 | int i; |
90 | 0 | int src_width = cpi->source->y_width; |
91 | 0 | int src_height = cpi->source->y_height; |
92 | 0 | int src_stride = cpi->source->y_stride; |
93 | | // clang-format off |
94 | 0 | static const double kIdentityParams[MAX_PARAMDIM - 1] = { |
95 | 0 | 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0 |
96 | 0 | }; |
97 | | // clang-format on |
98 | 0 | WarpedMotionParams tmp_wm_params; |
99 | 0 | const double *params_this_motion; |
100 | 0 | int inliers_by_motion[RANSAC_NUM_MOTIONS]; |
101 | 0 | assert(ref_buf[frame] != NULL); |
102 | 0 | TransformationType model; |
103 | | |
104 | | // TODO(sarahparker, debargha): Explore do_adaptive_gm_estimation = 1 |
105 | 0 | const int do_adaptive_gm_estimation = 0; |
106 | |
|
107 | 0 | const int ref_frame_dist = get_relative_dist( |
108 | 0 | &cm->seq_params->order_hint_info, cm->current_frame.order_hint, |
109 | 0 | cm->cur_frame->ref_order_hints[frame - LAST_FRAME]); |
110 | 0 | const GlobalMotionEstimationType gm_estimation_type = |
111 | 0 | cm->seq_params->order_hint_info.enable_order_hint && |
112 | 0 | abs(ref_frame_dist) <= 2 && do_adaptive_gm_estimation |
113 | 0 | ? GLOBAL_MOTION_DISFLOW_BASED |
114 | 0 | : GLOBAL_MOTION_FEATURE_BASED; |
115 | 0 | for (model = ROTZOOM; model < GLOBAL_TRANS_TYPES_ENC; ++model) { |
116 | 0 | int64_t best_warp_error = INT64_MAX; |
117 | | // Initially set all params to identity. |
118 | 0 | for (i = 0; i < RANSAC_NUM_MOTIONS; ++i) { |
119 | 0 | memcpy(params_by_motion[i].params, kIdentityParams, |
120 | 0 | (MAX_PARAMDIM - 1) * sizeof(*(params_by_motion[i].params))); |
121 | 0 | params_by_motion[i].num_inliers = 0; |
122 | 0 | } |
123 | |
|
124 | 0 | av1_compute_global_motion(model, src_buffer, src_width, src_height, |
125 | 0 | src_stride, src_corners, num_src_corners, |
126 | 0 | ref_buf[frame], cpi->common.seq_params->bit_depth, |
127 | 0 | gm_estimation_type, inliers_by_motion, |
128 | 0 | params_by_motion, RANSAC_NUM_MOTIONS); |
129 | 0 | int64_t ref_frame_error = 0; |
130 | 0 | for (i = 0; i < RANSAC_NUM_MOTIONS; ++i) { |
131 | 0 | if (inliers_by_motion[i] == 0) continue; |
132 | | |
133 | 0 | params_this_motion = params_by_motion[i].params; |
134 | 0 | av1_convert_model_to_params(params_this_motion, &tmp_wm_params); |
135 | |
|
136 | 0 | if (tmp_wm_params.wmtype != IDENTITY) { |
137 | 0 | av1_compute_feature_segmentation_map( |
138 | 0 | segment_map, segment_map_w, segment_map_h, |
139 | 0 | params_by_motion[i].inliers, params_by_motion[i].num_inliers); |
140 | |
|
141 | 0 | ref_frame_error = av1_segmented_frame_error( |
142 | 0 | is_cur_buf_hbd(xd), xd->bd, ref_buf[frame]->y_buffer, |
143 | 0 | ref_buf[frame]->y_stride, cpi->source->y_buffer, src_width, |
144 | 0 | src_height, src_stride, segment_map, segment_map_w); |
145 | |
|
146 | 0 | const int64_t erroradv_threshold = |
147 | 0 | calc_erroradv_threshold(ref_frame_error); |
148 | |
|
149 | 0 | const int64_t warp_error = av1_refine_integerized_param( |
150 | 0 | &tmp_wm_params, tmp_wm_params.wmtype, is_cur_buf_hbd(xd), xd->bd, |
151 | 0 | ref_buf[frame]->y_buffer, ref_buf[frame]->y_width, |
152 | 0 | ref_buf[frame]->y_height, ref_buf[frame]->y_stride, |
153 | 0 | cpi->source->y_buffer, src_width, src_height, src_stride, |
154 | 0 | GM_REFINEMENT_COUNT, best_warp_error, segment_map, segment_map_w, |
155 | 0 | erroradv_threshold); |
156 | |
|
157 | 0 | if (warp_error < best_warp_error) { |
158 | 0 | 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 | 0 | memcpy(&(cm->global_motion[frame]), &tmp_wm_params, |
163 | 0 | sizeof(WarpedMotionParams)); |
164 | 0 | } |
165 | 0 | } |
166 | 0 | } |
167 | 0 | if (cm->global_motion[frame].wmtype <= AFFINE) |
168 | 0 | if (!av1_get_shear_params(&cm->global_motion[frame])) |
169 | 0 | cm->global_motion[frame] = default_warp_params; |
170 | |
|
171 | 0 | if (cm->global_motion[frame].wmtype == TRANSLATION) { |
172 | 0 | cm->global_motion[frame].wmmat[0] = |
173 | 0 | convert_to_trans_prec(cm->features.allow_high_precision_mv, |
174 | 0 | cm->global_motion[frame].wmmat[0]) * |
175 | 0 | GM_TRANS_ONLY_DECODE_FACTOR; |
176 | 0 | cm->global_motion[frame].wmmat[1] = |
177 | 0 | convert_to_trans_prec(cm->features.allow_high_precision_mv, |
178 | 0 | cm->global_motion[frame].wmmat[1]) * |
179 | 0 | GM_TRANS_ONLY_DECODE_FACTOR; |
180 | 0 | } |
181 | |
|
182 | 0 | if (cm->global_motion[frame].wmtype == IDENTITY) continue; |
183 | | |
184 | 0 | if (ref_frame_error == 0) continue; |
185 | | |
186 | | // If the best error advantage found doesn't meet the threshold for |
187 | | // this motion type, revert to IDENTITY. |
188 | 0 | if (!av1_is_enough_erroradvantage( |
189 | 0 | (double)best_warp_error / ref_frame_error, |
190 | 0 | gm_get_params_cost(&cm->global_motion[frame], ref_params, |
191 | 0 | cm->features.allow_high_precision_mv))) { |
192 | 0 | cm->global_motion[frame] = default_warp_params; |
193 | 0 | } |
194 | |
|
195 | 0 | if (cm->global_motion[frame].wmtype != IDENTITY) break; |
196 | 0 | } |
197 | 0 | } |
198 | | |
199 | | // Computes global motion for the given reference frame. |
200 | | void av1_compute_gm_for_valid_ref_frames( |
201 | | AV1_COMP *cpi, YV12_BUFFER_CONFIG *ref_buf[REF_FRAMES], int frame, |
202 | | int num_src_corners, int *src_corners, unsigned char *src_buffer, |
203 | | MotionModel *params_by_motion, uint8_t *segment_map, int segment_map_w, |
204 | 0 | int segment_map_h) { |
205 | 0 | AV1_COMMON *const cm = &cpi->common; |
206 | 0 | const WarpedMotionParams *ref_params = |
207 | 0 | cm->prev_frame ? &cm->prev_frame->global_motion[frame] |
208 | 0 | : &default_warp_params; |
209 | |
|
210 | 0 | compute_global_motion_for_ref_frame( |
211 | 0 | cpi, ref_buf, frame, num_src_corners, src_corners, src_buffer, |
212 | 0 | params_by_motion, segment_map, segment_map_w, segment_map_h, ref_params); |
213 | 0 | } |
214 | | |
215 | | // Loops over valid reference frames and computes global motion estimation. |
216 | | static AOM_INLINE void compute_global_motion_for_references( |
217 | | AV1_COMP *cpi, YV12_BUFFER_CONFIG *ref_buf[REF_FRAMES], |
218 | | FrameDistPair reference_frame[REF_FRAMES - 1], int num_ref_frames, |
219 | | int num_src_corners, int *src_corners, unsigned char *src_buffer, |
220 | | MotionModel *params_by_motion, uint8_t *segment_map, |
221 | 0 | const int segment_map_w, const int segment_map_h) { |
222 | | // Computation of frame corners for the source frame will be done already. |
223 | 0 | assert(num_src_corners != -1); |
224 | 0 | AV1_COMMON *const cm = &cpi->common; |
225 | | // Compute global motion w.r.t. reference frames starting from the nearest ref |
226 | | // frame in a given direction. |
227 | 0 | for (int frame = 0; frame < num_ref_frames; frame++) { |
228 | 0 | int ref_frame = reference_frame[frame].frame; |
229 | 0 | av1_compute_gm_for_valid_ref_frames( |
230 | 0 | cpi, ref_buf, ref_frame, num_src_corners, src_corners, src_buffer, |
231 | 0 | params_by_motion, segment_map, segment_map_w, segment_map_h); |
232 | | // If global motion w.r.t. current ref frame is |
233 | | // INVALID/TRANSLATION/IDENTITY, skip the evaluation of global motion w.r.t |
234 | | // the remaining ref frames in that direction. The below exit is disabled |
235 | | // when ref frame distance w.r.t. current frame is zero. E.g.: |
236 | | // source_alt_ref_frame w.r.t. ARF frames. |
237 | 0 | if (cpi->sf.gm_sf.prune_ref_frame_for_gm_search && |
238 | 0 | reference_frame[frame].distance != 0 && |
239 | 0 | cm->global_motion[ref_frame].wmtype != ROTZOOM) |
240 | 0 | break; |
241 | 0 | } |
242 | 0 | } |
243 | | |
244 | | // Compares the distance in 'a' and 'b'. Returns 1 if the frame corresponding to |
245 | | // 'a' is farther, -1 if the frame corresponding to 'b' is farther, 0 otherwise. |
246 | 0 | static int compare_distance(const void *a, const void *b) { |
247 | 0 | const int diff = |
248 | 0 | ((FrameDistPair *)a)->distance - ((FrameDistPair *)b)->distance; |
249 | 0 | if (diff > 0) |
250 | 0 | return 1; |
251 | 0 | else if (diff < 0) |
252 | 0 | return -1; |
253 | 0 | return 0; |
254 | 0 | } |
255 | | |
256 | 0 | static int disable_gm_search_based_on_stats(const AV1_COMP *const cpi) { |
257 | 0 | int is_gm_present = 1; |
258 | | |
259 | | // Check number of GM models only in GF groups with ARF frames. GM param |
260 | | // estimation is always done in the case of GF groups with no ARF frames (flat |
261 | | // gops) |
262 | 0 | if (cpi->ppi->gf_group.arf_index > -1) { |
263 | | // valid_gm_model_found is initialized to INT32_MAX in the beginning of |
264 | | // every GF group. |
265 | | // Therefore, GM param estimation is always done for all frames until |
266 | | // atleast 1 frame each of ARF_UPDATE, INTNL_ARF_UPDATE and LF_UPDATE are |
267 | | // encoded in a GF group For subsequent frames, GM param estimation is |
268 | | // disabled, if no valid models have been found in all the three update |
269 | | // types. |
270 | 0 | is_gm_present = (cpi->ppi->valid_gm_model_found[ARF_UPDATE] != 0) || |
271 | 0 | (cpi->ppi->valid_gm_model_found[INTNL_ARF_UPDATE] != 0) || |
272 | 0 | (cpi->ppi->valid_gm_model_found[LF_UPDATE] != 0); |
273 | 0 | } |
274 | 0 | return !is_gm_present; |
275 | 0 | } |
276 | | |
277 | | // Prunes reference frames for global motion estimation based on the speed |
278 | | // feature 'gm_search_type'. |
279 | 0 | static int do_gm_search_logic(SPEED_FEATURES *const sf, int frame) { |
280 | 0 | (void)frame; |
281 | 0 | switch (sf->gm_sf.gm_search_type) { |
282 | 0 | case GM_FULL_SEARCH: return 1; |
283 | 0 | case GM_REDUCED_REF_SEARCH_SKIP_L2_L3: |
284 | 0 | return !(frame == LAST2_FRAME || frame == LAST3_FRAME); |
285 | 0 | case GM_REDUCED_REF_SEARCH_SKIP_L2_L3_ARF2: |
286 | 0 | return !(frame == LAST2_FRAME || frame == LAST3_FRAME || |
287 | 0 | (frame == ALTREF2_FRAME)); |
288 | 0 | case GM_DISABLE_SEARCH: return 0; |
289 | 0 | default: assert(0); |
290 | 0 | } |
291 | 0 | return 1; |
292 | 0 | } |
293 | | |
294 | | // Populates valid reference frames in past/future directions in |
295 | | // 'reference_frames' and their count in 'num_ref_frames'. |
296 | | static AOM_INLINE void update_valid_ref_frames_for_gm( |
297 | | AV1_COMP *cpi, YV12_BUFFER_CONFIG *ref_buf[REF_FRAMES], |
298 | | FrameDistPair reference_frames[MAX_DIRECTIONS][REF_FRAMES - 1], |
299 | 0 | int *num_ref_frames) { |
300 | 0 | AV1_COMMON *const cm = &cpi->common; |
301 | 0 | int *num_past_ref_frames = &num_ref_frames[0]; |
302 | 0 | int *num_future_ref_frames = &num_ref_frames[1]; |
303 | 0 | const GF_GROUP *gf_group = &cpi->ppi->gf_group; |
304 | 0 | int ref_pruning_enabled = is_frame_eligible_for_ref_pruning( |
305 | 0 | gf_group, cpi->sf.inter_sf.selective_ref_frame, 1, cpi->gf_frame_index); |
306 | 0 | int cur_frame_gm_disabled = 0; |
307 | |
|
308 | 0 | if (cpi->sf.gm_sf.disable_gm_search_based_on_stats) { |
309 | 0 | cur_frame_gm_disabled = disable_gm_search_based_on_stats(cpi); |
310 | 0 | } |
311 | |
|
312 | 0 | for (int frame = ALTREF_FRAME; frame >= LAST_FRAME; --frame) { |
313 | 0 | const MV_REFERENCE_FRAME ref_frame[2] = { frame, NONE_FRAME }; |
314 | 0 | RefCntBuffer *buf = get_ref_frame_buf(cm, frame); |
315 | 0 | const int ref_disabled = |
316 | 0 | !(cpi->ref_frame_flags & av1_ref_frame_flag_list[frame]); |
317 | 0 | ref_buf[frame] = NULL; |
318 | 0 | cm->global_motion[frame] = default_warp_params; |
319 | | // Skip global motion estimation for invalid ref frames |
320 | 0 | if (buf == NULL || |
321 | 0 | (ref_disabled && cpi->sf.hl_sf.recode_loop != DISALLOW_RECODE)) { |
322 | 0 | continue; |
323 | 0 | } else { |
324 | 0 | ref_buf[frame] = &buf->buf; |
325 | 0 | } |
326 | | |
327 | 0 | int prune_ref_frames = |
328 | 0 | ref_pruning_enabled && |
329 | 0 | prune_ref_by_selective_ref_frame(cpi, NULL, ref_frame, |
330 | 0 | cm->cur_frame->ref_display_order_hint); |
331 | |
|
332 | 0 | if (ref_buf[frame]->y_crop_width == cpi->source->y_crop_width && |
333 | 0 | ref_buf[frame]->y_crop_height == cpi->source->y_crop_height && |
334 | 0 | do_gm_search_logic(&cpi->sf, frame) && !prune_ref_frames && |
335 | 0 | !cur_frame_gm_disabled) { |
336 | 0 | assert(ref_buf[frame] != NULL); |
337 | 0 | const int relative_frame_dist = av1_encoder_get_relative_dist( |
338 | 0 | buf->display_order_hint, cm->cur_frame->display_order_hint); |
339 | | // Populate past and future ref frames. |
340 | | // reference_frames[0][] indicates past direction and |
341 | | // reference_frames[1][] indicates future direction. |
342 | 0 | if (relative_frame_dist <= 0) { |
343 | 0 | reference_frames[0][*num_past_ref_frames].distance = |
344 | 0 | abs(relative_frame_dist); |
345 | 0 | reference_frames[0][*num_past_ref_frames].frame = frame; |
346 | 0 | (*num_past_ref_frames)++; |
347 | 0 | } else { |
348 | 0 | reference_frames[1][*num_future_ref_frames].distance = |
349 | 0 | abs(relative_frame_dist); |
350 | 0 | reference_frames[1][*num_future_ref_frames].frame = frame; |
351 | 0 | (*num_future_ref_frames)++; |
352 | 0 | } |
353 | 0 | } |
354 | 0 | } |
355 | 0 | } |
356 | | |
357 | | // Allocates and initializes memory for segment_map and MotionModel. |
358 | | static AOM_INLINE void alloc_global_motion_data(MotionModel *params_by_motion, |
359 | | uint8_t **segment_map, |
360 | | const int segment_map_w, |
361 | 0 | const int segment_map_h) { |
362 | 0 | for (int m = 0; m < RANSAC_NUM_MOTIONS; m++) { |
363 | 0 | av1_zero(params_by_motion[m]); |
364 | 0 | params_by_motion[m].inliers = |
365 | 0 | aom_malloc(sizeof(*(params_by_motion[m].inliers)) * 2 * MAX_CORNERS); |
366 | 0 | } |
367 | |
|
368 | 0 | *segment_map = (uint8_t *)aom_malloc(sizeof(*segment_map) * segment_map_w * |
369 | 0 | segment_map_h); |
370 | 0 | av1_zero_array(*segment_map, segment_map_w * segment_map_h); |
371 | 0 | } |
372 | | |
373 | | // Deallocates segment_map and inliers. |
374 | | static AOM_INLINE void dealloc_global_motion_data(MotionModel *params_by_motion, |
375 | 0 | uint8_t *segment_map) { |
376 | 0 | aom_free(segment_map); |
377 | |
|
378 | 0 | for (int m = 0; m < RANSAC_NUM_MOTIONS; m++) { |
379 | 0 | aom_free(params_by_motion[m].inliers); |
380 | 0 | } |
381 | 0 | } |
382 | | |
383 | | // Initializes parameters used for computing global motion. |
384 | 0 | static AOM_INLINE void setup_global_motion_info_params(AV1_COMP *cpi) { |
385 | 0 | GlobalMotionInfo *const gm_info = &cpi->gm_info; |
386 | 0 | YV12_BUFFER_CONFIG *source = cpi->source; |
387 | |
|
388 | 0 | gm_info->src_buffer = source->y_buffer; |
389 | 0 | if (source->flags & YV12_FLAG_HIGHBITDEPTH) { |
390 | | // The source buffer is 16-bit, so we need to convert to 8 bits for the |
391 | | // following code. We cache the result until the source frame is released. |
392 | 0 | gm_info->src_buffer = |
393 | 0 | av1_downconvert_frame(source, cpi->common.seq_params->bit_depth); |
394 | 0 | } |
395 | |
|
396 | 0 | gm_info->segment_map_w = |
397 | 0 | (source->y_width + WARP_ERROR_BLOCK) >> WARP_ERROR_BLOCK_LOG; |
398 | 0 | gm_info->segment_map_h = |
399 | 0 | (source->y_height + WARP_ERROR_BLOCK) >> WARP_ERROR_BLOCK_LOG; |
400 | |
|
401 | 0 | memset(gm_info->reference_frames, -1, |
402 | 0 | sizeof(gm_info->reference_frames[0][0]) * MAX_DIRECTIONS * |
403 | 0 | (REF_FRAMES - 1)); |
404 | 0 | av1_zero(gm_info->num_ref_frames); |
405 | | |
406 | | // Populate ref_buf for valid ref frames in global motion |
407 | 0 | update_valid_ref_frames_for_gm(cpi, gm_info->ref_buf, |
408 | 0 | gm_info->reference_frames, |
409 | 0 | gm_info->num_ref_frames); |
410 | | |
411 | | // Sort the past and future ref frames in the ascending order of their |
412 | | // distance from the current frame. reference_frames[0] => past direction |
413 | | // and reference_frames[1] => future direction. |
414 | 0 | qsort(gm_info->reference_frames[0], gm_info->num_ref_frames[0], |
415 | 0 | sizeof(gm_info->reference_frames[0][0]), compare_distance); |
416 | 0 | qsort(gm_info->reference_frames[1], gm_info->num_ref_frames[1], |
417 | 0 | sizeof(gm_info->reference_frames[1][0]), compare_distance); |
418 | |
|
419 | 0 | gm_info->num_src_corners = -1; |
420 | | // If atleast one valid reference frame exists in past/future directions, |
421 | | // compute interest points of source frame using FAST features. |
422 | 0 | if (gm_info->num_ref_frames[0] > 0 || gm_info->num_ref_frames[1] > 0) { |
423 | 0 | gm_info->num_src_corners = av1_fast_corner_detect( |
424 | 0 | gm_info->src_buffer, source->y_width, source->y_height, |
425 | 0 | source->y_stride, gm_info->src_corners, MAX_CORNERS); |
426 | 0 | } |
427 | 0 | } |
428 | | |
429 | | // Computes global motion w.r.t. valid reference frames. |
430 | 0 | static AOM_INLINE void global_motion_estimation(AV1_COMP *cpi) { |
431 | 0 | GlobalMotionInfo *const gm_info = &cpi->gm_info; |
432 | 0 | MotionModel params_by_motion[RANSAC_NUM_MOTIONS]; |
433 | 0 | uint8_t *segment_map = NULL; |
434 | |
|
435 | 0 | alloc_global_motion_data(params_by_motion, &segment_map, |
436 | 0 | gm_info->segment_map_w, gm_info->segment_map_h); |
437 | | |
438 | | // Compute global motion w.r.t. past reference frames and future reference |
439 | | // frames |
440 | 0 | for (int dir = 0; dir < MAX_DIRECTIONS; dir++) { |
441 | 0 | if (gm_info->num_ref_frames[dir] > 0) |
442 | 0 | compute_global_motion_for_references( |
443 | 0 | cpi, gm_info->ref_buf, gm_info->reference_frames[dir], |
444 | 0 | gm_info->num_ref_frames[dir], gm_info->num_src_corners, |
445 | 0 | gm_info->src_corners, gm_info->src_buffer, params_by_motion, |
446 | 0 | segment_map, gm_info->segment_map_w, gm_info->segment_map_h); |
447 | 0 | } |
448 | |
|
449 | 0 | dealloc_global_motion_data(params_by_motion, segment_map); |
450 | 0 | } |
451 | | |
452 | | // Global motion estimation for the current frame is computed.This computation |
453 | | // happens once per frame and the winner motion model parameters are stored in |
454 | | // cm->cur_frame->global_motion. |
455 | 1.26k | void av1_compute_global_motion_facade(AV1_COMP *cpi) { |
456 | 1.26k | AV1_COMMON *const cm = &cpi->common; |
457 | 1.26k | GlobalMotionInfo *const gm_info = &cpi->gm_info; |
458 | | |
459 | 1.26k | if (cpi->oxcf.tool_cfg.enable_global_motion) { |
460 | 1.26k | if (cpi->gf_frame_index == 0) { |
461 | 10.0k | for (int i = 0; i < FRAME_UPDATE_TYPES; i++) { |
462 | 8.83k | cpi->ppi->valid_gm_model_found[i] = INT32_MAX; |
463 | | #if CONFIG_FRAME_PARALLEL_ENCODE && CONFIG_FPMT_TEST |
464 | | if (cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) |
465 | | cpi->ppi->temp_valid_gm_model_found[i] = INT32_MAX; |
466 | | #endif |
467 | 8.83k | } |
468 | 1.26k | } |
469 | 1.26k | } |
470 | | |
471 | 1.26k | if (cpi->common.current_frame.frame_type == INTER_FRAME && cpi->source && |
472 | 1.26k | cpi->oxcf.tool_cfg.enable_global_motion && !gm_info->search_done) { |
473 | 0 | setup_global_motion_info_params(cpi); |
474 | 0 | if (cpi->mt_info.num_workers > 1) |
475 | 0 | av1_global_motion_estimation_mt(cpi); |
476 | 0 | else |
477 | 0 | global_motion_estimation(cpi); |
478 | 0 | gm_info->search_done = 1; |
479 | 0 | } |
480 | 1.26k | memcpy(cm->cur_frame->global_motion, cm->global_motion, |
481 | 1.26k | sizeof(cm->cur_frame->global_motion)); |
482 | 1.26k | } |