From 92ec0674fdb21f3f195a1aba227e53adc1033621 Mon Sep 17 00:00:00 2001 From: Marco Date: Fri, 14 Apr 2017 11:32:19 -0700 Subject: [PATCH] vp9; Reduce artifact in non-rd pickmode for lighting changes. Add a low-variance high-sumdiff to the superblock content state and use it to limit the mv and bias some decisions in non-rd pickmode. Only affects speed >= 6. Reduces artifact for lighting changes. Small/no difference in metrics on RTC set. Change-Id: Ic84b2379fe0ae3fa71ae826ee6bae3eaf551a25b --- vp9/encoder/vp9_block.h | 2 ++ vp9/encoder/vp9_denoiser.c | 3 ++- vp9/encoder/vp9_encodeframe.c | 13 +++++++++++-- vp9/encoder/vp9_encoder.h | 1 + vp9/encoder/vp9_pickmode.c | 26 ++++++++++++++++++++------ 5 files changed, 36 insertions(+), 9 deletions(-) diff --git a/vp9/encoder/vp9_block.h b/vp9/encoder/vp9_block.h index 61a886e..bdd6662 100644 --- a/vp9/encoder/vp9_block.h +++ b/vp9/encoder/vp9_block.h @@ -168,6 +168,8 @@ struct macroblock { uint8_t skip_low_source_sad; + uint8_t lowvar_highsumdiff; + uint8_t last_sb_high_content; // For each superblock: saves the content value (e.g., low/high sad/sumdiff) diff --git a/vp9/encoder/vp9_denoiser.c b/vp9/encoder/vp9_denoiser.c index b92557a..5a5ca1f 100644 --- a/vp9/encoder/vp9_denoiser.c +++ b/vp9/encoder/vp9_denoiser.c @@ -573,7 +573,8 @@ void vp9_denoiser_set_noise_level(VP9_DENOISER *denoiser, int noise_level) { int64_t vp9_scale_part_thresh(int64_t threshold, VP9_DENOISER_LEVEL noise_level, int content_state) { if ((content_state == kLowSadLowSumdiff) || - (content_state == kHighSadLowSumdiff) || noise_level == kDenHigh) + (content_state == kHighSadLowSumdiff) || + (content_state == kLowVarHighSumdiff) || noise_level == kDenHigh) return (3 * threshold) >> 1; else return (5 * threshold) >> 2; diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 12dc226..fca378b 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -495,11 +495,13 @@ int64_t scale_part_thresh_sumdiff(int64_t threshold_base, int speed, int width, if (width <= 640 && height <= 480) return (5 * threshold_base) >> 2; else if ((content_state == kLowSadLowSumdiff) || - (content_state == kHighSadLowSumdiff)) + (content_state == kHighSadLowSumdiff) || + (content_state == kLowVarHighSumdiff)) return (5 * threshold_base) >> 2; } else if (speed == 7) { if ((content_state == kLowSadLowSumdiff) || - (content_state == kHighSadLowSumdiff)) { + (content_state == kHighSadLowSumdiff) || + (content_state == kLowVarHighSumdiff)) { return (5 * threshold_base) >> 2; } } @@ -994,6 +996,11 @@ static void avg_source_sad(VP9_COMP *cpi, MACROBLOCK *x, int shift, else x->content_state_sb = ((tmp_sse - tmp_variance) < 25) ? kHighSadLowSumdiff : kHighSadHighSumdiff; + + // Detect large lighting change. + if (tmp_variance < (tmp_sse >> 3) && (tmp_sse - tmp_variance) > 10000) + x->content_state_sb = kLowVarHighSumdiff; + if (cpi->content_state_sb_fd != NULL) { if (tmp_sad < avg_source_sad_threshold2) { // Cap the increment to 255. @@ -1061,6 +1068,7 @@ static int choose_partitioning(VP9_COMP *cpi, const TileInfo *const tile, content_state == kLowSadHighSumdiff) ? 1 : 0; + x->lowvar_highsumdiff = (content_state == kLowVarHighSumdiff) ? 1 : 0; if (cpi->content_state_sb_fd != NULL) x->last_sb_high_content = cpi->content_state_sb_fd[sb_offset2]; // If source_sad is low copy the partition without computing the y_sad. @@ -4110,6 +4118,7 @@ static void encode_nonrd_sb_row(VP9_COMP *cpi, ThreadData *td, x->color_sensitivity[1] = 0; x->sb_is_skin = 0; x->skip_low_source_sad = 0; + x->lowvar_highsumdiff = 0; x->content_state_sb = 0; if (seg->enabled) { diff --git a/vp9/encoder/vp9_encoder.h b/vp9/encoder/vp9_encoder.h index 94ebc3b..64571be 100644 --- a/vp9/encoder/vp9_encoder.h +++ b/vp9/encoder/vp9_encoder.h @@ -137,6 +137,7 @@ typedef enum { kLowSadHighSumdiff = 2, kHighSadLowSumdiff = 3, kHighSadHighSumdiff = 4, + kLowVarHighSumdiff = 5, } CONTENT_STATE_SB; typedef struct VP9EncoderConfig { diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c index 9c6138f..c82930f 100644 --- a/vp9/encoder/vp9_pickmode.c +++ b/vp9/encoder/vp9_pickmode.c @@ -170,6 +170,14 @@ static int combined_motion_search(VP9_COMP *cpi, MACROBLOCK *x, } vp9_set_mv_search_range(&x->mv_limits, &ref_mv); + // Limit motion vector for large lightning change. + if (cpi->oxcf.speed > 5 && x->lowvar_highsumdiff) { + x->mv_limits.col_min = VPXMAX(x->mv_limits.col_min, -10); + x->mv_limits.row_min = VPXMAX(x->mv_limits.row_min, -10); + x->mv_limits.col_max = VPXMIN(x->mv_limits.col_max, 10); + x->mv_limits.row_max = VPXMIN(x->mv_limits.row_max, 10); + } + assert(x->mv_best_ref_index[ref] <= 2); if (x->mv_best_ref_index[ref] < 2) mvp_full = x->mbmi_ext->ref_mvs[ref][x->mv_best_ref_index[ref]].as_mv; @@ -1219,7 +1227,8 @@ static INLINE void find_predictors( static void vp9_NEWMV_diff_bias(const NOISE_ESTIMATE *ne, MACROBLOCKD *xd, PREDICTION_MODE this_mode, RD_COST *this_rdc, BLOCK_SIZE bsize, int mv_row, int mv_col, - int is_last_frame) { + int is_last_frame, int lowvar_highsumdiff, + int is_skin) { // Bias against MVs associated with NEWMV mode that are very different from // top/left neighbors. if (this_mode == NEWMV) { @@ -1266,9 +1275,12 @@ static void vp9_NEWMV_diff_bias(const NOISE_ESTIMATE *ne, MACROBLOCKD *xd, // If noise estimation is enabled, and estimated level is above threshold, // add a bias to LAST reference with small motion, for large blocks. if (ne->enabled && ne->level >= kMedium && bsize >= BLOCK_32X32 && - is_last_frame && mv_row < 8 && mv_row > -8 && mv_col < 8 && mv_col > -8) { - this_rdc->rdcost = 7 * this_rdc->rdcost >> 3; - } + is_last_frame && mv_row < 8 && mv_row > -8 && mv_col < 8 && mv_col > -8) + this_rdc->rdcost = 7 * (this_rdc->rdcost >> 3); + else if (lowvar_highsumdiff && !is_skin && bsize >= BLOCK_16X16 && + is_last_frame && mv_row < 16 && mv_row > -16 && mv_col < 16 && + mv_col > -16) + this_rdc->rdcost = 7 * (this_rdc->rdcost >> 3); } #if CONFIG_VP9_TEMPORAL_DENOISING @@ -1966,7 +1978,8 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data, vp9_NEWMV_diff_bias(&cpi->noise_estimate, xd, this_mode, &this_rdc, bsize, frame_mv[this_mode][ref_frame].as_mv.row, frame_mv[this_mode][ref_frame].as_mv.col, - ref_frame == LAST_FRAME); + ref_frame == LAST_FRAME, x->lowvar_highsumdiff, + x->sb_is_skin); } // Skipping checking: test to see if this block can be reconstructed by @@ -2048,7 +2061,8 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, TileDataEnc *tile_data, if (best_rdc.rdcost == INT64_MAX || ((!force_skip_low_temp_var || bsize < BLOCK_32X32) && perform_intra_pred && !x->skip && best_rdc.rdcost > inter_mode_thresh && - bsize <= cpi->sf.max_intra_bsize && !x->skip_low_source_sad)) { + bsize <= cpi->sf.max_intra_bsize && !x->skip_low_source_sad && + !x->lowvar_highsumdiff)) { struct estimate_block_intra_args args = { cpi, x, DC_PRED, 1, 0 }; int i; TX_SIZE best_intra_tx_size = TX_SIZES; -- 2.7.4