From 57faddb7c5f1b9bd32863738251ee33e8fd297d4 Mon Sep 17 00:00:00 2001 From: Jim Bankoski Date: Thu, 24 May 2012 07:44:03 -0700 Subject: [PATCH] fix denoiser for temporal patterns and rd This extends the denoiser to work for temporally scalable coding. I believe this also fixes a very rare but really bad bug in the original implementation. Change-Id: I8b3593a8c54b86eb76f785af1970935f7d56262a --- vp8/common/blockd.h | 6 -- vp8/encoder/block.h | 10 +++ vp8/encoder/denoising.c | 205 ++++++++++++++++++++++++++-------------------- vp8/encoder/denoising.h | 4 +- vp8/encoder/encodeframe.c | 8 +- vp8/encoder/onyx_if.c | 42 +++++++++- vp8/encoder/pickinter.c | 112 ++++++++++++++----------- vp8/encoder/pickinter.h | 4 + vp8/encoder/rdopt.c | 129 ++++++++++++++++++----------- vp8_scalable_patterns.c | 1 + 10 files changed, 321 insertions(+), 200 deletions(-) diff --git a/vp8/common/blockd.h b/vp8/common/blockd.h index 1945edb..c7206b2 100644 --- a/vp8/common/blockd.h +++ b/vp8/common/blockd.h @@ -224,12 +224,6 @@ typedef struct macroblockd MODE_INFO *mode_info_context; int mode_info_stride; -#if CONFIG_TEMPORAL_DENOISING - MB_PREDICTION_MODE best_sse_inter_mode; - int_mv best_sse_mv; - unsigned char need_to_clamp_best_mvs; -#endif - FRAME_TYPE frame_type; int up_available; diff --git a/vp8/encoder/block.h b/vp8/encoder/block.h index 4ecbf1f..9756acc 100644 --- a/vp8/encoder/block.h +++ b/vp8/encoder/block.h @@ -119,6 +119,16 @@ typedef struct macroblock int optimize; int q_index; +#if CONFIG_TEMPORAL_DENOISING + MB_PREDICTION_MODE best_sse_inter_mode; + int_mv best_sse_mv; + MV_REFERENCE_FRAME best_reference_frame; + MV_REFERENCE_FRAME best_zeromv_reference_frame; + unsigned char need_to_clamp_best_mvs; +#endif + + + void (*short_fdct4x4)(short *input, short *output, int pitch); void (*short_fdct8x4)(short *input, short *output, int pitch); void (*short_walsh4x4)(short *input, short *output, int pitch); diff --git a/vp8/encoder/denoising.c b/vp8/encoder/denoising.c index 45d54ee..194d422 100644 --- a/vp8/encoder/denoising.c +++ b/vp8/encoder/denoising.c @@ -22,68 +22,6 @@ static const unsigned int SSE_DIFF_THRESHOLD = 16 * 16 * 20; static const unsigned int SSE_THRESHOLD = 16 * 16 * 40; -static unsigned int denoiser_motion_compensate(YV12_BUFFER_CONFIG *src, - YV12_BUFFER_CONFIG *dst, - MACROBLOCK *x, - unsigned int best_sse, - unsigned int zero_mv_sse, - int recon_yoffset, - int recon_uvoffset) -{ - MACROBLOCKD filter_xd = x->e_mbd; - int mv_col; - int mv_row; - int sse_diff = zero_mv_sse - best_sse; - // Compensate the running average. - filter_xd.pre.y_buffer = src->y_buffer + recon_yoffset; - filter_xd.pre.u_buffer = src->u_buffer + recon_uvoffset; - filter_xd.pre.v_buffer = src->v_buffer + recon_uvoffset; - // Write the compensated running average to the destination buffer. - filter_xd.dst.y_buffer = dst->y_buffer + recon_yoffset; - filter_xd.dst.u_buffer = dst->u_buffer + recon_uvoffset; - filter_xd.dst.v_buffer = dst->v_buffer + recon_uvoffset; - // Use the best MV for the compensation. - filter_xd.mode_info_context->mbmi.ref_frame = LAST_FRAME; - filter_xd.mode_info_context->mbmi.mode = filter_xd.best_sse_inter_mode; - filter_xd.mode_info_context->mbmi.mv = filter_xd.best_sse_mv; - filter_xd.mode_info_context->mbmi.need_to_clamp_mvs = - filter_xd.need_to_clamp_best_mvs; - mv_col = filter_xd.best_sse_mv.as_mv.col; - mv_row = filter_xd.best_sse_mv.as_mv.row; - - if (filter_xd.mode_info_context->mbmi.mode <= B_PRED || - (mv_row *mv_row + mv_col *mv_col <= NOISE_MOTION_THRESHOLD && - sse_diff < SSE_DIFF_THRESHOLD)) - { - // Handle intra blocks as referring to last frame with zero motion and - // let the absolute pixel difference affect the filter factor. - // Also consider small amount of motion as being random walk due to - // noise, if it doesn't mean that we get a much bigger error. - // Note that any changes to the mode info only affects the denoising. - filter_xd.mode_info_context->mbmi.ref_frame = LAST_FRAME; - filter_xd.mode_info_context->mbmi.mode = ZEROMV; - filter_xd.mode_info_context->mbmi.mv.as_int = 0; - x->e_mbd.best_sse_inter_mode = ZEROMV; - x->e_mbd.best_sse_mv.as_int = 0; - best_sse = zero_mv_sse; - } - - if (!x->skip) - { - vp8_build_inter_predictors_mb(&filter_xd); - } - else - { - vp8_build_inter16x16_predictors_mb(&filter_xd, - filter_xd.dst.y_buffer, - filter_xd.dst.u_buffer, - filter_xd.dst.v_buffer, - filter_xd.dst.y_stride, - filter_xd.dst.uv_stride); - } - - return best_sse; -} // The filtering coefficients used for denoizing are adjusted for static // blocks, or blocks with very small motion vectors. This is done through @@ -216,27 +154,34 @@ void vp8_denoiser_filter_c(YV12_BUFFER_CONFIG *mc_running_avg, int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height) { + int i; assert(denoiser); - denoiser->yv12_running_avg.flags = 0; - if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_running_avg), width, - height, VP8BORDERINPIXELS) < 0) + /* don't need one for intra start at 1 */ + for (i = 1; i < MAX_REF_FRAMES; i++) { - vp8_denoiser_free(denoiser); - return 1; - } + denoiser->yv12_running_avg[i].flags = 0; + if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_running_avg[i]), width, + height, VP8BORDERINPIXELS) + < 0) + { + vp8_denoiser_free(denoiser); + return 1; + } + vpx_memset(denoiser->yv12_running_avg[i].buffer_alloc, 0, + denoiser->yv12_running_avg[i].frame_size); + + } denoiser->yv12_mc_running_avg.flags = 0; if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_mc_running_avg), width, - height, VP8BORDERINPIXELS) < 0) + height, VP8BORDERINPIXELS) < 0) { vp8_denoiser_free(denoiser); return 1; } - vpx_memset(denoiser->yv12_running_avg.buffer_alloc, 0, - denoiser->yv12_running_avg.frame_size); vpx_memset(denoiser->yv12_mc_running_avg.buffer_alloc, 0, denoiser->yv12_mc_running_avg.frame_size); return 0; @@ -244,11 +189,18 @@ int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height) void vp8_denoiser_free(VP8_DENOISER *denoiser) { + int i; assert(denoiser); - vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_running_avg); + + /* we don't have one for intra ref frame */ + for (i = 1; i < MAX_REF_FRAMES ; i++) + { + vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_running_avg[i]); + } vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_mc_running_avg); } + void vp8_denoiser_denoise_mb(VP8_DENOISER *denoiser, MACROBLOCK *x, unsigned int best_sse, @@ -259,32 +211,103 @@ void vp8_denoiser_denoise_mb(VP8_DENOISER *denoiser, int mv_row; int mv_col; unsigned int motion_magnitude2; + + MV_REFERENCE_FRAME frame = x->best_reference_frame; + MV_REFERENCE_FRAME zero_frame = x->best_zeromv_reference_frame; + // Motion compensate the running average. - best_sse = denoiser_motion_compensate(&denoiser->yv12_running_avg, - &denoiser->yv12_mc_running_avg, - x, - best_sse, - zero_mv_sse, - recon_yoffset, - recon_uvoffset); - - mv_row = x->e_mbd.best_sse_mv.as_mv.row; - mv_col = x->e_mbd.best_sse_mv.as_mv.col; - motion_magnitude2 = mv_row * mv_row + mv_col * mv_col; + if(zero_frame) + { + YV12_BUFFER_CONFIG *src = &denoiser->yv12_running_avg[frame]; + YV12_BUFFER_CONFIG *dst = &denoiser->yv12_mc_running_avg; + YV12_BUFFER_CONFIG saved_pre,saved_dst; + MB_MODE_INFO saved_mbmi; + MACROBLOCKD *filter_xd = &x->e_mbd; + MB_MODE_INFO *mbmi = &filter_xd->mode_info_context->mbmi; + int mv_col; + int mv_row; + int sse_diff = zero_mv_sse - best_sse; + + saved_mbmi = *mbmi; + + // Use the best MV for the compensation. + mbmi->ref_frame = x->best_reference_frame; + mbmi->mode = x->best_sse_inter_mode; + mbmi->mv = x->best_sse_mv; + mbmi->need_to_clamp_mvs = x->need_to_clamp_best_mvs; + mv_col = x->best_sse_mv.as_mv.col; + mv_row = x->best_sse_mv.as_mv.row; + + if(frame == INTRA_FRAME || + (mv_row *mv_row + mv_col *mv_col <= NOISE_MOTION_THRESHOLD && + sse_diff < SSE_DIFF_THRESHOLD)) + { + // Handle intra blocks as referring to last frame with zero motion + // and let the absolute pixel difference affect the filter factor. + // Also consider small amount of motion as being random walk due to + // noise, if it doesn't mean that we get a much bigger error. + // Note that any changes to the mode info only affects the denoising. + mbmi->ref_frame = + x->best_zeromv_reference_frame; + + src = &denoiser->yv12_running_avg[zero_frame]; + + mbmi->mode = ZEROMV; + mbmi->mv.as_int = 0; + x->best_sse_inter_mode = ZEROMV; + x->best_sse_mv.as_int = 0; + best_sse = zero_mv_sse; + } + + saved_pre = filter_xd->pre; + saved_dst = filter_xd->dst; - if (best_sse > SSE_THRESHOLD || - motion_magnitude2 > 8 * NOISE_MOTION_THRESHOLD) + // Compensate the running average. + filter_xd->pre.y_buffer = src->y_buffer + recon_yoffset; + filter_xd->pre.u_buffer = src->u_buffer + recon_uvoffset; + filter_xd->pre.v_buffer = src->v_buffer + recon_uvoffset; + // Write the compensated running average to the destination buffer. + filter_xd->dst.y_buffer = dst->y_buffer + recon_yoffset; + filter_xd->dst.u_buffer = dst->u_buffer + recon_uvoffset; + filter_xd->dst.v_buffer = dst->v_buffer + recon_uvoffset; + + if (!x->skip) + { + vp8_build_inter_predictors_mb(filter_xd); + } + else + { + vp8_build_inter16x16_predictors_mb(filter_xd, + filter_xd->dst.y_buffer, + filter_xd->dst.u_buffer, + filter_xd->dst.v_buffer, + filter_xd->dst.y_stride, + filter_xd->dst.uv_stride); + } + filter_xd->pre = saved_pre; + filter_xd->dst = saved_dst; + *mbmi = saved_mbmi; + + } + + mv_row = x->best_sse_mv.as_mv.row; + mv_col = x->best_sse_mv.as_mv.col; + motion_magnitude2 = mv_row * mv_row + mv_col * mv_col; + if (best_sse > SSE_THRESHOLD || motion_magnitude2 + > 8 * NOISE_MOTION_THRESHOLD) { - // No filtering of this block since it differs too much from the - // predictor, or the motion vector magnitude is considered too big. - vp8_copy_mem16x16(x->thismb, 16, - denoiser->yv12_running_avg.y_buffer + recon_yoffset, - denoiser->yv12_running_avg.y_stride); + // No filtering of this block; it differs too much from the predictor, + // or the motion vector magnitude is considered too big. + vp8_copy_mem16x16( + x->thismb, 16, + denoiser->yv12_running_avg[LAST_FRAME].y_buffer + recon_yoffset, + denoiser->yv12_running_avg[LAST_FRAME].y_stride); return; } // Filter. vp8_denoiser_filter(&denoiser->yv12_mc_running_avg, - &denoiser->yv12_running_avg, x, motion_magnitude2, + &denoiser->yv12_running_avg[LAST_FRAME], x, + motion_magnitude2, recon_yoffset, recon_uvoffset); } diff --git a/vp8/encoder/denoising.h b/vp8/encoder/denoising.h index 0a54e71..441bccd 100644 --- a/vp8/encoder/denoising.h +++ b/vp8/encoder/denoising.h @@ -17,8 +17,8 @@ typedef struct vp8_denoiser { - YV12_BUFFER_CONFIG yv12_running_avg; - YV12_BUFFER_CONFIG yv12_mc_running_avg; + YV12_BUFFER_CONFIG yv12_running_avg[MAX_REF_FRAMES]; + YV12_BUFFER_CONFIG yv12_mc_running_avg; } VP8_DENOISER; int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height); diff --git a/vp8/encoder/encodeframe.c b/vp8/encoder/encodeframe.c index f0ffaea..2cef01e 100644 --- a/vp8/encoder/encodeframe.c +++ b/vp8/encoder/encodeframe.c @@ -1177,9 +1177,11 @@ int vp8cx_encode_inter_macroblock #if CONFIG_TEMPORAL_DENOISING // Reset the best sse mode/mv for each macroblock. - x->e_mbd.best_sse_inter_mode = 0; - x->e_mbd.best_sse_mv.as_int = 0; - x->e_mbd.need_to_clamp_best_mvs = 0; + x->best_reference_frame = INTRA_FRAME; + x->best_zeromv_reference_frame = INTRA_FRAME; + x->best_sse_inter_mode = 0; + x->best_sse_mv.as_int = 0; + x->need_to_clamp_best_mvs = 0; #endif if (cpi->sf.RD) diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c index 372d5aa..67a8b5a 100644 --- a/vp8/encoder/onyx_if.c +++ b/vp8/encoder/onyx_if.c @@ -3153,9 +3153,49 @@ void vp8_loopfilter_frame(VP8_COMP *cpi, VP8_COMMON *cm) #if CONFIG_TEMPORAL_DENOISING if (cpi->oxcf.noise_sensitivity) { - vp8_yv12_extend_frame_borders(&cpi->denoiser.yv12_running_avg); + + + /* we shouldn't have to keep multiple copies as we know in advance which + * buffer we should start - for now to get something up and running + * I've chosen to copy the buffers + */ + if (cm->frame_type == KEY_FRAME) + { + int i; + vp8_yv12_copy_frame( + cpi->Source, + &cpi->denoiser.yv12_running_avg[LAST_FRAME]); + + vp8_yv12_extend_frame_borders( + &cpi->denoiser.yv12_running_avg[LAST_FRAME]); + + for (i = 2; i < MAX_REF_FRAMES - 1; i++) + vp8_yv12_copy_frame( + cpi->Source, + &cpi->denoiser.yv12_running_avg[i]); + } + else /* For non key frames */ + { + vp8_yv12_extend_frame_borders( + &cpi->denoiser.yv12_running_avg[LAST_FRAME]); + + if (cm->refresh_alt_ref_frame || cm->copy_buffer_to_arf) + { + vp8_yv12_copy_frame( + &cpi->denoiser.yv12_running_avg[LAST_FRAME], + &cpi->denoiser.yv12_running_avg[ALTREF_FRAME]); + } + if (cm->refresh_golden_frame || cm->copy_buffer_to_gf) + { + vp8_yv12_copy_frame( + &cpi->denoiser.yv12_running_avg[LAST_FRAME], + &cpi->denoiser.yv12_running_avg[GOLDEN_FRAME]); + } + } + } #endif + } static void encode_frame_to_data_rate diff --git a/vp8/encoder/pickinter.c b/vp8/encoder/pickinter.c index 4de84fd..47d646f 100644 --- a/vp8/encoder/pickinter.c +++ b/vp8/encoder/pickinter.c @@ -61,7 +61,7 @@ int vp8_skip_fractional_mv_step(MACROBLOCK *mb, BLOCK *b, BLOCKD *d, } -static int get_inter_mbpred_error(MACROBLOCK *mb, +int vp8_get_inter_mbpred_error(MACROBLOCK *mb, const vp8_variance_fn_ptr_t *vfp, unsigned int *sse, int_mv this_mv) @@ -486,7 +486,7 @@ static int evaluate_inter_mode(unsigned int* sse, int rate2, int* distortion2, V if((this_mode != NEWMV) || !(cpi->sf.half_pixel_search) || cpi->common.full_pixel==1) - *distortion2 = get_inter_mbpred_error(x, + *distortion2 = vp8_get_inter_mbpred_error(x, &cpi->fn_ptr[BLOCK_16X16], sse, mv); @@ -523,7 +523,7 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int best_mode_index = 0; unsigned int sse = INT_MAX, best_rd_sse = INT_MAX; #if CONFIG_TEMPORAL_DENOISING - unsigned int zero_mv_sse = 0, best_sse = INT_MAX; + unsigned int zero_mv_sse = INT_MAX, best_sse = INT_MAX; #endif int_mv mvp; @@ -964,25 +964,27 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, #if CONFIG_TEMPORAL_DENOISING if (cpi->oxcf.noise_sensitivity) { - // Store for later use by denoiser. - if (this_mode == ZEROMV && - x->e_mbd.mode_info_context->mbmi.ref_frame == LAST_FRAME) - { - zero_mv_sse = sse; - } - - // Store the best NEWMV in x for later use in the denoiser. - // We are restricted to the LAST_FRAME since the denoiser only keeps - // one filter state. - if (x->e_mbd.mode_info_context->mbmi.mode == NEWMV && - x->e_mbd.mode_info_context->mbmi.ref_frame == LAST_FRAME) - { - best_sse = sse; - x->e_mbd.best_sse_inter_mode = NEWMV; - x->e_mbd.best_sse_mv = x->e_mbd.mode_info_context->mbmi.mv; - x->e_mbd.need_to_clamp_best_mvs = - x->e_mbd.mode_info_context->mbmi.need_to_clamp_mvs; - } + + // Store for later use by denoiser. + if (this_mode == ZEROMV && sse < zero_mv_sse ) + { + zero_mv_sse = sse; + x->best_zeromv_reference_frame = + x->e_mbd.mode_info_context->mbmi.ref_frame; + } + + // Store the best NEWMV in x for later use in the denoiser. + if (x->e_mbd.mode_info_context->mbmi.mode == NEWMV && + sse < best_sse) + { + best_sse = sse; + x->best_sse_inter_mode = NEWMV; + x->best_sse_mv = x->e_mbd.mode_info_context->mbmi.mv; + x->need_to_clamp_best_mvs = + x->e_mbd.mode_info_context->mbmi.need_to_clamp_mvs; + x->best_reference_frame = + x->e_mbd.mode_info_context->mbmi.ref_frame; + } } #endif @@ -1058,37 +1060,47 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, #if CONFIG_TEMPORAL_DENOISING if (cpi->oxcf.noise_sensitivity) { - if (x->e_mbd.best_sse_inter_mode == DC_PRED) { - // No best MV found. - x->e_mbd.best_sse_inter_mode = best_mbmode.mode; - x->e_mbd.best_sse_mv = best_mbmode.mv; - x->e_mbd.need_to_clamp_best_mvs = best_mbmode.need_to_clamp_mvs; - best_sse = best_rd_sse; - } - vp8_denoiser_denoise_mb(&cpi->denoiser, x, best_sse, zero_mv_sse, - recon_yoffset, recon_uvoffset); - - // Reevaluate ZEROMV after denoising. - if (best_mbmode.ref_frame == INTRA_FRAME) - { - int this_rd = 0; - rate2 = 0; - distortion2 = 0; - x->e_mbd.mode_info_context->mbmi.ref_frame = LAST_FRAME; - rate2 += x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame]; - this_mode = ZEROMV; - rate2 += vp8_cost_mv_ref(this_mode, mdcounts); - x->e_mbd.mode_info_context->mbmi.mode = this_mode; - x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; - x->e_mbd.mode_info_context->mbmi.mv.as_int = 0; - this_rd = evaluate_inter_mode(&sse, rate2, &distortion2, cpi, x); + if (x->best_sse_inter_mode == DC_PRED) + { + // No best MV found. + x->best_sse_inter_mode = best_mbmode.mode; + x->best_sse_mv = best_mbmode.mv; + x->need_to_clamp_best_mvs = best_mbmode.need_to_clamp_mvs; + x->best_reference_frame = best_mbmode.ref_frame; + best_sse = best_rd_sse; + } + vp8_denoiser_denoise_mb(&cpi->denoiser, x, best_sse, zero_mv_sse, + recon_yoffset, recon_uvoffset); - if (this_rd < best_rd || x->skip) + + // Reevaluate ZEROMV after denoising. + if (best_mbmode.ref_frame == INTRA_FRAME && + x->best_zeromv_reference_frame != INTRA_FRAME) { - vpx_memcpy(&best_mbmode, &x->e_mbd.mode_info_context->mbmi, - sizeof(MB_MODE_INFO)); + int this_rd = 0; + int this_ref_frame = x->best_zeromv_reference_frame; + rate2 = x->ref_frame_cost[this_ref_frame] + + vp8_cost_mv_ref(ZEROMV, mdcounts); + distortion2 = 0; + + // set up the proper prediction buffers for the frame + x->e_mbd.mode_info_context->mbmi.ref_frame = this_ref_frame; + x->e_mbd.pre.y_buffer = plane[this_ref_frame][0]; + x->e_mbd.pre.u_buffer = plane[this_ref_frame][1]; + x->e_mbd.pre.v_buffer = plane[this_ref_frame][2]; + + x->e_mbd.mode_info_context->mbmi.mode = ZEROMV; + x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; + x->e_mbd.mode_info_context->mbmi.mv.as_int = 0; + this_rd = evaluate_inter_mode(&sse, rate2, &distortion2, cpi, x); + + if (this_rd < best_rd) + { + vpx_memcpy(&best_mbmode, &x->e_mbd.mode_info_context->mbmi, + sizeof(MB_MODE_INFO)); + } } - } + } #endif diff --git a/vp8/encoder/pickinter.h b/vp8/encoder/pickinter.h index 3d83782..6fbd887 100644 --- a/vp8/encoder/pickinter.h +++ b/vp8/encoder/pickinter.h @@ -20,4 +20,8 @@ extern void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int mb_row, int mb_col); extern void vp8_pick_intra_mode(VP8_COMP *cpi, MACROBLOCK *x, int *rate); +extern int vp8_get_inter_mbpred_error(MACROBLOCK *mb, + const vp8_variance_fn_ptr_t *vfp, + unsigned int *sse, + int_mv this_mv); #endif diff --git a/vp8/encoder/rdopt.c b/vp8/encoder/rdopt.c index 1a2eb11..b457f03 100644 --- a/vp8/encoder/rdopt.c +++ b/vp8/encoder/rdopt.c @@ -21,6 +21,7 @@ #include "onyx_int.h" #include "modecosts.h" #include "encodeintra.h" +#include "pickinter.h" #include "vp8/common/entropymode.h" #include "vp8/common/reconinter.h" #include "vp8/common/reconintra4x4.h" @@ -36,7 +37,6 @@ #if CONFIG_TEMPORAL_DENOISING #include "denoising.h" #endif - extern void vp8_update_zbin_extra(VP8_COMP *cpi, MACROBLOCK *x); #define MAXF(a,b) (((a) > (b)) ? (a) : (b)) @@ -1965,6 +1965,11 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int intra_rd_penalty = 10* vp8_dc_quant(cpi->common.base_qindex, cpi->common.y1dc_delta_q); +#if CONFIG_TEMPORAL_DENOISING + unsigned int zero_mv_sse = INT_MAX, best_sse = INT_MAX, + best_rd_sse = INT_MAX; +#endif + mode_mv = mode_mv_sb[sign_bias]; best_ref_mv.as_int = 0; best_mode.rd = INT_MAX; @@ -2375,21 +2380,38 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, best_mode.intra_rd = this_rd; *returnintra = rd.distortion2 ; } - #if CONFIG_TEMPORAL_DENOISING if (cpi->oxcf.noise_sensitivity) { - // Store the best NEWMV in x for later use in the denoiser. - // We are restricted to the LAST_FRAME since the denoiser only keeps - // one filter state. - if (x->e_mbd.mode_info_context->mbmi.mode == NEWMV && - x->e_mbd.mode_info_context->mbmi.ref_frame == LAST_FRAME) - { - x->e_mbd.best_sse_inter_mode = NEWMV; - x->e_mbd.best_sse_mv = x->e_mbd.mode_info_context->mbmi.mv; - x->e_mbd.need_to_clamp_best_mvs = - x->e_mbd.mode_info_context->mbmi.need_to_clamp_mvs; - } + unsigned int sse; + vp8_get_inter_mbpred_error(x,&cpi->fn_ptr[BLOCK_16X16],&sse, + mode_mv[this_mode]); + + if (sse < best_rd_sse) + best_rd_sse = sse; + + // Store for later use by denoiser. + if (this_mode == ZEROMV && sse < zero_mv_sse ) + { + zero_mv_sse = sse; + x->best_zeromv_reference_frame = + x->e_mbd.mode_info_context->mbmi.ref_frame; + } + + // Store the best NEWMV in x for later use in the denoiser. + if (x->e_mbd.mode_info_context->mbmi.mode == NEWMV && + sse < best_sse) + { + best_sse = sse; + vp8_get_inter_mbpred_error(x,&cpi->fn_ptr[BLOCK_16X16],&best_sse, + mode_mv[this_mode]); + x->best_sse_inter_mode = NEWMV; + x->best_sse_mv = x->e_mbd.mode_info_context->mbmi.mv; + x->need_to_clamp_best_mvs = + x->e_mbd.mode_info_context->mbmi.need_to_clamp_mvs; + x->best_reference_frame = + x->e_mbd.mode_info_context->mbmi.ref_frame; + } } #endif @@ -2462,42 +2484,55 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, #if CONFIG_TEMPORAL_DENOISING if (cpi->oxcf.noise_sensitivity) { - if (x->e_mbd.best_sse_inter_mode == DC_PRED) { - // No best MV found. - x->e_mbd.best_sse_inter_mode = best_mode.mbmode.mode; - x->e_mbd.best_sse_mv = best_mode.mbmode.mv; - x->e_mbd.need_to_clamp_best_mvs = best_mode.mbmode.need_to_clamp_mvs; - } - - // TODO(holmer): No SSEs are calculated in rdopt.c. What else can be used? - vp8_denoiser_denoise_mb(&cpi->denoiser, x, 0, 0, - recon_yoffset, recon_uvoffset); - // Reevalute ZEROMV if the current mode is INTRA. - if (best_mode.mbmode.ref_frame == INTRA_FRAME) - { - int this_rd = INT_MAX; - int disable_skip = 0; - int other_cost = 0; - vpx_memset(&rd, 0, sizeof(rd)); - x->e_mbd.mode_info_context->mbmi.ref_frame = LAST_FRAME; - rd.rate2 += x->ref_frame_cost[LAST_FRAME]; - rd.rate2 += vp8_cost_mv_ref(ZEROMV, mdcounts); - x->e_mbd.mode_info_context->mbmi.mode = ZEROMV; - x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; - x->e_mbd.mode_info_context->mbmi.mv.as_int = 0; - this_rd = evaluate_inter_mode_rd(mdcounts, &rd, &disable_skip, cpi, x); - this_rd = calculate_final_rd_costs(this_rd, &rd, &other_cost, - disable_skip, uv_intra_tteob, - intra_rd_penalty, cpi, x); - if (this_rd < best_mode.rd || x->skip) + if (x->best_sse_inter_mode == DC_PRED) { - // Note index of best mode so far - best_mode_index = mode_index; - *returnrate = rd.rate2; - *returndistortion = rd.distortion2; - update_best_mode(&best_mode, this_rd, &rd, other_cost, x); + // No best MV found. + x->best_sse_inter_mode = best_mode.mbmode.mode; + x->best_sse_mv = best_mode.mbmode.mv; + x->need_to_clamp_best_mvs = best_mode.mbmode.need_to_clamp_mvs; + x->best_reference_frame = best_mode.mbmode.ref_frame; + best_sse = best_rd_sse; } - } + vp8_denoiser_denoise_mb(&cpi->denoiser, x, best_sse, zero_mv_sse, + recon_yoffset, recon_uvoffset); + + + // Reevaluate ZEROMV after denoising. + if (best_mode.mbmode.ref_frame == INTRA_FRAME && + x->best_zeromv_reference_frame != INTRA_FRAME) + { + int this_rd = INT_MAX; + int disable_skip = 0; + int other_cost = 0; + int this_ref_frame = x->best_zeromv_reference_frame; + rd.rate2 = x->ref_frame_cost[this_ref_frame] + + vp8_cost_mv_ref(ZEROMV, mdcounts); + rd.distortion2 = 0; + + // set up the proper prediction buffers for the frame + x->e_mbd.mode_info_context->mbmi.ref_frame = this_ref_frame; + x->e_mbd.pre.y_buffer = plane[this_ref_frame][0]; + x->e_mbd.pre.u_buffer = plane[this_ref_frame][1]; + x->e_mbd.pre.v_buffer = plane[this_ref_frame][2]; + + x->e_mbd.mode_info_context->mbmi.mode = ZEROMV; + x->e_mbd.mode_info_context->mbmi.uv_mode = DC_PRED; + x->e_mbd.mode_info_context->mbmi.mv.as_int = 0; + + this_rd = evaluate_inter_mode_rd(mdcounts, &rd, &disable_skip, cpi, x); + this_rd = calculate_final_rd_costs(this_rd, &rd, &other_cost, + disable_skip, uv_intra_tteob, + intra_rd_penalty, cpi, x); + if (this_rd < best_mode.rd || x->skip) + { + // Note index of best mode so far + best_mode_index = mode_index; + *returnrate = rd.rate2; + *returndistortion = rd.distortion2; + update_best_mode(&best_mode, this_rd, &rd, other_cost, x); + } + } + } #endif diff --git a/vp8_scalable_patterns.c b/vp8_scalable_patterns.c index aa931e2..8d151dd 100644 --- a/vp8_scalable_patterns.c +++ b/vp8_scalable_patterns.c @@ -493,6 +493,7 @@ int main(int argc, char **argv) { // Cap CPU & first I-frame size vpx_codec_control (&codec, VP8E_SET_CPUUSED, -6); vpx_codec_control (&codec, VP8E_SET_STATIC_THRESHOLD, 800); + vpx_codec_control (&codec, VP8E_SET_NOISE_SENSITIVITY, 1); max_intra_size_pct = (int) (((double)cfg.rc_buf_optimal_sz * 0.5) * ((double) cfg.g_timebase.den / cfg.g_timebase.num) -- 2.7.4