From 9c41143d6655f39c3b6f2f0023cd687214af599a Mon Sep 17 00:00:00 2001 From: Stefan Holmer Date: Tue, 6 Mar 2012 10:48:18 +0100 Subject: [PATCH] Adds a motion compensated temporal denoiser to the encoder. Some refactoring in rdopt.c and pickinter.c. Change-Id: I4f50020eb3313c37f4d441d708fedcaf219d3038 --- configure | 4 + vp8/common/alloccommon.c | 1 - vp8/common/blockd.h | 6 + vp8/common/postproc.c | 2 + vp8/encoder/denoising.c | 212 ++++++++++++++++ vp8/encoder/denoising.h | 33 +++ vp8/encoder/encodeframe.c | 7 + vp8/encoder/onyx_if.c | 23 +- vp8/encoder/onyx_int.h | 7 + vp8/encoder/pickinter.c | 151 ++++++++--- vp8/encoder/rdopt.c | 511 +++++++++++++++++++++++--------------- vp8/vp8_cx_iface.c | 8 +- vp8/vp8cx.mk | 2 + 13 files changed, 729 insertions(+), 238 deletions(-) create mode 100644 vp8/encoder/denoising.c create mode 100644 vp8/encoder/denoising.h diff --git a/configure b/configure index cf3eb32ec..2724c3008 100755 --- a/configure +++ b/configure @@ -47,6 +47,7 @@ Advanced options: ${toggle_small} favor smaller size over speed ${toggle_postproc_visualizer} macro block / block level visualizers ${toggle_multi_res_encoding} enable multiple-resolution encoding + ${toggle_temporal_denoising} enable temporal denoising and disable the spatial denoiser Codecs: Codecs can be selectively enabled or disabled individually, or by family: @@ -165,6 +166,7 @@ enable md5 enable spatial_resampling enable multithread enable os_support +enable temporal_denoising [ -d ${source_path}/../include ] && enable alt_tree_layout for d in vp8; do @@ -263,6 +265,7 @@ CONFIG_LIST=" os_support unit_tests multi_res_encoding + temporal_denoising " CMDLINE_SELECT=" extra_warnings @@ -307,6 +310,7 @@ CMDLINE_SELECT=" postproc_visualizer unit_tests multi_res_encoding + temporal_denoising " process_cmdline() { diff --git a/vp8/common/alloccommon.c b/vp8/common/alloccommon.c index b606aaca0..b32d8a939 100644 --- a/vp8/common/alloccommon.c +++ b/vp8/common/alloccommon.c @@ -37,7 +37,6 @@ static void update_mode_info_border(MODE_INFO *mi, int rows, int cols) void vp8_de_alloc_frame_buffers(VP8_COMMON *oci) { int i; - for (i = 0; i < NUM_YV12_BUFFERS; i++) vp8_yv12_de_alloc_frame_buffer(&oci->yv12_fb[i]); diff --git a/vp8/common/blockd.h b/vp8/common/blockd.h index c8d1bab7d..692f0ebd2 100644 --- a/vp8/common/blockd.h +++ b/vp8/common/blockd.h @@ -215,6 +215,12 @@ 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/common/postproc.c b/vp8/common/postproc.c index 401989ba5..a8b169170 100644 --- a/vp8/common/postproc.c +++ b/vp8/common/postproc.c @@ -362,6 +362,7 @@ void vp8_deblock(YV12_BUFFER_CONFIG *source, vp8_post_proc_down_and_across(source->v_buffer, post->v_buffer, source->uv_stride, post->uv_stride, source->uv_height, source->uv_width, ppl); } +#if !(CONFIG_TEMPORAL_DENOISING) void vp8_de_noise(YV12_BUFFER_CONFIG *source, YV12_BUFFER_CONFIG *post, int q, @@ -398,6 +399,7 @@ void vp8_de_noise(YV12_BUFFER_CONFIG *source, source->uv_width - 4, ppl); } +#endif double vp8_gaussian(double sigma, double mu, double x) { diff --git a/vp8/encoder/denoising.c b/vp8/encoder/denoising.c new file mode 100644 index 000000000..6773a659d --- /dev/null +++ b/vp8/encoder/denoising.c @@ -0,0 +1,212 @@ +/* + * Copyright (c) 2012 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#include "denoising.h" + +#include "vp8/common/reconinter.h" +#include "vpx/vpx_integer.h" +#include "vpx_mem/vpx_mem.h" +#include "vpx_rtcd.h" + +const unsigned int NOISE_MOTION_THRESHOLD = 20*20; +const unsigned int NOISE_DIFF2_THRESHOLD = 75; +// SSE_DIFF_THRESHOLD is selected as ~95% confidence assuming var(noise) ~= 100. +const unsigned int SSE_DIFF_THRESHOLD = 16*16*20; +const unsigned int SSE_THRESHOLD = 16*16*40; + +static __inline uint8_t blend(uint8_t state, uint8_t sample, uint8_t factor_q8) +{ + return (uint8_t)( + (((uint16_t)factor_q8 * ((uint16_t)state) + // Q8 + (uint16_t)(256 - factor_q8) * ((uint16_t)sample)) + 128) // Q8 + >> 8); +} + +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; +} + +static void denoiser_filter(YV12_BUFFER_CONFIG* mc_running_avg, + YV12_BUFFER_CONFIG* running_avg, + MACROBLOCK* signal, + unsigned int motion_magnitude2, + int y_offset, + int uv_offset) +{ + unsigned char* sig = signal->thismb; + int sig_stride = 16; + unsigned char* mc_running_avg_y = mc_running_avg->y_buffer + y_offset; + int mc_avg_y_stride = mc_running_avg->y_stride; + unsigned char* running_avg_y = running_avg->y_buffer + y_offset; + int avg_y_stride = running_avg->y_stride; + int r, c; + for (r = 0; r < 16; r++) + { + for (c = 0; c < 16; c++) + { + int diff; + int absdiff = 0; + unsigned int filter_coefficient; + absdiff = sig[c] - mc_running_avg_y[c]; + absdiff = absdiff > 0 ? absdiff : -absdiff; + assert(absdiff >= 0 && absdiff < 256); + filter_coefficient = (255 << 8) / (256 + ((absdiff * 330) >> 3)); + // Allow some additional filtering of static blocks, or blocks with very + // small motion vectors. + filter_coefficient += filter_coefficient / (3 + (motion_magnitude2 >> 3)); + filter_coefficient = filter_coefficient > 255 ? 255 : filter_coefficient; + + running_avg_y[c] = blend(mc_running_avg_y[c], sig[c], filter_coefficient); + diff = sig[c] - running_avg_y[c]; + + if (diff * diff < NOISE_DIFF2_THRESHOLD) + { + // Replace with mean to suppress the noise. + sig[c] = running_avg_y[c]; + } + else + { + // Replace the filter state with the signal since the change in this + // pixel isn't classified as noise. + running_avg_y[c] = sig[c]; + } + } + sig += sig_stride; + mc_running_avg_y += mc_avg_y_stride; + running_avg_y += avg_y_stride; + } +} + +int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height) +{ + assert(denoiser); + denoiser->yv12_running_avg.flags = 0; + if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_running_avg), width, + height, VP8BORDERINPIXELS) < 0) + { + vp8_denoiser_free(denoiser); + return 1; + } + denoiser->yv12_mc_running_avg.flags = 0; + if (vp8_yv12_alloc_frame_buffer(&(denoiser->yv12_mc_running_avg), width, + 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; +} + +void vp8_denoiser_free(VP8_DENOISER *denoiser) +{ + assert(denoiser); + vp8_yv12_de_alloc_frame_buffer(&denoiser->yv12_running_avg); + 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, + unsigned int zero_mv_sse, + int recon_yoffset, + int recon_uvoffset) { + int mv_row; + int mv_col; + unsigned int motion_magnitude2; + // 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 (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); + return; + } + // Filter. + denoiser_filter(&denoiser->yv12_mc_running_avg, + &denoiser->yv12_running_avg, + x, + motion_magnitude2, + recon_yoffset, + recon_uvoffset); +} diff --git a/vp8/encoder/denoising.h b/vp8/encoder/denoising.h new file mode 100644 index 000000000..343531bb1 --- /dev/null +++ b/vp8/encoder/denoising.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2012 The WebM project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. An additional intellectual property rights grant can be found + * in the file PATENTS. All contributing project authors may + * be found in the AUTHORS file in the root of the source tree. + */ + +#ifndef VP8_ENCODER_DENOISING_H_ +#define VP8_ENCODER_DENOISING_H_ + +#include "block.h" + +typedef struct vp8_denoiser +{ + YV12_BUFFER_CONFIG yv12_running_avg; + YV12_BUFFER_CONFIG yv12_mc_running_avg; +} VP8_DENOISER; + +int vp8_denoiser_allocate(VP8_DENOISER *denoiser, int width, int height); + +void vp8_denoiser_free(VP8_DENOISER *denoiser); + +void vp8_denoiser_denoise_mb(VP8_DENOISER *denoiser, + MACROBLOCK *x, + unsigned int best_sse, + unsigned int zero_mv_sse, + int recon_yoffset, + int recon_uvoffset); + +#endif // VP8_ENCODER_DENOISING_H_ diff --git a/vp8/encoder/encodeframe.c b/vp8/encoder/encodeframe.c index 21757f8f0..962a719c8 100644 --- a/vp8/encoder/encodeframe.c +++ b/vp8/encoder/encodeframe.c @@ -1179,6 +1179,13 @@ int vp8cx_encode_inter_macroblock else x->encode_breakout = cpi->oxcf.encode_breakout; +#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; +#endif + if (cpi->sf.RD) { int zbin_mode_boost_enabled = cpi->zbin_mode_boost_enabled; diff --git a/vp8/encoder/onyx_if.c b/vp8/encoder/onyx_if.c index 5ad51e846..dbb7bb368 100644 --- a/vp8/encoder/onyx_if.c +++ b/vp8/encoder/onyx_if.c @@ -1680,6 +1680,17 @@ void vp8_change_config(VP8_COMP *cpi, VP8_CONFIG *oxcf) cpi->alt_ref_source = NULL; cpi->is_src_frame_alt_ref = 0; +#if CONFIG_TEMPORAL_DENOISING + if (cpi->oxcf.noise_sensitivity) + { + if (!cpi->denoiser.yv12_mc_running_avg.buffer_alloc) + { + int width = (cpi->oxcf.Width + 15) & ~15; + int height = (cpi->oxcf.Height + 15) & ~15; + vp8_denoiser_allocate(&cpi->denoiser, width, height); + } + } +#endif #if 0 // Experimental RD Code @@ -2314,6 +2325,9 @@ void vp8_remove_compressor(VP8_COMP **ptr) vp8cx_remove_encoder_threads(cpi); #endif +#if CONFIG_TEMPORAL_DENOISING + vp8_denoiser_free(&cpi->denoiser); +#endif dealloc_compressor_data(cpi); vpx_free(cpi->mb.ss); vpx_free(cpi->tok); @@ -3133,7 +3147,12 @@ void vp8_loopfilter_frame(VP8_COMP *cpi, VP8_COMMON *cm) } vp8_yv12_extend_frame_borders_ptr(cm->frame_to_show); - +#if CONFIG_TEMPORAL_DENOISING + if (cpi->oxcf.noise_sensitivity) + { + vp8_yv12_extend_frame_borders(&cpi->denoiser.yv12_running_avg); + } +#endif } static void encode_frame_to_data_rate @@ -3589,7 +3608,7 @@ static void encode_frame_to_data_rate scale_and_extend_source(cpi->un_scaled_source, cpi); -#if !(CONFIG_REALTIME_ONLY) && CONFIG_POSTPROC +#if !(CONFIG_REALTIME_ONLY) && CONFIG_POSTPROC && !(CONFIG_TEMPORAL_DENOISING) if (cpi->oxcf.noise_sensitivity > 0) { diff --git a/vp8/encoder/onyx_int.h b/vp8/encoder/onyx_int.h index e17d8ead0..487cd6e61 100644 --- a/vp8/encoder/onyx_int.h +++ b/vp8/encoder/onyx_int.h @@ -28,6 +28,9 @@ #include "mcomp.h" #include "vp8/common/findnearmv.h" #include "lookahead.h" +#if CONFIG_TEMPORAL_DENOISING +#include "vp8/encoder/denoising.h" +#endif //#define SPEEDSTATS 1 #define MIN_GF_INTERVAL 4 @@ -661,6 +664,10 @@ typedef struct VP8_COMP int droppable; +#if CONFIG_TEMPORAL_DENOISING + VP8_DENOISER denoiser; +#endif + // Coding layer state variables unsigned int current_layer; LAYER_CONTEXT layer_context[MAX_LAYERS]; diff --git a/vp8/encoder/pickinter.c b/vp8/encoder/pickinter.c index 236cb2326..ef1fd9ffe 100644 --- a/vp8/encoder/pickinter.c +++ b/vp8/encoder/pickinter.c @@ -24,6 +24,9 @@ #include "mcomp.h" #include "rdopt.h" #include "vpx_mem/vpx_mem.h" +#if CONFIG_TEMPORAL_DENOISING +#include "denoising.h" +#endif extern int VP8_UVSSE(MACROBLOCK *x); @@ -450,6 +453,48 @@ void get_lower_res_motion_info(VP8_COMP *cpi, MACROBLOCKD *xd, int *dissim, } #endif +static void check_for_encode_breakout(unsigned int sse, MACROBLOCK* x) +{ + if (sse < x->encode_breakout) + { + // Check u and v to make sure skip is ok + int sse2 = 0; + + sse2 = VP8_UVSSE(x); + + if (sse2 * 2 < x->encode_breakout) + x->skip = 1; + else + x->skip = 0; + } +} + +static int evaluate_inter_mode(unsigned int* sse, int rate2, int* distortion2, VP8_COMP *cpi, MACROBLOCK *x) +{ + MB_PREDICTION_MODE this_mode = x->e_mbd.mode_info_context->mbmi.mode; + int_mv mv = x->e_mbd.mode_info_context->mbmi.mv; + int this_rd; + /* Exit early and don't compute the distortion if this macroblock + * is marked inactive. */ + if (cpi->active_map_enabled && x->active_ptr[0] == 0) + { + *sse = 0; + *distortion2 = 0; + x->skip = 1; + return INT_MAX; + } + + if((this_mode != NEWMV) || + !(cpi->sf.half_pixel_search) || cpi->common.full_pixel==1) + *distortion2 = get_inter_mbpred_error(x, + &cpi->fn_ptr[BLOCK_16X16], + sse, mv); + + this_rd = RDCOST(x->rdmult, x->rddiv, rate2, *distortion2); + + check_for_encode_breakout(*sse, x); + return this_rd; +} void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int recon_uvoffset, int *returnrate, @@ -476,7 +521,10 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int distortion2; int bestsme = INT_MAX; int best_mode_index = 0; - unsigned int sse = INT_MAX, best_sse = INT_MAX; + unsigned int sse = INT_MAX, best_rd_sse = INT_MAX; +#if CONFIG_TEMPORAL_DENOISING + unsigned int zero_mv_sse = 0, best_sse = INT_MAX; +#endif int_mv mvp; @@ -488,9 +536,6 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int ref_frame_map[4]; int sign_bias = 0; - int have_subp_search = cpi->sf.half_pixel_search; /* In real-time mode, - when Speed >= 15, no sub-pixel search. */ - #if CONFIG_MULTI_RES_ENCODING int dissim = INT_MAX; int parent_ref_frame = 0; @@ -657,7 +702,7 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, { case B_PRED: /* Pass best so far to pick_intra4x4mby_modes to use as breakout */ - distortion2 = best_sse; + distortion2 = best_rd_sse; pick_intra4x4mby_modes(x, &rate, &distortion2); if (distortion2 == INT_MAX) @@ -905,43 +950,38 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, rate2 += vp8_cost_mv_ref(this_mode, mdcounts); x->e_mbd.mode_info_context->mbmi.mv.as_int = mode_mv[this_mode].as_int; - - /* Exit early and don't compute the distortion if this macroblock - * is marked inactive. */ - if (cpi->active_map_enabled && x->active_ptr[0] == 0) - { - sse = 0; - distortion2 = 0; - x->skip = 1; - break; - } - - if((this_mode != NEWMV) || - !(have_subp_search) || cpi->common.full_pixel==1) - distortion2 = get_inter_mbpred_error(x, - &cpi->fn_ptr[BLOCK_16X16], - &sse, mode_mv[this_mode]); - - this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); - - if (sse < x->encode_breakout) - { - // Check u and v to make sure skip is ok - int sse2 = 0; - - sse2 = VP8_UVSSE(x); - - if (sse2 * 2 < x->encode_breakout) - x->skip = 1; - else - x->skip = 0; - } + this_rd = evaluate_inter_mode(&sse, rate2, &distortion2, cpi, x); break; default: break; } +#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; + } + } +#endif + if (this_rd < best_rd || x->skip) { // Note index of best mode @@ -949,7 +989,7 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, *returnrate = rate2; *returndistortion = distortion2; - best_sse = sse; + best_rd_sse = sse; best_rd = this_rd; vpx_memcpy(&best_mbmode, &x->e_mbd.mode_info_context->mbmi, sizeof(MB_MODE_INFO)); @@ -1011,6 +1051,43 @@ void vp8_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, cpi->error_bins[this_rdbin] ++; } +#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 (this_rd < best_rd || x->skip) + { + vpx_memcpy(&best_mbmode, &x->e_mbd.mode_info_context->mbmi, + sizeof(MB_MODE_INFO)); + } + } + } +#endif + if (cpi->is_src_frame_alt_ref && (best_mbmode.mode != ZEROMV || best_mbmode.ref_frame != ALTREF_FRAME)) { diff --git a/vp8/encoder/rdopt.c b/vp8/encoder/rdopt.c index d6c643222..c6ed701fd 100644 --- a/vp8/encoder/rdopt.c +++ b/vp8/encoder/rdopt.c @@ -33,11 +33,33 @@ #include "rdopt.h" #include "vpx_mem/vpx_mem.h" #include "vp8/common/systemdependent.h" +#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)) +typedef struct rate_distortion_struct +{ + int rate2; + int rate_y; + int rate_uv; + int distortion2; + int distortion_uv; +} RATE_DISTORTION; + +typedef struct best_mode_struct +{ + int yrd; + int rd; + int intra_rd; + MB_MODE_INFO mbmode; + union b_mode_info bmodes[16]; + PARTITION_INFO partition; +} BEST_MODE; + static const int auto_speed_thresh[17] = { 1000, @@ -1711,6 +1733,181 @@ static void rd_update_mvcount(VP8_COMP *cpi, MACROBLOCK *x, int_mv *best_ref_mv) } } +static int evaluate_inter_mode_rd(int mdcounts[4], + RATE_DISTORTION* rd, + int* disable_skip, + VP8_COMP *cpi, MACROBLOCK *x) +{ + MB_PREDICTION_MODE this_mode = x->e_mbd.mode_info_context->mbmi.mode; + BLOCK *b = &x->block[0]; + MACROBLOCKD *xd = &x->e_mbd; + int distortion; + vp8_build_inter16x16_predictors_mby(&x->e_mbd, x->e_mbd.predictor, 16); + + if (cpi->active_map_enabled && x->active_ptr[0] == 0) { + x->skip = 1; + } + else if (x->encode_breakout) + { + unsigned int sse; + unsigned int var; + int threshold = (xd->block[0].dequant[1] + * xd->block[0].dequant[1] >>4); + + if(threshold < x->encode_breakout) + threshold = x->encode_breakout; + + var = vp8_variance16x16 + (*(b->base_src), b->src_stride, + x->e_mbd.predictor, 16, &sse); + + if (sse < threshold) + { + unsigned int q2dc = xd->block[24].dequant[0]; + /* If theres is no codeable 2nd order dc + or a very small uniform pixel change change */ + if ((sse - var < q2dc * q2dc >>4) || + (sse /2 > var && sse-var < 64)) + { + // Check u and v to make sure skip is ok + int sse2= VP8_UVSSE(x); + if (sse2 * 2 < threshold) + { + x->skip = 1; + rd->distortion2 = sse + sse2; + rd->rate2 = 500; + + /* for best_yrd calculation */ + rd->rate_uv = 0; + rd->distortion_uv = sse2; + + *disable_skip = 1; + return RDCOST(x->rdmult, x->rddiv, rd->rate2, + rd->distortion2); + } + } + } + } + + + //intermodecost[mode_index] = vp8_cost_mv_ref(this_mode, mdcounts); // Experimental debug code + + // Add in the Mv/mode cost + rd->rate2 += vp8_cost_mv_ref(this_mode, mdcounts); + + // Y cost and distortion + macro_block_yrd(x, &rd->rate_y, &distortion); + rd->rate2 += rd->rate_y; + rd->distortion2 += distortion; + + // UV cost and distortion + rd_inter16x16_uv(cpi, x, &rd->rate_uv, &rd->distortion_uv, + cpi->common.full_pixel); + rd->rate2 += rd->rate_uv; + rd->distortion2 += rd->distortion_uv; + return INT_MAX; +} + +static int calculate_final_rd_costs(int this_rd, + RATE_DISTORTION* rd, + int* other_cost, + int disable_skip, + int uv_intra_tteob, + int intra_rd_penalty, + VP8_COMP *cpi, MACROBLOCK *x) +{ + MB_PREDICTION_MODE this_mode = x->e_mbd.mode_info_context->mbmi.mode; + // Where skip is allowable add in the default per mb cost for the no skip case. + // where we then decide to skip we have to delete this and replace it with the + // cost of signallying a skip + if (cpi->common.mb_no_coeff_skip) + { + *other_cost += vp8_cost_bit(cpi->prob_skip_false, 0); + rd->rate2 += *other_cost; + } + + /* Estimate the reference frame signaling cost and add it + * to the rolling cost variable. + */ + rd->rate2 += + x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame]; + + if (!disable_skip) + { + // Test for the condition where skip block will be activated because there are no non zero coefficients and make any necessary adjustment for rate + if (cpi->common.mb_no_coeff_skip) + { + int i; + int tteob; + int has_y2_block = (this_mode!=SPLITMV && this_mode!=B_PRED); + + tteob = 0; + if(has_y2_block) + tteob += x->e_mbd.eobs[24]; + + for (i = 0; i < 16; i++) + tteob += (x->e_mbd.eobs[i] > has_y2_block); + + if (x->e_mbd.mode_info_context->mbmi.ref_frame) + { + for (i = 16; i < 24; i++) + tteob += x->e_mbd.eobs[i]; + } + else + tteob += uv_intra_tteob; + + if (tteob == 0) + { + rd->rate2 -= (rd->rate_y + rd->rate_uv); + //for best_yrd calculation + rd->rate_uv = 0; + + // Back out no skip flag costing and add in skip flag costing + if (cpi->prob_skip_false) + { + int prob_skip_cost; + + prob_skip_cost = vp8_cost_bit(cpi->prob_skip_false, 1); + prob_skip_cost -= vp8_cost_bit(cpi->prob_skip_false, 0); + rd->rate2 += prob_skip_cost; + *other_cost += prob_skip_cost; + } + } + } + // Calculate the final RD estimate for this mode + this_rd = RDCOST(x->rdmult, x->rddiv, rd->rate2, rd->distortion2); + if (this_rd < INT_MAX && x->e_mbd.mode_info_context->mbmi.ref_frame + == INTRA_FRAME) + this_rd += intra_rd_penalty; + } + return this_rd; +} + +static void update_best_mode(BEST_MODE* best_mode, int this_rd, + RATE_DISTORTION* rd, int other_cost, MACROBLOCK *x) +{ + MB_PREDICTION_MODE this_mode = x->e_mbd.mode_info_context->mbmi.mode; + + other_cost += + x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame]; + + /* Calculate the final y RD estimate for this mode */ + best_mode->yrd = RDCOST(x->rdmult, x->rddiv, (rd->rate2-rd->rate_uv-other_cost), + (rd->distortion2-rd->distortion_uv)); + + best_mode->rd = this_rd; + vpx_memcpy(&best_mode->mbmode, &x->e_mbd.mode_info_context->mbmi, sizeof(MB_MODE_INFO)); + vpx_memcpy(&best_mode->partition, x->partition_info, sizeof(PARTITION_INFO)); + + if ((this_mode == B_PRED) || (this_mode == SPLITMV)) + { + int i; + for (i = 0; i < 16; i++) + { + best_mode->bmodes[i] = x->e_mbd.block[i].bmi; + } + } +} void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int recon_uvoffset, int *returnrate, @@ -1719,9 +1916,6 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, BLOCK *b = &x->block[0]; BLOCKD *d = &x->e_mbd.block[0]; MACROBLOCKD *xd = &x->e_mbd; - union b_mode_info best_bmodes[16]; - MB_MODE_INFO best_mbmode; - PARTITION_INFO best_partition; int_mv best_ref_mv_sb[2]; int_mv mode_mv_sb[2][MB_MODE_COUNT]; int_mv best_ref_mv; @@ -1729,21 +1923,16 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, MB_PREDICTION_MODE this_mode; int num00; int best_mode_index = 0; + BEST_MODE best_mode; int i; int mode_index; int mdcounts[4]; int rate; - int distortion; - int best_rd = INT_MAX; - int best_intra_rd = INT_MAX; - int rate2, distortion2; + RATE_DISTORTION rd; int uv_intra_rate, uv_intra_distortion, uv_intra_rate_tokenonly; int uv_intra_tteob = 0; int uv_intra_done = 0; - int rate_y, UNINITIALIZED_IS_SAFE(rate_uv); - int distortion_uv; - int best_yrd = INT_MAX; MB_PREDICTION_MODE uv_intra_mode = 0; int_mv mvp; @@ -1760,9 +1949,12 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, mode_mv = mode_mv_sb[sign_bias]; best_ref_mv.as_int = 0; + best_mode.rd = INT_MAX; + best_mode.yrd = INT_MAX; + best_mode.intra_rd = INT_MAX; vpx_memset(mode_mv_sb, 0, sizeof(mode_mv_sb)); - vpx_memset(&best_mbmode, 0, sizeof(best_mbmode)); - vpx_memset(&best_bmodes, 0, sizeof(best_bmodes)); + vpx_memset(&best_mode.mbmode, 0, sizeof(best_mode.mbmode)); + vpx_memset(&best_mode.bmodes, 0, sizeof(best_mode.bmodes)); /* Setup search priorities */ get_reference_search_order(cpi, ref_frame_map); @@ -1799,15 +1991,15 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int this_ref_frame = ref_frame_map[vp8_ref_frame_order[mode_index]]; // Test best rd so far against threshold for trying this mode. - if (best_rd <= cpi->rd_threshes[mode_index]) + if (best_mode.rd <= cpi->rd_threshes[mode_index]) continue; if (this_ref_frame < 0) continue; // These variables hold are rolling total cost and distortion for this mode - rate2 = 0; - distortion2 = 0; + rd.rate2 = 0; + rd.distortion2 = 0; this_mode = vp8_mode_order[mode_index]; @@ -1907,16 +2099,17 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, int tmp_rd; // Note the rate value returned here includes the cost of coding the BPRED mode : x->mbmode_cost[x->e_mbd.frame_type][BPRED]; - tmp_rd = rd_pick_intra4x4mby_modes(cpi, x, &rate, &rate_y, &distortion, best_yrd); - rate2 += rate; - distortion2 += distortion; + int distortion; + tmp_rd = rd_pick_intra4x4mby_modes(cpi, x, &rate, &rd.rate_y, &distortion, best_mode.yrd); + rd.rate2 += rate; + rd.distortion2 += distortion; - if(tmp_rd < best_yrd) + if(tmp_rd < best_mode.yrd) { - rate2 += uv_intra_rate; - rate_uv = uv_intra_rate_tokenonly; - distortion2 += uv_intra_distortion; - distortion_uv = uv_intra_distortion; + rd.rate2 += uv_intra_rate; + rd.rate_uv = uv_intra_rate_tokenonly; + rd.distortion2 += uv_intra_distortion; + rd.distortion_uv = uv_intra_distortion; } else { @@ -1930,24 +2123,25 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, { int tmp_rd; int this_rd_thresh; + int distortion; this_rd_thresh = (vp8_ref_frame_order[mode_index] == 1) ? cpi->rd_threshes[THR_NEW1] : cpi->rd_threshes[THR_NEW3]; this_rd_thresh = (vp8_ref_frame_order[mode_index] == 2) ? cpi->rd_threshes[THR_NEW2] : this_rd_thresh; tmp_rd = vp8_rd_pick_best_mbsegmentation(cpi, x, &best_ref_mv, - best_yrd, mdcounts, - &rate, &rate_y, &distortion, this_rd_thresh) ; + best_mode.yrd, mdcounts, + &rate, &rd.rate_y, &distortion, this_rd_thresh) ; - rate2 += rate; - distortion2 += distortion; + rd.rate2 += rate; + rd.distortion2 += distortion; // If even the 'Y' rd value of split is higher than best so far then dont bother looking at UV - if (tmp_rd < best_yrd) + if (tmp_rd < best_mode.yrd) { // Now work out UV cost and add it in - rd_inter4x4_uv(cpi, x, &rate_uv, &distortion_uv, cpi->common.full_pixel); - rate2 += rate_uv; - distortion2 += distortion_uv; + rd_inter4x4_uv(cpi, x, &rd.rate_uv, &rd.distortion_uv, cpi->common.full_pixel); + rd.rate2 += rd.rate_uv; + rd.distortion2 += rd.distortion_uv; } else { @@ -1960,18 +2154,21 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, case V_PRED: case H_PRED: case TM_PRED: + { + int distortion; x->e_mbd.mode_info_context->mbmi.ref_frame = INTRA_FRAME; vp8_build_intra_predictors_mby (&x->e_mbd); - macro_block_yrd(x, &rate_y, &distortion) ; - rate2 += rate_y; - distortion2 += distortion; - rate2 += x->mbmode_cost[x->e_mbd.frame_type][x->e_mbd.mode_info_context->mbmi.mode]; - rate2 += uv_intra_rate; - rate_uv = uv_intra_rate_tokenonly; - distortion2 += uv_intra_distortion; - distortion_uv = uv_intra_distortion; - break; + macro_block_yrd(x, &rd.rate_y, &distortion) ; + rd.rate2 += rd.rate_y; + rd.distortion2 += distortion; + rd.rate2 += x->mbmode_cost[x->e_mbd.frame_type][x->e_mbd.mode_info_context->mbmi.mode]; + rd.rate2 += uv_intra_rate; + rd.rate_uv = uv_intra_rate_tokenonly; + rd.distortion2 += uv_intra_distortion; + rd.distortion_uv = uv_intra_distortion; + } + break; case NEWMV: { @@ -2114,7 +2311,7 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, mode_mv[NEWMV].as_int = d->bmi.mv.as_int; // Add the new motion vector cost to our rolling cost variable - rate2 += vp8_mv_bit_cost(&mode_mv[NEWMV], &best_ref_mv, x->mvcost, 96); + rd.rate2 += vp8_mv_bit_cost(&mode_mv[NEWMV], &best_ref_mv, x->mvcost, 96); } case NEARESTMV: @@ -2136,177 +2333,57 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, continue; vp8_set_mbmode_and_mvs(x, this_mode, &mode_mv[this_mode]); - vp8_build_inter16x16_predictors_mby(&x->e_mbd, x->e_mbd.predictor, 16); - - if (cpi->active_map_enabled && x->active_ptr[0] == 0) { - x->skip = 1; - } - else if (x->encode_breakout) - { - unsigned int sse; - unsigned int var; - int threshold = (xd->block[0].dequant[1] - * xd->block[0].dequant[1] >>4); - - if(threshold < x->encode_breakout) - threshold = x->encode_breakout; - - var = vp8_variance16x16 - (*(b->base_src), b->src_stride, - x->e_mbd.predictor, 16, &sse); - - if (sse < threshold) - { - unsigned int q2dc = xd->block[24].dequant[0]; - /* If theres is no codeable 2nd order dc - or a very small uniform pixel change change */ - if ((sse - var < q2dc * q2dc >>4) || - (sse /2 > var && sse-var < 64)) - { - // Check u and v to make sure skip is ok - int sse2= VP8_UVSSE(x); - if (sse2 * 2 < threshold) - { - x->skip = 1; - distortion2 = sse + sse2; - rate2 = 500; - - /* for best_yrd calculation */ - rate_uv = 0; - distortion_uv = sse2; - - disable_skip = 1; - this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); - - break; - } - } - } - } - - - //intermodecost[mode_index] = vp8_cost_mv_ref(this_mode, mdcounts); // Experimental debug code - - // Add in the Mv/mode cost - rate2 += vp8_cost_mv_ref(this_mode, mdcounts); - - // Y cost and distortion - macro_block_yrd(x, &rate_y, &distortion); - rate2 += rate_y; - distortion2 += distortion; - - // UV cost and distortion - rd_inter16x16_uv(cpi, x, &rate_uv, &distortion_uv, cpi->common.full_pixel); - rate2 += rate_uv; - distortion2 += distortion_uv; + this_rd = evaluate_inter_mode_rd(mdcounts, &rd, + &disable_skip, cpi, x); break; default: break; } - // Where skip is allowable add in the default per mb cost for the no skip case. - // where we then decide to skip we have to delete this and replace it with the - // cost of signallying a skip - if (cpi->common.mb_no_coeff_skip) - { - other_cost += vp8_cost_bit(cpi->prob_skip_false, 0); - rate2 += other_cost; - } + this_rd = calculate_final_rd_costs(this_rd, &rd, &other_cost, + disable_skip, uv_intra_tteob, + intra_rd_penalty, cpi, x); - /* Estimate the reference frame signaling cost and add it - * to the rolling cost variable. - */ - rate2 += - x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame]; - - if (!disable_skip) + // Keep record of best intra distortion + if ((x->e_mbd.mode_info_context->mbmi.ref_frame == INTRA_FRAME) && + (this_rd < best_mode.intra_rd) ) { - // Test for the condition where skip block will be activated because there are no non zero coefficients and make any necessary adjustment for rate - if (cpi->common.mb_no_coeff_skip) - { - int tteob; - int has_y2_block = (this_mode!=SPLITMV && this_mode!=B_PRED); - - tteob = 0; - if(has_y2_block) - tteob += x->e_mbd.eobs[24]; - - for (i = 0; i < 16; i++) - tteob += (x->e_mbd.eobs[i] > has_y2_block); - - if (x->e_mbd.mode_info_context->mbmi.ref_frame) - { - for (i = 16; i < 24; i++) - tteob += x->e_mbd.eobs[i]; - } - else - tteob += uv_intra_tteob; - - if (tteob == 0) - { - rate2 -= (rate_y + rate_uv); - //for best_yrd calculation - rate_uv = 0; - - // Back out no skip flag costing and add in skip flag costing - if (cpi->prob_skip_false) - { - int prob_skip_cost; - - prob_skip_cost = vp8_cost_bit(cpi->prob_skip_false, 1); - prob_skip_cost -= vp8_cost_bit(cpi->prob_skip_false, 0); - rate2 += prob_skip_cost; - other_cost += prob_skip_cost; - } - } - } - // Calculate the final RD estimate for this mode - this_rd = RDCOST(x->rdmult, x->rddiv, rate2, distortion2); - if (this_rd < INT_MAX && x->e_mbd.mode_info_context->mbmi.ref_frame - == INTRA_FRAME) - this_rd += intra_rd_penalty; + best_mode.intra_rd = this_rd; + *returnintra = rd.distortion2 ; } - // Keep record of best intra distortion - if ((x->e_mbd.mode_info_context->mbmi.ref_frame == INTRA_FRAME) && - (this_rd < best_intra_rd) ) +#if CONFIG_TEMPORAL_DENOISING + if (cpi->oxcf.noise_sensitivity) { - best_intra_rd = this_rd; - *returnintra = distortion2 ; + // 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; + } } +#endif // Did this mode help.. i.i is it the new best mode - if (this_rd < best_rd || x->skip) + 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; if (this_mode <= B_PRED) { x->e_mbd.mode_info_context->mbmi.uv_mode = uv_intra_mode; /* required for left and above block mv */ x->e_mbd.mode_info_context->mbmi.mv.as_int = 0; } - - other_cost += - x->ref_frame_cost[x->e_mbd.mode_info_context->mbmi.ref_frame]; - - /* Calculate the final y RD estimate for this mode */ - best_yrd = RDCOST(x->rdmult, x->rddiv, (rate2-rate_uv-other_cost), - (distortion2-distortion_uv)); - - *returnrate = rate2; - *returndistortion = distortion2; - best_rd = this_rd; - vpx_memcpy(&best_mbmode, &x->e_mbd.mode_info_context->mbmi, sizeof(MB_MODE_INFO)); - vpx_memcpy(&best_partition, x->partition_info, sizeof(PARTITION_INFO)); - - if ((this_mode == B_PRED) || (this_mode == SPLITMV)) - for (i = 0; i < 16; i++) - { - best_bmodes[i] = x->e_mbd.block[i].bmi; - } + update_best_mode(&best_mode, this_rd, &rd, other_cost, x); // Testing this mode gave rise to an improvement in best error score. Lower threshold a bit for next time @@ -2359,9 +2436,50 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, // Note how often each mode chosen as best cpi->mode_chosen_counts[best_mode_index] ++; +#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) + { + // 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 if (cpi->is_src_frame_alt_ref && - (best_mbmode.mode != ZEROMV || best_mbmode.ref_frame != ALTREF_FRAME)) + (best_mode.mbmode.mode != ZEROMV || best_mode.mbmode.ref_frame != ALTREF_FRAME)) { x->e_mbd.mode_info_context->mbmi.mode = ZEROMV; x->e_mbd.mode_info_context->mbmi.ref_frame = ALTREF_FRAME; @@ -2370,26 +2488,25 @@ void vp8_rd_pick_inter_mode(VP8_COMP *cpi, MACROBLOCK *x, int recon_yoffset, x->e_mbd.mode_info_context->mbmi.mb_skip_coeff = (cpi->common.mb_no_coeff_skip); x->e_mbd.mode_info_context->mbmi.partitioning = 0; - return; } // macroblock modes - vpx_memcpy(&x->e_mbd.mode_info_context->mbmi, &best_mbmode, sizeof(MB_MODE_INFO)); + vpx_memcpy(&x->e_mbd.mode_info_context->mbmi, &best_mode.mbmode, sizeof(MB_MODE_INFO)); - if (best_mbmode.mode == B_PRED) + if (best_mode.mbmode.mode == B_PRED) { for (i = 0; i < 16; i++) - xd->mode_info_context->bmi[i].as_mode = best_bmodes[i].as_mode; + xd->mode_info_context->bmi[i].as_mode = best_mode.bmodes[i].as_mode; } - if (best_mbmode.mode == SPLITMV) + if (best_mode.mbmode.mode == SPLITMV) { for (i = 0; i < 16; i++) - xd->mode_info_context->bmi[i].mv.as_int = best_bmodes[i].mv.as_int; + xd->mode_info_context->bmi[i].mv.as_int = best_mode.bmodes[i].mv.as_int; - vpx_memcpy(x->partition_info, &best_partition, sizeof(PARTITION_INFO)); + vpx_memcpy(x->partition_info, &best_mode.partition, sizeof(PARTITION_INFO)); x->e_mbd.mode_info_context->mbmi.mv.as_int = x->partition_info->bmi[15].mv.as_int; diff --git a/vp8/vp8_cx_iface.c b/vp8/vp8_cx_iface.c index fa78ec31c..683194a1d 100644 --- a/vp8/vp8_cx_iface.c +++ b/vp8/vp8_cx_iface.c @@ -183,13 +183,19 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, RANGE_CHECK_BOOL(vp8_cfg, enable_auto_alt_ref); RANGE_CHECK(vp8_cfg, cpu_used, -16, 16); - +#if CONFIG_TEMPORAL_DENOISING + RANGE_CHECK(vp8_cfg, noise_sensitivity, 0, 1); +#endif #if !(CONFIG_REALTIME_ONLY) RANGE_CHECK(vp8_cfg, encoding_mode, VP8_BEST_QUALITY_ENCODING, VP8_REAL_TIME_ENCODING); +#if !(CONFIG_TEMPORAL_DENOISING) RANGE_CHECK_HI(vp8_cfg, noise_sensitivity, 6); +#endif #else RANGE_CHECK(vp8_cfg, encoding_mode, VP8_REAL_TIME_ENCODING, VP8_REAL_TIME_ENCODING); +#if !(CONFIG_TEMPORAL_DENOISING) RANGE_CHECK(vp8_cfg, noise_sensitivity, 0, 0); +#endif #endif RANGE_CHECK(vp8_cfg, token_partitions, VP8_ONE_TOKENPARTITION, VP8_EIGHT_TOKENPARTITION); diff --git a/vp8/vp8cx.mk b/vp8/vp8cx.mk index b96c9adab..9a82b19e7 100644 --- a/vp8/vp8cx.mk +++ b/vp8/vp8cx.mk @@ -47,6 +47,8 @@ VP8_CX_SRCS-yes += encoder/firstpass.c VP8_CX_SRCS-yes += encoder/block.h VP8_CX_SRCS-yes += encoder/boolhuff.h VP8_CX_SRCS-yes += encoder/bitstream.h +VP8_CX_SRCS-$(CONFIG_TEMPORAL_DENOISING) += encoder/denoising.h +VP8_CX_SRCS-$(CONFIG_TEMPORAL_DENOISING) += encoder/denoising.c VP8_CX_SRCS-yes += encoder/encodeintra.h VP8_CX_SRCS-yes += encoder/encodemb.h VP8_CX_SRCS-yes += encoder/encodemv.h -- 2.40.0