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,aomedia:2974

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

Change-Id: I85a62fec6759ee70b23f5a24999a7eb6582d8b90
(cherry picked from commit 08eb1d45f2f8c5dbeb2b77ba211c33c32b0fbe53)
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 822df7f..4792512 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,
@@ -402,6 +403,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 c6c5c52..b20f568 100644
--- a/av1/arg_defs.c
+++ b/av1/arg_defs.c
@@ -476,6 +476,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 ac0d636..26c9277 100644
--- a/av1/arg_defs.h
+++ b/av1/arg_defs.h
@@ -182,6 +182,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 ad7de20..e03a8d5e 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -135,6 +135,7 @@
 #if CONFIG_DENOISE
   float noise_level;
   int noise_block_size;
+  int enable_dnl_denoising;
 #endif
 
   unsigned int chroma_subsampling_x;
@@ -258,6 +259,7 @@
 #if CONFIG_DENOISE
   0,   // noise_level
   32,  // noise_block_size
+  1,   // enable_dnl_denoising
 #endif
   0,  // chroma_subsampling_x
   0,  // chroma_subsampling_y
@@ -960,6 +962,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
@@ -1835,6 +1838,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;
@@ -3121,6 +3137,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,
@@ -3283,6 +3302,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 3b415d7..8f8733e 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 7a65a9e..2bc1626 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -877,6 +877,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