From 9a1ce7be7d4a3056b9da1df64cb7d5115a513dd9 Mon Sep 17 00:00:00 2001 From: paulwilkins Date: Fri, 6 Mar 2015 17:21:36 +0000 Subject: [PATCH] Experimental rd bias based on source vs recon variance. This experiment biases the rd decision based on the impact a mode decision has on the relative spatial complexity of the reconstruction vs the source. The aim is to better retain a semblance of texture even if it is slightly misaligned / wrong, rather than use a simple rd measure that tends to favor use of a flat predictor if a perfect match can't be found. This improves the appearance of texture and visual quality on specific test clips but is hidden under a flag and currently off by default pending visual quality testing on a wider Yt set. Change-Id: Idf6e754a8949bf39ed9d314c6f2daaa20c888aad --- vp9/encoder/vp9_encodeframe.c | 16 +++++----- vp9/encoder/vp9_rdopt.c | 56 +++++++++++++++++++++++++++++++++++ vp9/encoder/vp9_rdopt.h | 9 ++++++ 3 files changed, 74 insertions(+), 7 deletions(-) diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index ac9de21cc..0c8f48c39 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -99,9 +99,9 @@ static const uint16_t VP9_HIGH_VAR_OFFS_12[64] = { }; #endif // CONFIG_VP9_HIGHBITDEPTH -static unsigned int get_sby_perpixel_variance(VP9_COMP *cpi, - const struct buf_2d *ref, - BLOCK_SIZE bs) { +unsigned int vp9_get_sby_perpixel_variance(VP9_COMP *cpi, + const struct buf_2d *ref, + BLOCK_SIZE bs) { unsigned int sse; const unsigned int var = cpi->fn_ptr[bs].vf(ref->buf, ref->stride, VP9_VAR_OFFS, 0, &sse); @@ -109,7 +109,7 @@ static unsigned int get_sby_perpixel_variance(VP9_COMP *cpi, } #if CONFIG_VP9_HIGHBITDEPTH -static unsigned int high_get_sby_perpixel_variance( +unsigned int vp9_high_get_sby_perpixel_variance( VP9_COMP *cpi, const struct buf_2d *ref, BLOCK_SIZE bs, int bd) { unsigned int var, sse; switch (bd) { @@ -1072,13 +1072,15 @@ static void rd_pick_sb_modes(VP9_COMP *cpi, #if CONFIG_VP9_HIGHBITDEPTH if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) { x->source_variance = - high_get_sby_perpixel_variance(cpi, &x->plane[0].src, bsize, xd->bd); + vp9_high_get_sby_perpixel_variance(cpi, &x->plane[0].src, + bsize, xd->bd); } else { x->source_variance = - get_sby_perpixel_variance(cpi, &x->plane[0].src, bsize); + vp9_get_sby_perpixel_variance(cpi, &x->plane[0].src, bsize); } #else - x->source_variance = get_sby_perpixel_variance(cpi, &x->plane[0].src, bsize); + x->source_variance = + vp9_get_sby_perpixel_variance(cpi, &x->plane[0].src, bsize); #endif // CONFIG_VP9_HIGHBITDEPTH // Save rdmult before it might be changed, so it can be restored later. diff --git a/vp9/encoder/vp9_rdopt.c b/vp9/encoder/vp9_rdopt.c index 51397a791..7dabb7bb5 100644 --- a/vp9/encoder/vp9_rdopt.c +++ b/vp9/encoder/vp9_rdopt.c @@ -50,6 +50,7 @@ #define MIN_EARLY_TERM_INDEX 3 #define NEW_MV_DISCOUNT_FACTOR 8 +#define SOURCE_VARIANCE_RD_ADJUSTMENT 0 typedef struct { PREDICTION_MODE mode; @@ -2824,6 +2825,55 @@ void vp9_rd_pick_intra_mode_sb(VP9_COMP *cpi, MACROBLOCK *x, rd_cost->rdcost = RDCOST(x->rdmult, x->rddiv, rd_cost->rate, rd_cost->dist); } +#if SOURCE_VARIANCE_RD_ADJUSTMENT +// This function is designed to apply a bias or adjustment to an rd value based +// on the relative variance of the source and reconstruction. +#define LOW_VAR_THRESH 16 +#define LOW_VAR_DIFF_THRESH 1 +#define VLOW_ADJ_MAX 25 +#define VHIGH_ADJ_MAX 10 +static void rd_variance_adjustment(VP9_COMP *cpi, + MACROBLOCK *x, + BLOCK_SIZE bsize, + int64_t *this_rd, + unsigned int source_variance) { + MACROBLOCKD *const xd = &x->e_mbd; + unsigned int recon_variance; + unsigned int var_diff; + + if (*this_rd == INT64_MAX) + return; + +#if CONFIG_VP9_HIGHBITDEPTH + if (xd->cur_buf->flags & YV12_FLAG_HIGHBITDEPTH) { + recon_variance = + vp9_high_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize, xd->bd); + } else { + recon_variance = + vp9_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize); + } +#else + recon_variance = + vp9_get_sby_perpixel_variance(cpi, &xd->plane[0].dst, bsize); +#endif // CONFIG_VP9_HIGHBITDEPTH + + var_diff = (source_variance > recon_variance) + ? (source_variance - recon_variance) : (recon_variance - source_variance); + + if ((source_variance > LOW_VAR_THRESH) && (var_diff > LOW_VAR_DIFF_THRESH)) { + unsigned int var_factor; + if (source_variance > recon_variance) { + var_factor = + MIN(VLOW_ADJ_MAX, (var_diff * VLOW_ADJ_MAX) / source_variance); + } else { + var_factor = + MIN(VHIGH_ADJ_MAX, (var_diff * VHIGH_ADJ_MAX) / source_variance); + } + *this_rd += (*this_rd * var_factor) / 100; + } +} +#endif + void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, TileDataEnc *tile_data, MACROBLOCK *x, @@ -3280,6 +3330,12 @@ void vp9_rd_pick_inter_mode_sb(VP9_COMP *cpi, this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); } +#if SOURCE_VARIANCE_RD_ADJUSTMENT + // Apply an adjustment to the rd value based on the similarity of the + // source variance and reconstructed variance. + rd_variance_adjustment(cpi, x, bsize, &this_rd, x->source_variance); +#endif + if (ref_frame == INTRA_FRAME) { // Keep record of best intra rd if (this_rd < best_intra_rd) { diff --git a/vp9/encoder/vp9_rdopt.h b/vp9/encoder/vp9_rdopt.h index 7bbc3c89a..459b0324b 100644 --- a/vp9/encoder/vp9_rdopt.h +++ b/vp9/encoder/vp9_rdopt.h @@ -29,6 +29,15 @@ void vp9_rd_pick_intra_mode_sb(struct VP9_COMP *cpi, struct macroblock *x, struct RD_COST *rd_cost, BLOCK_SIZE bsize, PICK_MODE_CONTEXT *ctx, int64_t best_rd); +unsigned int vp9_get_sby_perpixel_variance(VP9_COMP *cpi, + const struct buf_2d *ref, + BLOCK_SIZE bs); +#if CONFIG_VP9_HIGHBITDEPTH +unsigned int vp9_high_get_sby_perpixel_variance(VP9_COMP *cpi, + const struct buf_2d *ref, + BLOCK_SIZE bs, int bd); +#endif + void vp9_rd_pick_inter_mode_sb(struct VP9_COMP *cpi, struct TileDataEnc *tile_data, struct macroblock *x, -- 2.40.0