rtc-svc: Add set reference to SVC interface

Add set references to the SET_SVC_REF_FRAME_CONFIG
control, this allows user to completely specify
the layered pattern via the control, and avoids
the use of the flags AOM_EFLAG_NO_REF_.

Use this for the (3 spatial, 3 temporal) example
(mode >= 7) in the svc-rtc sample encoder.

Update SVC unittests with this reference set control.

Change-Id: I6b1403b1d00b2dd628714fb3161dbcba757ad416
diff --git a/aom/aomcx.h b/aom/aomcx.h
index c42725b..628c650 100644
--- a/aom/aomcx.h
+++ b/aom/aomcx.h
@@ -1320,6 +1320,7 @@
 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).
+  int reference[7]; /**< Reference flag for each of the 7 references. */
   /*! Buffer slot index for each of 7 references. */
   int ref_idx[7];
   int refresh[8]; /**< Refresh flag for each of the 8 slots. */
diff --git a/av1/av1_cx_iface.c b/av1/av1_cx_iface.c
index 5ca8256..e13ed95 100644
--- a/av1/av1_cx_iface.c
+++ b/av1/av1_cx_iface.c
@@ -2523,8 +2523,10 @@
   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)
+  for (unsigned int i = 0; i < INTER_REFS_PER_FRAME; ++i) {
+    cpi->svc.reference[i] = data->reference[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;
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 44ce442..69e125c 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -6993,6 +6993,16 @@
   }
 }
 
+static int svc_set_references_external_ref_frame_config(AV1_COMP *cpi) {
+  // LAST_FRAME (0), LAST2_FRAME(1), LAST3_FRAME(2), GOLDEN_FRAME(3),
+  // BWDREF_FRAME(4), ALTREF2_FRAME(5), ALTREF_FRAME(6).
+  int ref = AOM_REFFRAME_ALL;
+  for (int i = 0; i < INTER_REFS_PER_FRAME; i++) {
+    if (!cpi->svc.reference[i]) ref ^= (1 << i);
+  }
+  return ref;
+}
+
 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
@@ -7022,6 +7032,11 @@
     }
 
     av1_use_as_reference(cpi, ref);
+  } else {
+    if (cpi->svc.external_ref_frame_config) {
+      int ref = svc_set_references_external_ref_frame_config(cpi);
+      av1_use_as_reference(cpi, ref);
+    }
   }
 
   if (flags &
diff --git a/av1/encoder/svc_layercontext.h b/av1/encoder/svc_layercontext.h
index bbbd07a..7cb85a3 100644
--- a/av1/encoder/svc_layercontext.h
+++ b/av1/encoder/svc_layercontext.h
@@ -50,6 +50,9 @@
   int number_temporal_layers;
   int external_ref_frame_config;
   int non_reference_frame;
+  // LAST_FRAME (0), LAST2_FRAME(1), LAST3_FRAME(2), GOLDEN_FRAME(3),
+  // BWDREF_FRAME(4), ALTREF2_FRAME(5), ALTREF_FRAME(6).
+  int reference[INTER_REFS_PER_FRAME];
   int ref_idx[INTER_REFS_PER_FRAME];
   int refresh[REF_FRAMES];
   double base_framerate;
diff --git a/examples/svc_encoder_rtc.c b/examples/svc_encoder_rtc.c
index 77ae897..1316c6c 100644
--- a/examples/svc_encoder_rtc.c
+++ b/examples/svc_encoder_rtc.c
@@ -258,8 +258,10 @@
   // 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++) ref_frame_config->ref_idx[i] = i;
+  for (i = 0; i < INTER_REFS_PER_FRAME; i++) ref_frame_config->reference[i] = 0;
   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).
+  // Note for this layered patterns only use LAST and GF for prediction in
+  // non-rd mode (speed >= 7).
   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;
@@ -347,7 +349,7 @@
       }
       break;
     case 4:
-      // 2-temporla layer with the old update flags, not with the new
+      // 2-temporal layer with the old update flags, not with the new
       // SVC control.
       *use_svc_control = 0;
       //    1    3    5
@@ -420,6 +422,10 @@
       // 3 spatial and 3 temporal layer.
       // No overlap in buffer updates between TL2 and TL1.
       // TL2 updates slot 3 and 4, TL1 updates 5, 6, 7.
+      // Set the references via the svc_ref_frame_config control.
+      layer_flags = 0;
+      // Always reference LAST.
+      ref_frame_config->reference[0] = 1;
       if (superframe_cnt % 4 == 0) {
         // Base temporal layer.
         layer_id->temporal_layer_id = 0;
@@ -429,7 +435,6 @@
           for (i = 0; i < INTER_REFS_PER_FRAME; i++)
             ref_frame_config->ref_idx[i] = 0;
           ref_frame_config->refresh[0] = 1;
-          layer_flags |= AOM_EFLAG_NO_REF_GF;
         } else if (layer_id->spatial_layer_id == 1) {
           // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1,
           // GOLDEN (and all other refs) to slot 0.
@@ -458,7 +463,6 @@
             ref_frame_config->ref_idx[i] = 0;
           ref_frame_config->ref_idx[3] = 3;
           ref_frame_config->refresh[3] = 1;
-          layer_flags |= AOM_EFLAG_NO_REF_GF;
         } else if (layer_id->spatial_layer_id == 1) {
           // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1,
           // GOLDEN (and all other refs) to slot 3.
@@ -487,7 +491,6 @@
             ref_frame_config->ref_idx[i] = 0;
           ref_frame_config->ref_idx[3] = 5 - shift;
           ref_frame_config->refresh[5 - shift] = 1;
-          layer_flags |= AOM_EFLAG_NO_REF_GF;
         } else if (layer_id->spatial_layer_id == 1) {
           // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1,
           // GOLDEN (and all other refs) to slot 5.
@@ -519,7 +522,6 @@
           ref_frame_config->ref_idx[0] = 5 - shift;
           ref_frame_config->ref_idx[3] = 3;
           ref_frame_config->refresh[3] = 1;
-          layer_flags |= AOM_EFLAG_NO_REF_GF;
         } else if (layer_id->spatial_layer_id == 1) {
           // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 6,
           // GOLDEN to slot 3. Set LAST2 to slot 4 and update slot 4.
@@ -538,6 +540,8 @@
           ref_frame_config->ref_idx[3] = 4;
         }
       }
+      if (layer_id->spatial_layer_id > 0)
+        ref_frame_config->reference[3] = 1;  // Reference GOLDEN.
       break;
     default: assert(0); die("Error: Unsupported temporal layering mode!\n");
   }
diff --git a/test/svc_datarate_test.cc b/test/svc_datarate_test.cc
index f806f2d..1d950f9 100644
--- a/test/svc_datarate_test.cc
+++ b/test/svc_datarate_test.cc
@@ -19,6 +19,7 @@
 #include "test/util.h"
 #include "test/y4m_video_source.h"
 #include "aom/aom_codec.h"
+#include "av1/common/enums.h"
 
 namespace datarate_test {
 namespace {
@@ -114,12 +115,15 @@
     // 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 (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = i;
-    for (int i = 0; i < 8; 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;
+    for (int i = 0; i < INTER_REFS_PER_FRAME; i++) {
+      ref_frame_config->ref_idx[i] = i;
+      ref_frame_config->reference[i] = 0;
+    }
+    for (int i = 0; i < REF_FRAMES; i++) ref_frame_config->refresh[i] = 0;
+    // Set layer_flags to 0 when using ref_frame_config->reference.
+    int layer_flags = 0;
+    // Always reference LAST.
+    ref_frame_config->reference[0] = 1;
     if (number_temporal_layers_ == 3 && number_spatial_layers_ == 1) {
       // 3-layer:
       //   1    3   5    7
@@ -130,15 +134,14 @@
         layer_id->temporal_layer_id = 0;
         // Update LAST on layer 0, reference LAST and GF.
         ref_frame_config->refresh[0] = 1;
+        ref_frame_config->reference[3] = 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_REF_GF;
       } else if ((frame_cnt - 2) % 4 == 0) {
         layer_id->temporal_layer_id = 1;
         // 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.
@@ -146,7 +149,6 @@
         // 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;
       }
     } else if (number_temporal_layers_ == 1 && number_spatial_layers_ == 2) {
       layer_id->temporal_layer_id = 0;
@@ -155,7 +157,6 @@
         ref_frame_config->ref_idx[0] = 0;
         ref_frame_config->ref_idx[3] = 3;
         ref_frame_config->refresh[0] = 1;
-        layer_flags |= AOM_EFLAG_NO_REF_GF;
       } else if (layer_id->spatial_layer_id == 1) {
         // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 3
         // and GOLDEN to slot 0. Update slot 3 (LAST).
@@ -163,6 +164,8 @@
         ref_frame_config->ref_idx[3] = 0;
         ref_frame_config->refresh[3] = 1;
       }
+      // Reference GOLDEN.
+      if (layer_id->spatial_layer_id > 0) ref_frame_config->reference[3] = 1;
     } else if (number_temporal_layers_ == 1 && number_spatial_layers_ == 3) {
       // 3 spatial layers, 1 temporal.
       // Note for this case , we set the buffer idx for all references to be
@@ -174,7 +177,6 @@
         // Reference LAST, update LAST. Set all other buffer_idx to 0.
         for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 0;
         ref_frame_config->refresh[0] = 1;
-        layer_flags |= AOM_EFLAG_NO_REF_GF;
       } else if (layer_id->spatial_layer_id == 1) {
         // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1
         // and GOLDEN (and all other refs) to slot 0.
@@ -190,6 +192,8 @@
         ref_frame_config->ref_idx[0] = 2;
         ref_frame_config->refresh[2] = 1;
       }
+      // Reference GOLDEN.
+      if (layer_id->spatial_layer_id > 0) ref_frame_config->reference[3] = 1;
     } else if (number_temporal_layers_ == 3 && number_spatial_layers_ == 3) {
       // 3 spatial and 3 temporal layer.
       if (superframe_cnt_ % 4 == 0) {
@@ -200,7 +204,6 @@
           // Set all buffer_idx to 0.
           for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 0;
           ref_frame_config->refresh[0] = 1;
-          layer_flags |= AOM_EFLAG_NO_REF_GF;
         } else if (layer_id->spatial_layer_id == 1) {
           // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1,
           // GOLDEN (and all other refs) to slot 0.
@@ -226,7 +229,6 @@
           for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 0;
           ref_frame_config->ref_idx[3] = 3;
           ref_frame_config->refresh[3] = 1;
-          layer_flags |= AOM_EFLAG_NO_REF_GF;
         } else if (layer_id->spatial_layer_id == 1) {
           // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1,
           // GOLDEN (and all other refs) to slot 3.
@@ -252,7 +254,6 @@
           for (int i = 0; i < 7; i++) ref_frame_config->ref_idx[i] = 0;
           ref_frame_config->ref_idx[3] = 5;
           ref_frame_config->refresh[5] = 1;
-          layer_flags |= AOM_EFLAG_NO_REF_GF;
         } else if (layer_id->spatial_layer_id == 1) {
           // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 1,
           // GOLDEN (and all other refs) to slot 5.
@@ -281,7 +282,6 @@
           ref_frame_config->ref_idx[0] = 5;
           ref_frame_config->ref_idx[3] = 3;
           ref_frame_config->refresh[3] = 1;
-          layer_flags |= AOM_EFLAG_NO_REF_GF;
         } else if (layer_id->spatial_layer_id == 1) {
           // Reference LAST and GOLDEN. Set buffer_idx for LAST to slot 6,
           // GOLDEN to slot 3. Set LAST2 to slot 4 and update slot 4.
@@ -298,6 +298,8 @@
           ref_frame_config->ref_idx[3] = 4;
         }
       }
+      // Reference GOLDEN.
+      if (layer_id->spatial_layer_id > 0) ref_frame_config->reference[3] = 1;
     }
     return layer_flags;
   }