fix/augment scalability testing

* Fix scalable_encoder/scalable_decoder example code
* Fix decoder_peek_si_internal( ) to correctly return
  enhancement_layer_cnt
* Add basic scalability_test

Change-Id: Ic4cb882a556858371674184ecd64af2de611cba6
diff --git a/av1/av1_dx_iface.c b/av1/av1_dx_iface.c
index e24629c..9f292d1 100644
--- a/av1/av1_dx_iface.c
+++ b/av1/av1_dx_iface.c
@@ -163,13 +163,14 @@
   return length_field_size;
 }
 
-static void parse_operating_points(struct aom_read_bit_buffer *rb,
-                                   int red_hdr) {
+static void parse_operating_points(struct aom_read_bit_buffer *rb, int red_hdr,
+                                   aom_codec_stream_info_t *si) {
   if (red_hdr) {
     aom_rb_read_literal(rb, LEVEL_BITS);  // level
   } else {
     const uint8_t operating_points_minus1_cnt =
         aom_rb_read_literal(rb, OP_POINTS_MINUS1_BITS);
+    si->enhancement_layers_cnt = operating_points_minus1_cnt;
     for (int i = 0; i < operating_points_minus1_cnt + 1; i++) {
       aom_rb_read_literal(rb, OP_POINTS_IDC_BITS);  // idc
       aom_rb_read_literal(rb, LEVEL_BITS);          // level
@@ -244,7 +245,7 @@
     return AOM_CODEC_UNSUP_BITSTREAM;
   }
 
-  parse_operating_points(&rb, reduced_still_picture_hdr);
+  parse_operating_points(&rb, reduced_still_picture_hdr, si);
 
   int num_bits_width = aom_rb_read_literal(&rb, 4) + 1;
   int num_bits_height = aom_rb_read_literal(&rb, 4) + 1;
diff --git a/examples/scalable_decoder.c b/examples/scalable_decoder.c
index 23c3510..d5f11f1 100644
--- a/examples/scalable_decoder.c
+++ b/examples/scalable_decoder.c
@@ -121,17 +121,18 @@
   if (aom_codec_dec_init(&codec, decoder->codec_interface(), NULL, 0))
     die_codec(&codec, "Failed to initialize decoder.");
 
-  if (!file_is_obu(&obu_ctx))
-    die_codec(&codec, "Input is not a valid obu file");
-
   // peak sequence header OBU to get enhancement layer count, if any
   const size_t ret = fread(tmpbuf, 1, 32, inputfile);
   if (ret != 32) die_codec(&codec, "Input is not a valid obu file");
+  si.is_annexb = 0;
   if (aom_codec_peek_stream_info(decoder->codec_interface(), tmpbuf, 32, &si)) {
     die_codec(&codec, "Input is not a valid obu file");
   }
   fseek(inputfile, -32, SEEK_CUR);
 
+  if (!file_is_obu(&obu_ctx))
+    die_codec(&codec, "Input is not a valid obu file");
+
   // open output yuv files
   for (i = 0; i <= si.enhancement_layers_cnt; i++) {
     snprintf(filename, sizeof(filename), "out_lyr%d.yuv", i);
@@ -147,14 +148,19 @@
       die_codec(&codec, "Failed to decode frame.");
 
     while ((img = aom_codec_get_frame(&codec, &iter)) != NULL) {
+      aom_image_t *img_shifted =
+          aom_img_alloc(NULL, AOM_IMG_FMT_I420, img->d_w, img->d_h, 16);
+      img_shifted->bit_depth = 8;
+      aom_img_downshift(img_shifted, img,
+                        img->bit_depth - img_shifted->bit_depth);
       if (img->enhancement_id == 0) {
         printf("Writing       base layer 0 %d\n", frame_cnt);
-        aom_img_write(img, outfile[0]);
+        aom_img_write(img_shifted, outfile[0]);
         obu_ctx.last_layer_id++;
       } else if (img->enhancement_id <= (int)si.enhancement_layers_cnt) {
         printf("Writing enhancemnt layer %d %d\n", img->enhancement_id,
                frame_cnt);
-        aom_img_write(img, outfile[img->enhancement_id]);
+        aom_img_write(img_shifted, outfile[img->enhancement_id]);
         if (img->enhancement_id == (int)si.enhancement_layers_cnt)
           obu_ctx.last_layer_id = 0;
         else
diff --git a/examples/scalable_encoder.c b/examples/scalable_encoder.c
index 10b3587..12306b2 100644
--- a/examples/scalable_encoder.c
+++ b/examples/scalable_encoder.c
@@ -198,6 +198,7 @@
   cfg.g_error_resilient = 0;
   cfg.g_lag_in_frames = 0;
   cfg.rc_end_usage = AOM_Q;
+  cfg.save_as_annexb = 0;
 
   outfile = fopen(outfile_arg, "wb");
   if (!outfile) die("Failed to open %s for writing.", outfile_arg);
diff --git a/test/scalability_test.cc b/test/scalability_test.cc
new file mode 100644
index 0000000..7f90404
--- /dev/null
+++ b/test/scalability_test.cc
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2018, Alliance for Open Media. All rights reserved
+ *
+ * This source code is subject to the terms of the BSD 2 Clause License and
+ * the Alliance for Open Media Patent License 1.0. If the BSD 2 Clause License
+ * was not distributed with this source code in the LICENSE file, you can
+ * obtain it at www.aomedia.org/license/software. If the Alliance for Open
+ * Media Patent License 1.0 was not distributed with this source code in the
+ * PATENTS file, you can obtain it at www.aomedia.org/license/patent.
+ */
+
+#include "third_party/googletest/src/googletest/include/gtest/gtest.h"
+#include "test/codec_factory.h"
+#include "test/encode_test_driver.h"
+#include "test/i420_video_source.h"
+#include "test/util.h"
+
+namespace {
+
+const int kCpuUsed = 8;
+const int kBaseLayerQp = 55;
+const int kEnhancementLayerQp = 20;
+
+class ScalabilityTest
+    : public ::libaom_test::CodecTestWithParam<libaom_test::TestMode>,
+      public ::libaom_test::EncoderTest {
+ protected:
+  ScalabilityTest() : EncoderTest(GET_PARAM(0)) {}
+  virtual ~ScalabilityTest() {}
+
+  virtual void SetUp() {
+    InitializeConfig();
+    SetMode(GET_PARAM(1));
+    num_spatial_layers_ = 2;
+  }
+
+  virtual void PreEncodeFrameHook(::libaom_test::VideoSource *video,
+                                  ::libaom_test::Encoder *encoder) {
+    if (video->frame() == 0) {
+      encoder->Control(AOME_SET_CPUUSED, kCpuUsed);
+      encoder->Control(AOME_SET_NUMBER_SPATIAL_LAYERS, num_spatial_layers_);
+    } else if (video->frame() % num_spatial_layers_) {
+      frame_flags_ = AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 |
+                     AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF |
+                     AOM_EFLAG_NO_REF_BWD | AOM_EFLAG_NO_REF_ARF2 |
+                     AOM_EFLAG_NO_UPD_LAST | AOM_EFLAG_NO_UPD_GF |
+                     AOM_EFLAG_NO_UPD_ARF | AOM_EFLAG_NO_UPD_ENTROPY;
+      encoder->Control(AOME_SET_ENHANCEMENT_LAYER_ID, 1);
+      encoder->Control(AOME_SET_CQ_LEVEL, kEnhancementLayerQp);
+    } else {
+      frame_flags_ = AOM_EFLAG_NO_REF_LAST2 | AOM_EFLAG_NO_REF_LAST3 |
+                     AOM_EFLAG_NO_REF_GF | AOM_EFLAG_NO_REF_ARF |
+                     AOM_EFLAG_NO_REF_BWD | AOM_EFLAG_NO_REF_ARF2 |
+                     AOM_EFLAG_NO_UPD_GF | AOM_EFLAG_NO_UPD_ARF |
+                     AOM_EFLAG_NO_UPD_ENTROPY;
+      encoder->Control(AOME_SET_ENHANCEMENT_LAYER_ID, 0);
+      encoder->Control(AOME_SET_CQ_LEVEL, kBaseLayerQp);
+    }
+  }
+
+  void DoTest(int num_spatial_layers) {
+    num_spatial_layers_ = num_spatial_layers;
+    cfg_.rc_end_usage = AOM_Q;
+    cfg_.g_lag_in_frames = 0;
+
+    ::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352,
+                                         288, 30, 1, 0, 18);
+    ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+  }
+
+  int num_spatial_layers_;
+};
+
+TEST_P(ScalabilityTest, TestNoMismatch2SpatialLayers) { DoTest(2); }
+
+TEST_P(ScalabilityTest, TestNoMismatch3SpatialLayers) { DoTest(3); }
+
+AV1_INSTANTIATE_TEST_CASE(ScalabilityTest,
+                          ::testing::Values(::libaom_test::kRealTime));
+
+}  // namespace
diff --git a/test/test.cmake b/test/test.cmake
index dc2be4b..0a11e29 100644
--- a/test/test.cmake
+++ b/test/test.cmake
@@ -92,6 +92,7 @@
     "${AOM_ROOT}/test/i420_video_source.h"
     "${AOM_ROOT}/test/qm_test.cc"
     "${AOM_ROOT}/test/resize_test.cc"
+    "${AOM_ROOT}/test/scalability_test.cc"
     "${AOM_ROOT}/test/y4m_test.cc"
     "${AOM_ROOT}/test/y4m_video_source.h"
     "${AOM_ROOT}/test/yuv_video_source.h"