From 8a2fc54508801f6f4c17c69b3e7f8240993e2f05 Mon Sep 17 00:00:00 2001 From: Marco Date: Mon, 26 Oct 2015 14:56:46 -0700 Subject: [PATCH] Adjustments to vp9-denoising. Adjust variance threshold, delta-qp, and intra penalty cost, based on estimated noise level in source. Replace denoising_on with a level value=L/M/H. Change-Id: I0c017dae75a5d897367d2c42dec26f2f37e447c1 --- vp9/encoder/vp9_aq_cyclicrefresh.c | 11 +++++++++-- vp9/encoder/vp9_denoiser.c | 21 +++++++++++++-------- vp9/encoder/vp9_denoiser.h | 8 +++++++- vp9/encoder/vp9_encodeframe.c | 12 +++++++++++- vp9/encoder/vp9_pickmode.c | 21 ++++++++++++++++----- 5 files changed, 56 insertions(+), 17 deletions(-) diff --git a/vp9/encoder/vp9_aq_cyclicrefresh.c b/vp9/encoder/vp9_aq_cyclicrefresh.c index 2cd89c0..bdc95d4 100644 --- a/vp9/encoder/vp9_aq_cyclicrefresh.c +++ b/vp9/encoder/vp9_aq_cyclicrefresh.c @@ -486,10 +486,17 @@ void vp9_cyclic_refresh_update_parameters(VP9_COMP *const cpi) { // Account for larger interval on base layer for temporal layers. if (cr->percent_refresh > 0 && rc->frames_since_key < (4 * cpi->svc.number_temporal_layers) * - (100 / cr->percent_refresh)) + (100 / cr->percent_refresh)) { cr->rate_ratio_qdelta = 3.0; - else + } else { cr->rate_ratio_qdelta = 2.0; +#if CONFIG_VP9_TEMPORAL_DENOISING + if (cpi->oxcf.noise_sensitivity > 0 && + cpi->denoiser.denoising_level >= kMedium) + // Reduce the delta-qp if the estimated source noise is above threshold. + cr->rate_ratio_qdelta = 1.5; +#endif + } // Adjust some parameters for low resolutions at low bitrates. if (cm->width <= 352 && cm->height <= 288 && diff --git a/vp9/encoder/vp9_denoiser.c b/vp9/encoder/vp9_denoiser.c index 8623b42..3dff434 100644 --- a/vp9/encoder/vp9_denoiser.c +++ b/vp9/encoder/vp9_denoiser.c @@ -323,7 +323,7 @@ void vp9_denoiser_denoise(VP9_DENOISER *denoiser, MACROBLOCK *mb, struct buf_2d src = mb->plane[0].src; int is_skin = 0; - if (bs <= BLOCK_16X16 && denoiser->denoising_on) { + if (bs <= BLOCK_16X16 && denoiser->denoising_level >= kMedium) { // Take center pixel in block to determine is_skin. const int y_width_shift = (4 << b_width_log2_lookup[bs]) >> 1; const int y_height_shift = (4 << b_height_log2_lookup[bs]) >> 1; @@ -340,7 +340,7 @@ void vp9_denoiser_denoise(VP9_DENOISER *denoiser, MACROBLOCK *mb, is_skin = vp9_skin_pixel(ysource, usource, vsource); } - if (denoiser->denoising_on) + if (denoiser->denoising_level >= kMedium) decision = perform_motion_compensation(denoiser, mb, bs, denoiser->increase_denoising, mi_row, mi_col, ctx, @@ -523,8 +523,8 @@ void vp9_denoiser_init_noise_estimate(VP9_DENOISER *denoiser, int height) { // Denoiser is off by default, i.e., no denoising is performed. // Noise level is measured periodically, and if observed to be above - // thresh_noise_estimate, then denoising is performed, i.e., denoising_on = 1. - denoiser->denoising_on = 0; + // thresh_noise_estimate, then denoising is performed. + denoiser->denoising_level = kLow; denoiser->noise_estimate = 0; denoiser->noise_estimate_count = 0; denoiser->thresh_noise_estimate = 20; @@ -651,10 +651,15 @@ void vp9_denoiser_update_noise_estimate(VP9_COMP *const cpi) { if (cpi->denoiser.noise_estimate_count == num_frames_estimate) { // Reset counter and check noise level condition. cpi->denoiser.noise_estimate_count = 0; - if (cpi->denoiser.noise_estimate > cpi->denoiser.thresh_noise_estimate) - cpi->denoiser.denoising_on = 1; - else - cpi->denoiser.denoising_on = 0; + if (cpi->denoiser.noise_estimate > + (cpi->denoiser.thresh_noise_estimate << 1)) + cpi->denoiser.denoising_level = kHigh; + else + if (cpi->denoiser.noise_estimate > + cpi->denoiser.thresh_noise_estimate) + cpi->denoiser.denoising_level = kMedium; + else + cpi->denoiser.denoising_level = kLow; } } } diff --git a/vp9/encoder/vp9_denoiser.h b/vp9/encoder/vp9_denoiser.h index f8ad4ac..c149e9d 100644 --- a/vp9/encoder/vp9_denoiser.h +++ b/vp9/encoder/vp9_denoiser.h @@ -26,13 +26,19 @@ typedef enum vp9_denoiser_decision { FILTER_BLOCK } VP9_DENOISER_DECISION; +typedef enum vp9_denoiser_level { + kLow, + kMedium, + kHigh +} VP9_DENOISER_LEVEL; + typedef struct vp9_denoiser { YV12_BUFFER_CONFIG running_avg_y[MAX_REF_FRAMES]; YV12_BUFFER_CONFIG mc_running_avg_y; YV12_BUFFER_CONFIG last_source; int increase_denoising; int frame_buffer_initialized; - int denoising_on; + VP9_DENOISER_LEVEL denoising_level; int noise_estimate; int thresh_noise_estimate; int noise_estimate_count; diff --git a/vp9/encoder/vp9_encodeframe.c b/vp9/encoder/vp9_encodeframe.c index 2333a13..1f5709c 100644 --- a/vp9/encoder/vp9_encodeframe.c +++ b/vp9/encoder/vp9_encodeframe.c @@ -481,7 +481,7 @@ static void set_vbp_thresholds(VP9_COMP *cpi, int64_t thresholds[], int q) { VP9_COMMON *const cm = &cpi->common; const int is_key_frame = (cm->frame_type == KEY_FRAME); const int threshold_multiplier = is_key_frame ? 20 : 1; - const int64_t threshold_base = (int64_t)(threshold_multiplier * + int64_t threshold_base = (int64_t)(threshold_multiplier * cpi->y_dequant[q][1]); if (is_key_frame) { thresholds[0] = threshold_base; @@ -489,6 +489,16 @@ static void set_vbp_thresholds(VP9_COMP *cpi, int64_t thresholds[], int q) { thresholds[2] = threshold_base >> 2; thresholds[3] = threshold_base << 2; } else { +#if CONFIG_VP9_TEMPORAL_DENOISING + if (cpi->oxcf.noise_sensitivity > 0) { + // Increase base variance threshold is estimated noise level is high. + if (cpi->denoiser.denoising_level == kHigh) + threshold_base = threshold_base << 2; + else + if (cpi->denoiser.denoising_level == kMedium) + threshold_base = threshold_base << 1; + } +#endif thresholds[1] = threshold_base; if (cm->width <= 352 && cm->height <= 288) { thresholds[0] = threshold_base >> 2; diff --git a/vp9/encoder/vp9_pickmode.c b/vp9/encoder/vp9_pickmode.c index fc4d9ae..af04583 100644 --- a/vp9/encoder/vp9_pickmode.c +++ b/vp9/encoder/vp9_pickmode.c @@ -1068,6 +1068,21 @@ static const REF_MODE ref_mode_set_svc[RT_INTER_MODES] = { {GOLDEN_FRAME, NEWMV} }; +int set_intra_cost_penalty(const VP9_COMP *const cpi, BLOCK_SIZE bsize) { + const VP9_COMMON *const cm = &cpi->common; + // Reduce the intra cost penalty for small blocks (<=16x16). + int reduction_fac = + (bsize <= BLOCK_16X16) ? ((bsize <= BLOCK_8X8) ? 4 : 2) : 0; +#if CONFIG_VP9_TEMPORAL_DENOISING + if (cpi->oxcf.noise_sensitivity > 0 && + cpi->denoiser.denoising_level == kHigh) + // Don't reduce intra cost penalty if estimated noise level is high. + reduction_fac = 0; +#endif + return vp9_get_intra_cost_penalty( + cm->base_qindex, cm->y_dc_delta_q, cm->bit_depth) >> reduction_fac; +} + // TODO(jingning) placeholder for inter-frame non-RD mode decision. // this needs various further optimizations. to be continued.. void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, @@ -1094,11 +1109,7 @@ void vp9_pick_inter_mode(VP9_COMP *cpi, MACROBLOCK *x, // var_y and sse_y are saved to be used in skipping checking unsigned int var_y = UINT_MAX; unsigned int sse_y = UINT_MAX; - // Reduce the intra cost penalty for small blocks (<=16x16). - const int reduction_fac = (bsize <= BLOCK_16X16) ? - ((bsize <= BLOCK_8X8) ? 4 : 2) : 0; - const int intra_cost_penalty = vp9_get_intra_cost_penalty( - cm->base_qindex, cm->y_dc_delta_q, cm->bit_depth) >> reduction_fac; + const int intra_cost_penalty = set_intra_cost_penalty(cpi, bsize); const int64_t inter_mode_thresh = RDCOST(x->rdmult, x->rddiv, intra_cost_penalty, 0); const int *const rd_threshes = cpi->rd.threshes[mbmi->segment_id][bsize]; -- 2.7.4