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