Extend encoder control for refreshing buffer slots.

Extend the existing control to allow for refreshing any of the
allowed buffer slots (the current AOM_EFLAGS_UPD_# flags only
allow for updating 3 buffers (last/golden/altref)). So this
change removes the need to set the AOM_EFLAG_NO_UPD_# encoder flags,
and allows user to also update any reference.

This allows for greater flexibility for RTC applications to
configure SVC/layered structures.

Change-Id: I38fc957943d968636df9434071da82db335a2c30
diff --git a/aom/aomcx.h b/aom/aomcx.h
index 59dbe02..91f0eb3 100644
--- a/aom/aomcx.h
+++ b/aom/aomcx.h
@@ -18,6 +18,7 @@
  */
 #include "aom/aom.h"
 #include "aom/aom_encoder.h"
+#include "av1/common/enums.h"
 
 /*!\file
  * \brief Provides definitions for using AOM or AV1 encoder algorithm within the
@@ -1127,9 +1128,10 @@
    */
   AV1E_SET_SVC_PARAMS = 151,
 
-  /*!\brief Codec control function to set SVC reference frame map.
+  /*!\brief Codec control function to set reference frame config:
+   * the ref_idx and the refresh flags for each buffer slot.
    */
-  AV1E_SET_SVC_REF_IDX = 152
+  AV1E_SET_SVC_REF_FRAME_CONFIG = 152
 };
 
 /*!\brief aom 1-D scaling mode
@@ -1243,10 +1245,14 @@
   int framerate_factor[AOM_MAX_TS_LAYERS];
 } aom_svc_params_t;
 
-/*!brief Parameter type for SVC */
-typedef struct aom_svc_ref_idx {
-  int ref_idx[8]; /**< Reference buffer slot */
-} aom_svc_ref_idx_t;
+/*!brief Parameters for setting ref frame config */
+typedef struct aom_svc_ref_frame_config {
+  // 7 references: LAST_FRAME (0), LAST2_FRAME(1), LAST3_FRAME(2),
+  // GOLDEN_FRAME(3), BWDREF_FRAME(4), ALTREF2_FRAME(5), ALTREF_FRAME(6).
+  /*! Buffer slot index for each of 7 references. */
+  int ref_idx[INTER_REFS_PER_FRAME];
+  int refresh[REF_FRAMES]; /**< Refresh flag for each of the 8 slots. */
+} aom_svc_ref_frame_config_t;
 
 /*!\cond */
 /*!\brief Encoder control function parameter type
@@ -1592,8 +1598,8 @@
 AOM_CTRL_USE_TYPE(AV1E_SET_SVC_PARAMS, aom_svc_params_t *)
 #define AOME_CTRL_AV1E_SET_SVC_PARAMS
 
-AOM_CTRL_USE_TYPE(AV1E_SET_SVC_REF_IDX, aom_svc_ref_idx_t *)
-#define AOME_CTRL_AV1E_SET_SVC_REF_IDX
+AOM_CTRL_USE_TYPE(AV1E_SET_SVC_REF_FRAME_CONFIG, aom_svc_ref_frame_config_t *)
+#define AOME_CTRL_AV1E_SET_SVC_REF_FRAME_CONFIG
 
 /*!\endcond */
 /*! @} - end defgroup aom_encoder */
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index aa7b399..59a6d46 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -2182,13 +2182,16 @@
   return AOM_CODEC_OK;
 }
 
-static aom_codec_err_t ctrl_set_svc_ref_idx(aom_codec_alg_priv_t *ctx,
-                                            va_list args) {
+static aom_codec_err_t ctrl_set_svc_ref_frame_config(aom_codec_alg_priv_t *ctx,
+                                                     va_list args) {
   AV1_COMP *const cpi = ctx->cpi;
-  aom_svc_ref_idx_t *const data = va_arg(args, aom_svc_ref_idx_t *);
-  cpi->svc.apply_external_ref_idx = 1;
+  aom_svc_ref_frame_config_t *const data =
+      va_arg(args, aom_svc_ref_frame_config_t *);
+  cpi->svc.external_ref_frame_config = 1;
   for (unsigned int i = 0; i < INTER_REFS_PER_FRAME; ++i)
     cpi->svc.ref_idx[i] = data->ref_idx[i];
+  for (unsigned int i = 0; i < REF_FRAMES; ++i)
+    cpi->svc.refresh[i] = data->refresh[i];
   return AOM_CODEC_OK;
 }
 
@@ -2398,7 +2401,7 @@
   { AV1E_SET_MIN_CR, ctrl_set_min_cr },
   { AV1E_SET_SVC_LAYER_ID, ctrl_set_layer_id },
   { AV1E_SET_SVC_PARAMS, ctrl_set_svc_params },
-  { AV1E_SET_SVC_REF_IDX, ctrl_set_svc_ref_idx },
+  { AV1E_SET_SVC_REF_FRAME_CONFIG, ctrl_set_svc_ref_frame_config },
 
   // Getters
   { AOME_GET_LAST_QUANTIZER, ctrl_get_quantizer },
diff --git a/av1/encoder/encode_strategy.c b/av1/encoder/encode_strategy.c
index e139c5b..2ba90a9 100644
--- a/av1/encoder/encode_strategy.c
+++ b/av1/encoder/encode_strategy.c
@@ -158,7 +158,9 @@
 }
 
 static INLINE int is_frame_droppable(const AV1_COMP *const cpi) {
-  if (cpi->ext_refresh_frame_flags_pending)
+  if (cpi->svc.external_ref_frame_config)
+    return cpi->svc.non_reference_frame;
+  else if (cpi->ext_refresh_frame_flags_pending)
     return !(cpi->ext_refresh_alt_ref_frame ||
              cpi->ext_refresh_alt2_ref_frame ||
              cpi->ext_refresh_bwd_ref_frame || cpi->ext_refresh_golden_frame ||
@@ -900,6 +902,13 @@
   int refresh_mask = 0;
 
   if (cpi->ext_refresh_frame_flags_pending) {
+    if (cpi->svc.external_ref_frame_config) {
+      for (unsigned int i = 0; i < INTER_REFS_PER_FRAME; i++) {
+        int ref_frame_map_idx = cpi->svc.ref_idx[i];
+        refresh_mask |= cpi->svc.refresh[i] << ref_frame_map_idx;
+      }
+      return refresh_mask;
+    }
     // Unfortunately the encoder interface reflects the old refresh_*_frame
     // flags so we have to replicate the old refresh_frame_flags logic here in
     // order to preserve the behaviour of the flag overrides.
@@ -1363,7 +1372,7 @@
   if (oxcf->pass == 0 || oxcf->pass == 2) {
     if (!cpi->ext_refresh_frame_flags_pending) {
       av1_get_ref_frames(cpi, &cpi->ref_buffer_stack);
-    } else if (cpi->svc.apply_external_ref_idx) {
+    } else if (cpi->svc.external_ref_frame_config) {
       for (unsigned int i = 0; i < INTER_REFS_PER_FRAME; i++)
         cm->remapped_ref_idx[i] = cpi->svc.ref_idx[i];
     }
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 20368d8..ab30db7 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -1191,7 +1191,8 @@
   cpi->td.counts = &cpi->counts;
 
   cpi->use_svc = 0;
-  cpi->svc.apply_external_ref_idx = 0;
+  cpi->svc.external_ref_frame_config = 0;
+  cpi->svc.non_reference_frame = 0;
   cm->number_spatial_layers = 1;
   cm->number_temporal_layers = 1;
 
@@ -2588,7 +2589,8 @@
 
   set_tile_info(cpi);
 
-  cpi->ext_refresh_frame_flags_pending = 0;
+  if (!cpi->svc.external_ref_frame_config)
+    cpi->ext_refresh_frame_flags_pending = 0;
   cpi->ext_refresh_frame_context_pending = 0;
 
   highbd_set_var_fns(cpi);
@@ -6163,6 +6165,22 @@
   return AOM_CODEC_OK;
 }
 
+static void svc_set_updates_external_ref_frame_config(AV1_COMP *cpi) {
+  cpi->ext_refresh_frame_flags_pending = 1;
+  cpi->ext_refresh_last_frame = cpi->svc.refresh[cpi->svc.ref_idx[0]];
+  cpi->ext_refresh_golden_frame = cpi->svc.refresh[cpi->svc.ref_idx[3]];
+  cpi->ext_refresh_bwd_ref_frame = cpi->svc.refresh[cpi->svc.ref_idx[4]];
+  cpi->ext_refresh_alt2_ref_frame = cpi->svc.refresh[cpi->svc.ref_idx[5]];
+  cpi->ext_refresh_alt_ref_frame = cpi->svc.refresh[cpi->svc.ref_idx[6]];
+  cpi->svc.non_reference_frame = 1;
+  for (int i = 0; i < REF_FRAMES; i++) {
+    if (cpi->svc.refresh[i] == 1) {
+      cpi->svc.non_reference_frame = 0;
+      break;
+    }
+  }
+}
+
 void av1_apply_encoding_flags(AV1_COMP *cpi, aom_enc_frame_flags_t flags) {
   // TODO(yunqingwang): For what references to use, external encoding flags
   // should be consistent with internal reference frame selection. Need to
@@ -6220,7 +6238,10 @@
     cpi->ext_refresh_alt2_ref_frame = (upd & AOM_ALT2_FLAG) != 0;
     cpi->ext_refresh_frame_flags_pending = 1;
   } else {
-    cpi->ext_refresh_frame_flags_pending = 0;
+    if (cpi->svc.external_ref_frame_config)
+      svc_set_updates_external_ref_frame_config(cpi);
+    else
+      cpi->ext_refresh_frame_flags_pending = 0;
   }
 
   cpi->ext_use_ref_frame_mvs = cpi->oxcf.allow_ref_frame_mvs &
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 514d536..ecc1b8d 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -175,10 +175,12 @@
 } LAYER_CONTEXT;
 
 typedef struct SVC {
-  int apply_external_ref_idx;
+  int external_ref_frame_config;
+  int non_reference_frame;
   // Layer context used for rate control in one pass temporal CBR mode.
   LAYER_CONTEXT layer_context[AOM_MAX_LAYERS];
   int ref_idx[INTER_REFS_PER_FRAME];
+  int refresh[REF_FRAMES];
 } SVC;
 
 #define MAX_LENGTH_TPL_FRAME_STATS (27 + 9)
diff --git a/examples/svc_encoder_rtc.c b/examples/svc_encoder_rtc.c
index ae144c2..62ff8a0 100644
--- a/examples/svc_encoder_rtc.c
+++ b/examples/svc_encoder_rtc.c
@@ -238,16 +238,16 @@
 // Layer pattern configuration.
 static int set_layer_pattern(int layering_mode, int frame_cnt,
                              aom_svc_layer_id_t *layer_id,
-                             aom_svc_ref_idx_t *svc_ref_idx) {
+                             aom_svc_ref_frame_config_t *ref_frame_config) {
   int i;
   // No spatial layers in this test.
   layer_id->spatial_layer_id = 0;
-  // Set the referende map buffer idx for the 6 references:
+  // Set the referende map buffer idx for the 7 references:
   // LAST_FRAME (0), LAST2_FRAME(1), LAST3_FRAME(2), GOLDEN_FRAME(3),
   // BWDREF_FRAME(4), ALTREF2_FRAME(5), ALTREF_FRAME(6).
-  for (i = 0; i < INTER_REFS_PER_FRAME; i++)
-    svc_ref_idx->ref_idx[i] = (i < 3) ? 0 : i - 2;
-  // We only use LAST and GF for prediction in RTC mode.
+  for (i = 0; i < INTER_REFS_PER_FRAME; i++) ref_frame_config->ref_idx[i] = i;
+  for (i = 0; i < REF_FRAMES; i++) ref_frame_config->refresh[i] = 0;
+  // Note only use LAST and GF for prediction in non-rd mode (speed 8).
   int layer_flags = AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 |
                     AOM_EFLAG_NO_REF_ARF | AOM_EFLAG_NO_REF_BWD |
                     AOM_EFLAG_NO_REF_ARF2;
@@ -255,7 +255,7 @@
     case 0:
       // 1-layer: update LAST on every frame, reference LAST and GF.
       layer_id->temporal_layer_id = 0;
-      layer_flags |= AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF;
+      ref_frame_config->refresh[0] = 1;
       break;
     case 1:
       // 2-layer.
@@ -264,12 +264,11 @@
       if (frame_cnt % 2 == 0) {
         layer_id->temporal_layer_id = 0;
         // Update LAST on layer 0, reference LAST and GF.
-        layer_flags |= AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF;
+        ref_frame_config->refresh[0] = 1;
       } else {
         layer_id->temporal_layer_id = 1;
         // No updates on layer 1, only reference LAST (TL0).
-        layer_flags |= AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF |
-                       AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_REF_GF;
+        layer_flags |= AOM_EFLAG_NO_REF_GF;
       }
       break;
     case 2:
@@ -281,27 +280,24 @@
         // Base layer.
         layer_id->temporal_layer_id = 0;
         // Update LAST on layer 0, reference LAST and GF.
-        layer_flags |= AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF;
+        ref_frame_config->refresh[0] = 1;
       } else if ((frame_cnt - 1) % 4 == 0) {
         layer_id->temporal_layer_id = 2;
         // First top layer: no updates, only reference LAST (TL0).
-        layer_flags |= AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF |
-                       AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_REF_GF;
+        layer_flags |= AOM_EFLAG_NO_REF_GF;
       } else if ((frame_cnt - 2) % 4 == 0) {
         layer_id->temporal_layer_id = 1;
-        // Middle layer (TL1): update ARF, only reference LAST (TL0).
-        // Updating ARF corresponds to buffer slot 6.
-        layer_flags |=
-            AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_REF_GF;
+        // Middle layer (TL1): update LAST2, only reference LAST (TL0).
+        ref_frame_config->refresh[1] = 1;
+        layer_flags |= AOM_EFLAG_NO_REF_GF;
       } else if ((frame_cnt - 3) % 4 == 0) {
         layer_id->temporal_layer_id = 2;
         // Second top layer: no updates, only reference LAST.
-        // Set buffer idx for LAST to slot 6, since that was the slot
-        // updated in previous frame. So LAST is TL1.
-        layer_flags |= AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF |
-                       AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_REF_GF;
-        svc_ref_idx->ref_idx[0] = 4;
-        svc_ref_idx->ref_idx[4] = 0;
+        // Set buffer idx for LAST to slot 1, since that was the slot
+        // updated in previous frame. So LAST is TL1 frame.
+        ref_frame_config->ref_idx[0] = 1;
+        ref_frame_config->ref_idx[1] = 0;
+        layer_flags |= AOM_EFLAG_NO_REF_GF;
       }
       break;
     default: assert(0); die("Error: Unsupported temporal layering mode!\n");
@@ -329,7 +325,7 @@
   int layering_mode = 0;
   aom_svc_layer_id_t layer_id;
   aom_svc_params_t svc_params;
-  aom_svc_ref_idx_t svc_ref_idx;
+  aom_svc_ref_frame_config_t ref_frame_config;
   const AvxInterface *encoder = NULL;
   struct AvxInputContext input_ctx;
   struct RateControlMetrics rc;
@@ -525,10 +521,10 @@
 
     // Set the reference/update flags, layer_id, and reference_map
     // buffer index.
-    flags =
-        set_layer_pattern(layering_mode, frame_cnt, &layer_id, &svc_ref_idx);
+    flags = set_layer_pattern(layering_mode, frame_cnt, &layer_id,
+                              &ref_frame_config);
     aom_codec_control(&codec, AV1E_SET_SVC_LAYER_ID, &layer_id);
-    aom_codec_control(&codec, AV1E_SET_SVC_REF_IDX, &svc_ref_idx);
+    aom_codec_control(&codec, AV1E_SET_SVC_REF_FRAME_CONFIG, &ref_frame_config);
 
     frame_avail = read_frame(&input_ctx, &raw);
     if (frame_avail) ++rc.layer_input_frames[layer_id.temporal_layer_id];