From 5b0ddb931d1bc8f890e138f5fa36950f385c6480 Mon Sep 17 00:00:00 2001 From: Marco Date: Fri, 13 Nov 2015 15:58:42 -0800 Subject: [PATCH] vp9 denoiser: Re-evaluate ZEROMV after denoiser filtering. For denoising, and for noise level above threshold, re-evaluate ZEROMV for mode selection after denoising. Current change only does this check if selected best mode (before denoising) was intra. Change-Id: I4b1435b68d26c78f7597b995ee7bff0ddd5f9511 --- vp9/encoder/vp9_denoiser.c | 4 ++- vp9/encoder/vp9_denoiser.h | 3 +- vp9/encoder/vp9_encodeframe.c | 10 ------ vp9/encoder/vp9_pickmode.c | 57 +++++++++++++++++++++++++++++++- vp9/encoder/vp9_speed_features.c | 10 ++++++ 5 files changed, 71 insertions(+), 13 deletions(-) diff --git a/vp9/encoder/vp9_denoiser.c b/vp9/encoder/vp9_denoiser.c index e87a12e44..f6e0c69fa 100644 --- a/vp9/encoder/vp9_denoiser.c +++ b/vp9/encoder/vp9_denoiser.c @@ -316,7 +316,8 @@ static VP9_DENOISER_DECISION perform_motion_compensation(VP9_DENOISER *denoiser, void vp9_denoiser_denoise(VP9_DENOISER *denoiser, MACROBLOCK *mb, int mi_row, int mi_col, BLOCK_SIZE bs, - PICK_MODE_CONTEXT *ctx) { + PICK_MODE_CONTEXT *ctx, + VP9_DENOISER_DECISION *denoiser_decision) { int mv_col, mv_row; int motion_magnitude = 0; VP9_DENOISER_DECISION decision = COPY_BLOCK; @@ -380,6 +381,7 @@ void vp9_denoiser_denoise(VP9_DENOISER *denoiser, MACROBLOCK *mb, num_4x4_blocks_wide_lookup[bs] << 2, num_4x4_blocks_high_lookup[bs] << 2); } + *denoiser_decision = decision; } static void copy_frame(YV12_BUFFER_CONFIG * const dest, diff --git a/vp9/encoder/vp9_denoiser.h b/vp9/encoder/vp9_denoiser.h index bc676e925..c8c93528b 100644 --- a/vp9/encoder/vp9_denoiser.h +++ b/vp9/encoder/vp9_denoiser.h @@ -54,7 +54,8 @@ void vp9_denoiser_update_frame_info(VP9_DENOISER *denoiser, void vp9_denoiser_denoise(VP9_DENOISER *denoiser, MACROBLOCK *mb, int mi_row, int mi_col, BLOCK_SIZE bs, - PICK_MODE_CONTEXT *ctx); + PICK_MODE_CONTEXT *ctx , + VP9_DENOISER_DECISION *denoiser_decision); void vp9_denoiser_reset_frame_stats(PICK_MODE_CONTEXT *ctx); diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index f9c28f6a9..7e569899e 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -1746,16 +1746,6 @@ static void encode_b_rt(VP9_COMP *cpi, ThreadData *td, set_offsets(cpi, tile, x, mi_row, mi_col, bsize); update_state_rt(cpi, td, ctx, mi_row, mi_col, bsize); -#if CONFIG_VP9_TEMPORAL_DENOISING - if (cpi->oxcf.noise_sensitivity > 0 && - output_enabled && - cpi->common.frame_type != KEY_FRAME && - cpi->resize_pending == 0) { - vp9_denoiser_denoise(&cpi->denoiser, x, mi_row, mi_col, - VPXMAX(BLOCK_8X8, bsize), ctx); - } -#endif - encode_superblock(cpi, td, tp, output_enabled, mi_row, mi_col, bsize, ctx); update_stats(&cpi->common, td); diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c index 8aafae1d4..ef29c272f 100644 --- a/vp9/encoder/vp9_pickmode.c +++ b/vp9/encoder/vp9_pickmode.c @@ -1143,6 +1143,9 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, int best_pred_sad = INT_MAX; int best_early_term = 0; int ref_frame_cost[MAX_REF_FRAMES]; +#if CONFIG_VP9_TEMPORAL_DENOISING + int64_t zero_last_cost_orig = INT64_MAX; +#endif init_ref_frame_cost(cm, xd, ref_frame_cost); @@ -1524,8 +1527,12 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, } #if CONFIG_VP9_TEMPORAL_DENOISING - if (cpi->oxcf.noise_sensitivity > 0) + if (cpi->oxcf.noise_sensitivity > 0) { vp9_denoiser_update_frame_stats(mbmi, sse_y, this_mode, ctx); + // Keep track of zero_last cost. + if (ref_frame == LAST_FRAME && frame_mv[this_mode][ref_frame].as_int == 0) + zero_last_cost_orig = this_rdc.rdcost; + } #else (void)ctx; #endif @@ -1683,6 +1690,54 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, } } +#if CONFIG_VP9_TEMPORAL_DENOISING + if (cpi->oxcf.noise_sensitivity > 0 && + cpi->resize_pending == 0) { + VP9_DENOISER_DECISION decision = COPY_BLOCK; + vp9_denoiser_denoise(&cpi->denoiser, x, mi_row, mi_col, + VPXMAX(BLOCK_8X8, bsize), ctx, &decision); + // If INTRA mode 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 INTRA MODE. + if (best_ref_frame == INTRA_FRAME && + decision == FILTER_BLOCK && + cpi->noise_estimate.enabled && + cpi->noise_estimate.level > kLow && + zero_last_cost_orig < (best_rdc.rdcost << 2) && + !reuse_inter_pred) { + // Check if we should pick ZEROMV on denoised signal. + int rate = 0; + int64_t dist = 0; + mbmi->mode = ZEROMV; + mbmi->ref_frame[0] = LAST_FRAME; + mbmi->ref_frame[1] = NONE; + mbmi->mv[0].as_int = 0; + mbmi->interp_filter = EIGHTTAP; + vp9_build_inter_predictors_sby(xd, mi_row, mi_col, bsize); + model_rd_for_sb_y(cpi, bsize, x, xd, &rate, &dist, &var_y, &sse_y); + this_rdc.rate = rate + ref_frame_cost[LAST_FRAME] + + cpi->inter_mode_cost[x->mbmi_ext->mode_context[LAST_FRAME]] + [INTER_OFFSET(ZEROMV)]; + this_rdc.dist = dist; + this_rdc.rdcost = RDCOST(x->rdmult, x->rddiv, rate, dist); + // Switch to ZEROMV if the rdcost for ZEROMV on denoised source + // is lower than INTRA (on original source). + if (this_rdc.rdcost > best_rdc.rdcost) { + this_rdc = best_rdc; + mbmi->mode = best_mode; + mbmi->ref_frame[0] = best_ref_frame; + mbmi->mv[0].as_int = INVALID_MV; + mbmi->interp_filter = best_pred_filter; + mbmi->tx_size = best_tx_size; + x->skip_txfm[0] = best_mode_skip_txfm; + } else { + best_ref_frame = LAST_FRAME; + best_rdc = this_rdc; + } + } + } +#endif + if (cpi->sf.adaptive_rd_thresh) { THR_MODES best_mode_idx = mode_idx[best_ref_frame][mode_offset(mbmi->mode)]; diff --git a/vp9/encoder/vp9_speed_features.c b/vp9/encoder/vp9_speed_features.c index 318d8100c..20516a0c9 100644 --- a/vp9/encoder/vp9_speed_features.c +++ b/vp9/encoder/vp9_speed_features.c @@ -380,6 +380,16 @@ static void set_rt_speed_feature(VP9_COMP *cpi, SPEED_FEATURES *sf, sf->adaptive_rd_thresh = 2; // This feature is only enabled when partition search is disabled. sf->reuse_inter_pred_sby = 1; + // TODO(marpan): When denoising, we may re-evaluate the mode selection and + // this seems to cause problems when reuse_inter_pred_sby is enabled. + // Disabling reuse_inter_pred_sby for now (under denoising conditions), and + // will look into re-enabling it. +#if CONFIG_VP9_TEMPORAL_DENOISING + if (cpi->oxcf.noise_sensitivity > 0 && + cpi->noise_estimate.enabled && + cpi->noise_estimate.level > kLow) + sf->reuse_inter_pred_sby = 0; +#endif sf->partition_search_breakout_rate_thr = 200; sf->coeff_prob_appx_step = 4; sf->use_fast_coef_updates = is_keyframe ? TWO_LOOP : ONE_LOOP_REDUCED; -- 2.40.0