Misc. resize fixes along with the resize test

Re-enables most of the previously disabled tests.
The ones that are still disabled expect resize to be triggered
through rate control, which is no longer supported in Av1.

Change-Id: Ie5e9ba3eb0843cd44ff1ac988500081470ba0fe2
diff --git a/av1/common/alloccommon.c b/av1/common/alloccommon.c
index 357543e..fe22667 100644
--- a/av1/common/alloccommon.c
+++ b/av1/common/alloccommon.c
@@ -91,6 +91,7 @@
   if (!cm->frame_parallel_decode) {
     cm->last_frame_seg_map = NULL;
   }
+  cm->seg_map_alloc_size = 0;
 }
 
 void av1_free_ref_frame_buffers(BufferPool *pool) {
@@ -155,6 +156,7 @@
   }
   aom_free(cm->above_seg_context);
   cm->above_seg_context = NULL;
+  cm->above_context_alloc_cols = 0;
 #if CONFIG_VAR_TX
   aom_free(cm->above_txfm_context);
   cm->above_txfm_context = NULL;
diff --git a/av1/encoder/aq_cyclicrefresh.c b/av1/encoder/aq_cyclicrefresh.c
index 5f595d5..8f61c7e 100644
--- a/av1/encoder/aq_cyclicrefresh.c
+++ b/av1/encoder/aq_cyclicrefresh.c
@@ -397,6 +397,7 @@
   // Set the segmentation map: cycle through the superblocks, starting at
   // cr->mb_index, and stopping when either block_count blocks have been found
   // to be refreshed, or we have passed through whole frame.
+  if (cr->sb_index >= sbs_in_frame) cr->sb_index = 0;
   assert(cr->sb_index < sbs_in_frame);
   i = cr->sb_index;
   cr->target_num_seg_blocks = 0;
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 9787097..9e2f96c 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -425,6 +425,7 @@
   cm->mi_grid_base = NULL;
   aom_free(cm->prev_mi_grid_base);
   cm->prev_mi_grid_base = NULL;
+  cm->mi_alloc_size = 0;
 }
 
 static void swap_mi_and_prev_mi(AV1_COMMON *cm) {
@@ -465,11 +466,26 @@
   }
 }
 
+static void dealloc_context_buffers_ext(AV1_COMP *cpi) {
+  if (cpi->mbmi_ext_base) {
+    aom_free(cpi->mbmi_ext_base);
+    cpi->mbmi_ext_base = NULL;
+  }
+}
+
+static void alloc_context_buffers_ext(AV1_COMP *cpi) {
+  AV1_COMMON *cm = &cpi->common;
+  int mi_size = cm->mi_cols * cm->mi_rows;
+
+  dealloc_context_buffers_ext(cpi);
+  CHECK_MEM_ERROR(cm, cpi->mbmi_ext_base,
+                  aom_calloc(mi_size, sizeof(*cpi->mbmi_ext_base)));
+}
+
 static void dealloc_compressor_data(AV1_COMP *cpi) {
   AV1_COMMON *const cm = &cpi->common;
 
-  aom_free(cpi->mbmi_ext_base);
-  cpi->mbmi_ext_base = NULL;
+  dealloc_context_buffers_ext(cpi);
 
 #if CONFIG_PVQ
   if (cpi->oxcf.pass != 1) {
@@ -821,14 +837,6 @@
                        "Failed to allocate scaled last source buffer");
 }
 
-static void alloc_context_buffers_ext(AV1_COMP *cpi) {
-  AV1_COMMON *cm = &cpi->common;
-  int mi_size = cm->mi_cols * cm->mi_rows;
-
-  CHECK_MEM_ERROR(cm, cpi->mbmi_ext_base,
-                  aom_calloc(mi_size, sizeof(*cpi->mbmi_ext_base)));
-}
-
 static void alloc_compressor_data(AV1_COMP *cpi) {
   AV1_COMMON *cm = &cpi->common;
 
@@ -1038,7 +1046,6 @@
                        NULL);
   memset(cpi->mbmi_ext_base, 0,
          cm->mi_rows * cm->mi_cols * sizeof(*cpi->mbmi_ext_base));
-
   set_tile_info(cpi);
 }
 
@@ -1097,6 +1104,10 @@
   cpi->static_mb_pct = 0;
   cpi->ref_frame_flags = 0;
 
+  // Reset resize pending flags
+  cpi->resize_pending_width = 0;
+  cpi->resize_pending_height = 0;
+
   init_buffer_indices(cpi);
 }
 
@@ -2421,6 +2432,7 @@
   if (cpi->initial_width) {
     if (cm->width > cpi->initial_width || cm->height > cpi->initial_height) {
       av1_free_context_buffers(cm);
+      av1_free_pc_tree(&cpi->td);
       alloc_compressor_data(cpi);
       realloc_segmentation_maps(cpi);
       cpi->initial_width = cpi->initial_height = 0;
@@ -3326,6 +3338,7 @@
         rdc->global_motion_used[i] * GM_RECODE_LOOP_NUM4X4_FACTOR <
             cpi->gmparams_cost[i]) {
       set_default_warp_params(&cm->global_motion[i]);
+      assert(cm->global_motion[i].wmtype == IDENTITY);
       cpi->gmparams_cost[i] = 0;
       recode = 1;
       recode |= (rdc->global_motion_used[i] > 0);
@@ -4124,20 +4137,16 @@
   if (width <= 0 || height <= 0) return 1;
 
   cm->width = width;
-  if (cm->width > cpi->initial_width) {
-    cm->width = cpi->initial_width;
-    printf("Warning: Desired width too large, changed to %d\n", cm->width);
-  }
-
   cm->height = height;
-  if (cm->height > cpi->initial_height) {
-    cm->height = cpi->initial_height;
-    printf("Warning: Desired height too large, changed to %d\n", cm->height);
+
+  if (cpi->initial_width && cpi->initial_height &&
+      (cm->width > cpi->initial_width || cm->height > cpi->initial_height)) {
+    av1_free_context_buffers(cm);
+    av1_free_pc_tree(&cpi->td);
+    alloc_compressor_data(cpi);
+    realloc_segmentation_maps(cpi);
+    cpi->initial_width = cpi->initial_height = 0;
   }
-
-  assert(cm->width <= cpi->initial_width);
-  assert(cm->height <= cpi->initial_height);
-
   update_frame_size(cpi);
 
   return 0;
@@ -4303,56 +4312,98 @@
 }
 
 static int validate_size_scales(RESIZE_MODE resize_mode,
-                                SUPERRES_MODE superres_mode,
-                                size_params_type *rsz) {
-  if (rsz->resize_num * rsz->superres_num * 2 >
-      SCALE_DENOMINATOR * SCALE_DENOMINATOR)
+                                SUPERRES_MODE superres_mode, int owidth,
+                                int oheight, size_params_type *rsz) {
+  if (rsz->resize_width * rsz->superres_num >= SCALE_DENOMINATOR * owidth / 2 &&
+      rsz->resize_height * rsz->superres_num >= SCALE_DENOMINATOR * oheight / 2)
     return 1;
+  int resize_num = AOMMIN(((rsz->resize_width * 16 + owidth / 2) / owidth),
+                          ((rsz->resize_height * 16 + oheight / 2) / oheight));
   if (resize_mode != RESIZE_RANDOM && superres_mode == SUPERRES_RANDOM) {
     rsz->superres_num =
-        (SCALE_DENOMINATOR * SCALE_DENOMINATOR + 2 * rsz->resize_num - 1) /
-        (2 * rsz->resize_num);
+        (SCALE_DENOMINATOR * SCALE_DENOMINATOR + 2 * resize_num - 1) /
+        (2 * resize_num);
+    if (rsz->resize_width * rsz->superres_num <
+            SCALE_DENOMINATOR * owidth / 2 ||
+        rsz->resize_height * rsz->superres_num <
+            SCALE_DENOMINATOR * oheight / 2) {
+      if (rsz->superres_num < SCALE_DENOMINATOR) rsz->superres_num++;
+    }
   } else if (resize_mode == RESIZE_RANDOM && superres_mode != SUPERRES_RANDOM) {
-    rsz->resize_num =
+    resize_num =
         (SCALE_DENOMINATOR * SCALE_DENOMINATOR + 2 * rsz->superres_num - 1) /
         (2 * rsz->superres_num);
+    rsz->resize_width = owidth;
+    rsz->resize_height = oheight;
+    av1_calculate_scaled_size(&rsz->resize_width, &rsz->resize_height,
+                              resize_num);
+    if (rsz->resize_width * rsz->superres_num <
+            SCALE_DENOMINATOR * owidth / 2 ||
+        rsz->resize_height * rsz->superres_num <
+            SCALE_DENOMINATOR * oheight / 2) {
+      if (resize_num < SCALE_DENOMINATOR) resize_num++;
+    }
   } else if (resize_mode == RESIZE_RANDOM && superres_mode == SUPERRES_RANDOM) {
     do {
-      if (rsz->resize_num < rsz->superres_num)
-        ++rsz->resize_num;
+      if (resize_num < rsz->superres_num)
+        ++resize_num;
       else
         ++rsz->superres_num;
-    } while (rsz->resize_num * rsz->superres_num * 2 <=
-             SCALE_DENOMINATOR * SCALE_DENOMINATOR);
+      rsz->resize_width = owidth;
+      rsz->resize_height = oheight;
+      av1_calculate_scaled_size(&rsz->resize_width, &rsz->resize_height,
+                                resize_num);
+    } while ((rsz->resize_width * rsz->superres_num <
+                  SCALE_DENOMINATOR * owidth / 2 ||
+              rsz->resize_height * rsz->superres_num <
+                  SCALE_DENOMINATOR * oheight / 2) &&
+             (resize_num < SCALE_DENOMINATOR ||
+              rsz->superres_num < SCALE_DENOMINATOR));
   } else {
     return 0;
   }
-  return 1;
+  if (rsz->resize_width * rsz->superres_num >= SCALE_DENOMINATOR * owidth / 2 &&
+      rsz->resize_height * rsz->superres_num >= SCALE_DENOMINATOR * oheight / 2)
+    return 1;
+  return 0;
 }
 #endif  // CONFIG_FRAME_SUPERRES
 
+// Calculates resize and superres params for next frame
 size_params_type av1_calculate_next_size_params(AV1_COMP *cpi) {
   const AV1EncoderConfig *oxcf = &cpi->oxcf;
   size_params_type rsz = {
-    SCALE_DENOMINATOR,
+    oxcf->width,
+    oxcf->height,
 #if CONFIG_FRAME_SUPERRES
     SCALE_DENOMINATOR
 #endif  // CONFIG_FRAME_SUPERRES
   };
+  int resize_num;
   if (oxcf->pass == 1) return rsz;
-  rsz.resize_num = calculate_next_resize_scale(cpi);
+  if (cpi->resize_pending_width && cpi->resize_pending_height) {
+    rsz.resize_width = cpi->resize_pending_width;
+    rsz.resize_height = cpi->resize_pending_height;
+    cpi->resize_pending_width = cpi->resize_pending_height = 0;
+  } else {
+    resize_num = calculate_next_resize_scale(cpi);
+    rsz.resize_width = cpi->oxcf.width;
+    rsz.resize_height = cpi->oxcf.height;
+    av1_calculate_scaled_size(&rsz.resize_width, &rsz.resize_height,
+                              resize_num);
+  }
 #if CONFIG_FRAME_SUPERRES
   rsz.superres_num = calculate_next_superres_scale(cpi);
-  if (!validate_size_scales(oxcf->resize_mode, oxcf->superres_mode, &rsz))
+  if (!validate_size_scales(oxcf->resize_mode, oxcf->superres_mode, oxcf->width,
+                            oxcf->height, &rsz))
     assert(0 && "Invalid scale parameters");
 #endif  // CONFIG_FRAME_SUPERRES
   return rsz;
 }
 
 static void setup_frame_size_from_params(AV1_COMP *cpi, size_params_type *rsz) {
-  int encode_width = cpi->oxcf.width;
-  int encode_height = cpi->oxcf.height;
-  av1_calculate_scaled_size(&encode_width, &encode_height, rsz->resize_num);
+  int encode_width = rsz->resize_width;
+  int encode_height = rsz->resize_height;
 
 #if CONFIG_FRAME_SUPERRES
   AV1_COMMON *cm = &cpi->common;
@@ -4365,8 +4416,7 @@
 }
 
 static void setup_frame_size(AV1_COMP *cpi) {
-  size_params_type rsz;
-  rsz = av1_calculate_next_size_params(cpi);
+  size_params_type rsz = av1_calculate_next_size_params(cpi);
   setup_frame_size_from_params(cpi, &rsz);
 }
 
@@ -4622,12 +4672,15 @@
                                        &frame_over_shoot_limit);
     }
 
-    cpi->source =
-        av1_scale_if_required(cm, cpi->unscaled_source, &cpi->scaled_source);
 #if CONFIG_GLOBAL_MOTION
     // if frame was scaled calculate global_motion_search again if already done
-    if (cpi->source != cpi->unscaled_source) cpi->global_motion_search_done = 0;
+    if (loop_count > 0 && cpi->source && cpi->global_motion_search_done)
+      if (cpi->source->y_crop_width != cm->width ||
+          cpi->source->y_crop_height != cm->height)
+        cpi->global_motion_search_done = 0;
 #endif  // CONFIG_GLOBAL_MOTION
+    cpi->source =
+        av1_scale_if_required(cm, cpi->unscaled_source, &cpi->scaled_source);
     if (cpi->unscaled_last_source != NULL)
       cpi->last_source = av1_scale_if_required(cm, cpi->unscaled_last_source,
                                                &cpi->scaled_last_source);
@@ -6561,7 +6614,6 @@
 
 int av1_set_internal_size(AV1_COMP *cpi, AOM_SCALING horiz_mode,
                           AOM_SCALING vert_mode) {
-  AV1_COMMON *cm = &cpi->common;
   int hr = 0, hs = 0, vr = 0, vs = 0;
 
   if (horiz_mode > ONETWO || vert_mode > ONETWO) return -1;
@@ -6570,12 +6622,8 @@
   Scale2Ratio(vert_mode, &vr, &vs);
 
   // always go to the next whole number
-  cm->width = (hs - 1 + cpi->oxcf.width * hr) / hs;
-  cm->height = (vs - 1 + cpi->oxcf.height * vr) / vs;
-  assert(cm->width <= cpi->initial_width);
-  assert(cm->height <= cpi->initial_height);
-
-  update_frame_size(cpi);
+  cpi->resize_pending_width = (hs - 1 + cpi->oxcf.width * hr) / hs;
+  cpi->resize_pending_height = (vs - 1 + cpi->oxcf.height * vr) / vs;
 
   return 0;
 }
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 889d48a..3930721 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -571,6 +571,13 @@
                     // number of MBs in the current frame when the frame is
                     // scaled.
 
+  // When resize is triggered through external control, the desired width/height
+  // are stored here until use in the next frame coded. They are effective only
+  // for
+  // one frame and are reset after use.
+  int resize_pending_width;
+  int resize_pending_height;
+
   int frame_flags;
 
   search_site_config ss_cfg;
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index b82d29f..9172ca7 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -50,7 +50,8 @@
 #endif  // CONFIG_EXT_REFS
 
 typedef struct {
-  uint8_t resize_num;
+  int resize_width;
+  int resize_height;
 #if CONFIG_FRAME_SUPERRES
   uint8_t superres_num;
 #endif  // CONFIG_FRAME_SUPERRES
diff --git a/test/resize_test.cc b/test/resize_test.cc
index 2c838dd..14b10e0 100644
--- a/test/resize_test.cc
+++ b/test/resize_test.cc
@@ -351,11 +351,11 @@
         encoder->Config(&cfg_);
       }
     } else {
-      if (video->frame() == kStepDownFrame) {
+      if (video->frame() >= kStepDownFrame && video->frame() < kStepUpFrame) {
         struct aom_scaling_mode mode = { AOME_FOURFIVE, AOME_THREEFIVE };
         encoder->Control(AOME_SET_SCALEMODE, &mode);
       }
-      if (video->frame() == kStepUpFrame) {
+      if (video->frame() >= kStepUpFrame) {
         struct aom_scaling_mode mode = { AOME_NORMAL, AOME_NORMAL };
         encoder->Control(AOME_SET_SCALEMODE, &mode);
       }
@@ -388,7 +388,7 @@
 #endif
 };
 
-TEST_P(ResizeInternalTest, DISABLED_TestInternalResizeWorks) {
+TEST_P(ResizeInternalTest, TestInternalResizeWorks) {
   ::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
                                        30, 1, 0, 10);
   init_flags_ = AOM_CODEC_USE_PSNR;
@@ -406,6 +406,9 @@
 
   for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
        info != frame_info_list_.end(); ++info) {
+  }
+  for (std::vector<FrameInfo>::const_iterator info = frame_info_list_.begin();
+       info != frame_info_list_.end(); ++info) {
     const aom_codec_pts_t pts = info->pts;
     if (pts >= kStepDownFrame && pts < kStepUpFrame) {
       ASSERT_EQ(282U, info->w) << "Frame " << pts << " had unexpected width";
@@ -417,7 +420,7 @@
   }
 }
 
-TEST_P(ResizeInternalTest, DISABLED_TestInternalResizeChangeConfig) {
+TEST_P(ResizeInternalTest, TestInternalResizeChangeConfig) {
   ::libaom_test::I420VideoSource video("hantro_collage_w352h288.yuv", 352, 288,
                                        30, 1, 0, 10);
   cfg_.g_w = 352;
@@ -493,7 +496,7 @@
   int mismatch_nframes_;
 };
 
-TEST_P(ResizeRealtimeTest, DISABLED_TestExternalResizeWorks) {
+TEST_P(ResizeRealtimeTest, TestExternalResizeWorks) {
   ResizingVideoSource video;
   video.flag_codec_ = 1;
   DefaultConfig();
@@ -693,15 +696,6 @@
   }
 };
 
-#ifdef DISABLE_TRELLISQ_SEARCH
-TEST_P(ResizeCspTest, DISABLED_TestResizeCspWorks) {
-  ResizingCspVideoSource video;
-  init_flags_ = AOM_CODEC_USE_PSNR;
-  cfg_.rc_min_quantizer = cfg_.rc_max_quantizer = 48;
-  cfg_.g_lag_in_frames = 0;
-  ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
-}
-#else
 TEST_P(ResizeCspTest, TestResizeCspWorks) {
   ResizingCspVideoSource video;
   init_flags_ = AOM_CODEC_USE_PSNR;
@@ -709,7 +703,6 @@
   cfg_.g_lag_in_frames = 0;
   ASSERT_NO_FATAL_FAILURE(RunLoop(&video));
 }
-#endif
 
 AV1_INSTANTIATE_TEST_CASE(ResizeTest,
                           ::testing::Values(::libaom_test::kRealTime));