Add S_FRAME presence test when altref is enabled

This patch modifies the existing unit test to check the
presence of S_FRAME configured using encoder option, when
altref is enabled. Also checks if all the s_frames are
introduced at altref frames.

Change-Id: I87c7fa551228755e91354ced4ea61effbcb74edc
diff --git a/aom/aomdx.h b/aom/aomdx.h
index 399c669..aa4f435 100644
--- a/aom/aomdx.h
+++ b/aom/aomdx.h
@@ -145,6 +145,18 @@
   int is_reduced_still_picture_hdr;
 } aom_still_picture_info;
 
+/*!\brief Structure to hold information about S_FRAME.
+ *
+ * Defines a structure to hold a information regarding S_FRAME
+ * and its position.
+ */
+typedef struct aom_s_frame_info {
+  /*! Indicates if current frame is S_FRAME */
+  int is_s_frame;
+  /*! Indicates if current S_FRAME is present at ALTREF frame*/
+  int is_s_frame_at_altref;
+} aom_s_frame_info;
+
 /*!\brief Structure to hold information about screen content tools.
  *
  * Defines a structure to hold information about screen content
@@ -410,6 +422,10 @@
    * decoded has show existing frame flag set.
    */
   AOMD_GET_SHOW_EXISTING_FRAME_FLAG,
+
+  /*!\brief Codec control function to get the S_FRAME coding information
+   */
+  AOMD_GET_S_FRAME_INFO,
 };
 
 /*!\cond */
@@ -461,6 +477,9 @@
 AOM_CTRL_USE_TYPE(AOMD_GET_SHOW_EXISTING_FRAME_FLAG, int *)
 #define AOMD_CTRL_AOMD_GET_SHOW_EXISTING_FRAME_FLAG
 
+AOM_CTRL_USE_TYPE(AOMD_GET_S_FRAME_INFO, aom_s_frame_info *)
+#define AOMD_CTRL_AOMD_GET_S_FRAME_INFO
+
 AOM_CTRL_USE_TYPE(AV1D_GET_DISPLAY_SIZE, int *)
 #define AOM_CTRL_AV1D_GET_DISPLAY_SIZE
 
diff --git a/av1/av1_dx_iface.c b/av1/av1_dx_iface.c
index bc85f54..4ba411a 100644
--- a/av1/av1_dx_iface.c
+++ b/av1/av1_dx_iface.c
@@ -1128,6 +1128,26 @@
   return AOM_CODEC_OK;
 }
 
+static aom_codec_err_t ctrl_get_s_frame_info(aom_codec_alg_priv_t *ctx,
+                                             va_list args) {
+  aom_s_frame_info *const s_frame_info = va_arg(args, aom_s_frame_info *);
+  if (s_frame_info) {
+    if (ctx->frame_worker) {
+      AVxWorker *const worker = ctx->frame_worker;
+      FrameWorkerData *const frame_worker_data =
+          (FrameWorkerData *)worker->data1;
+      const AV1Decoder *pbi = frame_worker_data->pbi;
+      s_frame_info->is_s_frame = pbi->sframe_info.is_s_frame;
+      s_frame_info->is_s_frame_at_altref =
+          pbi->sframe_info.is_s_frame_at_altref;
+      return AOM_CODEC_OK;
+    } else {
+      return AOM_CODEC_ERROR;
+    }
+  }
+  return AOM_CODEC_OK;
+}
+
 static aom_codec_err_t ctrl_get_frame_corrupted(aom_codec_alg_priv_t *ctx,
                                                 va_list args) {
   int *corrupted = va_arg(args, int *);
@@ -1528,6 +1548,7 @@
   { AOMD_GET_STILL_PICTURE, ctrl_get_still_picture },
   { AOMD_GET_SB_SIZE, ctrl_get_sb_size },
   { AOMD_GET_SHOW_EXISTING_FRAME_FLAG, ctrl_get_show_existing_frame_flag },
+  { AOMD_GET_S_FRAME_INFO, ctrl_get_s_frame_info },
 
   CTRL_MAP_END,
 };
diff --git a/av1/decoder/decodeframe.c b/av1/decoder/decodeframe.c
index 46bddc5..6638c1d 100644
--- a/av1/decoder/decodeframe.c
+++ b/av1/decoder/decodeframe.c
@@ -4440,6 +4440,9 @@
   MACROBLOCKD *const xd = &pbi->dcb.xd;
   BufferPool *const pool = cm->buffer_pool;
   RefCntBuffer *const frame_bufs = pool->frame_bufs;
+  aom_s_frame_info *sframe_info = &pbi->sframe_info;
+  sframe_info->is_s_frame = 0;
+  sframe_info->is_s_frame_at_altref = 0;
 
   if (!pbi->sequence_header_ready) {
     aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
@@ -4548,6 +4551,10 @@
     if (cm->show_frame == 0) pbi->is_arf_frame_present = 1;
     if (cm->show_frame == 0 && cm->current_frame.frame_type == KEY_FRAME)
       pbi->is_fwd_kf_present = 1;
+    if (cm->current_frame.frame_type == S_FRAME) {
+      sframe_info->is_s_frame = 1;
+      sframe_info->is_s_frame_at_altref = cm->show_frame ? 0 : 1;
+    }
     if (seq_params->still_picture &&
         (current_frame->frame_type != KEY_FRAME || !cm->show_frame)) {
       aom_internal_error(&cm->error, AOM_CODEC_CORRUPT_FRAME,
diff --git a/av1/decoder/decoder.h b/av1/decoder/decoder.h
index 98bf3cc..b20e9c1 100644
--- a/av1/decoder/decoder.h
+++ b/av1/decoder/decoder.h
@@ -329,6 +329,7 @@
   int is_fwd_kf_present;
   int is_arf_frame_present;
   int num_tile_groups;
+  aom_s_frame_info sframe_info;
 } AV1Decoder;
 
 // Returns 0 on success. Sets pbi->common.error.error_code to a nonzero error
diff --git a/test/error_resilience_test.cc b/test/error_resilience_test.cc
index 5449303..f7e4287 100644
--- a/test/error_resilience_test.cc
+++ b/test/error_resilience_test.cc
@@ -465,14 +465,15 @@
 
 // This class is used to check the presence of SFrame.
 class SFramePresenceTestLarge
-    : public ::libaom_test::CodecTestWith2Params<libaom_test::TestMode,
-                                                 aom_rc_mode>,
+    : public ::libaom_test::CodecTestWith3Params<libaom_test::TestMode,
+                                                 aom_rc_mode, int>,
       public ::libaom_test::EncoderTest {
  protected:
   SFramePresenceTestLarge()
       : EncoderTest(GET_PARAM(0)), encoding_mode_(GET_PARAM(1)),
-        rc_end_usage_(GET_PARAM(2)) {
+        rc_end_usage_(GET_PARAM(2)), enable_altref_(GET_PARAM(3)) {
     is_sframe_present_ = 0;
+    is_sframe_position_violated_ = 0;
   }
   virtual ~SFramePresenceTestLarge() {}
 
@@ -487,6 +488,7 @@
     cfg_.kf_max_dist = 60;
     cfg_.g_lag_in_frames = 35;
     cfg_.sframe_dist = 5;
+    if (enable_altref_) cfg_.sframe_mode = 2;
   }
 
   virtual bool DoDecode() const { return 1; }
@@ -495,21 +497,22 @@
                                   ::libaom_test::Encoder *encoder) {
     if (video->frame() == 0) {
       encoder->Control(AOME_SET_CPUUSED, 5);
-      encoder->Control(AOME_SET_ENABLEAUTOALTREF, 0);
+      encoder->Control(AOME_SET_ENABLEAUTOALTREF, enable_altref_);
     }
   }
 
   virtual bool HandleDecodeResult(const aom_codec_err_t res_dec,
                                   libaom_test::Decoder *decoder) {
     EXPECT_EQ(AOM_CODEC_OK, res_dec) << decoder->DecodeError();
-    if (is_sframe_present_ != 1 && AOM_CODEC_OK == res_dec) {
+    if (AOM_CODEC_OK == res_dec) {
       aom_codec_ctx_t *ctx_dec = decoder->GetDecoder();
-      int frame_flags = 0;
-      AOM_CODEC_CONTROL_TYPECHECKED(ctx_dec, AOMD_GET_FRAME_FLAGS,
-                                    &frame_flags);
-      if ((frame_flags & AOM_FRAME_IS_SWITCH) ==
-          static_cast<aom_codec_frame_flags_t>(AOM_FRAME_IS_SWITCH)) {
+      AOM_CODEC_CONTROL_TYPECHECKED(ctx_dec, AOMD_GET_S_FRAME_INFO,
+                                    &sframe_info);
+      if (sframe_info.is_s_frame) {
         is_sframe_present_ = 1;
+        if (enable_altref_ && is_sframe_position_violated_ == 0 &&
+            sframe_info.is_s_frame_at_altref == 0)
+          is_sframe_position_violated_ = 1;
       }
     }
     return AOM_CODEC_OK == res_dec;
@@ -518,18 +521,29 @@
   ::libaom_test::TestMode encoding_mode_;
   aom_rc_mode rc_end_usage_;
   int is_sframe_present_;
+  int is_sframe_position_violated_;
+  int enable_altref_;
+  aom_s_frame_info sframe_info;
 };
 
 TEST_P(SFramePresenceTestLarge, SFramePresenceTest) {
   libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
                                      cfg_.g_timebase.den, cfg_.g_timebase.num,
-                                     0, 10);
+                                     0, 100);
   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
   ASSERT_EQ(is_sframe_present_, 1);
+  if (enable_altref_) {
+    ASSERT_EQ(is_sframe_position_violated_, 0);
+  }
 }
 
+/* TODO(anyone): Currently SFramePresenceTest fails when enable_altref_ = 1.
+ * Hence this configuration is not added. Add this configuration after the
+ * bug is fixed.
+ */
 AV1_INSTANTIATE_TEST_SUITE(SFramePresenceTestLarge,
                            ::testing::Values(::libaom_test::kOnePassGood,
                                              ::libaom_test::kTwoPassGood),
-                           ::testing::Values(AOM_Q, AOM_VBR, AOM_CBR, AOM_CQ));
+                           ::testing::Values(AOM_Q, AOM_VBR, AOM_CBR, AOM_CQ),
+                           ::testing::Values(0));
 }  // namespace