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. * *\ingroupnonrd_mode_search *\callgraph *\callergraph *FindsthebestMotionVectorbydoingMotionEstimation.Usesreduced *complexityMEfornon-LASTframesorcalls\ccombined_motion_search *forLASTreferenceframe *\param[in]cpiTop-levelencoderstructure *\param[in]xPointertostructureholdingallthe *dataforthecurrentmacroblock *\param[in]frame_mvArraythatholdsMVsforallmodes *andrefframes *\param[in]ref_frameReferenceframeforwhichtofind *thebestNewMVs *\param[in]gf_temporal_refFlag,indicatingtemporalreference *forGOLDENframe *\param[in]bsizeCurrentblocksize *\param[in]mi_rowRowindexin4x4units *\param[in]mi_colColumnindexin4x4units *\param[in]rate_mvPointertoRateofthebestnewMV *\param[in]best_rdcPointertotheRDCostforthebest *modefoundsofar * *\returnReturns-1ifthesearchwasnotdone,otherwisereturns0. *BestNewMVisplacedinto\cframe_mvarray,Rateestimationforthis *vectorisplacedto\crate_mv
*/ static int 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]; unsigned int y_sad_zero;
if (ref_frame > LAST_FRAME && cpi->oxcf.rc_cfg.mode == AOM_CBR &&
(cpi->ref_frame_flags & AOM_LAST_FLAG) && gf_temporal_ref &&
!is_one_pass_rt_lag_params(cpi)) {
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;
static inline void set_force_skip_flag(const AV1_COMP *const cpi,
MACROBLOCK *const x, unsigned int 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) { const int qstep = x->plane[AOM_PLANE_Y].dequant_QTX[1] >> (x->e_mbd.bd - 5); constunsigned int 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, unsigned int var, unsigned int 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; unsigned int var_thresh = 0; unsigned int is_high_var = 1; // Use quantizer based thresholds to determine transform size.
if (cpi->sf.rt_sf.tx_size_level_based_on_qstep) { const int qband = x->qindex >> (QINDEX_BITS - 2); const int mult[4] = { 8, 7, 6, 5 };
assert(qband < 4);
multiplier = mult[qband]; const int qstep = x->plane[AOM_PLANE_Y].dequant_QTX[1] >> (xd->bd - 5); constunsigned int 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, unsigned int *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, unsigned int *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, unsigned int *sse_i, int *sum_i, unsigned int *var_o, unsigned int *sse_o,
int *sum_o) { const BLOCK_SIZE unit_size = txsize_to_bsize[tx_size]; const int nw = 1 << (bw - b_width_log2_lookup[unit_size]); const int 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 static int ac_thr_factor(int speed, int width, int height, int norm_sum) {
if (speed >= 8 && norm_sum < 5) {
if (width <= 640 && height <= 480) return4; else return2;
} return1;
}
// Sets early_term flag based on chroma planes prediction static inline void 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, constunsigned int *sse_tx, constunsigned int *var_tx, int sum, unsigned int var, unsigned int 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; const int bw = b_width_log2_lookup[bsize]; const int bh = b_height_log2_lookup[bsize];
int ac_test = 1;
int dc_test = 1; const int 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 }; unsigned int var_uv[2]; unsigned int 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. const int shift_ac = cpi->sf.rt_sf.increase_source_sad_thresh ? 5 : 3; const int 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;
}
}
}
static inline void calc_rate_dist_block_param(AV1_COMP *cpi, MACROBLOCK *x,
RD_STATS *rd_stats,
int calculate_rd, int *early_term,
BLOCK_SIZE bsize, unsigned int sse) {
if (calculate_rd) {
if (!*early_term) { const int bw = block_size_wide[bsize]; const int 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, unsigned int *var_output, unsigned int 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. unsigned int 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; unsigned int var;
int sum; const int bw = b_width_log2_lookup[bsize]; const int bh = b_height_log2_lookup[bsize]; unsigned int sse16x16[64] = { 0 }; unsigned int 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 - (unsigned int)(((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) { constunsigned int *sse_tx = sse16x16; constunsigned int *var_tx = var16x16; constunsigned int 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, unsigned int *var_output, unsigned int 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. unsigned int 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; unsigned int var;
int sum;
const int bw = b_width_log2_lookup[bsize]; const int bh = b_height_log2_lookup[bsize]; unsigned int sse8x8[256] = { 0 };
int sum8x8[256] = { 0 }; unsigned int var8x8[256] = { 0 };
TX_SIZE tx_size;
// 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 - (unsigned int)(((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) { unsigned int sse16x16[64] = { 0 };
int sum16x16[64] = { 0 }; unsigned int var16x16[64] = { 0 }; constunsigned int *sse_tx = sse8x8; constunsigned int *var_tx = var8x8; unsigned int 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. const int 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]; unsigned int sse;
int rate;
int64_t dist;
unsigned int 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)) { const int bwide = block_size_wide[bsize]; const int 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] = (unsigned int)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;
if (cpi->sf.inter_sf.extra_prune_warped) return0;
if (has_second_ref(mbmi)) return0;
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) { return1;
}
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;
const int 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;
}
memcpy(pts, pts0, total_samples * 2 * sizeof(*pts0));
memcpy(pts_inref, pts_inref0, total_samples * 2 * sizeof(*pts_inref0)); // Select the samples according to motion vector difference
if (mi->num_proj_ref > 1) {
mi->num_proj_ref = av1_selectSamples(&mi->mv[0].as_mv, pts, pts_inref,
mi->num_proj_ref, bsize);
}
// Compute the warped motion parameters with a least squares fit // using the collected samples
if (!av1_find_projection(mi->num_proj_ref, pts, pts_inref, bsize,
mi->mv[0].as_mv.row, mi->mv[0].as_mv.col,
&mi->wm_params, mi_row, mi_col)) {
if (mi->mode == NEWMV) { const int_mv mv0 = mi->mv[0]; const WarpedMotionParams wm_params0 = mi->wm_params; const int num_proj_ref0 = mi->num_proj_ref;
// 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) return false;
// 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;
int *bmode_costs;
PREDICTION_MODE best_mode = DC_PRED; const MB_MODE_INFO *above_mi = xd->above_mbmi; const MB_MODE_INFO *left_mi = xd->left_mbmi; const PREDICTION_MODE A = av1_above_block_mode(above_mi); const PREDICTION_MODE L = av1_left_block_mode(left_mi); const int above_ctx = intra_mode_context[A]; const int left_ctx = intra_mode_context[L]; constunsigned int source_variance = x->source_variance;
bmode_costs = x->mode_costs.y_mode_costs[above_ctx][left_ctx]; const int mi_row = xd->mi_row; const int mi_col = xd->mi_col; // Use this flag to signal large flat blocks that may need special // treatment: in the current case H/V/SMOOTH may not be skipped if // DC has nonzero distortion and skippable is set. This is to remove // visual artifacts observed for screen in realtime mode. constbool flat_blocks_screen =
cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN &&
cpi->oxcf.mode == REALTIME && x->source_variance == 0 &&
bsize >= BLOCK_32X32;
av1_invalid_rd_stats(&best_rdc);
av1_invalid_rd_stats(&this_rdc);
bool allow_skip_nondc = 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 && allow_skip_nondc) 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 && allow_skip_nondc) 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 && allow_skip_nondc) 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 (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;
}
static inline void 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; const int 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) { const int 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);
}
static inline int 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) return0; // filt search purely based on mode properties
if (!cb_pred_filter_search) return1;
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;
} else if (!(is_inter_block(xd->left_mbmi) &&
is_inter_block(xd->above_mbmi))) { // neighbor is INTRA
enable_interp_search = 2;
} else if (xd->left_mbmi->interp_filters.as_int !=
xd->above_mbmi->interp_filters.as_int) { // filters are different
enable_interp_search = 2;
} else if ((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; const int 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;
}
static inline int skip_mode_by_threshold(PREDICTION_MODE mode,
MV_REFERENCE_FRAME ref_frame,
int_mv mv, int frames_since_golden, const int *const rd_threshes, const int *const rd_thresh_freq_fact,
int64_t best_cost, int best_skip,
int extra_shift) {
int skip_this_mode = 0; const THR_MODES mode_index = mode_idx[ref_frame][INTER_OFFSET(mode)];
int64_t mode_rd_thresh =
best_skip ? ((int64_t)rd_threshes[mode_index]) << (extra_shift + 1)
: ((int64_t)rd_threshes[mode_index]) << extra_shift;
// Increase mode_rd_thresh value for non-LAST for improved encoding // speed
if (ref_frame != LAST_FRAME) {
mode_rd_thresh = mode_rd_thresh << 1;
if (ref_frame == GOLDEN_FRAME && frames_since_golden > 4)
mode_rd_thresh = mode_rd_thresh << (extra_shift + 1);
}
if (rd_less_than_thresh(best_cost, mode_rd_thresh,
rd_thresh_freq_fact[mode_index]))
if (mv.as_int != 0) skip_this_mode = 1;
return skip_this_mode;
}
static inline int skip_mode_by_low_temp(
PREDICTION_MODE mode, MV_REFERENCE_FRAME ref_frame, BLOCK_SIZE bsize,
CONTENT_STATE_SB content_state_sb, int_mv mv, int force_skip_low_temp_var) { // Skip non-zeromv mode search for non-LAST frame if force_skip_low_temp_var // is set. If nearestmv for golden frame is 0, zeromv mode will be skipped // later.
if (force_skip_low_temp_var && ref_frame != LAST_FRAME && mv.as_int != 0) { return1;
}
static inline int skip_mode_by_bsize_and_ref_frame(
PREDICTION_MODE mode, MV_REFERENCE_FRAME ref_frame, BLOCK_SIZE bsize,
int extra_prune, unsigned int sse_zeromv_norm, int more_prune,
int skip_nearmv) { constunsigned int thresh_skip_golden = 500;
// 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)) return1;
if (ref_frame != LAST_FRAME && mode == NEARMV) return1;
staticvoid set_color_sensitivity(AV1_COMP *cpi, MACROBLOCK *x,
BLOCK_SIZE bsize, int y_sad, unsigned int source_variance, struct buf_2d yv12_mb[MAX_MB_PLANE]) { const int subsampling_x = cpi->common.seq_params->subsampling_x; const int subsampling_y = cpi->common.seq_params->subsampling_y; const int source_sad_nonrd = x->content_state_sb.source_sad_nonrd; const int 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. unsigned int 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]); unsigned int 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;
} const int 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);
const int uv_sad = cpi->ppi->fn_ptr[bs].sdf(
p->src.buf, p->src.stride, yv12_mb[plane].buf, yv12_mb[plane].stride);
// Prune compound mode if the single mode variance is lower than a fixed // percentage of the median value. staticbool skip_comp_based_on_var( constunsigned int (*single_vars)[REF_FRAMES], BLOCK_SIZE bsize) { unsigned int 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]);
}
} constunsigned int thresh_64 = (unsigned int)(0.57356805f * 8659); constunsigned int thresh_32 = (unsigned int)(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: return false;
}
}
// Skip the mode if use reference frame mask flag is not set.
if (!search_state->use_ref_frame_mask[*ref_frame]) 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;
} else if (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)) {
if (get_segdata(seg, segment_id, SEG_LVL_REF_FRAME) != (int)(*ref_frame)) returntrue; return false;
}
// Don't skip non_last references if LAST is not used a reference.
if (!(cpi->ref_frame_flags & AOM_LAST_FLAG) &&
(*ref_frame == GOLDEN_FRAME || *ref_frame == ALTREF_FRAME)) return false;
// 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) { return false;
}
if (*this_mode == NEARMV &&
search_state->frame_mv[NEARMV][LAST_FRAME].as_int ==
x->sb_me_mv.as_int) { return false;
}
if (*this_mode == NEWMV) { return false;
}
}
// 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 &&
!is_one_pass_rt_lag_params(cpi) &&
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;
}
// 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;
}
if (is_one_pass_rt_lag_params(cpi)) return false;
// 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;
} return false;
}
// 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, unsigned int *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; const int mi_row = xd->mi_row; const int mi_col = xd->mi_col; struct macroblockd_plane *const pd = &xd->plane[AOM_PLANE_Y]; const int 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]; unsigned int var = UINT_MAX;
int this_early_term = 0;
int rate_mv = 0;
int is_skippable;
int skip_this_mv = 0; unsigned int var_threshold = UINT_MAX;
PREDICTION_MODE this_best_mode;
RD_STATS nonskip_rdc;
av1_invalid_rd_stats(&nonskip_rdc);
(void)ctx;
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;
} else if (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;
}
const int skip_ctx = av1_get_skip_txfm_context(xd); const int skip_txfm_cost = mode_costs->skip_txfm_cost[skip_ctx][1]; const int no_skip_txfm_cost = mode_costs->skip_txfm_cost[skip_ctx][0]; const int64_t sse_y = search_state->this_rdc.sse;
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,
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);
}
const int bh = block_size_high[bsize]; const int bw = block_size_wide[bsize]; const int pixels_in_block = bh * bw; struct buf_2d orig_dst = pd->dst; const TxfmSearchParams *txfm_params = &x->txfm_search_params;
TxfmSearchInfo *txfm_info = &x->txfm_search_info; #if COLLECT_NONRD_PICK_MODE_STAT // Mode statistics can be collected only when num_workers is 1
assert(cpi->mt_info.num_workers <= 1);
aom_usec_timer_start(&x->ms_stat_nonrd.bsize_timer); #endif
int64_t thresh_sad_pred = INT64_MAX; const int mi_row = xd->mi_row; const int mi_col = xd->mi_col;
int_mv svc_mv = { .as_int = 0 };
int force_mv_inter_layer = 0; bool comp_use_zero_zeromv_only = 0;
int tot_num_comp_modes = is_one_pass_rt_lag_params(cpi)
? NUM_COMP_INTER_MODES_RT_FULL
: NUM_COMP_INTER_MODES_RT; #if CONFIG_AV1_TEMPORAL_DENOISING const int denoise_recheck_zeromv = 1;
AV1_PICKMODE_CTX_DEN ctx_den;
int64_t zero_last_cost_orig = INT64_MAX;
int denoise_svc_pickmode = 1; const int resize_pending = is_frame_resize_pending(cpi); #endif const ModeCosts *mode_costs = &x->mode_costs; struct scale_factors sf_no_scale;
av1_setup_scale_factors_for_frame(&sf_no_scale, cm->width, cm->height,
cm->width, cm->height);
if (reuse_inter_pred) {
for (int buf_idx = 0; buf_idx < 3; buf_idx++) {
tmp_buffer[buf_idx].data = &pred_buf[pixels_in_block * buf_idx];
tmp_buffer[buf_idx].stride = bw;
tmp_buffer[buf_idx].in_use = 0;
}
tmp_buffer[3].data = pd->dst.buf;
tmp_buffer[3].stride = pd->dst.stride;
tmp_buffer[3].in_use = 0;
}
const int gf_temporal_ref = is_same_gf_and_last_scale(cm);
// 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;
}
// No compound if SEG_LVL_REF_FRAME is set.
if (segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME))
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);
}
const int use_model_yrd_large = get_model_rd_flag(cpi, xd, bsize);
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; else if (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;
}
int force_palette_test = 0;
if (cpi->oxcf.tune_cfg.content == AOM_CONTENT_SCREEN &&
x->content_state_sb.source_sad_nonrd != kZeroSad &&
bsize <= BLOCK_16X16) { unsigned int thresh_sse = cpi->rc.high_source_sad ? 15000 : 100000; unsigned int thresh_source_var = cpi->rc.high_source_sad ? 50 : 200; unsigned int best_sse_inter_motion =
(unsigned int)(search_state.best_rdc.sse >>
(b_width_log2_lookup[bsize] +
b_height_log2_lookup[bsize]));
if (best_sse_inter_motion > thresh_sse &&
x->source_variance > thresh_source_var)
force_palette_test = 1;
}
// For the SEG_LVL_REF_FRAME inter_mode must be selected if reference set is // not INTRA_FRAME, so skip all intra mode (and palette below). const int inter_forced_on_segment =
segfeature_active(seg, segment_id, SEG_LVL_REF_FRAME) &&
get_segdata(seg, segment_id, SEG_LVL_REF_FRAME) != INTRA_FRAME;
// Evaluate Intra modes in inter frame unsigned int best_intra_sad_norm = UINT_MAX;
if (!x->force_zeromv_skip_for_blk && !inter_forced_on_segment)
av1_estimate_intra_mode(cpi, x, bsize, best_early_term,
search_state.ref_costs_single[INTRA_FRAME],
reuse_inter_pred, &orig_dst, tmp_buffer,
&this_mode_pred, &search_state.best_rdc,
best_pickmode, &best_intra_sad_norm);
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;
} 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
¤ 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.0.113Bemerkung:
¤
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.