From: Marco Date: Tue, 11 Jul 2017 00:38:03 +0000 (-0700) Subject: vp9: Fix to SVC and denoising for fixed pattern case. X-Git-Tag: v1.7.0~313^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3818a3723b630252973ca85d9fc6b5dd7f8437dd;p=libvpx vp9: Fix to SVC and denoising for fixed pattern case. For fixed pattern SVC: keep track of denoised last_frame buffer for base temporal layer, and if alt_ref is updated on middle/upper temporal layers, force an update to denoised last_frame buffer. This allows for improved denoising on top temporal layers. Change-Id: Icbd08566027d4d2eabc024d3b7a0d959d2f8c18b --- diff --git a/vp9/encoder/vp9_denoiser.c b/vp9/encoder/vp9_denoiser.c index e8356155f..a4da44408 100644 --- a/vp9/encoder/vp9_denoiser.c +++ b/vp9/encoder/vp9_denoiser.c @@ -420,12 +420,23 @@ static void swap_frame_buffer(YV12_BUFFER_CONFIG *const dest, src->y_buffer = tmp_buf; } -void vp9_denoiser_update_frame_info(VP9_DENOISER *denoiser, - YV12_BUFFER_CONFIG src, - FRAME_TYPE frame_type, - int refresh_golden_frame, - int refresh_last_frame, int resized, - int svc_base_is_key) { +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) { // 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. @@ -440,12 +451,15 @@ void vp9_denoiser_update_frame_info(VP9_DENOISER *denoiser, } // If more than one refresh occurs, must copy frame buffer. - if (refresh_golden_frame + refresh_last_frame > 1) { + if (refresh_golden_frame + refresh_last_frame + refresh_alt_ref_frame > 1) { if (refresh_golden_frame) { copy_frame(&denoiser->running_avg_y[GOLDEN_FRAME], &denoiser->running_avg_y[INTRA_FRAME]); } - if (refresh_last_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], &denoiser->running_avg_y[INTRA_FRAME]); } @@ -454,11 +468,24 @@ void vp9_denoiser_update_frame_info(VP9_DENOISER *denoiser, swap_frame_buffer(&denoiser->running_avg_y[GOLDEN_FRAME], &denoiser->running_avg_y[INTRA_FRAME]); } - if (refresh_last_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], &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) { diff --git a/vp9/encoder/vp9_denoiser.h b/vp9/encoder/vp9_denoiser.h index 727ce8538..7ed20856e 100644 --- a/vp9/encoder/vp9_denoiser.h +++ b/vp9/encoder/vp9_denoiser.h @@ -62,12 +62,13 @@ typedef struct { struct VP9_COMP; -void vp9_denoiser_update_frame_info(VP9_DENOISER *denoiser, - YV12_BUFFER_CONFIG src, - FRAME_TYPE frame_type, - int refresh_golden_frame, - int refresh_last_frame, int resized, - int svc_base_is_key); +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); void vp9_denoiser_denoise(struct VP9_COMP *cpi, MACROBLOCK *mb, int mi_row, int mi_col, BLOCK_SIZE bs, PICK_MODE_CONTEXT *ctx, diff --git a/vp9/encoder/vp9_encoder.c b/vp9/encoder/vp9_encoder.c index b7addd202..fc6d75590 100644 --- a/vp9/encoder/vp9_encoder.c +++ b/vp9/encoder/vp9_encoder.c @@ -2806,17 +2806,21 @@ 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 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); } vp9_denoiser_update_frame_info( &cpi->denoiser, *cpi->Source, cpi->common.frame_type, - cpi->refresh_golden_frame, cpi->refresh_last_frame, cpi->resize_pending, - svc_base_is_key); + 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); } #endif if (is_one_pass_cbr_svc(cpi)) { @@ -3448,6 +3452,12 @@ 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).