| /* |
| * Copyright (c) 2021, Alliance for Open Media. All rights reserved |
| * |
| * This source code is subject to the terms of the BSD 3-Clause Clear License |
| * and the Alliance for Open Media Patent License 1.0. If the BSD 3-Clause Clear |
| * License was not distributed with this source code in the LICENSE file, you |
| * can obtain it at aomedia.org/license/software-license/bsd-3-c-c/. If the |
| * Alliance for Open Media Patent License 1.0 was not distributed with this |
| * source code in the PATENTS file, you can obtain it at |
| * aomedia.org/license/patent-license/. |
| */ |
| |
| #ifndef AOM_AV1_ENCODER_MCOMP_H_ |
| #define AOM_AV1_ENCODER_MCOMP_H_ |
| |
| #include "av1/common/mv.h" |
| #include "av1/encoder/block.h" |
| #if CONFIG_ADAPTIVE_MVD || CONFIG_JOINT_MVD |
| #include "av1/common/reconinter.h" |
| #endif // CONFIG_ADAPTIVE_MVD || CONFIG_JOINT_MVD |
| |
| #include "aom_dsp/variance.h" |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| // The maximum number of steps in a step search given the largest |
| // allowed initial step |
| #define MAX_MVSEARCH_STEPS 11 |
| // Max full pel mv specified in the unit of full pixel |
| // Enable the use of motion vector in range [-1023, 1023]. |
| #define MAX_FULL_PEL_VAL ((1 << (MAX_MVSEARCH_STEPS - 1)) - 1) |
| // Maximum size of the first step in full pel units |
| #define MAX_FIRST_STEP (1 << (MAX_MVSEARCH_STEPS - 1)) |
| |
| #define SEARCH_RANGE_8P 3 |
| #define SEARCH_GRID_STRIDE_8P (2 * SEARCH_RANGE_8P + 1) |
| #define SEARCH_GRID_CENTER_8P \ |
| (SEARCH_RANGE_8P * SEARCH_GRID_STRIDE_8P + SEARCH_RANGE_8P) |
| |
| // motion search site |
| typedef struct search_site { |
| FULLPEL_MV mv; |
| int offset; |
| } search_site; |
| |
| typedef struct search_site_config { |
| search_site site[MAX_MVSEARCH_STEPS * 2][16 + 1]; |
| // Number of search steps. |
| int num_search_steps; |
| int searches_per_step[MAX_MVSEARCH_STEPS * 2]; |
| int radius[MAX_MVSEARCH_STEPS * 2]; |
| int stride; |
| } search_site_config; |
| |
| typedef struct { |
| FULLPEL_MV coord; |
| int coord_offset; |
| } search_neighbors; |
| |
| struct AV1_COMP; |
| struct SPEED_FEATURES; |
| |
| // ============================================================================= |
| // Cost functions |
| // ============================================================================= |
| |
| enum { |
| MV_COST_ENTROPY, // Use the entropy rate of the mv as the cost |
| MV_COST_L1_LOWRES, // Use the l1 norm of the mv as the cost (<480p) |
| MV_COST_L1_MIDRES, // Use the l1 norm of the mv as the cost (>=480p) |
| MV_COST_L1_HDRES, // Use the l1 norm of the mv as the cost (>=720p) |
| MV_COST_NONE // Use 0 as as cost irrespective of the current mv |
| } UENUM1BYTE(MV_COST_TYPE); |
| |
| typedef struct { |
| // The reference mv used to compute the mv cost |
| const MV *ref_mv; |
| FULLPEL_MV full_ref_mv; |
| MV_COST_TYPE mv_cost_type; |
| const int *mvjcost; |
| const int *mvcost[2]; |
| int error_per_bit; |
| // A multiplier used to convert rate to sad cost |
| int sad_per_bit; |
| } MV_COST_PARAMS; |
| |
| int av1_mv_bit_cost(const MV *mv, const MV *ref_mv, const int *mvjcost, |
| int *mvcost[2], int weight); |
| |
| int av1_get_mvpred_sse(const MV_COST_PARAMS *mv_cost_params, |
| const FULLPEL_MV best_mv, |
| const aom_variance_fn_ptr_t *vfp, |
| const struct buf_2d *src, const struct buf_2d *pre); |
| int av1_get_mvpred_compound_var(const MV_COST_PARAMS *ms_params, |
| const FULLPEL_MV best_mv, |
| const uint8_t *second_pred, const uint8_t *mask, |
| int mask_stride, int invert_mask, |
| const aom_variance_fn_ptr_t *vfp, |
| const struct buf_2d *src, |
| const struct buf_2d *pre); |
| |
| // ============================================================================= |
| // Motion Search |
| // ============================================================================= |
| typedef struct { |
| // The reference buffer |
| const struct buf_2d *ref; |
| |
| // The source and predictors/mask used by translational search |
| const struct buf_2d *src; |
| const uint8_t *second_pred; |
| const uint8_t *mask; |
| int mask_stride; |
| int inv_mask; |
| |
| // The weighted source and mask used by OBMC |
| const int32_t *wsrc; |
| const int32_t *obmc_mask; |
| } MSBuffers; |
| |
| static INLINE void av1_set_ms_compound_refs(MSBuffers *ms_buffers, |
| const uint8_t *second_pred, |
| const uint8_t *mask, |
| int mask_stride, int invert_mask) { |
| ms_buffers->second_pred = second_pred; |
| ms_buffers->mask = mask; |
| ms_buffers->mask_stride = mask_stride; |
| ms_buffers->inv_mask = invert_mask; |
| } |
| |
| // ============================================================================= |
| // Fullpixel Motion Search |
| // ============================================================================= |
| enum { |
| // Search 8-points in the radius grid around center, up to 11 search stages. |
| DIAMOND = 0, |
| // Search 12-points in the radius/tan_radius grid around center, |
| // up to 15 search stages. |
| NSTEP = 1, |
| // Search maximum 8-points in the radius grid around center, |
| // up to 11 search stages. First stage consists of 8 search points |
| // and the rest with 6 search points each in hex shape. |
| HEX = 2, |
| // Search maximum 8-points in the radius grid around center, |
| // up to 11 search stages. First stage consists of 4 search |
| // points and the rest with 8 search points each. |
| BIGDIA = 3, |
| // Search 8-points in the square grid around center, up to 11 search stages. |
| SQUARE = 4, |
| // HEX search with up to 2 stages. |
| FAST_HEX = 5, |
| // BIGDIA search with up to 2 stages. |
| FAST_DIAMOND = 6, |
| // BIGDIA search with up to 3 stages. |
| FAST_BIGDIA = 7, |
| // Total number of search methods. |
| NUM_SEARCH_METHODS, |
| // Number of distinct search methods. |
| NUM_DISTINCT_SEARCH_METHODS = SQUARE + 1, |
| } UENUM1BYTE(SEARCH_METHODS); |
| |
| // This struct holds fullpixel motion search parameters that should be constant |
| // during the search |
| typedef struct { |
| BLOCK_SIZE bsize; |
| // A function pointer to the simd function for fast computation |
| const aom_variance_fn_ptr_t *vfp; |
| |
| #if CONFIG_IBC_SR_EXT |
| const MACROBLOCKD *xd; |
| int mib_size_log2; |
| const AV1_COMMON *cm; |
| int mi_row; |
| int mi_col; |
| #endif // CONFIG_IBC_SR_EXT |
| #if CONFIG_BVP_IMPROVEMENT |
| MACROBLOCK *x; |
| int ref_bv_cnt; |
| #endif // CONFIG_BVP_IMPROVEMENT |
| |
| MSBuffers ms_buffers; |
| |
| // WARNING: search_method should be regarded as a private variable and should |
| // not be modified directly so it is in sync with search_sites. To modify it, |
| // use av1_set_mv_search_method. |
| SEARCH_METHODS search_method; |
| const search_site_config *search_sites; |
| FullMvLimits mv_limits; |
| |
| int run_mesh_search; // Sets mesh search unless it got pruned by |
| // prune_mesh_search. |
| int prune_mesh_search; // Disables mesh search if the best_mv after a normal |
| // search if close to the start_mv. |
| int force_mesh_thresh; // Forces mesh search if the residue variance is |
| // higher than the threshold. |
| const struct MESH_PATTERN *mesh_patterns[2]; |
| |
| // Use maximum search interval of 4 if true. This helps motion search to find |
| // the best motion vector for screen content types. |
| int fine_search_interval; |
| |
| int is_intra_mode; |
| |
| int fast_obmc_search; |
| |
| // For calculating mv cost |
| MV_COST_PARAMS mv_cost_params; |
| |
| // Stores the function used to compute the sad. This can be different from the |
| // sdf in vfp (e.g. downsampled sad and not sad) to allow speed up. |
| aom_sad_fn_t sdf; |
| aom_sad_multi_d_fn_t sdx4df; |
| } FULLPEL_MOTION_SEARCH_PARAMS; |
| |
| void av1_make_default_fullpel_ms_params( |
| FULLPEL_MOTION_SEARCH_PARAMS *ms_params, const struct AV1_COMP *cpi, |
| const MACROBLOCK *x, BLOCK_SIZE bsize, const MV *ref_mv, |
| const search_site_config search_sites[NUM_DISTINCT_SEARCH_METHODS], |
| int fine_search_interval); |
| |
| // Sets up configs for fullpixel diamond search method. |
| void av1_init_dsmotion_compensation(search_site_config *cfg, int stride); |
| // Sets up configs for firstpass motion search. |
| void av1_init_motion_fpf(search_site_config *cfg, int stride); |
| // Sets up configs for all other types of motion search method. |
| void av1_init_motion_compensation_nstep(search_site_config *cfg, int stride); |
| // Sets up configs for BIGDIA / FAST_DIAMOND / FAST_BIGDIA |
| // motion search method. |
| void av1_init_motion_compensation_bigdia(search_site_config *cfg, int stride); |
| // Sets up configs for HEX or FAST_HEX motion search method. |
| void av1_init_motion_compensation_hex(search_site_config *cfg, int stride); |
| // Sets up configs for SQUARE motion search method. |
| void av1_init_motion_compensation_square(search_site_config *cfg, int stride); |
| |
| // Mv beyond the range do not produce new/different prediction block. |
| static INLINE void av1_set_mv_search_method( |
| FULLPEL_MOTION_SEARCH_PARAMS *ms_params, |
| const search_site_config search_sites[NUM_DISTINCT_SEARCH_METHODS], |
| SEARCH_METHODS search_method) { |
| // Array to inform which all search methods are having |
| // same candidates and different in number of search steps. |
| static const SEARCH_METHODS search_method_lookup[NUM_SEARCH_METHODS] = { |
| DIAMOND, // DIAMOND |
| NSTEP, // NSTEP |
| HEX, // HEX |
| BIGDIA, // BIGDIA |
| SQUARE, // SQUARE |
| HEX, // FAST_HEX |
| BIGDIA, // FAST_DIAMOND |
| BIGDIA // FAST_BIGDIA |
| }; |
| |
| ms_params->search_method = search_method; |
| ms_params->search_sites = |
| &search_sites[search_method_lookup[ms_params->search_method]]; |
| } |
| |
| // Set up limit values for MV components. |
| // Mv beyond the range do not produce new/different prediction block. |
| static INLINE void av1_set_mv_row_limits( |
| const CommonModeInfoParams *const mi_params, FullMvLimits *mv_limits, |
| int mi_row, int mi_height, int border) { |
| const int min1 = -(mi_row * MI_SIZE + border - 2 * AOM_INTERP_EXTEND); |
| const int min2 = -(((mi_row + mi_height) * MI_SIZE) + 2 * AOM_INTERP_EXTEND); |
| mv_limits->row_min = AOMMAX(min1, min2); |
| const int max1 = (mi_params->mi_rows - mi_row - mi_height) * MI_SIZE + |
| border - 2 * AOM_INTERP_EXTEND; |
| const int max2 = |
| (mi_params->mi_rows - mi_row) * MI_SIZE + 2 * AOM_INTERP_EXTEND; |
| mv_limits->row_max = AOMMIN(max1, max2); |
| } |
| |
| static INLINE void av1_set_mv_col_limits( |
| const CommonModeInfoParams *const mi_params, FullMvLimits *mv_limits, |
| int mi_col, int mi_width, int border) { |
| const int min1 = -(mi_col * MI_SIZE + border - 2 * AOM_INTERP_EXTEND); |
| const int min2 = -(((mi_col + mi_width) * MI_SIZE) + 2 * AOM_INTERP_EXTEND); |
| mv_limits->col_min = AOMMAX(min1, min2); |
| const int max1 = (mi_params->mi_cols - mi_col - mi_width) * MI_SIZE + border - |
| 2 * AOM_INTERP_EXTEND; |
| const int max2 = |
| (mi_params->mi_cols - mi_col) * MI_SIZE + 2 * AOM_INTERP_EXTEND; |
| mv_limits->col_max = AOMMIN(max1, max2); |
| } |
| |
| static INLINE void av1_set_mv_limits( |
| const CommonModeInfoParams *const mi_params, FullMvLimits *mv_limits, |
| int mi_row, int mi_col, int mi_height, int mi_width, int border) { |
| av1_set_mv_row_limits(mi_params, mv_limits, mi_row, mi_height, border); |
| av1_set_mv_col_limits(mi_params, mv_limits, mi_col, mi_width, border); |
| } |
| |
| void av1_set_mv_search_range(FullMvLimits *mv_limits, const MV *mv); |
| |
| #if CONFIG_TIP |
| void av1_set_tip_mv_search_range(FullMvLimits *mv_limits); |
| #endif // CONFIG_TIP |
| |
| int av1_init_search_range(int size); |
| |
| unsigned int av1_int_pro_motion_estimation(const struct AV1_COMP *cpi, |
| MACROBLOCK *x, BLOCK_SIZE bsize, |
| int mi_row, int mi_col, |
| const MV *ref_mv); |
| |
| int av1_refining_search_8p_c(const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, |
| const FULLPEL_MV start_mv, FULLPEL_MV *best_mv); |
| |
| int av1_full_pixel_search(const FULLPEL_MV start_mv, |
| const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, |
| const int step_param, int *cost_list, |
| FULLPEL_MV *best_mv, FULLPEL_MV *second_best_mv); |
| |
| int av1_intrabc_hash_search(const struct AV1_COMP *cpi, const MACROBLOCKD *xd, |
| const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, |
| IntraBCHashInfo *intrabc_hash_info, |
| FULLPEL_MV *best_mv); |
| |
| int av1_obmc_full_pixel_search(const FULLPEL_MV start_mv, |
| const FULLPEL_MOTION_SEARCH_PARAMS *ms_params, |
| const int step_param, FULLPEL_MV *best_mv); |
| |
| static INLINE int av1_is_fullmv_in_range(const FullMvLimits *mv_limits, |
| FULLPEL_MV mv) { |
| return (mv.col >= mv_limits->col_min) && (mv.col <= mv_limits->col_max) && |
| (mv.row >= mv_limits->row_min) && (mv.row <= mv_limits->row_max); |
| } |
| // ============================================================================= |
| // Subpixel Motion Search |
| // ============================================================================= |
| enum { |
| EIGHTH_PEL, |
| QUARTER_PEL, |
| HALF_PEL, |
| FULL_PEL |
| } UENUM1BYTE(SUBPEL_FORCE_STOP); |
| |
| typedef struct { |
| const aom_variance_fn_ptr_t *vfp; |
| SUBPEL_SEARCH_TYPE subpel_search_type; |
| // Source and reference buffers |
| MSBuffers ms_buffers; |
| int w, h; |
| } SUBPEL_SEARCH_VAR_PARAMS; |
| |
| // This struct holds subpixel motion search parameters that should be constant |
| // during the search |
| typedef struct { |
| // High level motion search settings |
| int allow_hp; |
| const int *cost_list; |
| SUBPEL_FORCE_STOP forced_stop; |
| int iters_per_step; |
| SubpelMvLimits mv_limits; |
| |
| // For calculating mv cost |
| MV_COST_PARAMS mv_cost_params; |
| |
| // Distortion calculation params |
| SUBPEL_SEARCH_VAR_PARAMS var_params; |
| } SUBPEL_MOTION_SEARCH_PARAMS; |
| |
| #if CONFIG_JOINT_MVD |
| // motion search for joint MVD coding |
| int joint_mvd_search(const AV1_COMMON *const cm, MACROBLOCKD *xd, |
| SUBPEL_MOTION_SEARCH_PARAMS *ms_params, MV ref_mv, |
| MV *start_mv, MV *bestmv, int *distortion, |
| unsigned int *sse1, int ref_idx, MV *other_mv, |
| MV *best_other_mv, uint8_t *second_pred, |
| InterPredParams *inter_pred_params, |
| int_mv *last_mv_search_list); |
| #endif // CONFIG_JOINT_MVD |
| #if CONFIG_ADAPTIVE_MVD |
| // motion search for near_new and new_near mode when adaptive MVD resolution is |
| // applied |
| int adaptive_mvd_search(const AV1_COMMON *const cm, MACROBLOCKD *xd, |
| SUBPEL_MOTION_SEARCH_PARAMS *ms_params, MV start_mv, |
| MV *bestmv, int *distortion, unsigned int *sse1); |
| #endif // CONFIG_ADAPTIVE_MVD |
| #if IMPROVED_AMVD && CONFIG_JOINT_MVD |
| int av1_joint_amvd_motion_search(const AV1_COMMON *const cm, MACROBLOCKD *xd, |
| SUBPEL_MOTION_SEARCH_PARAMS *ms_params, |
| const MV *start_mv, MV *bestmv, |
| int *distortion, unsigned int *sse1, |
| int ref_idx, MV *other_mv, MV *best_other_mv, |
| uint8_t *second_pred, |
| InterPredParams *inter_pred_params); |
| #endif // IMPROVED_AMVD && CONFIG_JOINT_MVD |
| |
| void av1_make_default_subpel_ms_params(SUBPEL_MOTION_SEARCH_PARAMS *ms_params, |
| const struct AV1_COMP *cpi, |
| const MACROBLOCK *x, BLOCK_SIZE bsize, |
| const MV *ref_mv, const int *cost_list); |
| |
| typedef int(fractional_mv_step_fp)(MACROBLOCKD *xd, const AV1_COMMON *const cm, |
| const SUBPEL_MOTION_SEARCH_PARAMS *ms_params, |
| MV start_mv, MV *bestmv, int *distortion, |
| unsigned int *sse1, |
| int_mv *last_mv_search_list); |
| |
| extern fractional_mv_step_fp av1_find_best_sub_pixel_tree; |
| extern fractional_mv_step_fp av1_find_best_sub_pixel_tree_pruned; |
| extern fractional_mv_step_fp av1_find_best_sub_pixel_tree_pruned_more; |
| extern fractional_mv_step_fp av1_find_best_sub_pixel_tree_pruned_evenmore; |
| extern fractional_mv_step_fp av1_return_max_sub_pixel_mv; |
| extern fractional_mv_step_fp av1_return_min_sub_pixel_mv; |
| extern fractional_mv_step_fp av1_find_best_obmc_sub_pixel_tree_up; |
| |
| unsigned int av1_refine_warped_mv(MACROBLOCKD *xd, const AV1_COMMON *const cm, |
| const SUBPEL_MOTION_SEARCH_PARAMS *ms_params, |
| BLOCK_SIZE bsize, const int *pts0, |
| const int *pts_inref0, int total_samples); |
| |
| static INLINE void av1_set_fractional_mv(int_mv *fractional_best_mv) { |
| for (int z = 0; z < 3; z++) { |
| fractional_best_mv[z].as_int = INVALID_MV; |
| } |
| } |
| |
| static INLINE void av1_set_subpel_mv_search_range(SubpelMvLimits *subpel_limits, |
| const FullMvLimits *mv_limits, |
| const MV *ref_mv) { |
| const int max_mv = GET_MV_SUBPEL(MAX_FULL_PEL_VAL); |
| const int minc = |
| AOMMAX(GET_MV_SUBPEL(mv_limits->col_min), ref_mv->col - max_mv); |
| const int maxc = |
| AOMMIN(GET_MV_SUBPEL(mv_limits->col_max), ref_mv->col + max_mv); |
| const int minr = |
| AOMMAX(GET_MV_SUBPEL(mv_limits->row_min), ref_mv->row - max_mv); |
| const int maxr = |
| AOMMIN(GET_MV_SUBPEL(mv_limits->row_max), ref_mv->row + max_mv); |
| |
| subpel_limits->col_min = AOMMAX(MV_LOW + 1, minc); |
| subpel_limits->col_max = AOMMIN(MV_UPP - 1, maxc); |
| subpel_limits->row_min = AOMMAX(MV_LOW + 1, minr); |
| subpel_limits->row_max = AOMMIN(MV_UPP - 1, maxr); |
| } |
| |
| #if CONFIG_TIP |
| static INLINE void av1_set_tip_subpel_mv_search_range( |
| SubpelMvLimits *subpel_limits, const FullMvLimits *mv_limits) { |
| const int tmvp_mv = GET_MV_SUBPEL(TIP_MV_SEARCH_RANGE << TMVP_MI_SZ_LOG2); |
| |
| subpel_limits->col_min = AOMMAX(GET_MV_SUBPEL(mv_limits->col_min), -tmvp_mv); |
| subpel_limits->col_max = AOMMIN(GET_MV_SUBPEL(mv_limits->col_max), tmvp_mv); |
| subpel_limits->row_min = AOMMAX(GET_MV_SUBPEL(mv_limits->row_min), -tmvp_mv); |
| subpel_limits->row_max = AOMMIN(GET_MV_SUBPEL(mv_limits->row_max), tmvp_mv); |
| } |
| #endif // CONFIG_TIP |
| |
| static INLINE int av1_is_subpelmv_in_range(const SubpelMvLimits *mv_limits, |
| MV mv) { |
| return (mv.col >= mv_limits->col_min) && (mv.col <= mv_limits->col_max) && |
| (mv.row >= mv_limits->row_min) && (mv.row <= mv_limits->row_max); |
| } |
| |
| #if CONFIG_BVP_IMPROVEMENT |
| // Returns the cost of using the current mv during the motion search |
| int av1_get_mv_err_cost(const MV *mv, const MV_COST_PARAMS *mv_cost_params); |
| |
| // Set the reference MV for the motion search |
| void av1_init_ref_mv(MV_COST_PARAMS *mv_cost_params, const MV *ref_mv); |
| |
| // Compute the cost for signalling the intrabc DRL index |
| int av1_get_intrabc_drl_idx_cost(int max_ref_bv_num, int intrabc_drl_idx, |
| const MACROBLOCK *x); |
| |
| // Compute the cost for signalling the intrabc mode and intrabc DRL index. This |
| // is only used during the motion search |
| int av1_get_ref_bv_rate_cost(int intrabc_mode, int intrabc_drl_idx, |
| MACROBLOCK *x, |
| FULLPEL_MOTION_SEARCH_PARAMS fullms_params, |
| int ref_bv_cnt); |
| |
| // Pick the best reference BV for the current BV |
| int av1_pick_ref_bv(FULLPEL_MV *best_full_mv, |
| const FULLPEL_MOTION_SEARCH_PARAMS *fullms_params); |
| |
| // Compute the estimated RD cost for the reference BV |
| int av1_get_ref_mvpred_var_cost(const struct AV1_COMP *cpi, |
| const MACROBLOCKD *xd, |
| const FULLPEL_MOTION_SEARCH_PARAMS *ms_params); |
| #endif // CONFIG_BVP_IMPROVEMENT |
| |
| #ifdef __cplusplus |
| } // extern "C" |
| #endif |
| |
| #endif // AOM_AV1_ENCODER_MCOMP_H_ |