Add option to skip applying denoising with denoise-noise-level

Adds --enable-dnl-denoising. This option only takes effect when
--denoise-noise-level > 0. When --enable-dnl-denoising is 1 (default),
the encoder denoises the frame for noise modeling and encodes the
denoise frame with film grain synthesis. When 0, the encoder denoises
the frame for noise modeling, but encodes the original (noisy) frame
with film grain synthesis.

BUG=aomedia:2817

Co-authored-by: Zak <zakdjeb@gmail.com>

Change-Id: I85a62fec6759ee70b23f5a24999a7eb6582d8b90
diff --git a/aom/aomcx.h b/aom/aomcx.h
index 15ef820..bf3212a 100644
--- a/aom/aomcx.h
+++ b/aom/aomcx.h
@@ -1309,6 +1309,13 @@
   /*!\brief Control to get baseline gf interval
    */
   AV1E_GET_BASELINE_GF_INTERVAL = 158,
+
+  /*\brief Control to set encoding the denoised frame from denoise-noise-level
+   *
+   * - 0 = disabled/encode the original frame
+   * - 1 = enabled/encode the denoised frame (default)
+   */
+  AV1E_SET_ENABLE_DNL_DENOISING = 159,
 };
 
 /*!\brief aom 1-D scaling mode
@@ -1832,6 +1839,9 @@
 AOM_CTRL_USE_TYPE(AV1E_SET_VBR_CORPUS_COMPLEXITY_LAP, unsigned int)
 #define AOM_CTRL_AV1E_SET_VBR_CORPUS_COMPLEXITY_LAP
 
+AOM_CTRL_USE_TYPE(AV1E_SET_ENABLE_DNL_DENOISING, int)
+#define AOM_CTRL_AV1E_SET_ENABLE_DNL_DENOISING
+
 /*!\endcond */
 /*! @} - end defgroup aom_encoder */
 #ifdef __cplusplus
diff --git a/aom_dsp/noise_model.c b/aom_dsp/noise_model.c
index 1ad3a66..f56fdd5 100644
--- a/aom_dsp/noise_model.c
+++ b/aom_dsp/noise_model.c
@@ -1591,7 +1591,7 @@
 
 int aom_denoise_and_model_run(struct aom_denoise_and_model_t *ctx,
                               YV12_BUFFER_CONFIG *sd,
-                              aom_film_grain_t *film_grain) {
+                              aom_film_grain_t *film_grain, int apply_denoise) {
   const int block_size = ctx->block_size;
   const int use_highbd = (sd->flags & YV12_FLAG_HIGHBITDEPTH) != 0;
   uint8_t *raw_data[3] = {
@@ -1643,12 +1643,14 @@
     if (!film_grain->random_seed) {
       film_grain->random_seed = 7391;
     }
-    memcpy(raw_data[0], ctx->denoised[0],
-           (strides[0] * sd->y_height) << use_highbd);
-    memcpy(raw_data[1], ctx->denoised[1],
-           (strides[1] * sd->uv_height) << use_highbd);
-    memcpy(raw_data[2], ctx->denoised[2],
-           (strides[2] * sd->uv_height) << use_highbd);
+    if (apply_denoise) {
+      memcpy(raw_data[0], ctx->denoised[0],
+             (strides[0] * sd->y_height) << use_highbd);
+      memcpy(raw_data[1], ctx->denoised[1],
+             (strides[1] * sd->uv_height) << use_highbd);
+      memcpy(raw_data[2], ctx->denoised[2],
+             (strides[2] * sd->uv_height) << use_highbd);
+    }
   }
   return 1;
 }
diff --git a/aom_dsp/noise_model.h b/aom_dsp/noise_model.h
index 5e7de9b..bb2b419 100644
--- a/aom_dsp/noise_model.h
+++ b/aom_dsp/noise_model.h
@@ -292,14 +292,18 @@
  * parameter will be true when the input buffer was successfully denoised and
  * grain was modelled. Returns false on error.
  *
- * \param[in]      ctx   Struct allocated with aom_denoise_and_model_alloc
- *                       that holds some buffers for denoising and the current
- *                       noise estimate.
- * \param[in/out]   buf  The raw input buffer to be denoised.
- * \param[out]    grain  Output film grain parameters
+ * \param[in]      ctx          Struct allocated with
+ *                              aom_denoise_and_model_alloc that holds some
+ *                              buffers for denoising and the current noise
+ *                              estimate.
+ * \param[in/out]   buf         The raw input buffer to be denoised.
+ * \param[out]    grain         Output film grain parameters
+ * \param[out]    apply_denoise Whether or not to apply the denoising to the
+ *                              frame that will be encoded
  */
 int aom_denoise_and_model_run(struct aom_denoise_and_model_t *ctx,
-                              YV12_BUFFER_CONFIG *buf, aom_film_grain_t *grain);
+                              YV12_BUFFER_CONFIG *buf, aom_film_grain_t *grain,
+                              int apply_denoise);
 
 /*!\brief Allocates a context that can be used for denoising and noise modeling.
  *
diff --git a/apps/aomenc.c b/apps/aomenc.c
index 41101d1..4ea03ae 100644
--- a/apps/aomenc.c
+++ b/apps/aomenc.c
@@ -212,6 +212,7 @@
 #if CONFIG_DENOISE
                                         AV1E_SET_DENOISE_NOISE_LEVEL,
                                         AV1E_SET_DENOISE_BLOCK_SIZE,
+                                        AV1E_SET_ENABLE_DNL_DENOISING,
 #endif  // CONFIG_DENOISE
                                         AV1E_SET_MAX_REFERENCE_FRAMES,
                                         AV1E_SET_REDUCED_REFERENCE_SET,
@@ -403,6 +404,7 @@
 #if CONFIG_DENOISE
   &g_av1_codec_arg_defs.denoise_noise_level,
   &g_av1_codec_arg_defs.denoise_block_size,
+  &g_av1_codec_arg_defs.enable_dnl_denoising,
 #endif  // CONFIG_DENOISE
   &g_av1_codec_arg_defs.max_reference_frames,
   &g_av1_codec_arg_defs.reduced_reference_set,
diff --git a/av1/arg_defs.c b/av1/arg_defs.c
index 7b90197..dcf9afb 100644
--- a/av1/arg_defs.c
+++ b/av1/arg_defs.c
@@ -478,6 +478,10 @@
               "Amount of noise (from 0 = don't denoise, to 50)"),
   .denoise_block_size = ARG_DEF(NULL, "denoise-block-size", 1,
                                 "Denoise block size (default = 32)"),
+  .enable_dnl_denoising = ARG_DEF(NULL, "enable-dnl-denoising", 1,
+                                  "Apply denoising to the frame "
+                                  "being encoded when denoise-noise-level is "
+                                  "enabled (0: false, 1: true (default))"),
 #endif
   .enable_ref_frame_mvs =
       ARG_DEF(NULL, "enable-ref-frame-mvs", 1,
diff --git a/av1/arg_defs.h b/av1/arg_defs.h
index 4d74e3d..568fc39 100644
--- a/av1/arg_defs.h
+++ b/av1/arg_defs.h
@@ -183,6 +183,7 @@
 #if CONFIG_DENOISE
   arg_def_t denoise_noise_level;
   arg_def_t denoise_block_size;
+  arg_def_t enable_dnl_denoising;
 #endif
   arg_def_t enable_ref_frame_mvs;
   arg_def_t frame_parallel_decoding;
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index 4066fc3..9c098b1 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -133,6 +133,7 @@
 #if CONFIG_DENOISE
   float noise_level;
   int noise_block_size;
+  int enable_dnl_denoising;
 #endif
 
   unsigned int chroma_subsampling_x;
@@ -256,6 +257,7 @@
 #if CONFIG_DENOISE
   0,   // noise_level
   32,  // noise_block_size
+  1,   // enable_dnl_denoising
 #endif
   0,  // chroma_subsampling_x
   0,  // chroma_subsampling_y
@@ -965,6 +967,7 @@
 #if CONFIG_DENOISE
   oxcf->noise_level = extra_cfg->noise_level;
   oxcf->noise_block_size = extra_cfg->noise_block_size;
+  oxcf->enable_dnl_denoising = extra_cfg->enable_dnl_denoising;
 #endif
 
 #if CONFIG_AV1_TEMPORAL_DENOISING
@@ -1840,6 +1843,19 @@
 #endif
 }
 
+static aom_codec_err_t ctrl_set_enable_dnl_denoising(aom_codec_alg_priv_t *ctx,
+                                                     va_list args) {
+#if !CONFIG_DENOISE
+  (void)ctx;
+  (void)args;
+  return AOM_CODEC_INCAPABLE;
+#else
+  struct av1_extracfg extra_cfg = ctx->extra_cfg;
+  extra_cfg.enable_dnl_denoising = CAST(AV1E_SET_ENABLE_DNL_DENOISING, args);
+  return update_extra_cfg(ctx, &extra_cfg);
+#endif
+}
+
 static aom_codec_err_t ctrl_set_deltaq_mode(aom_codec_alg_priv_t *ctx,
                                             va_list args) {
   struct av1_extracfg extra_cfg = ctx->extra_cfg;
@@ -3105,6 +3121,9 @@
   } else if (arg_match_helper(&arg, &g_av1_codec_arg_defs.denoise_block_size,
                               argv, err_string)) {
     extra_cfg.noise_block_size = arg_parse_uint_helper(&arg, err_string);
+  } else if (arg_match_helper(&arg, &g_av1_codec_arg_defs.enable_dnl_denoising,
+                              argv, err_string)) {
+    extra_cfg.enable_dnl_denoising = arg_parse_uint_helper(&arg, err_string);
   }
 #endif
   else if (arg_match_helper(&arg, &g_av1_codec_arg_defs.target_seq_level_idx,
@@ -3267,6 +3286,7 @@
   { AV1E_SET_FILM_GRAIN_TABLE, ctrl_set_film_grain_table },
   { AV1E_SET_DENOISE_NOISE_LEVEL, ctrl_set_denoise_noise_level },
   { AV1E_SET_DENOISE_BLOCK_SIZE, ctrl_set_denoise_block_size },
+  { AV1E_SET_ENABLE_DNL_DENOISING, ctrl_set_enable_dnl_denoising },
   { AV1E_ENABLE_MOTION_VECTOR_UNIT_TEST, ctrl_enable_motion_vector_unit_test },
   { AV1E_ENABLE_EXT_TILE_DEBUG, ctrl_enable_ext_tile_debug },
   { AV1E_SET_TARGET_SEQ_LEVEL_IDX, ctrl_set_target_seq_level_idx },
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index bbabffe..27d0760 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -3393,7 +3393,8 @@
     memset(cpi->film_grain_table, 0, sizeof(*cpi->film_grain_table));
   }
   if (aom_denoise_and_model_run(cpi->denoise_and_model, sd,
-                                &cm->film_grain_params)) {
+                                &cm->film_grain_params,
+                                cpi->oxcf.enable_dnl_denoising)) {
     if (cm->film_grain_params.apply_grain) {
       aom_film_grain_table_append(cpi->film_grain_table, time_stamp, end_time,
                                   &cm->film_grain_params);
@@ -3434,7 +3435,11 @@
 #endif
 
 #if CONFIG_DENOISE
-  if (cpi->oxcf.noise_level > 0)
+  // even if denoise_noise_level is > 0, we don't need need to denoise on pass
+  // 1 of 2 if enable_dnl_denoising is disabled since the 2nd pass will be
+  // encoding the original (non-denoised) frame
+  if (cpi->oxcf.noise_level > 0 &&
+      !(cpi->oxcf.pass == AOM_RC_FIRST_PASS && !cpi->oxcf.enable_dnl_denoising))
     if (apply_denoise_2d(cpi, sd, cpi->oxcf.noise_block_size,
                          cpi->oxcf.noise_level, time_stamp, end_time) < 0)
       res = -1;
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 4e9ec00..677ef75 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -879,6 +879,8 @@
   float noise_level;
   // Indicates the the denoisers block size.
   int noise_block_size;
+  // Indicates whether to apply denoising to the frame to be encoded
+  int enable_dnl_denoising;
 #endif
 
 #if CONFIG_AV1_TEMPORAL_DENOISING