rtc: Fixes for resize when scalemode is used

Make sure sb_size is based on config width/height
(in case scalemode resize is done on first frame),
and add check in variance partition to avoid
computing variance when reference is different resoln.
Also add return in calculate_next_size_params when
not in superres mode, and fix to CBR rate control
on resize.

Added unittest for resize via scalemode.

Change-Id: I9421ee9efccd5094072bb89a5e909b44692fe665
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 1c9170c..a7984e5 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -252,8 +252,10 @@
 
   assert(oxcf->superblock_size == AOM_SUPERBLOCK_SIZE_DYNAMIC);
 
-  if (cpi->svc.number_spatial_layers > 1) {
-    // Use the configured size (top resolution) for spatial layers.
+  if (cpi->svc.number_spatial_layers > 1 ||
+      oxcf->resize_cfg.resize_mode != RESIZE_NONE) {
+    // Use the configured size (top resolution) for spatial layers or
+    // on resize.
     return AOMMIN(oxcf->frm_dim_cfg.width, oxcf->frm_dim_cfg.height) > 480
                ? BLOCK_128X128
                : BLOCK_64X64;
@@ -4546,6 +4548,8 @@
   resize_pending_params->width = (hs - 1 + oxcf->frm_dim_cfg.width * hr) / hs;
   resize_pending_params->height = (vs - 1 + oxcf->frm_dim_cfg.height * vr) / vs;
 
+  if (horiz_mode != NORMAL || vert_mode != NORMAL)
+    oxcf->resize_cfg.resize_mode = RESIZE_FIXED;
   return 0;
 }
 
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 43311f1..03b94dd 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -1638,10 +1638,11 @@
   rc->this_frame_target = target;
 
   // Modify frame size target when down-scaled.
-  if (av1_frame_scaled(cm))
+  if (av1_frame_scaled(cm) && cpi->oxcf.rc_cfg.mode != AOM_CBR) {
     rc->this_frame_target =
         (int)(rc->this_frame_target *
               resize_rate_factor(&cpi->oxcf.frm_dim_cfg, width, height));
+  }
 
   // Target rate per SB64 (including partial SB64s.
   rc->sb64_target_rate =
diff --git a/av1/encoder/superres_scale.c b/av1/encoder/superres_scale.c
index 2d79c95..7c6f840 100644
--- a/av1/encoder/superres_scale.c
+++ b/av1/encoder/superres_scale.c
@@ -359,6 +359,7 @@
     rsz.resize_width = resize_pending_params->width;
     rsz.resize_height = resize_pending_params->height;
     resize_pending_params->width = resize_pending_params->height = 0;
+    if (oxcf->superres_cfg.superres_mode == AOM_SUPERRES_NONE) return rsz;
   } else {
     resize_denom = calculate_next_resize_scale(cpi);
     rsz.resize_width = frm_dim_cfg->width;
diff --git a/av1/encoder/var_based_part.c b/av1/encoder/var_based_part.c
index d8fd4f4..6fc0c38 100644
--- a/av1/encoder/var_based_part.c
+++ b/av1/encoder/var_based_part.c
@@ -824,7 +824,7 @@
   int sp;
   int dp;
 
-  const int is_key_frame =
+  int is_key_frame =
       (frame_is_intra_only(cm) ||
        (cpi->use_svc &&
         cpi->svc.layer_context[cpi->svc.temporal_layer_id].is_key_frame));
@@ -875,6 +875,21 @@
   memset(x->part_search_info.variance_low, 0,
          sizeof(x->part_search_info.variance_low));
 
+  // Check if LAST frame is NULL or if the resolution of LAST is
+  // different than the current frame resolution, and if so, treat this frame
+  // as a key frame, for the purpose of the superblock partitioning.
+  // LAST == NULL can happen in cases where enhancement spatial layers are
+  // enabled dyanmically and the only reference is the spatial(GOLDEN).
+  // TODO(marpan): Check se of scaled references for the different resoln.
+  if (!frame_is_intra_only(cm)) {
+    const YV12_BUFFER_CONFIG *const ref =
+        get_ref_frame_yv12_buf(cm, LAST_FRAME);
+    if (ref == NULL || ref->y_crop_height != cm->height ||
+        ref->y_crop_width != cm->width) {
+      is_key_frame = 1;
+    }
+  }
+
   if (!is_key_frame) {
     setup_planes(cpi, x, &y_sad, &y_sad_g, &ref_frame_partition, mi_row,
                  mi_col);
diff --git a/test/resize_test.cc b/test/resize_test.cc
index bcf6794..1c12715 100644
--- a/test/resize_test.cc
+++ b/test/resize_test.cc
@@ -19,6 +19,7 @@
 #include "test/i420_video_source.h"
 #include "test/video_source.h"
 #include "test/util.h"
+#include "test/y4m_video_source.h"
 
 // Enable(1) or Disable(0) writing of the compressed bitstream.
 #define WRITE_COMPRESSED_STREAM 0
@@ -377,6 +378,16 @@
       encoder->Control(AOME_SET_CPUUSED, set_cpu_used_);
       encoder->Control(AV1E_SET_FRAME_PARALLEL_DECODING, 1);
     }
+    if (set_scale_mode_) {
+      struct aom_scaling_mode mode;
+      if (video->frame() <= 20)
+        mode = { AOME_ONETWO, AOME_ONETWO };
+      else if (video->frame() <= 40)
+        mode = { AOME_ONEFOUR, AOME_ONEFOUR };
+      else if (video->frame() > 40)
+        mode = { AOME_NORMAL, AOME_NORMAL };
+      encoder->Control(AOME_SET_SCALEMODE, &mode);
+    }
 
     if (change_bitrate_ && video->frame() == 120) {
       change_bitrate_ = false;
@@ -426,6 +437,11 @@
     // the width and height of the frame are swapped
     cfg_.g_forced_max_frame_width = cfg_.g_forced_max_frame_height =
         AOMMAX(kInitialWidth, kInitialHeight);
+    if (set_scale_mode_) {
+      cfg_.rc_dropframe_thresh = 0;
+      cfg_.g_forced_max_frame_width = 1280;
+      cfg_.g_forced_max_frame_height = 1280;
+    }
   }
 
   std::vector<FrameInfo> frame_info_list_;
@@ -433,13 +449,48 @@
   bool change_bitrate_;
   double mismatch_psnr_;
   int mismatch_nframes_;
+  bool set_scale_mode_;
 };
 
+// Check the AOME_SET_SCALEMODE control by downsizing to
+// 1/2, then 1/4, and then back up to originsal.
+TEST_P(ResizeRealtimeTest, TestInternalResizeSetScaleMode) {
+  ::libaom_test::Y4mVideoSource video("niklas_1280_720_30.y4m", 0, 60);
+  cfg_.g_w = 1280;
+  cfg_.g_h = 720;
+  set_scale_mode_ = true;
+  DefaultConfig();
+  change_bitrate_ = false;
+  mismatch_nframes_ = 0;
+  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
+  // Check we decoded the same number of frames as we attempted to encode
+  ASSERT_EQ(frame_info_list_.size(), video.limit());
+  for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
+       info != frame_info_list_.end(); ++info) {
+    const unsigned int frame = static_cast<unsigned>(info->pts);
+    unsigned int expected_w = 1280 >> 1;
+    unsigned int expected_h = 720 >> 1;
+    if (frame > 40) {
+      expected_w = 1280;
+      expected_h = 720;
+    } else if (frame > 20 && frame <= 40) {
+      expected_w = 1280 >> 2;
+      expected_h = 720 >> 2;
+    }
+    EXPECT_EQ(expected_w, info->w)
+        << "Frame " << frame << " had unexpected width";
+    EXPECT_EQ(expected_h, info->h)
+        << "Frame " << frame << " had unexpected height";
+    EXPECT_EQ(static_cast<unsigned int>(0), GetMismatchFrames());
+  }
+}
+
 TEST_P(ResizeRealtimeTest, TestExternalResizeWorks) {
   ResizingVideoSource video;
   video.flag_codec_ = 1;
   DefaultConfig();
   change_bitrate_ = false;
+  set_scale_mode_ = false;
   mismatch_psnr_ = 0.0;
   mismatch_nframes_ = 0;
   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));