// return mv_diff static inline int is_interp_filter_good_match( const INTERPOLATION_FILTER_STATS *st, MB_MODE_INFO *const mi,
int skip_level) { const int is_comp = has_second_ref(mi);
int i;
for (i = 0; i < 1 + is_comp; ++i) {
if (st->ref_frames[i] != mi->ref_frame[i]) return INT_MAX;
}
if (skip_level == 1 && is_comp) {
if (st->comp_type != mi->interinter_comp.type) return INT_MAX;
if (st->compound_idx != mi->compound_idx) return INT_MAX;
}
int mv_diff = 0;
for (i = 0; i < 1 + is_comp; ++i) {
mv_diff += abs(st->mv[i].as_mv.row - mi->mv[i].as_mv.row) +
abs(st->mv[i].as_mv.col - mi->mv[i].as_mv.col);
} return mv_diff;
}
static inline int save_interp_filter_search_stat(
MB_MODE_INFO *const mbmi, int64_t rd, unsigned int pred_sse,
INTERPOLATION_FILTER_STATS *interp_filter_stats,
int interp_filter_stats_idx) {
if (interp_filter_stats_idx < MAX_INTERP_FILTER_STATS) {
INTERPOLATION_FILTER_STATS stat = { mbmi->interp_filters,
{ mbmi->mv[0], mbmi->mv[1] },
{ mbmi->ref_frame[0],
mbmi->ref_frame[1] },
mbmi->interinter_comp.type,
mbmi->compound_idx,
rd,
pred_sse };
interp_filter_stats[interp_filter_stats_idx] = stat;
interp_filter_stats_idx++;
} return interp_filter_stats_idx;
}
static inline int find_interp_filter_in_stats(
MB_MODE_INFO *const mbmi, INTERPOLATION_FILTER_STATS *interp_filter_stats,
int interp_filter_stats_idx, int skip_level) { // [skip_levels][single or comp] const int thr[2][2] = { { 0, 0 }, { 3, 7 } }; const int is_comp = has_second_ref(mbmi);
// Find good enough match. // TODO(yunqing): Separate single-ref mode and comp mode stats for fast // search.
int best = INT_MAX;
int match = -1;
for (int j = 0; j < interp_filter_stats_idx; ++j) { const INTERPOLATION_FILTER_STATS *st = &interp_filter_stats[j]; const int mv_diff = is_interp_filter_good_match(st, mbmi, skip_level); // Exact match is found.
if (mv_diff == 0) {
match = j; break;
} else if (mv_diff < best && mv_diff <= thr[skip_level - 1][is_comp]) {
best = mv_diff;
match = j;
}
}
if (match != -1) {
mbmi->interp_filters = interp_filter_stats[match].filters; return match;
} return -1; // no match result found
}
static int find_interp_filter_match(
MB_MODE_INFO *const mbmi, const AV1_COMP *const cpi, const InterpFilter assign_filter, const int need_search,
INTERPOLATION_FILTER_STATS *interp_filter_stats,
int interp_filter_stats_idx) {
int match_found_idx = -1;
if (cpi->sf.interp_sf.use_interp_filter && need_search)
match_found_idx = find_interp_filter_in_stats(
mbmi, interp_filter_stats, interp_filter_stats_idx,
cpi->sf.interp_sf.use_interp_filter);
static inline int get_switchable_rate(MACROBLOCK *const x, const int_interpfilters filters, const int ctx[2], int dual_filter) { const InterpFilter filter0 = filters.as_filters.y_filter;
int inter_filter_cost =
x->mode_costs.switchable_interp_costs[ctx[0]][filter0];
if (dual_filter) { const InterpFilter filter1 = filters.as_filters.x_filter;
inter_filter_cost += x->mode_costs.switchable_interp_costs[ctx[1]][filter1];
} return SWITCHABLE_INTERP_RATE_FACTOR * inter_filter_cost;
}
// Build inter predictor and calculate model rd // for a given plane. static inline void interp_model_rd_eval(
MACROBLOCK *const x, const AV1_COMP *const cpi, BLOCK_SIZE bsize, const BUFFER_SET *const orig_dst, int plane_from, int plane_to,
RD_STATS *rd_stats, int is_skip_build_pred) { const AV1_COMMON *cm = &cpi->common;
MACROBLOCKD *const xd = &x->e_mbd;
RD_STATS tmp_rd_stats;
av1_init_rd_stats(&tmp_rd_stats);
// Skip inter predictor if the predictor is already available.
if (!is_skip_build_pred) { const int mi_row = xd->mi_row; const int mi_col = xd->mi_col;
av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize,
plane_from, plane_to);
}
// When skip_txfm pred is equal to default_interp_skip_flags, // skip both luma and chroma MC. // For mono-chrome images: // num_planes = 1 and cpi->default_interp_skip_flags = 1, // skip_pred = 1: skip both luma and chroma // skip_pred = 0: Evaluate luma and as num_planes=1, // skip chroma evaluation
int tmp_skip_pred =
(skip_pred == interp_search_flags->default_interp_skip_flags)
? INTERP_SKIP_LUMA_SKIP_CHROMA
: skip_pred;
assert(IMPLIES(tmp_skip_pred == INTERP_EVAL_LUMA_SKIP_CHROMA,
cpi->sf.interp_sf.skip_model_rd_uv));
if (tmp_rd * mul / 100 < *rd) {
*rd = tmp_rd;
*switchable_rate = tmp_rs;
if (skip_pred != interp_search_flags->default_interp_skip_flags) {
if (skip_pred == INTERP_EVAL_LUMA_EVAL_CHROMA) { // Overwrite the data as current filter is the best one
*rd_stats_luma = this_rd_stats_luma;
*rd_stats = this_rd_stats; // As luma MC data is computed, no need to recompute after the search
x->recalc_luma_mc_data = 0;
} else if (skip_pred == INTERP_SKIP_LUMA_EVAL_CHROMA) { // As luma MC data is not computed, update of luma data can be skipped
*rd_stats = this_rd_stats; // As luma MC data is not recomputed and current filter is the best, // indicate the possibility of recomputing MC data // If current buffer contains valid MC data, toggle to indicate that // luma MC data needs to be recomputed
x->recalc_luma_mc_data ^= 1;
}
swap_dst_buf(xd, dst_bufs, num_planes);
} return1;
}
mbmi->interp_filters = last_best; return0;
}
// If no filter are set to be evaluated, return from function
if (allow_interp_mask == 0x0) return best_filt_type; // For block width or height is 4, skip the pred evaluation of SHARP_SHARP
tmp_skip_pred = is_w4_or_h4
? cpi->interp_search_flags.default_interp_skip_flags
: skip_pred;
// Loop over the all filter types and evaluate for only allowed filter types
for (int filt_type = SHARP_SHARP; filt_type >= REG_REG; --filt_type) { const int is_filter_allowed =
get_interp_filter_allowed_mask(allow_interp_mask, filt_type);
if (is_filter_allowed)
if (interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
rd_stats_y, rd_stats, switchable_rate,
dst_bufs, filt_type, switchable_ctx,
tmp_skip_pred))
best_filt_type = filt_type;
tmp_skip_pred = skip_pred;
} return best_filt_type;
}
if (cpi->sf.interp_sf.adaptive_interp_filter_search == 2) { const FRAME_UPDATE_TYPE update_type =
get_frame_update_type(&cpi->ppi->gf_group, cpi->gf_frame_index); const int ctx0 = av1_get_pred_context_switchable_interp(xd, 0); const int ctx1 = av1_get_pred_context_switchable_interp(xd, 1);
int use_actual_frame_probs = 1; const int *switchable_interp_p0; const int *switchable_interp_p1; #if CONFIG_FPMT_TEST
use_actual_frame_probs =
(cpi->ppi->fpmt_unit_test_cfg == PARALLEL_SIMULATION_ENCODE) ? 0 : 1;
if (!use_actual_frame_probs) {
switchable_interp_p0 = (int *)cpi->ppi->temp_frame_probs
.switchable_interp_probs[update_type][ctx0];
switchable_interp_p1 = (int *)cpi->ppi->temp_frame_probs
.switchable_interp_probs[update_type][ctx1];
} #endif
if (use_actual_frame_probs) {
switchable_interp_p0 =
cpi->ppi->frame_probs.switchable_interp_probs[update_type][ctx0];
switchable_interp_p1 =
cpi->ppi->frame_probs.switchable_interp_probs[update_type][ctx1];
} staticconst int thr[7] = { 0, 8, 8, 8, 8, 0, 8 }; const int thresh = thr[update_type];
for (i = 0; i < SWITCHABLE_FILTERS; i++) { // For non-dual case, the 2 dir's prob should be identical.
assert(switchable_interp_p0[i] == switchable_interp_p1[i]);
if (switchable_interp_p0[i] < thresh &&
switchable_interp_p1[i] < thresh) {
DUAL_FILTER_TYPE filt_type = i + SWITCHABLE_FILTERS * i;
reset_interp_filter_allowed_mask(&interp_filter_search_mask, filt_type);
}
if (cpi->oxcf.algo_cfg.sharpness == 3 && i == EIGHTTAP_SMOOTH) {
DUAL_FILTER_TYPE filt_type = i + SWITCHABLE_FILTERS * i;
reset_interp_filter_allowed_mask(&interp_filter_search_mask, filt_type);
}
}
}
// Regular filter evaluation should have been done and hence the same should // be the winner
assert(x->e_mbd.mi[0]->interp_filters.as_int == filter_sets[0].as_int);
if ((skip_hor & skip_ver) != interp_search_flags->default_interp_skip_flags) {
INTERP_PRED_TYPE pred_filter_type = INTERP_HORZ_NEQ_VERT_NEQ;
int_interpfilters af = av1_broadcast_interp_filter(INTERP_INVALID);
int_interpfilters lf = af;
pred_filter_type = is_pred_filter_search_allowed(cpi, xd, bsize, &af, &lf);
if (pred_filter_type) {
assert(af.as_filters.x_filter != INTERP_INVALID);
int filter_idx = SWITCHABLE * af.as_filters.x_filter; // This assert tells that (filter_x == filter_y) for non-dual filter case
assert(filter_sets[filter_idx].as_filters.x_filter ==
filter_sets[filter_idx].as_filters.y_filter);
if (cpi->sf.interp_sf.adaptive_interp_filter_search &&
!(get_interp_filter_allowed_mask(interp_filter_search_mask,
filter_idx))) { return;
}
if (filter_idx) {
interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
rd_stats_y, rd_stats, switchable_rate, dst_bufs,
filter_idx, switchable_ctx,
(skip_hor & skip_ver));
} return;
}
} // Reuse regular filter's modeled rd data for sharp filter for following // cases // 1) When bsize is 4x4 // 2) When block width is 4 (i.e. 4x8/4x16 blocks) and MV in vertical // direction is full-pel // 3) When block height is 4 (i.e. 8x4/16x4 blocks) and MV in horizontal // direction is full-pel // TODO(any): Optimize cases 2 and 3 further if luma MV in relavant direction // alone is full-pel
// REG_REG filter type is evaluated beforehand, hence skip it
set_interp_filter_allowed_mask(&allowed_interp_mask, SHARP_SHARP);
set_interp_filter_allowed_mask(&allowed_interp_mask, SMOOTH_SMOOTH);
if (cpi->sf.interp_sf.adaptive_interp_filter_search)
allowed_interp_mask &= interp_filter_search_mask;
find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd,
rd_stats_y, rd_stats, switchable_rate, dst_bufs,
switchable_ctx, skip_pred, allowed_interp_mask, 1);
} else {
int skip_pred = (skip_hor & skip_ver);
for (i = (SWITCHABLE_FILTERS + 1); i < DUAL_FILTER_SET_SIZE;
i += (SWITCHABLE_FILTERS + 1)) { // This assert tells that (filter_x == filter_y) for non-dual filter case
assert(filter_sets[i].as_filters.x_filter ==
filter_sets[i].as_filters.y_filter);
if (cpi->sf.interp_sf.adaptive_interp_filter_search &&
!(get_interp_filter_allowed_mask(interp_filter_search_mask, i))) { continue;
}
interpolation_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
rd_stats_y, rd_stats, switchable_rate, dst_bufs,
i, switchable_ctx, skip_pred); // In first iteration, smooth filter is evaluated. If smooth filter // (which is less sharper) is the winner among regular and smooth filters, // sharp filter evaluation is skipped // TODO(any): Refine this gating based on modelled rd only (i.e., by not // accounting switchable filter rate)
if (cpi->sf.interp_sf.skip_sharp_interp_filter_search &&
skip_pred != interp_search_flags->default_interp_skip_flags) {
if (mbmi->interp_filters.as_int == filter_sets[SMOOTH_SMOOTH].as_int) break;
}
}
}
}
static inline void calc_interp_skip_pred_flag(MACROBLOCK *const x, const AV1_COMP *const cpi,
int *skip_hor, int *skip_ver) { const AV1_COMMON *cm = &cpi->common;
MACROBLOCKD *const xd = &x->e_mbd;
MB_MODE_INFO *const mbmi = xd->mi[0]; const int num_planes = av1_num_planes(cm); const int is_compound = has_second_ref(mbmi);
assert(is_intrabc_block(mbmi) == 0);
for (int ref = 0; ref < 1 + is_compound; ++ref) { conststruct scale_factors *const sf =
get_ref_scale_factors_const(cm, mbmi->ref_frame[ref]); // TODO(any): Refine skip flag calculation considering scaling
if (av1_is_scaled(sf)) {
*skip_hor = 0;
*skip_ver = 0; break;
} const MV mv = mbmi->mv[ref].as_mv;
int skip_hor_plane = 0;
int skip_ver_plane = 0;
for (int plane_idx = 0; plane_idx < AOMMAX(1, (num_planes - 1));
++plane_idx) { struct macroblockd_plane *const pd = &xd->plane[plane_idx]; const int bw = pd->width; const int bh = pd->height; const MV mv_q4 = clamp_mv_to_umv_border_sb(
xd, &mv, bw, bh, pd->subsampling_x, pd->subsampling_y); const int sub_x = (mv_q4.col & SUBPEL_MASK) << SCALE_EXTRA_BITS; const int sub_y = (mv_q4.row & SUBPEL_MASK) << SCALE_EXTRA_BITS;
skip_hor_plane |= ((sub_x == 0) << plane_idx);
skip_ver_plane |= ((sub_y == 0) << plane_idx);
}
*skip_hor &= skip_hor_plane;
*skip_ver &= skip_ver_plane; // It is not valid that "luma MV is sub-pel, whereas chroma MV is not"
assert(*skip_hor != 2);
assert(*skip_ver != 2);
} // When compond prediction type is compound segment wedge, luma MC and chroma // MC need to go hand in hand as mask generated during luma MC is reuired for // chroma MC. If skip_hor = 0 and skip_ver = 1, mask used for chroma MC during // vertical filter decision may be incorrect as temporary MC evaluation // overwrites the mask. Make skip_ver as 0 for this case so that mask is // populated during luma MC
if (is_compound && mbmi->compound_idx == 1 &&
mbmi->interinter_comp.type == COMPOUND_DIFFWTD) {
assert(mbmi->comp_group_idx == 1);
if (*skip_hor == 0 && *skip_ver == 1) *skip_ver = 0;
}
// Configure flags to skip chroma RD evaluation when skip_model_rd_uv is // enabled
if (cpi->sf.interp_sf.skip_model_rd_uv) {
*skip_hor |= INTERP_EVAL_LUMA_SKIP_CHROMA;
*skip_ver |= INTERP_EVAL_LUMA_SKIP_CHROMA;
}
}
// Do MC evaluation for default filter_type. // Luma MC
interp_model_rd_eval(x, cpi, bsize, orig_dst, AOM_PLANE_Y, AOM_PLANE_Y,
&rd_stats_luma, *skip_build_pred);
if (assign_filter != SWITCHABLE || match_found_idx != -1) { return0;
}
if (!need_search) {
int_interpfilters filters = av1_broadcast_interp_filter(EIGHTTAP_REGULAR);
assert(mbmi->interp_filters.as_int == filters.as_int);
(void)filters; return0;
}
if (args->modelled_rd != NULL) {
if (has_second_ref(mbmi)) { const int ref_mv_idx = mbmi->ref_mv_idx;
MV_REFERENCE_FRAME *refs = mbmi->ref_frame; const int mode0 = compound_ref0_mode(mbmi->mode); const int mode1 = compound_ref1_mode(mbmi->mode); const int64_t mrd = AOMMIN(args->modelled_rd[mode0][ref_mv_idx][refs[0]],
args->modelled_rd[mode1][ref_mv_idx][refs[1]]);
if ((*rd >> 1) > mrd && ref_best_rd < INT64_MAX) { return INT64_MAX;
}
}
}
x->recalc_luma_mc_data = 0; // skip_flag=xx (in binary form) // Setting 0th flag corresonds to skipping luma MC and setting 1st bt // corresponds to skipping chroma MC skip_flag=0 corresponds to "Don't skip // luma and chroma MC" Skip flag=1 corresponds to "Skip Luma MC only" // Skip_flag=2 corresponds to "Skip chroma MC only". This is valid only when // skip_model_rd_uv speed feature is enabled // skip_flag=3 corresponds to "Skip both luma and chroma MC"
int skip_hor = interp_search_flags->default_interp_skip_flags;
int skip_ver = interp_search_flags->default_interp_skip_flags;
calc_interp_skip_pred_flag(x, cpi, &skip_hor, &skip_ver);
// do interp_filter search
restore_dst_buf(xd, *tmp_dst, num_planes); const BUFFER_SET *dst_bufs[2] = { tmp_dst, orig_dst }; // Evaluate dual interp filters
if (cm->seq_params->enable_dual_filter) {
if (cpi->sf.interp_sf.use_fast_interpolation_filter_search) {
fast_dual_interp_filter_rd(x, cpi, tile_data, bsize, orig_dst, rd,
&rd_stats_luma, &rd_stats, switchable_rate,
dst_bufs, switchable_ctx, skip_hor, skip_ver);
} else { // Use full interpolation filter search
uint16_t allowed_interp_mask = ALLOW_ALL_INTERP_FILT_MASK; // REG_REG filter type is evaluated beforehand, so loop is repeated over // REG_SMOOTH to SHARP_SHARP for full interpolation filter search
reset_interp_filter_allowed_mask(&allowed_interp_mask, REG_REG);
find_best_interp_rd_facade(x, cpi, tile_data, bsize, orig_dst, rd,
&rd_stats_luma, &rd_stats, switchable_rate,
dst_bufs, switchable_ctx,
(skip_hor & skip_ver), allowed_interp_mask, 0);
}
} else { // Evaluate non-dual interp filters
find_best_non_dual_interp_filter(
x, cpi, tile_data, bsize, orig_dst, rd, &rd_stats_luma, &rd_stats,
switchable_rate, dst_bufs, switchable_ctx, skip_ver, skip_hor);
}
swap_dst_buf(xd, dst_bufs, num_planes); // Recompute final MC data if required
if (x->recalc_luma_mc_data == 1) { // Recomputing final luma MC data is required only if the same was skipped // in either of the directions Condition below is necessary, but not // sufficient
assert((skip_hor == 1) || (skip_ver == 1)); const int mi_row = xd->mi_row; const int mi_col = xd->mi_col;
av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, orig_dst, bsize,
AOM_PLANE_Y, AOM_PLANE_Y);
}
x->pred_sse[ref_frame] = (unsigned int)(rd_stats_luma.sse >> 4);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.