diff options
-rw-r--r-- | vp9/encoder/vp9_denoiser.c | 134 | ||||
-rw-r--r-- | vp9/encoder/vp9_denoiser.h | 14 | ||||
-rw-r--r-- | vp9/encoder/vp9_encoder.c | 24 |
3 files changed, 109 insertions, 63 deletions
diff --git a/vp9/encoder/vp9_denoiser.c b/vp9/encoder/vp9_denoiser.c index 50b495e2f..3069f10e6 100644 --- a/vp9/encoder/vp9_denoiser.c +++ b/vp9/encoder/vp9_denoiser.c @@ -190,11 +190,12 @@ static VP9_DENOISER_DECISION perform_motion_compensation( VP9_COMMON *const cm, VP9_DENOISER *denoiser, MACROBLOCK *mb, BLOCK_SIZE bs, int increase_denoising, int mi_row, int mi_col, PICK_MODE_CONTEXT *ctx, int motion_magnitude, int is_skin, int *zeromv_filter, int consec_zeromv, - int num_spatial_layers, int width) { + int num_spatial_layers, int width, int lst_fb_idx, int gld_fb_idx, + int use_svc) { const int sse_diff = (ctx->newmv_sse == UINT_MAX) ? 0 : ((int)ctx->zeromv_sse - (int)ctx->newmv_sse); - MV_REFERENCE_FRAME frame; + int frame; MACROBLOCKD *filter_mbd = &mb->e_mbd; MODE_INFO *mi = filter_mbd->mi[0]; MODE_INFO saved_mi; @@ -202,8 +203,10 @@ static VP9_DENOISER_DECISION perform_motion_compensation( struct buf_2d saved_dst[MAX_MB_PLANE]; struct buf_2d saved_pre[MAX_MB_PLANE]; RefBuffer *saved_block_refs[2]; + MV_REFERENCE_FRAME saved_frame; frame = ctx->best_reference_frame; + saved_mi = *mi; if (is_skin && (motion_magnitude > 0 || consec_zeromv < 4)) return COPY_BLOCK; @@ -246,6 +249,15 @@ static VP9_DENOISER_DECISION perform_motion_compensation( } } + saved_frame = frame; + // When using SVC, we need to map REF_FRAME to the frame buffer index. + if (use_svc) { + if (frame == LAST_FRAME) + frame = lst_fb_idx + 1; + else if (frame == GOLDEN_FRAME) + frame = gld_fb_idx + 1; + } + if (ctx->newmv_sse > sse_thresh(bs, increase_denoising)) { // Restore everything to its original state *mi = saved_mi; @@ -292,7 +304,7 @@ static VP9_DENOISER_DECISION perform_motion_compensation( denoiser->mc_running_avg_y.uv_stride, mi_row, mi_col); filter_mbd->plane[2].dst.stride = denoiser->mc_running_avg_y.uv_stride; - set_ref_ptrs(cm, filter_mbd, frame, NONE); + set_ref_ptrs(cm, filter_mbd, saved_frame, NONE); vp9_build_inter_predictors_sby(filter_mbd, mi_row, mi_col, bs); // Restore everything to its original state @@ -370,7 +382,8 @@ void vp9_denoiser_denoise(VP9_COMP *cpi, MACROBLOCK *mb, int mi_row, int mi_col, decision = perform_motion_compensation( &cpi->common, denoiser, mb, bs, increase_denoising, mi_row, mi_col, ctx, motion_magnitude, is_skin, &zeromv_filter, consec_zeromv, - cpi->svc.number_spatial_layers, cpi->Source->y_width); + cpi->svc.number_spatial_layers, cpi->Source->y_width, cpi->lst_fb_idx, + cpi->gld_fb_idx, cpi->use_svc); if (decision == FILTER_BLOCK) { decision = vp9_denoiser_filter(src.buf, src.stride, mc_avg_start, @@ -417,23 +430,11 @@ static void swap_frame_buffer(YV12_BUFFER_CONFIG *const dest, src->y_buffer = tmp_buf; } -void vp9_denoise_init_svc(VP9_COMP *cpi) { - // For fixed pattern SVC, on base temporal layer. Note we only denoise - // higher spatial layer for SVC. - if (cpi->svc.temporal_layering_mode != VP9E_TEMPORAL_LAYERING_MODE_BYPASS && - cpi->svc.spatial_layer_id == cpi->svc.number_spatial_layers - 1 && - cpi->svc.temporal_layer_id == 0) { - VP9_DENOISER *denoiser = &cpi->denoiser; - copy_frame(&denoiser->running_avg_y[LAST_FRAME], - &denoiser->running_avg_y[GOLDEN_FRAME]); - } -} - void vp9_denoiser_update_frame_info( VP9_DENOISER *denoiser, YV12_BUFFER_CONFIG src, FRAME_TYPE frame_type, int refresh_alt_ref_frame, int refresh_golden_frame, int refresh_last_frame, - int resized, int svc_base_is_key, int svc_fixed_pattern, - int temporal_layer_id) { + int alt_fb_idx, int gld_fb_idx, int lst_fb_idx, int resized, + int svc_base_is_key) { // Copy source into denoised reference buffers on KEY_FRAME or // if the just encoded frame was resized. For SVC, copy source if the base // spatial layer was key frame. @@ -441,48 +442,42 @@ void vp9_denoiser_update_frame_info( svc_base_is_key) { int i; // Start at 1 so as not to overwrite the INTRA_FRAME - for (i = 1; i < denoiser->num_ref_frames; ++i) - copy_frame(&denoiser->running_avg_y[i], &src); + for (i = 1; i < denoiser->num_ref_frames; ++i) { + if (denoiser->running_avg_y[i].buffer_alloc != NULL) + copy_frame(&denoiser->running_avg_y[i], &src); + } denoiser->reset = 0; return; } // If more than one refresh occurs, must copy frame buffer. - if (refresh_golden_frame + refresh_last_frame + refresh_alt_ref_frame > 1) { + if ((refresh_alt_ref_frame + refresh_golden_frame + refresh_last_frame) > 1) { + if (refresh_alt_ref_frame) { + copy_frame(&denoiser->running_avg_y[alt_fb_idx + 1], + &denoiser->running_avg_y[INTRA_FRAME]); + } if (refresh_golden_frame) { - copy_frame(&denoiser->running_avg_y[GOLDEN_FRAME], + copy_frame(&denoiser->running_avg_y[gld_fb_idx + 1], &denoiser->running_avg_y[INTRA_FRAME]); } - // For fixed pattern SVC: update denoised last_frame if alt_ref is - // refreshed, only for non-zero temporal layer. - if (refresh_last_frame || - (refresh_alt_ref_frame && svc_fixed_pattern && temporal_layer_id > 0)) { - copy_frame(&denoiser->running_avg_y[LAST_FRAME], + if (refresh_last_frame) { + copy_frame(&denoiser->running_avg_y[lst_fb_idx + 1], &denoiser->running_avg_y[INTRA_FRAME]); } } else { + if (refresh_alt_ref_frame) { + swap_frame_buffer(&denoiser->running_avg_y[alt_fb_idx + 1], + &denoiser->running_avg_y[INTRA_FRAME]); + } if (refresh_golden_frame) { - swap_frame_buffer(&denoiser->running_avg_y[GOLDEN_FRAME], + swap_frame_buffer(&denoiser->running_avg_y[gld_fb_idx + 1], &denoiser->running_avg_y[INTRA_FRAME]); } - // For fixed pattern SVC: update denoised last_frame if alt_ref is - // refreshed, only for non-zero temporal layer. - if (refresh_last_frame || - (refresh_alt_ref_frame && svc_fixed_pattern && temporal_layer_id > 0)) { - swap_frame_buffer(&denoiser->running_avg_y[LAST_FRAME], + if (refresh_last_frame) { + swap_frame_buffer(&denoiser->running_avg_y[lst_fb_idx + 1], &denoiser->running_avg_y[INTRA_FRAME]); } } - // For fixed pattern SVC we need to keep track of denoised last_frame for base - // temporal layer (since alt_ref refresh may update denoised last_frame on - // the upper/middle temporal layers).We do this by copying the current - // denoised last into the denoised golden_frame, for temporal_layer_id = 0. - // For the fixed pattern SVC golden is always spatial reference and is never - // used for denoising, so we can use it to keep track of denoised last_frame. - if (svc_fixed_pattern && temporal_layer_id == 0) { - copy_frame(&denoiser->running_avg_y[GOLDEN_FRAME], - &denoiser->running_avg_y[LAST_FRAME]); - } } void vp9_denoiser_reset_frame_stats(PICK_MODE_CONTEXT *ctx) { @@ -509,21 +504,62 @@ void vp9_denoiser_update_frame_stats(MODE_INFO *mi, unsigned int sse, } } +static int vp9_denoiser_realloc_svc_helper(VP9_COMMON *cm, + VP9_DENOISER *denoiser, int fb_idx) { + int fail = 0; + if (denoiser->running_avg_y[fb_idx].buffer_alloc == NULL) { + fail = + vpx_alloc_frame_buffer(&denoiser->running_avg_y[fb_idx], cm->width, + cm->height, cm->subsampling_x, cm->subsampling_y, +#if CONFIG_VP9_HIGHBITDEPTH + cm->use_highbitdepth, +#endif + VP9_ENC_BORDER_IN_PIXELS, 0); + if (fail) { + vp9_denoiser_free(denoiser); + return 1; + } + } + return 0; +} + +int vp9_denoiser_realloc_svc(VP9_COMMON *cm, VP9_DENOISER *denoiser, + int refresh_alt, int refresh_gld, int refresh_lst, + int alt_fb_idx, int gld_fb_idx, int lst_fb_idx) { + int fail = 0; + if (refresh_alt) { + // Increase the frame buffer index by 1 to map it to the buffer index in the + // denoiser. + fail = vp9_denoiser_realloc_svc_helper(cm, denoiser, alt_fb_idx + 1); + if (fail) return 1; + } + if (refresh_gld) { + fail = vp9_denoiser_realloc_svc_helper(cm, denoiser, gld_fb_idx + 1); + if (fail) return 1; + } + if (refresh_lst) { + fail = vp9_denoiser_realloc_svc_helper(cm, denoiser, lst_fb_idx + 1); + if (fail) return 1; + } + return 0; +} + int vp9_denoiser_alloc(VP9_COMMON *cm, int use_svc, VP9_DENOISER *denoiser, int width, int height, int ssx, int ssy, #if CONFIG_VP9_HIGHBITDEPTH int use_highbitdepth, #endif int border) { - int i, fail; + int i, fail, init_num_ref_frames; const int legacy_byte_alignment = 0; assert(denoiser != NULL); - denoiser->num_ref_frames = use_svc ? MAX_REF_FRAMES : NONSVC_REF_FRAMES; + denoiser->num_ref_frames = use_svc ? SVC_REF_FRAMES : NONSVC_REF_FRAMES; + init_num_ref_frames = use_svc ? MAX_REF_FRAMES : NONSVC_REF_FRAMES; CHECK_MEM_ERROR( cm, denoiser->running_avg_y, vpx_calloc(denoiser->num_ref_frames, sizeof(denoiser->running_avg_y[0]))); - for (i = 0; i < denoiser->num_ref_frames; ++i) { + for (i = 0; i < init_num_ref_frames; ++i) { fail = vpx_alloc_frame_buffer(&denoiser->running_avg_y[i], width, height, ssx, ssy, #if CONFIG_VP9_HIGHBITDEPTH @@ -594,7 +630,8 @@ void vp9_denoiser_set_noise_level(VP9_DENOISER *denoiser, int noise_level) { denoiser->prev_denoising_level = denoiser->denoising_level; } -// Scale/increase the partition threshold for denoiser speed-up. +// Scale/increase the partition threshold +// for denoiser speed-up. int64_t vp9_scale_part_thresh(int64_t threshold, VP9_DENOISER_LEVEL noise_level, int content_state, int temporal_layer_id) { if ((content_state == kLowSadLowSumdiff) || @@ -609,7 +646,8 @@ int64_t vp9_scale_part_thresh(int64_t threshold, VP9_DENOISER_LEVEL noise_level, } } -// Scale/increase the ac skip threshold for denoiser speed-up. +// Scale/increase the ac skip threshold for +// denoiser speed-up. int64_t vp9_scale_acskip_thresh(int64_t threshold, VP9_DENOISER_LEVEL noise_level, int abs_sumdiff, int temporal_layer_id) { diff --git a/vp9/encoder/vp9_denoiser.h b/vp9/encoder/vp9_denoiser.h index f23e6faea..ee0752729 100644 --- a/vp9/encoder/vp9_denoiser.h +++ b/vp9/encoder/vp9_denoiser.h @@ -25,6 +25,10 @@ extern "C" { // need to allocate for it, and hence we need MAX_REF_FRAME - 1 #define NONSVC_REF_FRAMES MAX_REF_FRAMES - 1 +// Number of frame buffers when SVC is used. [0] for current denoised buffer and +// [1..8] for REF_FRAMES +#define SVC_REF_FRAMES 9 + typedef enum vp9_denoiser_decision { COPY_BLOCK, FILTER_BLOCK, @@ -63,13 +67,11 @@ typedef struct { struct VP9_COMP; -void vp9_denoise_init_svc(struct VP9_COMP *cpi); - void vp9_denoiser_update_frame_info( VP9_DENOISER *denoiser, YV12_BUFFER_CONFIG src, FRAME_TYPE frame_type, int refresh_alt_ref_frame, int refresh_golden_frame, int refresh_last_frame, - int resized, int svc_base_is_key, int svc_fixed_pattern, - int temporal_layer_id); + int alt_fb_idx, int gld_fb_idx, int lst_fb_idx, int resized, + int svc_base_is_key); void vp9_denoiser_denoise(struct VP9_COMP *cpi, MACROBLOCK *mb, int mi_row, int mi_col, BLOCK_SIZE bs, PICK_MODE_CONTEXT *ctx, @@ -81,6 +83,10 @@ void vp9_denoiser_update_frame_stats(MODE_INFO *mi, unsigned int sse, PREDICTION_MODE mode, PICK_MODE_CONTEXT *ctx); +int vp9_denoiser_realloc_svc(VP9_COMMON *cm, VP9_DENOISER *denoiser, + int refresh_alt, int refresh_gld, int refresh_lst, + int alt_fb_idx, int gld_fb_idx, int lst_fb_idx); + int vp9_denoiser_alloc(VP9_COMMON *cm, int use_svc, VP9_DENOISER *denoiser, int width, int height, int ssx, int ssy, #if CONFIG_VP9_HIGHBITDEPTH diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index c6e34117e..034b95ac9 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -2833,21 +2833,29 @@ void vp9_update_reference_frames(VP9_COMP *cpi) { if (cpi->oxcf.noise_sensitivity > 0 && denoise_svc(cpi) && cpi->denoiser.denoising_level > kDenLowLow) { int svc_base_is_key = 0; - int svc_fixed_pattern = 0; if (cpi->use_svc) { + int realloc_fail = 0; int layer = LAYER_IDS_TO_IDX(cpi->svc.spatial_layer_id, cpi->svc.temporal_layer_id, cpi->svc.number_temporal_layers); LAYER_CONTEXT *lc = &cpi->svc.layer_context[layer]; svc_base_is_key = lc->is_key_frame; - svc_fixed_pattern = (cpi->svc.temporal_layering_mode != - VP9E_TEMPORAL_LAYERING_MODE_BYPASS); + + // Check if we need to allocate extra buffers in the denoiser for + // refreshed frames. + realloc_fail = vp9_denoiser_realloc_svc( + cm, &cpi->denoiser, cpi->refresh_alt_ref_frame, + cpi->refresh_golden_frame, cpi->refresh_last_frame, cpi->alt_fb_idx, + cpi->gld_fb_idx, cpi->lst_fb_idx); + if (realloc_fail) + vpx_internal_error(&cm->error, VPX_CODEC_MEM_ERROR, + "Failed to re-allocate denoiser for SVC"); } vp9_denoiser_update_frame_info( &cpi->denoiser, *cpi->Source, cpi->common.frame_type, cpi->refresh_alt_ref_frame, cpi->refresh_golden_frame, - cpi->refresh_last_frame, cpi->resize_pending, svc_base_is_key, - svc_fixed_pattern, cpi->svc.temporal_layer_id); + cpi->refresh_last_frame, cpi->alt_fb_idx, cpi->gld_fb_idx, + cpi->lst_fb_idx, cpi->resize_pending, svc_base_is_key); } #endif if (is_one_pass_cbr_svc(cpi)) { @@ -3481,12 +3489,6 @@ static void encode_without_recode_loop(VP9_COMP *cpi, size_t *size, vp9_update_noise_estimate(cpi); -#if CONFIG_VP9_TEMPORAL_DENOISING - if (cpi->oxcf.noise_sensitivity > 0 && cpi->use_svc && - cpi->denoiser.denoising_level > kDenLowLow) - vp9_denoise_init_svc(cpi); -#endif - // Scene detection is always used for VBR mode or screen-content case. // For other cases (e.g., CBR mode) use it for 5 <= speed < 8 for now // (need to check encoding time cost for doing this for speed 8). |