Add pyramid level check in subgop unit test

This patch extends subgop unit test to validate pyramid level
and corresponding qindex assignment of each frame.

Change-Id: I5c18e513aaab86c11a4f0e6af0544419f4d183e2
diff --git a/av1/av1_dx_iface.c b/av1/av1_dx_iface.c
index ec920db..76568cf 100644
--- a/av1/av1_dx_iface.c
+++ b/av1/av1_dx_iface.c
@@ -1168,17 +1168,20 @@
   FrameWorkerData *const frame_worker_data = (FrameWorkerData *)worker->data1;
   const AV1Decoder *const pbi = frame_worker_data->pbi;
   const SubGOPStatsDec *const subgop_stats = &pbi->subgop_stats;
-  SubGOPStepData *step_data = subgop_data->step;
+  SubGOPStepData *subgop_step = subgop_data->step;
   const int stat_count = subgop_stats->stat_count;
 
   // Collects already decoded out of order frames info along with in-order
   // frame
-  step_data += subgop_data->step_idx_dec;
+  subgop_step += subgop_data->step_idx_dec;
   for (int step_idx = 0; step_idx < stat_count; step_idx++) {
-    step_data[step_idx].disp_frame_idx = subgop_stats->disp_frame_idx[step_idx];
-    step_data[step_idx].show_existing_frame =
+    SubGOPStepData *step_data = &subgop_step[step_idx];
+    step_data->disp_frame_idx = subgop_stats->disp_frame_idx[step_idx];
+    step_data->show_existing_frame =
         subgop_stats->show_existing_frame[step_idx];
-    step_data[step_idx].show_frame = subgop_stats->show_frame[step_idx];
+    step_data->show_frame = subgop_stats->show_frame[step_idx];
+    step_data->qindex = subgop_stats->qindex[step_idx];
+
     subgop_data->step_idx_dec++;
   }
   return AOM_CODEC_OK;
diff --git a/av1/av1_iface_common.h b/av1/av1_iface_common.h
index 18c3eb4..af1f48d 100644
--- a/av1/av1_iface_common.h
+++ b/av1/av1_iface_common.h
@@ -24,6 +24,7 @@
   int show_frame;
   int show_existing_frame;
   int pyramid_level;
+  int qindex;
 } SubGOPStepData;
 
 typedef struct {
diff --git a/av1/decoder/decoder.c b/av1/decoder/decoder.c
index 608b1a7..c13fa15 100644
--- a/av1/decoder/decoder.c
+++ b/av1/decoder/decoder.c
@@ -55,6 +55,7 @@
   subgop_stats->show_existing_frame[subgop_stats->stat_count] =
       cm->show_existing_frame;
   subgop_stats->show_frame[subgop_stats->stat_count] = cm->show_frame;
+  subgop_stats->qindex[subgop_stats->stat_count] = cm->quant_params.base_qindex;
   assert(subgop_stats->stat_count < MAX_SUBGOP_STATS_SIZE);
   subgop_stats->stat_count++;
 }
diff --git a/av1/decoder/decoder.h b/av1/decoder/decoder.h
index b4dabce..e483623 100644
--- a/av1/decoder/decoder.h
+++ b/av1/decoder/decoder.h
@@ -225,6 +225,7 @@
   unsigned char disp_frame_idx[MAX_SUBGOP_STATS_SIZE];
   int show_existing_frame[MAX_SUBGOP_STATS_SIZE];
   int show_frame[MAX_SUBGOP_STATS_SIZE];
+  int qindex[MAX_SUBGOP_STATS_SIZE];
   int refresh_frame_flags[MAX_SUBGOP_STATS_SIZE];
   unsigned char stat_count;
 } SubGOPStatsDec;
diff --git a/test/subgop_test.cc b/test/subgop_test.cc
index 29a4b54..0b9f769 100644
--- a/test/subgop_test.cc
+++ b/test/subgop_test.cc
@@ -252,6 +252,8 @@
       subgop_data_.step[idx].show_existing_frame = -1;
       subgop_data_.step[idx].show_frame = -1;
       subgop_data_.step[idx].is_filtered = -1;
+      subgop_data_.step[idx].pyramid_level = 0;
+      subgop_data_.step[idx].qindex = 0;
     }
     subgop_data_.num_steps = 0;
     subgop_data_.step_idx_enc = 0;
@@ -309,6 +311,8 @@
     for (int idx = 0; idx < subgop_data_.num_steps; idx++) {
       subgop_cfg_test_.step[idx].disp_frame_idx =
           (int8_t)(subgop_data_.step[idx].disp_frame_idx - frames_from_key_);
+      subgop_cfg_test_.step[idx].pyr_level =
+          (int8_t)subgop_data_.step[idx].pyramid_level;
       if (subgop_data_.step[idx].is_filtered) {
         filtered_frames[buf_idx++] =
             subgop_data_.step[idx].disp_frame_idx - frames_from_key_;
@@ -380,6 +384,47 @@
     return 1;
   }
 
+  // Validates Pyramid level with user config
+  void ValidatePyramidLevel() {
+    int8_t max_pyramid_level = 0;
+    for (int idx = 0; idx < subgop_cfg_ref_->num_steps; idx++) {
+      if (max_pyramid_level < subgop_cfg_ref_->step[idx].pyr_level)
+        max_pyramid_level = subgop_cfg_ref_->step[idx].pyr_level;
+    }
+    for (int idx = 0; idx < subgop_cfg_ref_->num_steps; idx++) {
+      int8_t ref_pyramid_level =
+          (subgop_cfg_ref_->step[idx].pyr_level == max_pyramid_level)
+              ? 6
+              : subgop_cfg_ref_->step[idx].pyr_level;
+      EXPECT_EQ(subgop_cfg_test_.step[idx].pyr_level, ref_pyramid_level)
+          << "Error:pyramid level doesn't match";
+    }
+  }
+
+  // Validates Pyramid level along with qindex assignment
+  void ValidatePyramidLevelQIndex() {
+    int level_qindex[REF_FRAMES] = { 0 };
+    int8_t pyramid_level;
+    for (int idx = 0; idx < subgop_cfg_ref_->num_steps; idx++) {
+      pyramid_level = subgop_cfg_test_.step[idx].pyr_level;
+      if (!level_qindex[pyramid_level]) {
+        level_qindex[pyramid_level] = subgop_data_.step[idx].qindex;
+      } else if (!subgop_data_.step[idx].show_existing_frame &&
+                 !subgop_data_.step[idx].is_filtered) {
+        EXPECT_EQ(level_qindex[pyramid_level], subgop_data_.step[idx].qindex)
+            << "Error:qindex in a pyramid level doesn't match";
+      }
+    }
+    pyramid_level = 1;
+    for (int idx = 1; idx < REF_FRAMES; idx++) {
+      if (level_qindex[pyramid_level]) {
+        EXPECT_LT(level_qindex[pyramid_level - 1], level_qindex[pyramid_level])
+            << "Error:qindex should be higher in hierarchical pyramid level";
+        pyramid_level++;
+      }
+    }
+  }
+
   bool IsInputSubgopCfgUsed() {
     int num_ooo_frames_ref = 0;
     int num_ooo_frames_test = 0;
@@ -428,6 +473,8 @@
           EXPECT_EQ(subgop_code_test_, subgop_info_.pos_code)
               << "Error:subgop code doesn't match";
           ValidateSubgopFrametype();
+          ValidatePyramidLevel();
+          if (rc_end_usage_ == AOM_Q) ValidatePyramidLevelQIndex();
         }
       }
       frames_from_key_ += subgop_info_.size;