shithub: libvpx

Download patch

ref: 3818a3723b630252973ca85d9fc6b5dd7f8437dd
parent: 4b78c6e6f70809cac27536b181ac9ff1f8759928
author: Marco <marpan@google.com>
date: Mon Jul 10 13:38:03 EDT 2017

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

--- a/vp9/encoder/vp9_denoiser.c
+++ b/vp9/encoder/vp9_denoiser.c
@@ -420,12 +420,23 @@
   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 @@
   }
 
   // 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,10 +468,23 @@
       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]);
   }
 }
 
--- a/vp9/encoder/vp9_denoiser.h
+++ b/vp9/encoder/vp9_denoiser.h
@@ -62,12 +62,13 @@
 
 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,
--- a/vp9/encoder/vp9_encoder.c
+++ b/vp9/encoder/vp9_encoder.c
@@ -2806,6 +2806,7 @@
   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,
@@ -2812,11 +2813,14 @@
                                    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)) {
@@ -3447,6 +3451,12 @@
   }
 
   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