/* * 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);
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.