/* * Copyright (c) 2016, Alliance for Open Media. All rights reserved. * * This source code is subject to the terms of the BSD 2 Clause License and * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License * was not distributed with this source code in the LICENSE file, you can * obtain it at www.aomedia.org/license/software. 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 www.aomedia.org/license/patent.
// Terminate inter mode search early based on best sse so far. if ((early_term_idx > 0) && (threshold * this_sse > best_sse)) { return 1;
} return 0;
}
/*!\brief Runs Motion Estimation for a specific block and specific ref frame. * * \ingroup nonrd_mode_search * \callgraph * \callergraph * Finds the best Motion Vector by running Motion Estimation for a specific * block and a specific reference frame. Exits early if RDCost of Full Pel part * exceeds best RD Cost fund so far * \param[in] cpi Top-level encoder structure * \param[in] x Pointer to structure holding all the * data for the current macroblock * \param[in] bsize Current block size * \param[in] tmp_mv Pointer to best found New MV * \param[in] rate_mv Pointer to Rate of the best new MV * \param[in] best_rd_sofar RD Cost of the best mode found so far * \param[in] use_base_mv Flag, indicating that tmp_mv holds * specific MV to start the search with * * \return Returns 0 if ME was terminated after Full Pel Search because too * high RD Cost. Otherwise returns 1. Best New MV is placed into \c tmp_mv. * Rate estimation for this vector is placed to \c rate_mv
*/ staticint combined_motion_search(AV1_COMP *cpi, MACROBLOCK *x,
BLOCK_SIZE bsize, int_mv *tmp_mv, int *rate_mv, int64_t best_rd_sofar, int use_base_mv) {
MACROBLOCKD *xd = &x->e_mbd; const AV1_COMMON *cm = &cpi->common; const SPEED_FEATURES *sf = &cpi->sf;
MB_MODE_INFO *mi = xd->mi[0]; int step_param = (sf->rt_sf.fullpel_search_step_param)
? sf->rt_sf.fullpel_search_step_param
: cpi->mv_search_params.mv_step_param;
FULLPEL_MV start_mv; constint ref = mi->ref_frame[0]; const MV ref_mv = av1_get_ref_mv(x, mi->ref_mv_idx).as_mv;
MV center_mv; int dis; int rv = 0; int cost_list[5]; int search_subpel = 1;
start_mv = get_fullmv_from_mv(&ref_mv);
if (!use_base_mv)
center_mv = ref_mv; else
center_mv = tmp_mv->as_mv;
MV subpel_start_mv = get_mv_from_fullmv(&tmp_mv->as_fullmv);
assert(av1_is_subpelmv_in_range(&ms_params.mv_limits, subpel_start_mv)); // adaptively downgrade subpel search method based on block properties if (use_aggressive_subpel_search_method(
x, sf->rt_sf.use_adaptive_subpel_search, fullpel_performed_well))
av1_find_best_sub_pixel_tree_pruned_more(
xd, cm, &ms_params, subpel_start_mv, &best_mv_stats, &tmp_mv->as_mv,
&dis, &x->pred_sse[ref], NULL); else
cpi->mv_search_params.find_fractional_mv_step(
xd, cm, &ms_params, subpel_start_mv, &best_mv_stats, &tmp_mv->as_mv,
&dis, &x->pred_sse[ref], NULL);
*rate_mv =
av1_mv_bit_cost(&tmp_mv->as_mv, &ref_mv, x->mv_costs->nmv_joint_cost,
x->mv_costs->mv_cost_stack, MV_COST_WEIGHT);
} // The final MV can not be equal to the reference MV as this will trigger an // assert later. This can happen if both NEAREST and NEAR modes were skipped.
rv = (tmp_mv->as_mv.col != ref_mv.col || tmp_mv->as_mv.row != ref_mv.row); return rv;
}
/*!\brief Searches for the best New Motion Vector. * * \ingroup nonrd_mode_search * \callgraph * \callergraph * Finds the best Motion Vector by doing Motion Estimation. Uses reduced * complexity ME for non-LAST frames or calls \c combined_motion_search * for LAST reference frame * \param[in] cpi Top-level encoder structure * \param[in] x Pointer to structure holding all the * data for the current macroblock * \param[in] frame_mv Array that holds MVs for all modes * and ref frames * \param[in] ref_frame Reference frame for which to find * the best New MVs * \param[in] gf_temporal_ref Flag, indicating temporal reference * for GOLDEN frame * \param[in] bsize Current block size * \param[in] mi_row Row index in 4x4 units * \param[in] mi_col Column index in 4x4 units * \param[in] rate_mv Pointer to Rate of the best new MV * \param[in] best_rdc Pointer to the RD Cost for the best * mode found so far * * \return Returns -1 if the search was not done, otherwise returns 0. * Best New MV is placed into \c frame_mv array, Rate estimation for this * vector is placed to \c rate_mv
*/ staticint search_new_mv(AV1_COMP *cpi, MACROBLOCK *x,
int_mv frame_mv[][REF_FRAMES],
MV_REFERENCE_FRAME ref_frame, int gf_temporal_ref,
BLOCK_SIZE bsize, int mi_row, int mi_col, int *rate_mv,
RD_STATS *best_rdc) {
MACROBLOCKD *const xd = &x->e_mbd;
MB_MODE_INFO *const mi = xd->mi[0];
AV1_COMMON *cm = &cpi->common;
int_mv *this_ref_frm_newmv = &frame_mv[NEWMV][ref_frame]; unsignedint y_sad_zero; if (ref_frame > LAST_FRAME && cpi->oxcf.rc_cfg.mode == AOM_CBR &&
gf_temporal_ref) { int tmp_sad; int dis;
// When NEWMV is same as ref_mv from the drl, it is preferred to code the // MV as NEARESTMV or NEARMV. In this case, NEWMV needs to be skipped to // avoid an assert failure at a later stage. The scenario can occur if // NEARESTMV was not evaluated for ALTREF. if (this_ref_frm_newmv->as_mv.col == ref_mv.col &&
this_ref_frm_newmv->as_mv.row == ref_mv.row) return -1;
staticinlinevoid set_force_skip_flag(const AV1_COMP *const cpi,
MACROBLOCK *const x, unsignedint sse, int *force_skip) { if (x->txfm_search_params.tx_mode_search_type == TX_MODE_SELECT &&
cpi->sf.rt_sf.tx_size_level_based_on_qstep &&
cpi->sf.rt_sf.tx_size_level_based_on_qstep >= 2) { constint qstep = x->plane[AOM_PLANE_Y].dequant_QTX[1] >> (x->e_mbd.bd - 5); constunsignedint qstep_sq = qstep * qstep; // If the sse is low for low source variance blocks, mark those as // transform skip. // Note: Though qstep_sq is based on ac qstep, the threshold is kept // low so that reliable early estimate of tx skip can be obtained // through its comparison with sse. if (sse < qstep_sq && x->source_variance < qstep_sq &&
x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_U)] == 0 &&
x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_V)] == 0)
*force_skip = 1;
}
}
static TX_SIZE calculate_tx_size(const AV1_COMP *const cpi, BLOCK_SIZE bsize,
MACROBLOCK *const x, unsignedint var, unsignedint sse, int *force_skip) {
MACROBLOCKD *const xd = &x->e_mbd;
TX_SIZE tx_size; const TxfmSearchParams *txfm_params = &x->txfm_search_params; if (txfm_params->tx_mode_search_type == TX_MODE_SELECT) { int multiplier = 8; unsignedint var_thresh = 0; unsignedint is_high_var = 1; // Use quantizer based thresholds to determine transform size. if (cpi->sf.rt_sf.tx_size_level_based_on_qstep) { constint qband = x->qindex >> (QINDEX_BITS - 2); constint mult[4] = { 8, 7, 6, 5 };
assert(qband < 4);
multiplier = mult[qband]; constint qstep = x->plane[AOM_PLANE_Y].dequant_QTX[1] >> (xd->bd - 5); constunsignedint qstep_sq = qstep * qstep;
var_thresh = qstep_sq * 2; if (cpi->sf.rt_sf.tx_size_level_based_on_qstep >= 2) { // If the sse is low for low source variance blocks, mark those as // transform skip. // Note: Though qstep_sq is based on ac qstep, the threshold is kept // low so that reliable early estimate of tx skip can be obtained // through its comparison with sse. if (sse < qstep_sq && x->source_variance < qstep_sq &&
x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_U)] == 0 &&
x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_V)] == 0)
*force_skip = 1; // Further lower transform size based on aq mode only if residual // variance is high.
is_high_var = (var >= var_thresh);
}
} // Choose larger transform size for blocks where dc component is dominant or // the ac component is low. if (sse > ((var * multiplier) >> 2) || (var < var_thresh))
tx_size =
AOMMIN(max_txsize_lookup[bsize],
tx_mode_to_biggest_tx_size[txfm_params->tx_mode_search_type]); else
tx_size = TX_8X8;
if (CAP_TX_SIZE_FOR_BSIZE_GT32(txfm_params->tx_mode_search_type, bsize))
tx_size = TX_SIZE_FOR_BSIZE_GT32;
return AOMMIN(tx_size, TX_16X16);
}
staticvoid block_variance(const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, int w, int h, unsignedint *sse, int *sum, int block_size,
uint32_t *sse8x8, int *sum8x8, uint32_t *var8x8) { int k = 0;
*sse = 0;
*sum = 0;
// This function is called for block sizes >= BLOCK_32x32. As per the design // the aom_get_var_sse_sum_8x8_quad() processes four 8x8 blocks (in a 8x32) // per call. Hence the width and height of the block need to be at least 8 and // 32 samples respectively.
assert(w >= 32);
assert(h >= 8); for (int row = 0; row < h; row += block_size) { for (int col = 0; col < w; col += 32) {
aom_get_var_sse_sum_8x8_quad(src + src_stride * row + col, src_stride,
ref + ref_stride * row + col, ref_stride,
&sse8x8[k], &sum8x8[k], sse, sum,
&var8x8[k]);
k += 4;
}
}
}
staticvoid block_variance_16x16_dual(const uint8_t *src, int src_stride, const uint8_t *ref, int ref_stride, int w, int h, unsignedint *sse, int *sum, int block_size, uint32_t *sse16x16,
uint32_t *var16x16) { int k = 0;
*sse = 0;
*sum = 0; // This function is called for block sizes >= BLOCK_32x32. As per the design // the aom_get_var_sse_sum_16x16_dual() processes four 16x16 blocks (in a // 16x32) per call. Hence the width and height of the block need to be at // least 16 and 32 samples respectively.
assert(w >= 32);
assert(h >= 16); for (int row = 0; row < h; row += block_size) { for (int col = 0; col < w; col += 32) {
aom_get_var_sse_sum_16x16_dual(src + src_stride * row + col, src_stride,
ref + ref_stride * row + col, ref_stride,
&sse16x16[k], sse, sum, &var16x16[k]);
k += 2;
}
}
}
staticvoid calculate_variance(int bw, int bh, TX_SIZE tx_size, unsignedint *sse_i, int *sum_i, unsignedint *var_o, unsignedint *sse_o, int *sum_o) { const BLOCK_SIZE unit_size = txsize_to_bsize[tx_size]; constint nw = 1 << (bw - b_width_log2_lookup[unit_size]); constint nh = 1 << (bh - b_height_log2_lookup[unit_size]); int row, col, k = 0;
// Adjust the ac_thr according to speed, width, height and normalized sum staticint ac_thr_factor(int speed, int width, int height, int norm_sum) { if (speed >= 8 && norm_sum < 5) { if (width <= 640 && height <= 480) return 4; else return 2;
} return 1;
}
// Sets early_term flag based on chroma planes prediction staticinlinevoid set_early_term_based_on_uv_plane(
AV1_COMP *cpi, MACROBLOCK *x, BLOCK_SIZE bsize, MACROBLOCKD *xd, int mi_row, int mi_col, int *early_term, int num_blk, constunsignedint *sse_tx, constunsignedint *var_tx, int sum, unsignedint var, unsignedint sse) {
AV1_COMMON *const cm = &cpi->common; struct macroblock_plane *const p = &x->plane[AOM_PLANE_Y]; const uint32_t dc_quant = p->dequant_QTX[0]; const uint32_t ac_quant = p->dequant_QTX[1];
int64_t dc_thr = dc_quant * dc_quant >> 6;
int64_t ac_thr = ac_quant * ac_quant >> 6; constint bw = b_width_log2_lookup[bsize]; constint bh = b_height_log2_lookup[bsize]; int ac_test = 1; int dc_test = 1; constint norm_sum = abs(sum) >> (bw + bh);
for (int k = 0; k < num_blk; k++) { // Check if all ac coefficients can be quantized to zero. if (!(var_tx[k] < ac_thr || var == 0)) {
ac_test = 0; break;
} // Check if dc coefficient can be quantized to zero. if (!(sse_tx[k] - var_tx[k] < dc_thr || sse == var)) {
dc_test = 0; break;
}
}
// Check if chroma can be skipped based on ac and dc test flags. if (ac_test && dc_test) { int skip_uv[2] = { 0 }; unsignedint var_uv[2]; unsignedint sse_uv[2]; // Transform skipping test in UV planes. for (int plane = AOM_PLANE_U; plane <= AOM_PLANE_V; plane++) { int j = plane - 1;
skip_uv[j] = 1; if (x->color_sensitivity[COLOR_SENS_IDX(plane)]) {
skip_uv[j] = 0; struct macroblock_plane *const puv = &x->plane[plane]; struct macroblockd_plane *const puvd = &xd->plane[plane]; const BLOCK_SIZE uv_bsize = get_plane_block_size(
bsize, puvd->subsampling_x, puvd->subsampling_y); // Adjust these thresholds for UV. constint shift_ac = cpi->sf.rt_sf.increase_source_sad_thresh ? 5 : 3; constint shift_dc = cpi->sf.rt_sf.increase_source_sad_thresh ? 4 : 3; const int64_t uv_dc_thr =
(puv->dequant_QTX[0] * puv->dequant_QTX[0]) >> shift_dc; const int64_t uv_ac_thr =
(puv->dequant_QTX[1] * puv->dequant_QTX[1]) >> shift_ac;
av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize,
plane, plane);
var_uv[j] = cpi->ppi->fn_ptr[uv_bsize].vf(puv->src.buf, puv->src.stride,
puvd->dst.buf,
puvd->dst.stride, &sse_uv[j]); if ((var_uv[j] < uv_ac_thr || var_uv[j] == 0) &&
(sse_uv[j] - var_uv[j] < uv_dc_thr || sse_uv[j] == var_uv[j]))
skip_uv[j] = 1; else break;
}
} if (skip_uv[0] & skip_uv[1]) {
*early_term = 1;
}
}
}
staticinlinevoid calc_rate_dist_block_param(AV1_COMP *cpi, MACROBLOCK *x,
RD_STATS *rd_stats, int calculate_rd, int *early_term,
BLOCK_SIZE bsize, unsignedint sse) { if (calculate_rd) { if (!*early_term) { constint bw = block_size_wide[bsize]; constint bh = block_size_high[bsize];
staticvoid model_skip_for_sb_y_large_64(AV1_COMP *cpi, BLOCK_SIZE bsize, int mi_row, int mi_col, MACROBLOCK *x,
MACROBLOCKD *xd, RD_STATS *rd_stats, int *early_term, int calculate_rd,
int64_t best_sse, unsignedint *var_output, unsignedint var_prune_threshold) { // Note our transform coeffs are 8 times an orthogonal transform. // Hence quantizer step is also 8 times. To get effective quantizer // we need to divide by 8 before sending to modeling function. unsignedint sse; struct macroblock_plane *const p = &x->plane[AOM_PLANE_Y]; struct macroblockd_plane *const pd = &xd->plane[AOM_PLANE_Y]; int test_skip = 1; unsignedint var; int sum; constint bw = b_width_log2_lookup[bsize]; constint bh = b_height_log2_lookup[bsize]; unsignedint sse16x16[64] = { 0 }; unsignedint var16x16[64] = { 0 };
assert(xd->mi[0]->tx_size == TX_16X16);
assert(bsize > BLOCK_32X32);
// Calculate variance for whole partition, and also save 16x16 blocks' // variance to be used in following transform skipping test.
block_variance_16x16_dual(p->src.buf, p->src.stride, pd->dst.buf,
pd->dst.stride, 4 << bw, 4 << bh, &sse, &sum, 16,
sse16x16, var16x16);
var = sse - (unsignedint)(((int64_t)sum * sum) >> (bw + bh + 4)); if (var_output) {
*var_output = var; if (*var_output > var_prune_threshold) { return;
}
}
rd_stats->sse = sse; // Skipping test
*early_term = 0;
set_force_skip_flag(cpi, x, sse, early_term); // The code below for setting skip flag assumes transform size of at least // 8x8, so force this lower limit on transform.
MB_MODE_INFO *const mi = xd->mi[0]; if (!calculate_rd && cpi->sf.rt_sf.sse_early_term_inter_search &&
early_term_inter_search_with_sse(
cpi->sf.rt_sf.sse_early_term_inter_search, bsize, sse, best_sse,
mi->mode))
test_skip = 0;
if (*early_term) test_skip = 0;
// Evaluate if the partition block is a skippable block in Y plane. if (test_skip) { constunsignedint *sse_tx = sse16x16; constunsignedint *var_tx = var16x16; constunsignedint num_block = (1 << (bw + bh - 2)) >> 2;
set_early_term_based_on_uv_plane(cpi, x, bsize, xd, mi_row, mi_col,
early_term, num_block, sse_tx, var_tx, sum,
var, sse);
}
calc_rate_dist_block_param(cpi, x, rd_stats, calculate_rd, early_term, bsize,
sse);
}
staticvoid model_skip_for_sb_y_large(AV1_COMP *cpi, BLOCK_SIZE bsize, int mi_row, int mi_col, MACROBLOCK *x,
MACROBLOCKD *xd, RD_STATS *rd_stats, int *early_term, int calculate_rd,
int64_t best_sse, unsignedint *var_output, unsignedint var_prune_threshold) { if (x->force_zeromv_skip_for_blk) {
*early_term = 1;
rd_stats->rate = 0;
rd_stats->dist = 0;
rd_stats->sse = 0; return;
}
// For block sizes greater than 32x32, the transform size is always 16x16. // This function avoids calling calculate_variance() for tx_size 16x16 cases // by directly populating variance at tx_size level from // block_variance_16x16_dual() function. const TxfmSearchParams *txfm_params = &x->txfm_search_params; if (CAP_TX_SIZE_FOR_BSIZE_GT32(txfm_params->tx_mode_search_type, bsize)) {
xd->mi[0]->tx_size = TX_SIZE_FOR_BSIZE_GT32;
model_skip_for_sb_y_large_64(cpi, bsize, mi_row, mi_col, x, xd, rd_stats,
early_term, calculate_rd, best_sse, var_output,
var_prune_threshold); return;
}
// Note our transform coeffs are 8 times an orthogonal transform. // Hence quantizer step is also 8 times. To get effective quantizer // we need to divide by 8 before sending to modeling function. unsignedint sse; struct macroblock_plane *const p = &x->plane[AOM_PLANE_Y]; struct macroblockd_plane *const pd = &xd->plane[AOM_PLANE_Y]; int test_skip = 1; unsignedint var; int sum;
// Calculate variance for whole partition, and also save 8x8 blocks' variance // to be used in following transform skipping test.
block_variance(p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride,
4 << bw, 4 << bh, &sse, &sum, 8, sse8x8, sum8x8, var8x8);
var = sse - (unsignedint)(((int64_t)sum * sum) >> (bw + bh + 4)); if (var_output) {
*var_output = var; if (*var_output > var_prune_threshold) { return;
}
}
rd_stats->sse = sse; // Skipping test
*early_term = 0;
tx_size = calculate_tx_size(cpi, bsize, x, var, sse, early_term);
assert(tx_size <= TX_16X16); // The code below for setting skip flag assumes transform size of at least // 8x8, so force this lower limit on transform. if (tx_size < TX_8X8) tx_size = TX_8X8;
xd->mi[0]->tx_size = tx_size;
MB_MODE_INFO *const mi = xd->mi[0]; if (!calculate_rd && cpi->sf.rt_sf.sse_early_term_inter_search &&
early_term_inter_search_with_sse(
cpi->sf.rt_sf.sse_early_term_inter_search, bsize, sse, best_sse,
mi->mode))
test_skip = 0;
if (*early_term) test_skip = 0;
// Evaluate if the partition block is a skippable block in Y plane. if (test_skip) { unsignedint sse16x16[64] = { 0 }; int sum16x16[64] = { 0 }; unsignedint var16x16[64] = { 0 }; constunsignedint *sse_tx = sse8x8; constunsignedint *var_tx = var8x8; unsignedint num_blks = 1 << (bw + bh - 2);
// Note our transform coeffs are 8 times an orthogonal transform. // Hence quantizer step is also 8 times. To get effective quantizer // we need to divide by 8 before sending to modeling function. constint ref = xd->mi[0]->ref_frame[0];
assert(bsize < BLOCK_SIZES_ALL);
struct macroblock_plane *const p = &x->plane[AOM_PLANE_Y]; struct macroblockd_plane *const pd = &xd->plane[AOM_PLANE_Y]; unsignedint sse; int rate;
int64_t dist;
unsignedint var = cpi->ppi->fn_ptr[bsize].vf(
p->src.buf, p->src.stride, pd->dst.buf, pd->dst.stride, &sse); int force_skip = 0;
xd->mi[0]->tx_size = calculate_tx_size(cpi, bsize, x, var, sse, &force_skip); if (var_out) {
*var_out = var;
}
if (calculate_rd && (!force_skip || ref == INTRA_FRAME)) { constint bwide = block_size_wide[bsize]; constint bhigh = block_size_high[bsize];
model_rd_with_curvfit(cpi, x, bsize, AOM_PLANE_Y, sse, bwide * bhigh, &rate,
&dist);
} else {
rate = INT_MAX; // this will be overwritten later with av1_block_yrd
dist = INT_MAX;
}
rd_stats->sse = sse;
x->pred_sse[ref] = (unsignedint)AOMMIN(sse, UINT_MAX);
staticvoid recheck_zeromv_after_denoising(
AV1_COMP *cpi, MB_MODE_INFO *const mi, MACROBLOCK *x, MACROBLOCKD *const xd,
AV1_DENOISER_DECISION decision, AV1_PICKMODE_CTX_DEN *ctx_den, struct buf_2d yv12_mb[4][MAX_MB_PLANE], RD_STATS *best_rdc,
BEST_PICKMODE *best_pickmode, BLOCK_SIZE bsize, int mi_row, int mi_col) { // If INTRA or GOLDEN reference was selected, re-evaluate ZEROMV on // denoised result. Only do this under noise conditions, and if rdcost of // ZEROMV on original source is not significantly higher than rdcost of best // mode. if (cpi->noise_estimate.enabled && cpi->noise_estimate.level > kLow &&
ctx_den->zero_last_cost_orig < (best_rdc->rdcost << 3) &&
((ctx_den->best_ref_frame == INTRA_FRAME && decision >= FILTER_BLOCK) ||
(ctx_den->best_ref_frame == GOLDEN_FRAME &&
cpi->svc.number_spatial_layers == 1 &&
decision == FILTER_ZEROMV_BLOCK))) { // Check if we should pick ZEROMV on denoised signal.
AV1_COMMON *const cm = &cpi->common;
RD_STATS this_rdc; const ModeCosts *mode_costs = &x->mode_costs;
TxfmSearchInfo *txfm_info = &x->txfm_search_info;
MB_MODE_INFO_EXT *const mbmi_ext = &x->mbmi_ext;
this_rdc.rate += ctx_den->ref_frame_cost[LAST_FRAME];
this_rdc.rdcost = RDCOST(x->rdmult, this_rdc.rate, this_rdc.dist);
txfm_info->skip_txfm = this_rdc.skip_txfm; // Don't switch to ZEROMV if the rdcost for ZEROMV on denoised source // is higher than best_ref mode (on original source). if (this_rdc.rdcost > best_rdc->rdcost) {
this_rdc = *best_rdc;
mi->mode = best_pickmode->best_mode;
mi->ref_frame[0] = best_pickmode->best_ref_frame;
set_ref_ptrs(cm, xd, mi->ref_frame[0], NONE_FRAME);
mi->interp_filters = best_pickmode->best_pred_filter; if (best_pickmode->best_ref_frame == INTRA_FRAME) {
mi->mv[0].as_int = INVALID_MV;
} else {
mi->mv[0].as_int = ctx_den
->frame_mv[best_pickmode->best_mode]
[best_pickmode->best_ref_frame]
.as_int; if (ctx_den->reuse_inter_pred) {
xd->plane[AOM_PLANE_Y].pre[0] = yv12_mb[GOLDEN_FRAME][AOM_PLANE_Y];
av1_enc_build_inter_predictor_y(xd, mi_row, mi_col);
}
}
mi->tx_size = best_pickmode->best_tx_size;
txfm_info->skip_txfm = best_pickmode->best_mode_skip_txfm;
} else {
ctx_den->best_ref_frame = LAST_FRAME;
*best_rdc = this_rdc;
}
}
} #endif// CONFIG_AV1_TEMPORAL_DENOISING
/*!\brief Searches for the best interpolation filter * * \ingroup nonrd_mode_search * \callgraph * \callergraph * Iterates through subset of possible interpolation filters (EIGHTTAP_REGULAR, * EIGTHTAP_SMOOTH, MULTITAP_SHARP, depending on FILTER_SEARCH_SIZE) and selects * the one that gives lowest RD cost. RD cost is calculated using curvfit model. * Support for dual filters (different filters in the x & y directions) is * allowed if sf.interp_sf.disable_dual_filter = 0. * * \param[in] cpi Top-level encoder structure * \param[in] x Pointer to structure holding all the * data for the current macroblock * \param[in] this_rdc Pointer to calculated RD Cost * \param[in] inter_pred_params_sr Pointer to structure holding parameters of inter prediction for single reference * \param[in] mi_row Row index in 4x4 units * \param[in] mi_col Column index in 4x4 units * \param[in] tmp_buffer Pointer to a temporary buffer for * prediction re-use * \param[in] bsize Current block size * \param[in] reuse_inter_pred Flag, indicating prediction re-use * \param[out] this_mode_pred Pointer to store prediction buffer * for prediction re-use * \param[out] this_early_term Flag, indicating that transform can be * skipped * \param[out] var The residue variance of the current * predictor. * \param[in] use_model_yrd_large Flag, indicating special logic to handle * large blocks * \param[in] best_sse Best sse so far. * \param[in] is_single_pred Flag, indicating single mode. * * \remark Nothing is returned. Instead, calculated RD cost is placed to * \c this_rdc and best filter is placed to \c mi->interp_filters. In case * \c reuse_inter_pred flag is set, this function also outputs * \c this_mode_pred. Also \c this_early_temp is set if transform can be * skipped
*/ staticvoid search_filter_ref(AV1_COMP *cpi, MACROBLOCK *x, RD_STATS *this_rdc,
InterPredParams *inter_pred_params_sr, int mi_row, int mi_col, PRED_BUFFER *tmp_buffer,
BLOCK_SIZE bsize, int reuse_inter_pred,
PRED_BUFFER **this_mode_pred, int *this_early_term, unsignedint *var, int use_model_yrd_large, int64_t best_sse, int is_single_pred) {
AV1_COMMON *const cm = &cpi->common;
MACROBLOCKD *const xd = &x->e_mbd; struct macroblockd_plane *const pd = &xd->plane[AOM_PLANE_Y];
MB_MODE_INFO *const mi = xd->mi[0]; constint bw = block_size_wide[bsize]; int dim_factor =
(cpi->sf.interp_sf.disable_dual_filter == 0) ? FILTER_SEARCH_SIZE : 1;
RD_STATS pf_rd_stats[FILTER_SEARCH_SIZE * FILTER_SEARCH_SIZE] = { 0 };
TX_SIZE pf_tx_size[FILTER_SEARCH_SIZE * FILTER_SEARCH_SIZE] = { 0 };
PRED_BUFFER *current_pred = *this_mode_pred; int best_skip = 0; int best_early_term = 0;
int64_t best_cost = INT64_MAX; int best_filter_index = -1;
SubpelParams subpel_params; // Initialize inter prediction params at mode level for single reference // mode. if (is_single_pred)
init_inter_mode_params(&mi->mv[0].as_mv, inter_pred_params_sr,
&subpel_params, xd->block_ref_scale_factors[0],
pd->pre->width, pd->pre->height); for (int filter_idx = 0; filter_idx < FILTER_SEARCH_SIZE * FILTER_SEARCH_SIZE;
++filter_idx) {
int64_t cost; if (cpi->sf.interp_sf.disable_dual_filter &&
filters_ref_set[filter_idx].as_filters.x_filter !=
filters_ref_set[filter_idx].as_filters.y_filter) continue;
if (cpi->sf.inter_sf.extra_prune_warped) return 0; if (has_second_ref(mbmi)) return 0;
MOTION_MODE last_motion_mode_allowed = SIMPLE_TRANSLATION;
if (features->switchable_motion_mode) { // Determine which motion modes to search if more than SIMPLE_TRANSLATION // is allowed.
last_motion_mode_allowed = motion_mode_allowed(
xd->global_motion, xd, mbmi, features->allow_warped_motion);
}
if (last_motion_mode_allowed == WARPED_CAUSAL) { return 1;
}
mi->num_proj_ref = 1;
WARP_SAMPLE_INFO *const warp_sample_info =
&x->warp_sample_info[mi->ref_frame[0]]; int *pts0 = warp_sample_info->pts; int *pts_inref0 = warp_sample_info->pts_inref;
MOTION_MODE last_motion_mode_allowed = SIMPLE_TRANSLATION;
if (features->switchable_motion_mode) { // Determine which motion modes to search if more than SIMPLE_TRANSLATION // is allowed.
last_motion_mode_allowed = motion_mode_allowed(
xd->global_motion, xd, mi, features->allow_warped_motion);
}
WARP_SAMPLE_INFO *const warp_sample_info =
&x->warp_sample_info[mi->ref_frame[0]]; int *pts0 = warp_sample_info->pts; int *pts_inref0 = warp_sample_info->pts_inref;
constint total_samples = mi->num_proj_ref; if (total_samples == 0) { // Do not search WARPED_CAUSAL if there are no samples to use to determine // warped parameters.
mode_search_size = 1;
}
// Refine MV in a small range.
av1_refine_warped_mv(xd, cm, &ms_params, bsize, pts0, pts_inref0,
total_samples, cpi->sf.mv_sf.warp_search_method,
cpi->sf.mv_sf.warp_search_iters); if (mi->mv[0].as_int == ref_mv.as_int) { continue;
}
if (mv0.as_int != mi->mv[0].as_int) { // Keep the refined MV and WM parameters. int tmp_rate_mv = av1_mv_bit_cost(
&mi->mv[0].as_mv, &ref_mv.as_mv, x->mv_costs->nmv_joint_cost,
x->mv_costs->mv_cost_stack, MV_COST_WEIGHT);
*rate_mv = tmp_rate_mv;
} else { // Restore the old MV and WM parameters.
mi->mv[0] = mv0;
mi->wm_params = wm_params0;
mi->num_proj_ref = num_proj_ref0;
}
} // Build the warped predictor
av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize,
AOM_PLANE_Y, av1_num_planes(cm) - 1); if (use_model_yrd_large)
model_skip_for_sb_y_large(cpi, bsize, mi_row, mi_col, x, xd,
&pf_rd_stats[mode_index], this_early_term,
1, best_sse, NULL, UINT_MAX); else
model_rd_for_sb_y(cpi, bsize, x, xd, &pf_rd_stats[mode_index], NULL,
1, NULL);
// Avoid pruning of DC_PRED as it is the most probable mode to win as per the // statistics generated for nonrd intra mode evaluations. if (this_mode == DC_PRED) returnfalse;
// Enable the pruning for current mode only if it is not the winner mode of // both the neighboring blocks (left/top). return xd->up_available && this_mode != above_mode && xd->left_available &&
this_mode != left_mode;
}
// If the current block size is the same as the transform block size, enable // mode pruning based on the best SAD so far. if (cpi->sf.rt_sf.prune_intra_mode_using_best_sad_so_far && bsize == tx_bsize)
args.prune_mode_based_on_sad = true;
// Change the limit of this loop to add other intra prediction // mode tests. for (int mode_index = 0; mode_index < RTC_INTRA_MODES; ++mode_index) {
PREDICTION_MODE this_mode = intra_mode_list[mode_index];
// Force DC for spatially flat block for large bsize, on top-left corner. // This removed potential artifact observed in gray scale image for high Q. if (x->source_variance == 0 && mi_col == 0 && mi_row == 0 &&
bsize >= BLOCK_32X32 && this_mode > 0) continue;
// As per the statistics generated for intra mode evaluation in the nonrd // path, it is found that the probability of H_PRED mode being the winner is // very low when the best mode so far is V_PRED (out of DC_PRED and V_PRED). // If V_PRED is the winner mode out of DC_PRED and V_PRED, it could imply // the presence of a vertically dominant pattern. Hence, H_PRED mode is not // evaluated. if (cpi->sf.rt_sf.prune_h_pred_using_best_mode_so_far &&
this_mode == H_PRED && best_mode == V_PRED) continue;
if (should_prune_intra_modes_using_neighbors(
xd, cpi->sf.rt_sf.enable_intra_mode_pruning_using_neighbors,
this_mode, A, L)) { // Prune V_PRED and H_PRED if source variance of the block is less than // or equal to 50. The source variance threshold is obtained empirically. if ((this_mode == V_PRED || this_mode == H_PRED) && source_variance <= 50) continue;
// As per the statistics, probability of SMOOTH_PRED being the winner is // low when best mode so far is DC_PRED (out of DC_PRED, V_PRED and // H_PRED). Hence, SMOOTH_PRED mode is not evaluated. if (best_mode == DC_PRED && this_mode == SMOOTH_PRED) continue;
}
// Search palette mode for Luma plane in intra frame.
av1_search_palette_mode_luma(cpi, x, bsize, intra_ref_frame_cost, ctx,
&this_rdc, best_rdc.rdcost); // Update best mode data. if (this_rdc.rdcost < best_rdc.rdcost) {
best_mode = DC_PRED;
mi->mv[0].as_int = INVALID_MV;
mi->mv[1].as_int = INVALID_MV;
best_rdc.rate = this_rdc.rate;
best_rdc.dist = this_rdc.dist;
best_rdc.rdcost = this_rdc.rdcost; if (!this_rdc.skip_txfm) {
memcpy(ctx->blk_skip, txfm_info->blk_skip, sizeof(txfm_info->blk_skip[0]) * ctx->num_4x4_blk);
} if (xd->tx_type_map[0] != DCT_DCT)
av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
} else {
av1_zero(mi->palette_mode_info);
}
}
mi->mode = best_mode; // Keep DC for UV since mode test is based on Y channel only.
mi->uv_mode = UV_DC_PRED;
*rd_cost = best_rdc;
// For lossless: always force the skip flags off. // Even though the blk_skip is set to 0 above in the rdcost comparison, // do it here again in case the above logic changes. if (is_lossless_requested(&cpi->oxcf.rc_cfg)) {
x->txfm_search_info.skip_txfm = 0;
memset(ctx->blk_skip, 0, sizeof(x->txfm_search_info.blk_skip[0]) * ctx->num_4x4_blk);
}
staticinlinevoid get_ref_frame_use_mask(AV1_COMP *cpi, MACROBLOCK *x,
MB_MODE_INFO *mi, int mi_row, int mi_col, BLOCK_SIZE bsize, int gf_temporal_ref, int use_ref_frame[], int *force_skip_low_temp_var) {
AV1_COMMON *const cm = &cpi->common; conststruct segmentation *const seg = &cm->seg; constint is_small_sb = (cm->seq_params->sb_size == BLOCK_64X64);
// When the ref_frame_config is used to set the reference frame structure // then the usage of alt_ref is determined by the ref_frame_flags // (and not the speed feature use_nonrd_altref_frame). int use_alt_ref_frame = cpi->ppi->rtc_ref.set_ref_frame_config ||
cpi->sf.rt_sf.use_nonrd_altref_frame;
int use_golden_ref_frame = 1; int use_last_ref_frame = 1;
// When the ref_frame_config is used to set the reference frame structure: // check if LAST is used as a reference. And only remove golden and altref // references below if last is used as a reference. if (cpi->ppi->rtc_ref.set_ref_frame_config)
use_last_ref_frame =
cpi->ref_frame_flags & AOM_LAST_FLAG ? use_last_ref_frame : 0;
// frame_since_golden is not used when user sets the referene structure. if (!cpi->ppi->rtc_ref.set_ref_frame_config && use_last_ref_frame &&
cpi->rc.frames_since_golden == 0 && gf_temporal_ref) {
use_golden_ref_frame = 0;
}
if (use_last_ref_frame && cpi->sf.rt_sf.short_circuit_low_temp_var &&
x->nonrd_prune_ref_frame_search) { if (is_small_sb)
*force_skip_low_temp_var = av1_get_force_skip_low_temp_var_small_sb(
&x->part_search_info.variance_low[0], mi_row, mi_col, bsize); else
*force_skip_low_temp_var = av1_get_force_skip_low_temp_var(
&x->part_search_info.variance_low[0], mi_row, mi_col, bsize); // If force_skip_low_temp_var is set, skip golden reference. if (*force_skip_low_temp_var) {
use_golden_ref_frame = 0;
use_alt_ref_frame = 0;
}
}
// Skip golden/altref reference if color is set, on flat blocks with motion. // For screen: always skip golden/alt (if color_sensitivity_sb_g/alt is set) // except when x->nonrd_prune_ref_frame_search = 0. This latter flag // may be set in the variance partition when golden is a much better // reference than last, in which case it may not be worth skipping // golden/altref completely. // Condition on use_last_ref to make sure there remains at least one // reference. if (use_last_ref_frame &&
((cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN &&
x->nonrd_prune_ref_frame_search != 0) ||
(x->source_variance < 200 &&
x->content_state_sb.source_sad_nonrd >= kLowSad))) { if (x->color_sensitivity_sb_g[COLOR_SENS_IDX(AOM_PLANE_U)] == 1 ||
x->color_sensitivity_sb_g[COLOR_SENS_IDX(AOM_PLANE_V)] == 1)
use_golden_ref_frame = 0; if (x->color_sensitivity_sb_alt[COLOR_SENS_IDX(AOM_PLANE_U)] == 1 ||
x->color_sensitivity_sb_alt[COLOR_SENS_IDX(AOM_PLANE_V)] == 1)
use_alt_ref_frame = 0;
}
// For non-screen: if golden and altref are not being selected as references // (use_golden_ref_frame/use_alt_ref_frame = 0) check to allow golden back // based on the sad of nearest/nearmv of LAST ref. If this block sad is large, // keep golden as reference. Only do this for the agrressive pruning mode and // avoid it when color is set for golden reference. if (cpi->oxcf.tune_cfg.content != AOM_CONTENT_SCREEN &&
(cpi->ref_frame_flags & AOM_LAST_FLAG) && !use_golden_ref_frame &&
!use_alt_ref_frame && x->pred_mv_sad[LAST_FRAME] != INT_MAX &&
x->nonrd_prune_ref_frame_search > 2 &&
x->color_sensitivity_sb_g[COLOR_SENS_IDX(AOM_PLANE_U)] == 0 &&
x->color_sensitivity_sb_g[COLOR_SENS_IDX(AOM_PLANE_V)] == 0) { int thr = (cm->width * cm->height > RESOLUTION_288P) ? 100 : 150; int pred = x->pred_mv_sad[LAST_FRAME] >>
(b_width_log2_lookup[bsize] + b_height_log2_lookup[bsize]); if (pred > thr) use_golden_ref_frame = 1;
}
// For spatial layers: enable golden ref if it is set by user and // corresponds to the lower spatial layer. if (cpi->svc.spatial_layer_id > 0 && (cpi->ref_frame_flags & AOM_GOLD_FLAG) &&
x->content_state_sb.source_sad_nonrd < kHighSad) { constint buffslot_golden =
cpi->ppi->rtc_ref.ref_idx[GOLDEN_FRAME - LAST_FRAME]; if (cpi->ppi->rtc_ref.buffer_time_index[buffslot_golden] ==
cpi->svc.current_superframe)
use_golden_ref_frame = 1;
}
use_ref_frame[ALTREF_FRAME] = use_alt_ref_frame;
use_ref_frame[GOLDEN_FRAME] = use_golden_ref_frame;
use_ref_frame[LAST_FRAME] = use_last_ref_frame; // Keep this assert on, as only 3 references are used in nonrd_pickmode // (LAST, GOLDEN, ALTREF), and if all 3 are not set by user then this // frame must be an intra-only frame and hence should never enter the // pickmode here for inter frames.
assert(use_last_ref_frame || use_golden_ref_frame || use_alt_ref_frame);
}
staticinlineint is_filter_search_enabled_blk(AV1_COMP *cpi, MACROBLOCK *x, int mi_row, int mi_col,
BLOCK_SIZE bsize, int segment_id, int cb_pred_filter_search,
InterpFilter *filt_select) { const AV1_COMMON *const cm = &cpi->common; // filt search disabled if (!cpi->sf.rt_sf.use_nonrd_filter_search) return 0; // filt search purely based on mode properties if (!cb_pred_filter_search) return 1;
MACROBLOCKD *const xd = &x->e_mbd; int enable_interp_search = 0; if (!(xd->left_mbmi && xd->above_mbmi)) { // neighbors info unavailable
enable_interp_search = 2;
} elseif (!(is_inter_block(xd->left_mbmi) &&
is_inter_block(xd->above_mbmi))) { // neighbor is INTRA
enable_interp_search = 2;
} elseif (xd->left_mbmi->interp_filters.as_int !=
xd->above_mbmi->interp_filters.as_int) { // filters are different
enable_interp_search = 2;
} elseif ((cb_pred_filter_search == 1) &&
(xd->left_mbmi->interp_filters.as_filters.x_filter !=
EIGHTTAP_REGULAR)) { // not regular
enable_interp_search = 2;
} else { // enable prediction based on chessboard pattern if (xd->left_mbmi->interp_filters.as_filters.x_filter == EIGHTTAP_SMOOTH)
*filt_select = EIGHTTAP_SMOOTH; constint bsl = mi_size_wide_log2[bsize];
enable_interp_search =
(bool)((((mi_row + mi_col) >> bsl) +
get_chessboard_index(cm->current_frame.frame_number)) &
0x1); if (cyclic_refresh_segment_id_boosted(segment_id)) enable_interp_search = 1;
} return enable_interp_search;
}
// Skip testing non-LAST if this flag is set. if (extra_prune) { if (extra_prune > 1 && ref_frame != LAST_FRAME &&
(bsize > BLOCK_16X16 && mode == NEWMV)) return 1;
if (ref_frame != LAST_FRAME && mode == NEARMV) return 1;
staticvoid set_color_sensitivity(AV1_COMP *cpi, MACROBLOCK *x,
BLOCK_SIZE bsize, int y_sad, unsignedint source_variance, struct buf_2d yv12_mb[MAX_MB_PLANE]) { constint subsampling_x = cpi->common.seq_params->subsampling_x; constint subsampling_y = cpi->common.seq_params->subsampling_y; constint source_sad_nonrd = x->content_state_sb.source_sad_nonrd; constint high_res = cpi->common.width * cpi->common.height >= 640 * 360; if (bsize == cpi->common.seq_params->sb_size &&
!x->force_color_check_block_level) { // At superblock level color_sensitivity is already set to 0, 1, or 2. // 2 is middle/uncertain level. To avoid additional sad // computations when bsize = sb_size force level 2 to 1 (certain color) // for motion areas. Avoid this shortcut if x->force_color_check_block_level // is set. if (x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_U)] == 2) {
x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_U)] =
source_sad_nonrd >= kMedSad ? 1 : 0;
} if (x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_V)] == 2) {
x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_V)] =
source_sad_nonrd >= kMedSad ? 1 : 0;
} return;
} // Divide factor for comparing uv_sad to y_sad. int shift = 3; // Threshold for the block spatial source variance. unsignedint source_var_thr = 50; // Thresholds for normalized uv_sad, the first one is used for // low source_varaince. int norm_uv_sad_thresh = 100; int norm_uv_sad_thresh2 = 40; if (source_sad_nonrd >= kMedSad && x->source_variance > 0 && high_res)
shift = 4; if (cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN) { if (cpi->rc.high_source_sad) shift = 6; if (source_sad_nonrd > kMedSad) {
source_var_thr = 1200;
norm_uv_sad_thresh = 10;
} if (cpi->rc.percent_blocks_with_motion > 90 &&
cpi->rc.frame_source_sad > 10000 && source_sad_nonrd > kLowSad) { // Aggressive setting for color_sensitivity for this content.
shift = 10;
norm_uv_sad_thresh = 0;
norm_uv_sad_thresh2 = 0;
}
}
NOISE_LEVEL noise_level = kLow; int norm_sad =
y_sad >> (b_width_log2_lookup[bsize] + b_height_log2_lookup[bsize]); unsignedint thresh_spatial = (cpi->common.width > 1920) ? 5000 : 1000; // If the spatial source variance is high and the normalized y_sad // is low, then y-channel is likely good for mode estimation, so keep // color_sensitivity off. For low noise content for now, since there is // some bdrate regression for noisy color clip. if (cpi->noise_estimate.enabled)
noise_level = av1_noise_estimate_extract_level(&cpi->noise_estimate); if (noise_level == kLow && source_variance > thresh_spatial &&
cpi->oxcf.tune_cfg.content != AOM_CONTENT_SCREEN && norm_sad < 50) {
x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_U)] = 0;
x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_V)] = 0; return;
} constint num_planes = av1_num_planes(&cpi->common);
for (int plane = AOM_PLANE_U; plane < num_planes; ++plane) { // Always check if level = 2. If level = 0 check again for // motion areas for higher resolns, where color artifacts // are more noticeable. Always check if // x->force_color_check_block_level is set. if (x->color_sensitivity[COLOR_SENS_IDX(plane)] == 2 ||
x->force_color_check_block_level ||
(x->color_sensitivity[COLOR_SENS_IDX(plane)] == 0 &&
source_sad_nonrd >= kMedSad && high_res)) { struct macroblock_plane *const p = &x->plane[plane]; const BLOCK_SIZE bs =
get_plane_block_size(bsize, subsampling_x, subsampling_y);
// Prune compound mode if the single mode variance is lower than a fixed // percentage of the median value. staticbool skip_comp_based_on_var( constunsignedint (*single_vars)[REF_FRAMES], BLOCK_SIZE bsize) { unsignedint best_var = UINT_MAX; for (int cur_mode_idx = 0; cur_mode_idx < RTC_INTER_MODES; cur_mode_idx++) { for (int ref_idx = 0; ref_idx < REF_FRAMES; ref_idx++) {
best_var = AOMMIN(best_var, single_vars[cur_mode_idx][ref_idx]);
}
} constunsignedint thresh_64 = (unsignedint)(0.57356805f * 8659); constunsignedint thresh_32 = (unsignedint)(0.23964763f * 4281);
// Currently, the thresh for 128 and 16 are not well-tuned. We are using the // results from 64 and 32 as an heuristic. switch (bsize) { case BLOCK_128X128: return best_var < 4 * thresh_64; case BLOCK_64X64: return best_var < thresh_64; case BLOCK_32X32: return best_var < thresh_32; case BLOCK_16X16: return best_var < thresh_32 / 4; default: returnfalse;
}
}
// Skip the mode if use reference frame mask flag is not set. if (!search_state->use_ref_frame_mask[*ref_frame]) returntrue;
// Skip mode for some modes and reference frames when // force_zeromv_skip_for_blk flag is true. if (x->force_zeromv_skip_for_blk &&
((!(*this_mode == NEARESTMV &&
search_state->frame_mv[*this_mode][*ref_frame].as_int == 0) &&
*this_mode != GLOBALMV) ||
*ref_frame != LAST_FRAME)) returntrue;
if (x->sb_me_block && *ref_frame == LAST_FRAME) { // We want to make sure to test the superblock MV: // so don't skip (return false) for NEAREST_LAST or NEAR_LAST if they // have this sb MV. And don't skip NEWMV_LAST: this will be set to // sb MV in handle_inter_mode_nonrd(), in case NEAREST or NEAR don't // have it. if (*this_mode == NEARESTMV &&
search_state->frame_mv[NEARESTMV][LAST_FRAME].as_int ==
x->sb_me_mv.as_int) { returnfalse;
} if (*this_mode == NEARMV &&
search_state->frame_mv[NEARMV][LAST_FRAME].as_int ==
x->sb_me_mv.as_int) { returnfalse;
} if (*this_mode == NEWMV) { returnfalse;
}
}
// Skip the single reference mode for which mode check flag is set. if (*is_single_pred && search_state->mode_checked[*this_mode][*ref_frame]) { returntrue;
}
// Skip GLOBALMV mode if check_globalmv flag is not enabled. if (!check_globalmv && *this_mode == GLOBALMV) { returntrue;
}
// Skip compound mode based on variance of previously evaluated single // reference modes. if (rt_sf->prune_compoundmode_with_singlemode_var && !*is_single_pred &&
prune_compoundmode_with_singlemode_var(
*this_mode, *ref_frame, *ref_frame2, search_state->frame_mv,
search_state->mode_checked, search_state->vars,
search_state->uv_dist)) { returntrue;
}
*force_mv_inter_layer = 0; if (cpi->ppi->use_svc && svc->spatial_layer_id > 0 &&
((*ref_frame == LAST_FRAME && svc->skip_mvsearch_last) ||
(*ref_frame == GOLDEN_FRAME && svc->skip_mvsearch_gf) ||
(*ref_frame == ALTREF_FRAME && svc->skip_mvsearch_altref))) { // Only test mode if NEARESTMV/NEARMV is (svc_mv.mv.col, svc_mv.mv.row), // otherwise set NEWMV to (svc_mv.mv.col, svc_mv.mv.row). // Skip newmv and filter search.
*force_mv_inter_layer = 1; if (*this_mode == NEWMV) {
search_state->frame_mv[*this_mode][*ref_frame] = svc_mv;
} elseif (search_state->frame_mv[*this_mode][*ref_frame].as_int !=
svc_mv.as_int) { returntrue;
}
}
// If the segment reference frame feature is enabled then do nothing if the // current ref frame is not allowed. if (segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME) &&
get_segdata(seg, segment_id, SEG_LVL_REF_FRAME) != (int)(*ref_frame)) returntrue;
// For screen content: skip mode testing based on source_sad. if (cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN &&
!x->force_zeromv_skip_for_blk) { // If source_sad is computed: skip non-zero motion // check for stationary (super)blocks. Otherwise if superblock // has motion skip the modes with zero motion on last reference // for flat blocks, and color is not set. // For the latter condition: the same condition should apply // to newmv if (0, 0), so this latter condition is repeated // below after search_new_mv. if (rt_sf->source_metrics_sb_nonrd) { if ((search_state->frame_mv[*this_mode][*ref_frame].as_int != 0 &&
x->content_state_sb.source_sad_nonrd == kZeroSad) ||
(search_state->frame_mv[*this_mode][*ref_frame].as_int == 0 &&
x->block_is_zero_sad == 0 && *ref_frame == LAST_FRAME &&
((x->color_sensitivity_sb[COLOR_SENS_IDX(AOM_PLANE_U)] == 0 &&
x->color_sensitivity_sb[COLOR_SENS_IDX(AOM_PLANE_V)] == 0) ||
cpi->rc.high_source_sad) &&
x->source_variance == 0)) returntrue;
} // Skip NEWMV search for flat blocks. if (rt_sf->skip_newmv_flat_blocks_screen && *this_mode == NEWMV &&
x->source_variance < 100) returntrue; // Skip non-LAST for color on flat blocks. if (*ref_frame > LAST_FRAME && x->source_variance == 0 &&
(x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_U)] == 1 ||
x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_V)] == 1)) returntrue;
}
// Skip mode based on block size, reference frame mode and other block // properties. if (skip_mode_by_bsize_and_ref_frame(
*this_mode, *ref_frame, bsize, x->nonrd_prune_ref_frame_search,
sse_zeromv_norm, rt_sf->nonrd_aggressive_skip,
rt_sf->increase_source_sad_thresh)) returntrue;
// Skip mode based on low temporal variance and souce sad. if (skip_mode_by_low_temp(*this_mode, *ref_frame, bsize, x->content_state_sb,
search_state->frame_mv[*this_mode][*ref_frame],
force_skip_low_temp_var)) returntrue;
// Disable this drop out case if the ref frame segment level feature is // enabled for this segment. This is to prevent the possibility that we // end up unable to pick any mode. if (!segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME)) { // Check for skipping GOLDEN and ALTREF based pred_mv_sad. if (rt_sf->nonrd_prune_ref_frame_search > 0 &&
x->pred_mv_sad[*ref_frame] != INT_MAX && *ref_frame != LAST_FRAME) { if ((int64_t)(x->pred_mv_sad[*ref_frame]) > *thresh_sad_pred) returntrue;
}
}
// Check for skipping NEARMV based on pred_mv_sad. if (*this_mode == NEARMV && x->pred_mv1_sad[*ref_frame] != INT_MAX &&
x->pred_mv1_sad[*ref_frame] > (x->pred_mv0_sad[*ref_frame] << 1)) returntrue;
// Skip single reference mode based on rd threshold. if (*is_single_pred) { if (skip_mode_by_threshold(
*this_mode, *ref_frame,
search_state->frame_mv[*this_mode][*ref_frame],
cpi->rc.frames_since_golden, cpi->rd.threshes[segment_id][bsize],
x->thresh_freq_fact[bsize], search_state->best_rdc.rdcost,
search_state->best_pickmode.best_mode_skip_txfm,
(rt_sf->nonrd_aggressive_skip ? 1 : 0))) returntrue;
} returnfalse;
}
// Function to perform inter mode evaluation for non-rd static AOM_FORCE_INLINE bool handle_inter_mode_nonrd(
AV1_COMP *cpi, MACROBLOCK *x, InterModeSearchStateNonrd *search_state,
PICK_MODE_CONTEXT *ctx, PRED_BUFFER **this_mode_pred,
PRED_BUFFER *tmp_buffer, InterPredParams inter_pred_params_sr, int *best_early_term, unsignedint *sse_zeromv_norm, bool *check_globalmv, #if CONFIG_AV1_TEMPORAL_DENOISING
int64_t *zero_last_cost_orig, int denoise_svc_pickmode, #endif int idx, int force_mv_inter_layer, int is_single_pred, int gf_temporal_ref, int use_model_yrd_large, int filter_search_enabled_blk, BLOCK_SIZE bsize,
PREDICTION_MODE this_mode, InterpFilter filt_select, int cb_pred_filter_search, int reuse_inter_pred, int *sb_me_has_been_tested) {
AV1_COMMON *const cm = &cpi->common;
MACROBLOCKD *const xd = &x->e_mbd;
MB_MODE_INFO *const mi = xd->mi[0]; const MB_MODE_INFO_EXT *const mbmi_ext = &x->mbmi_ext; constint mi_row = xd->mi_row; constint mi_col = xd->mi_col; struct macroblockd_plane *const pd = &xd->plane[AOM_PLANE_Y]; constint bw = block_size_wide[bsize]; const InterpFilter filter_ref = cm->features.interp_filter; const InterpFilter default_interp_filter = EIGHTTAP_REGULAR;
TxfmSearchInfo *txfm_info = &x->txfm_search_info; const ModeCosts *mode_costs = &x->mode_costs; const REAL_TIME_SPEED_FEATURES *const rt_sf = &cpi->sf.rt_sf;
BEST_PICKMODE *const best_pickmode = &search_state->best_pickmode;
MV_REFERENCE_FRAME ref_frame = mi->ref_frame[0];
MV_REFERENCE_FRAME ref_frame2 = mi->ref_frame[1];
int_mv *const this_mv = &search_state->frame_mv[this_mode][ref_frame]; unsignedint var = UINT_MAX; int this_early_term = 0; int rate_mv = 0; int is_skippable; int skip_this_mv = 0; unsignedint var_threshold = UINT_MAX;
PREDICTION_MODE this_best_mode;
RD_STATS nonskip_rdc;
av1_invalid_rd_stats(&nonskip_rdc);
if (x->sb_me_block && this_mode == NEWMV && ref_frame == LAST_FRAME) { // Set the NEWMV_LAST to the sb MV.
search_state->frame_mv[NEWMV][LAST_FRAME].as_int = x->sb_me_mv.as_int;
} elseif (this_mode == NEWMV && !force_mv_inter_layer) { #if COLLECT_NONRD_PICK_MODE_STAT
aom_usec_timer_start(&x->ms_stat_nonrd.timer2); #endif // Find the best motion vector for single/compound mode. constbool skip_newmv = search_new_mv(
cpi, x, search_state->frame_mv, ref_frame, gf_temporal_ref, bsize,
mi_row, mi_col, &rate_mv, &search_state->best_rdc); #if COLLECT_NONRD_PICK_MODE_STAT
aom_usec_timer_mark(&x->ms_stat_nonrd.timer2);
x->ms_stat_nonrd.ms_time[bsize][this_mode] +=
aom_usec_timer_elapsed(&x->ms_stat_nonrd.timer2); #endif // Skip NEWMV mode, // (i). For bsize smaller than 16X16 // (ii). Based on sad of the predicted mv w.r.t LAST_FRAME // (iii). When motion vector is same as that of reference mv if (skip_newmv) { returntrue;
}
}
// Check the current motion vector is same as that of previously evaluated // motion vectors. for (PREDICTION_MODE inter_mv_mode = NEARESTMV; inter_mv_mode <= NEWMV;
inter_mv_mode++) { if (inter_mv_mode == this_mode) continue; if (is_single_pred &&
search_state->mode_checked[inter_mv_mode][ref_frame] &&
this_mv->as_int ==
search_state->frame_mv[inter_mv_mode][ref_frame].as_int) {
skip_this_mv = 1; break;
}
}
// Skip single mode if current motion vector is same that of previously // evaluated motion vectors. if (skip_this_mv && is_single_pred) returntrue;
// For screen: for spatially flat blocks with non-zero motion, // skip newmv if the motion vector is (0, 0)-LAST, and color is not set. if (this_mode == NEWMV && cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN &&
cpi->svc.spatial_layer_id == 0 && rt_sf->source_metrics_sb_nonrd) { if (this_mv->as_int == 0 && ref_frame == LAST_FRAME &&
x->block_is_zero_sad == 0 &&
((x->color_sensitivity_sb[COLOR_SENS_IDX(AOM_PLANE_U)] == 0 &&
x->color_sensitivity_sb[COLOR_SENS_IDX(AOM_PLANE_V)] == 0) ||
cpi->rc.high_source_sad) &&
x->source_variance == 0) returntrue;
}
// If it is sub-pel motion and cb_pred_filter_search is enabled, select // the pre-decided filter if (is_mv_subpel && cb_pred_filter_search)
mi->interp_filters = av1_broadcast_interp_filter(filt_select);
#if COLLECT_NONRD_PICK_MODE_STAT
aom_usec_timer_start(&x->ms_stat_nonrd.timer2); #endif if (is_single_pred) {
SubpelParams subpel_params; // Initialize inter mode level params for single reference mode.
init_inter_mode_params(&mi->mv[0].as_mv, &inter_pred_params_sr,
&subpel_params, xd->block_ref_scale_factors[0],
pd->pre->width, pd->pre->height);
av1_enc_build_inter_predictor_y_nonrd(xd, &inter_pred_params_sr,
&subpel_params);
} else {
av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize,
AOM_PLANE_Y, AOM_PLANE_Y);
}
// update variance for single mode if (is_single_pred) {
search_state->vars[INTER_OFFSET(this_mode)][ref_frame] = var; if (this_mv->as_int == 0) {
search_state->vars[INTER_OFFSET(GLOBALMV)][ref_frame] = var;
}
} // prune compound mode based on single mode var threshold if (!is_single_pred && var > var_threshold) { if (reuse_inter_pred) free_pred_buffer(*this_mode_pred); returntrue;
}
// Perform early termination based on sse. if (rt_sf->sse_early_term_inter_search &&
early_term_inter_search_with_sse(rt_sf->sse_early_term_inter_search,
bsize, search_state->this_rdc.sse,
best_pickmode->best_sse, this_mode)) { if (reuse_inter_pred) free_pred_buffer(*this_mode_pred); returntrue;
}
if (this_early_term) {
search_state->this_rdc.skip_txfm = 1;
search_state->this_rdc.rate = skip_txfm_cost;
search_state->this_rdc.dist = search_state->this_rdc.sse << 4;
} else { #if COLLECT_NONRD_PICK_MODE_STAT
aom_usec_timer_start(&x->ms_stat_nonrd.timer2); #endif // Calculates RD Cost using Hadamard transform.
av1_block_yrd(x, &search_state->this_rdc, &is_skippable, bsize,
mi->tx_size); if (search_state->this_rdc.skip_txfm ||
RDCOST(x->rdmult, search_state->this_rdc.rate,
search_state->this_rdc.dist) >=
RDCOST(x->rdmult, 0, search_state->this_rdc.sse)) { if (!search_state->this_rdc.skip_txfm) { // Need to store "real" rdc for possible future use if UV rdc // disallows tx skip
nonskip_rdc = search_state->this_rdc;
nonskip_rdc.rate += no_skip_txfm_cost;
}
search_state->this_rdc.rate = skip_txfm_cost;
search_state->this_rdc.skip_txfm = 1;
search_state->this_rdc.dist = search_state->this_rdc.sse;
} else {
search_state->this_rdc.rate += no_skip_txfm_cost;
}
// Populate predicted sample for chroma planes based on color sensitivity. if ((x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_U)] ||
x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_V)])) {
RD_STATS rdc_uv; const BLOCK_SIZE uv_bsize =
get_plane_block_size(bsize, xd->plane[AOM_PLANE_U].subsampling_x,
xd->plane[AOM_PLANE_U].subsampling_y); if (x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_U)]) {
av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize,
AOM_PLANE_U, AOM_PLANE_U);
} if (x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_V)]) {
av1_enc_build_inter_predictor(cm, xd, mi_row, mi_col, NULL, bsize,
AOM_PLANE_V, AOM_PLANE_V);
} // Compute sse for chroma planes. const int64_t sse_uv = av1_model_rd_for_sb_uv(
cpi, uv_bsize, x, xd, &rdc_uv, AOM_PLANE_U, AOM_PLANE_V); if (rdc_uv.dist < x->min_dist_inter_uv)
x->min_dist_inter_uv = rdc_uv.dist;
search_state->this_rdc.sse += sse_uv; // Restore Y rdc if UV rdc disallows txfm skip if (search_state->this_rdc.skip_txfm && !rdc_uv.skip_txfm &&
nonskip_rdc.rate != INT_MAX)
search_state->this_rdc = nonskip_rdc; if (is_single_pred) {
search_state->uv_dist[INTER_OFFSET(this_mode)][ref_frame] = rdc_uv.dist;
}
search_state->this_rdc.rate += rdc_uv.rate;
search_state->this_rdc.dist += rdc_uv.dist;
search_state->this_rdc.skip_txfm =
search_state->this_rdc.skip_txfm && rdc_uv.skip_txfm;
} #if COLLECT_NONRD_PICK_MODE_STAT
aom_usec_timer_mark(&x->ms_stat_nonrd.timer2);
x->ms_stat_nonrd.txfm_time[bsize][this_mode] +=
aom_usec_timer_elapsed(&x->ms_stat_nonrd.timer2); #endif
}
this_best_mode = this_mode; // TODO(kyslov) account for UV prediction cost
search_state->this_rdc.rate += rate_mv; if (!is_single_pred) { const int16_t mode_ctx =
av1_mode_context_analyzer(mbmi_ext->mode_context, mi->ref_frame);
search_state->this_rdc.rate += cost_mv_ref(mode_costs, this_mode, mode_ctx);
} else { // If the current mode has zeromv but is not GLOBALMV, compare the rate // cost. If GLOBALMV is cheaper, use GLOBALMV instead. if (this_mode != GLOBALMV &&
this_mv->as_int == search_state->frame_mv[GLOBALMV][ref_frame].as_int) { if (is_globalmv_better(this_mode, ref_frame, rate_mv, mode_costs,
search_state->single_inter_mode_costs, mbmi_ext)) {
this_best_mode = GLOBALMV;
}
}
if (*check_globalmv) {
int32_t abs_mv =
abs(search_state->frame_mv[this_best_mode][ref_frame].as_mv.row) +
abs(search_state->frame_mv[this_best_mode][ref_frame].as_mv.col); // Early exit check: if the magnitude of this_best_mode's mv is small // enough, we skip GLOBALMV check in the next loop iteration. if (abs_mv < 2) {
*check_globalmv = false;
}
} #if COLLECT_NONRD_PICK_MODE_STAT
aom_usec_timer_mark(&x->ms_stat_nonrd.timer1);
x->ms_stat_nonrd.nonskipped_search_times[bsize][this_mode] +=
aom_usec_timer_elapsed(&x->ms_stat_nonrd.timer1); #endif
// Copy best mode params to search state if (search_state->this_rdc.rdcost < search_state->best_rdc.rdcost) {
search_state->best_rdc = search_state->this_rdc;
*best_early_term = this_early_term;
update_search_state_nonrd(search_state, mi, txfm_info, &nonskip_rdc, ctx,
this_best_mode, sse_y);
// This is needed for the compound modes.
search_state->frame_mv_best[this_best_mode][ref_frame].as_int =
search_state->frame_mv[this_best_mode][ref_frame].as_int; if (ref_frame2 > NONE_FRAME) {
search_state->frame_mv_best[this_best_mode][ref_frame2].as_int =
search_state->frame_mv[this_best_mode][ref_frame2].as_int;
}
if (reuse_inter_pred) {
free_pred_buffer(best_pickmode->best_pred);
best_pickmode->best_pred = *this_mode_pred;
}
} else { if (reuse_inter_pred) free_pred_buffer(*this_mode_pred);
}
if (*best_early_term && (idx > 0 || rt_sf->nonrd_aggressive_skip)) {
txfm_info->skip_txfm = 1; if (!x->sb_me_block || *sb_me_has_been_tested) returnfalse;
} returntrue;
}
// Function to perform screen content mode evaluation for non-rd static AOM_FORCE_INLINE void handle_screen_content_mode_nonrd(
AV1_COMP *cpi, MACROBLOCK *x, InterModeSearchStateNonrd *search_state,
PRED_BUFFER *this_mode_pred, PICK_MODE_CONTEXT *ctx,
PRED_BUFFER *tmp_buffer, struct buf_2d *orig_dst, int skip_idtx_palette, int try_palette, BLOCK_SIZE bsize, int reuse_inter_pred, int mi_col, int mi_row) {
AV1_COMMON *const cm = &cpi->common; const REAL_TIME_SPEED_FEATURES *const rt_sf = &cpi->sf.rt_sf;
MACROBLOCKD *const xd = &x->e_mbd;
MB_MODE_INFO *const mi = xd->mi[0]; struct macroblockd_plane *const pd = &xd->plane[0]; constint bw = block_size_wide[bsize]; constint bh = block_size_high[bsize];
TxfmSearchInfo *txfm_info = &x->txfm_search_info;
BEST_PICKMODE *const best_pickmode = &search_state->best_pickmode;
if (!try_palette) return; constunsignedint intra_ref_frame_cost =
search_state->ref_costs_single[INTRA_FRAME];
if (!is_mode_intra(best_pickmode->best_mode)) {
PRED_BUFFER *const best_pred = best_pickmode->best_pred; if (reuse_inter_pred && best_pred != NULL) { if (best_pred->data == orig_dst->buf) {
this_mode_pred = &tmp_buffer[get_pred_buffer(tmp_buffer, 3)];
aom_convolve_copy(best_pred->data, best_pred->stride,
this_mode_pred->data, this_mode_pred->stride, bw, bh);
best_pickmode->best_pred = this_mode_pred;
}
}
pd->dst = *orig_dst;
} // Search palette mode for Luma plane in inter frame.
av1_search_palette_mode_luma(cpi, x, bsize, intra_ref_frame_cost, ctx,
&search_state->this_rdc,
search_state->best_rdc.rdcost); // Update best mode data in search_state if (search_state->this_rdc.rdcost < search_state->best_rdc.rdcost) {
best_pickmode->pmi = mi->palette_mode_info;
best_pickmode->best_mode = DC_PRED;
mi->mv[0].as_int = INVALID_MV;
mi->mv[1].as_int = INVALID_MV;
best_pickmode->best_ref_frame = INTRA_FRAME;
best_pickmode->best_second_ref_frame = NONE;
search_state->best_rdc.rate = search_state->this_rdc.rate;
search_state->best_rdc.dist = search_state->this_rdc.dist;
search_state->best_rdc.rdcost = search_state->this_rdc.rdcost;
best_pickmode->best_mode_skip_txfm = search_state->this_rdc.skip_txfm; // Keep the skip_txfm off if the color_sensitivity is set. if (x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_U)] ||
x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_V)])
search_state->this_rdc.skip_txfm = 0; if (!search_state->this_rdc.skip_txfm) {
memcpy(ctx->blk_skip, txfm_info->blk_skip, sizeof(txfm_info->blk_skip[0]) * ctx->num_4x4_blk);
} if (xd->tx_type_map[0] != DCT_DCT)
av1_copy_array(ctx->tx_type_map, xd->tx_type_map, ctx->num_4x4_blk);
}
}
staticinlinebool enable_palette(AV1_COMP *cpi, bool is_mode_intra,
BLOCK_SIZE bsize, unsignedint source_variance, int force_zeromv_skip, int skip_idtx_palette, int force_palette_test, unsignedint best_intra_sad_norm) { if (!cpi->oxcf.tool_cfg.enable_palette) returnfalse; if (!av1_allow_palette(cpi->common.features.allow_screen_content_tools,
bsize)) { returnfalse;
} if (skip_idtx_palette) returnfalse;
/*!\brief AV1 inter mode selection based on Non-RD optimized model. * * \ingroup nonrd_mode_search * \callgraph * Top level function for Non-RD optimized inter mode selection. * This finction will loop over subset of inter modes and select the best one * based on calculated modelled RD cost. While making decisions which modes to * check, this function applies heuristics based on previously checked modes, * block residual variance, block size, and other factors to prune certain * modes and reference frames. Currently only single reference frame modes * are checked. Additional heuristics are applied to decide if intra modes * need to be checked. * * * \param[in] cpi Top-level encoder structure * \param[in] tile_data Pointer to struct holding adaptive data/contexts/models for the tile during encoding * \param[in] x Pointer to structure holding all the data for the current macroblock * \param[in] rd_cost Struct to keep track of the RD information * \param[in] bsize Current block size * \param[in] ctx Structure to hold snapshot of coding context during the mode picking process * * \remark Nothing is returned. Instead, the MB_MODE_INFO struct inside x * is modified to store information about the best mode computed * in this function. The rd_cost struct is also updated with the RD stats * corresponding to the best mode found.
*/ void av1_nonrd_pick_inter_mode_sb(AV1_COMP *cpi, TileDataEnc *tile_data,
MACROBLOCK *x, RD_STATS *rd_cost,
BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx) {
AV1_COMMON *const cm = &cpi->common;
SVC *const svc = &cpi->svc;
MACROBLOCKD *const xd = &x->e_mbd;
MB_MODE_INFO *const mi = xd->mi[0]; struct macroblockd_plane *const pd = &xd->plane[AOM_PLANE_Y]; const MB_MODE_INFO_EXT *const mbmi_ext = &x->mbmi_ext;
MV_REFERENCE_FRAME ref_frame, ref_frame2; constunsignedchar segment_id = mi->segment_id; int best_early_term = 0; int force_skip_low_temp_var = 0; unsignedint sse_zeromv_norm = UINT_MAX; constint num_inter_modes = NUM_INTER_MODES; const REAL_TIME_SPEED_FEATURES *const rt_sf = &cpi->sf.rt_sf; bool check_globalmv = rt_sf->check_globalmv_on_single_ref;
PRED_BUFFER tmp_buffer[4];
DECLARE_ALIGNED(16, uint8_t, pred_buf[MAX_MB_PLANE * MAX_SB_SQUARE]);
PRED_BUFFER *this_mode_pred = NULL; constint reuse_inter_pred =
rt_sf->reuse_inter_pred_nonrd && cm->seq_params->bit_depth == AOM_BITS_8;
InterModeSearchStateNonrd search_state;
av1_zero(search_state.use_ref_frame_mask);
av1_zero(search_state.use_scaled_ref_frame);
BEST_PICKMODE *const best_pickmode = &search_state.best_pickmode;
(void)tile_data;
// If the lower spatial layer uses an averaging filter for downsampling // (phase = 8), the target decimated pixel is shifted by (1/2, 1/2) relative // to source, so use subpel motion vector to compensate. The nonzero motion // is half pixel shifted to left and top, so (-4, -4). This has more effect // on higher resolutions, so condition it on that for now. // Exclude quality layers, which have the same resolution and hence no shift. if (cpi->ppi->use_svc && svc->spatial_layer_id > 0 &&
!svc->has_lower_quality_layer &&
svc->downsample_filter_phase[svc->spatial_layer_id - 1] == 8 &&
cm->width * cm->height > 640 * 480) {
svc_mv.as_mv.row = -4;
svc_mv.as_mv.col = -4;
}
// Setup parameters used for inter mode evaluation.
set_params_nonrd_pick_inter_mode(cpi, x, &search_state, rd_cost,
&force_skip_low_temp_var, mi_row, mi_col,
gf_temporal_ref, segment_id, bsize #if CONFIG_AV1_TEMPORAL_DENOISING
,
ctx, denoise_svc_pickmode #endif
);
if (rt_sf->use_comp_ref_nonrd && is_comp_ref_allowed(bsize)) { // Only search compound if bsize \gt BLOCK_16X16. if (bsize > BLOCK_16X16) {
comp_use_zero_zeromv_only = rt_sf->check_only_zero_zeromv_on_large_blocks;
} else {
tot_num_comp_modes = 0;
}
} else {
tot_num_comp_modes = 0;
}
if (x->pred_mv_sad[LAST_FRAME] != INT_MAX) {
thresh_sad_pred = ((int64_t)x->pred_mv_sad[LAST_FRAME]) << 1; // Increase threshold for less aggressive pruning. if (rt_sf->nonrd_prune_ref_frame_search == 1)
thresh_sad_pred += (x->pred_mv_sad[LAST_FRAME] >> 2);
}
int sb_me_has_been_tested = 0;
x->sb_me_block = x->sb_me_partition; // Only use this feature (force testing of superblock motion) if coding // block size is large. if (x->sb_me_block) { if (cm->seq_params->sb_size == BLOCK_128X128 && bsize < BLOCK_64X64)
x->sb_me_block = 0; elseif (cm->seq_params->sb_size == BLOCK_64X64 && bsize < BLOCK_32X32)
x->sb_me_block = 0;
}
x->min_dist_inter_uv = INT64_MAX; for (int idx = 0; idx < num_inter_modes + tot_num_comp_modes; ++idx) { // If we are at the first compound mode, and the single modes already // perform well, then end the search. if (rt_sf->skip_compound_based_on_var && idx == num_inter_modes &&
skip_comp_based_on_var(search_state.vars, bsize)) { break;
}
int is_single_pred = 1;
PREDICTION_MODE this_mode;
if (idx == 0 && !x->force_zeromv_skip_for_blk) { // Set color sensitivity on first tested mode only. // Use y-sad already computed in find_predictors: take the sad with motion // vector closest to 0; the uv-sad computed below in set_color_sensitivity // is for zeromv. // For screen: first check if golden reference is being used, if so, // force color_sensitivity on (=1) if the color sensitivity for sb_g is 1. // The check in set_color_sensitivity() will then follow and check for // setting the flag if the level is still 2 or 0. if (cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN &&
search_state.use_ref_frame_mask[GOLDEN_FRAME]) { if (x->color_sensitivity_sb_g[COLOR_SENS_IDX(AOM_PLANE_U)] == 1)
x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_U)] = 1; if (x->color_sensitivity_sb_g[COLOR_SENS_IDX(AOM_PLANE_V)] == 1)
x->color_sensitivity[COLOR_SENS_IDX(AOM_PLANE_V)] = 1;
} if (search_state.use_ref_frame_mask[LAST_FRAME] &&
x->pred_mv0_sad[LAST_FRAME] != INT_MAX) { int y_sad = x->pred_mv0_sad[LAST_FRAME]; if (x->pred_mv1_sad[LAST_FRAME] != INT_MAX &&
(abs(search_state.frame_mv[NEARMV][LAST_FRAME].as_mv.col) +
abs(search_state.frame_mv[NEARMV][LAST_FRAME].as_mv.row)) <
(abs(search_state.frame_mv[NEARESTMV][LAST_FRAME].as_mv.col) +
abs(search_state.frame_mv[NEARESTMV][LAST_FRAME].as_mv.row)))
y_sad = x->pred_mv1_sad[LAST_FRAME];
set_color_sensitivity(cpi, x, bsize, y_sad, x->source_variance,
search_state.yv12_mb[LAST_FRAME]);
}
}
// Check the inter mode can be skipped based on mode statistics and speed // features settings. if (skip_inter_mode_nonrd(cpi, x, &search_state, &thresh_sad_pred,
&force_mv_inter_layer, &is_single_pred,
&this_mode, &last_comp_ref_frame, &ref_frame,
&ref_frame2, idx, svc_mv, force_skip_low_temp_var,
sse_zeromv_norm, num_inter_modes, segment_id,
bsize, comp_use_zero_zeromv_only, check_globalmv)) continue;
// Check if the scaled reference frame should be used. This is set in the // find_predictors() for each usable reference. If so, set the // block_ref_scale_factors[] to no reference scaling. if (search_state.use_scaled_ref_frame[ref_frame]) {
xd->block_ref_scale_factors[0] = &sf_no_scale;
} if (!is_single_pred && search_state.use_scaled_ref_frame[ref_frame2]) {
xd->block_ref_scale_factors[1] = &sf_no_scale;
}
pd->dst = orig_dst; // Best mode is finalized. Restore the mode data to mbmi if (try_palette) mi->palette_mode_info = best_pickmode->pmi;
mi->mode = best_pickmode->best_mode;
mi->ref_frame[0] = best_pickmode->best_ref_frame;
mi->ref_frame[1] = best_pickmode->best_second_ref_frame; // For lossless: always force the skip flags off. if (is_lossless_requested(&cpi->oxcf.rc_cfg)) {
txfm_info->skip_txfm = 0;
memset(ctx->blk_skip, 0, sizeof(ctx->blk_skip[0]) * ctx->num_4x4_blk);
} else {
txfm_info->skip_txfm = best_pickmode->best_mode_skip_txfm;
} if (has_second_ref(mi)) {
mi->comp_group_idx = 0;
mi->compound_idx = 1;
mi->interinter_comp.type = COMPOUND_AVERAGE;
}
if (!is_inter_block(mi)) {
mi->interp_filters = av1_broadcast_interp_filter(SWITCHABLE_FILTERS);
} else { // If inter mode is selected and ref_frame was one that uses the // scaled reference frame, then we can't use reuse_inter_pred. if (search_state.use_scaled_ref_frame[best_pickmode->best_ref_frame] ||
(has_second_ref(mi) &&
search_state
.use_scaled_ref_frame[best_pickmode->best_second_ref_frame]))
x->reuse_inter_pred = 0;
}
// Restore the predicted samples of best mode to final buffer if (reuse_inter_pred && best_pickmode->best_pred != NULL) {
PRED_BUFFER *const best_pred = best_pickmode->best_pred; if (best_pred->data != orig_dst.buf && is_inter_mode(mi->mode)) {
aom_convolve_copy(best_pred->data, best_pred->stride, pd->dst.buf,
pd->dst.stride, bw, bh);
}
}
// Update the factors used for RD thresholding for all modes. if (cpi->sf.inter_sf.adaptive_rd_thresh && !has_second_ref(mi)) {
THR_MODES best_mode_idx =
mode_idx[best_pickmode->best_ref_frame][mode_offset(mi->mode)]; if (best_pickmode->best_ref_frame == INTRA_FRAME) { // Only consider the modes that are included in the intra_mode_list. int intra_modes = sizeof(intra_mode_list) / sizeof(PREDICTION_MODE); for (int mode_index = 0; mode_index < intra_modes; mode_index++) {
update_thresh_freq_fact(cpi, x, bsize, INTRA_FRAME, best_mode_idx,
intra_mode_list[mode_index]);
}
} else {
PREDICTION_MODE this_mode; for (this_mode = NEARESTMV; this_mode <= NEWMV; ++this_mode) {
update_thresh_freq_fact(cpi, x, bsize, best_pickmode->best_ref_frame,
best_mode_idx, this_mode);
}
}
}
// Reset the xd->block_ref_scale_factors[i], as they may have // been set to pointer &sf_no_scale, which becomes invalid afer // this function.
set_ref_ptrs(cm, xd, mi->ref_frame[0], mi->ref_frame[1]);
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.64 Sekunden
(vorverarbeitet am 2026-04-28)
¤
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.