Superres recode bugfix

When we try recoding the 1st frame with/without superres, different
superblock sizes may be picked depending on frame resolution. This
change in superblock size leads to some dimensions like 'mi_cols',
'mi_rows', 'mi_stride' etc becoming invalid. In turn, allocated sizes
and strides of some arrays become invalid as well.

We avoid this by separate variables for superres_mode provided by user
(existing one in 'oxcf'), and the one used by current encoding (new one
in 'cpi').

Certain top-level decisions like superblock size use the user-provided
oxcf->superres_mode, while most other logic uses cpi->superres_mode.

Fixes a couple of bugs.

Tested that SUPERRES_RECODE_ALL_RATIOS=1 works correctly as well.

BUG=aomedia:2536
BUG=aomedia:2569

Change-Id: I581951e1942779913ab2b7450e0e3cc58d79d87a
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index 142959a..44992c4 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -295,7 +295,7 @@
   if (tpl_frame->is_valid == 0) return deltaq_rdmult;
   if (!is_frame_tpl_eligible((AV1_COMP *)cpi)) return deltaq_rdmult;
   if (tpl_idx >= MAX_LAG_BUFFERS) return deltaq_rdmult;
-  if (cpi->oxcf.superres_mode != SUPERRES_NONE) return deltaq_rdmult;
+  if (cpi->superres_mode != SUPERRES_NONE) return deltaq_rdmult;
   if (cpi->oxcf.aq_mode != NO_AQ) return deltaq_rdmult;
 
   const int bsize_base = BLOCK_16X16;
@@ -3970,7 +3970,7 @@
                            int mi_col, int64_t *intra_cost_b,
                            int64_t *inter_cost_b, int *stride) {
   if (!cpi->oxcf.enable_tpl_model) return 0;
-  if (cpi->oxcf.superres_mode != SUPERRES_NONE) return 0;
+  if (cpi->superres_mode != SUPERRES_NONE) return 0;
   if (cpi->common.current_frame.frame_type == KEY_FRAME) return 0;
   const FRAME_UPDATE_TYPE update_type = get_frame_update_type(&cpi->gf_group);
   if (update_type == INTNL_OVERLAY_UPDATE || update_type == OVERLAY_UPDATE)
@@ -4567,7 +4567,7 @@
   if (tpl_frame->is_valid == 0) return;
   if (!is_frame_tpl_eligible(cpi)) return;
   if (frame_idx >= MAX_LAG_BUFFERS) return;
-  if (cpi->oxcf.superres_mode != SUPERRES_NONE) return;
+  if (cpi->superres_mode != SUPERRES_NONE) return;
   if (cpi->oxcf.aq_mode != NO_AQ) return;
 
   const int is_overlay = cpi->gf_group.update_type[frame_idx] == OVERLAY_UPDATE;
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index a70df19..1ee38b6 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -2829,6 +2829,7 @@
   update_film_grain_parameters(cpi, oxcf);
 
   cpi->oxcf = *oxcf;
+  cpi->superres_mode = oxcf->superres_mode;  // default
   x->e_mbd.bd = (int)seq_params->bit_depth;
   x->e_mbd.global_motion = cm->global_motion;
 
@@ -4533,6 +4534,7 @@
   */
 #if CONFIG_SUPERRES_IN_RECODE
   if (superres_in_recode_allowed(cpi)) {
+    assert(cpi->superres_mode != SUPERRES_NONE);
     // Force superres to be tried in the recode loop, as full-res is also going
     // to be tried anyway.
     denom = AOMMAX(denom, SCALE_NUMERATOR + 1);
@@ -4558,8 +4560,14 @@
                  cpi->common.seq_params.enable_superres));
   assert(IMPLIES(!cpi->common.seq_params.enable_superres,
                  oxcf->superres_mode == SUPERRES_NONE));
+  // Make sure that superres mode for current encoding is consistent with user
+  // provided superres mode.
+  assert(IMPLIES(oxcf->superres_mode != SUPERRES_AUTO,
+                 cpi->superres_mode == oxcf->superres_mode));
 
-  switch (oxcf->superres_mode) {
+  // Note: we must look at the current superres_mode to be tried in 'cpi' here,
+  // not the user given mode in 'oxcf'.
+  switch (cpi->superres_mode) {
     case SUPERRES_NONE: new_denom = SCALE_NUMERATOR; break;
     case SUPERRES_FIXED:
       if (cpi->common.current_frame.frame_type == KEY_FRAME)
@@ -4713,7 +4721,7 @@
                               resize_denom);
   }
   rsz.superres_denom = calculate_next_superres_scale(cpi);
-  if (!validate_size_scales(oxcf->resize_mode, oxcf->superres_mode, oxcf->width,
+  if (!validate_size_scales(oxcf->resize_mode, cpi->superres_mode, oxcf->width,
                             oxcf->height, &rsz))
     assert(0 && "Invalid scale parameters");
   return rsz;
@@ -5303,7 +5311,7 @@
   const int is_screen_content_type_orig_decision = cpi->is_screen_content_type;
   // Turn off the encoding trial for forward key frame and superres.
   if (cpi->sf.rt_sf.use_nonrd_pick_mode || cpi->oxcf.fwd_kf_enabled ||
-      cpi->oxcf.superres_mode != SUPERRES_NONE || cpi->oxcf.mode == REALTIME ||
+      cpi->superres_mode != SUPERRES_NONE || cpi->oxcf.mode == REALTIME ||
       is_screen_content_type_orig_decision || !is_key_frame) {
     return;
   }
@@ -5396,10 +5404,11 @@
   av1_setup_frame_size(cpi);
 
 #if CONFIG_SUPERRES_IN_RECODE
-  if (superres_in_recode_allowed(cpi) &&
+  if (superres_in_recode_allowed(cpi) && cpi->superres_mode != SUPERRES_NONE &&
       cm->superres_scale_denominator == SCALE_NUMERATOR) {
-    // Superres won't be picked, so no need to try, as we will go through
-    // another recode loop for full-resolution after this anyway.
+    // Superres mode in currently enabled, but the denominator selected will
+    // disable superres. So no need to continue, as we will go through another
+    // recode loop for full-resolution after this anyway.
     return -1;
   }
 #endif  // CONFIG_SUPERRES_IN_RECODE
@@ -5827,7 +5836,6 @@
                                             uint8_t *dest,
                                             int *largest_tile_id) {
   const AV1_COMMON *const cm = &cpi->common;
-  AV1EncoderConfig *const oxcf = &cpi->oxcf;
   assert(cm->seq_params.enable_superres);
   assert(superres_in_recode_allowed(cpi));
   aom_codec_err_t err = AOM_CODEC_OK;
@@ -5835,6 +5843,7 @@
 
   // Encode with superres.
 #if SUPERRES_RECODE_ALL_RATIOS
+  AV1EncoderConfig *const oxcf = &cpi->oxcf;
   int64_t superres_sses[SCALE_NUMERATOR];
   int64_t superres_rates[SCALE_NUMERATOR];
   int superres_largest_tile_ids[SCALE_NUMERATOR];
@@ -5878,10 +5887,11 @@
   int64_t sse2 = INT64_MAX;
   int64_t rate2 = INT64_MAX;
   int largest_tile_id2;
-  oxcf->superres_mode = SUPERRES_NONE;  // To force full-res.
+  cpi->superres_mode = SUPERRES_NONE;  // To force full-res.
   err = encode_with_recode_loop_and_filter(cpi, size, dest, &sse2, &rate2,
                                            &largest_tile_id2);
-  oxcf->superres_mode = SUPERRES_AUTO;  // Reset.
+  cpi->superres_mode = cpi->oxcf.superres_mode;  // Reset.
+  assert(cpi->oxcf.superres_mode == SUPERRES_AUTO);
   if (err != AOM_CODEC_OK) return err;
 
   // Note: Both use common rdmult based on base qindex of fullres.
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 4274aec..06c093a 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -1247,6 +1247,11 @@
   int max_qmlevel;
   int use_quant_b_adapt;
   int num_tg;
+
+  // Super-resolution mode currently being used by the encoder.
+  // This may / may not be same as user-supplied mode in oxcf->superres_mode
+  // (when we are recoding to try multiple options for example).
+  SUPERRES_MODE superres_mode;
 } AV1_COMP;
 
 typedef struct {
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 3c8bb80..144d9e0 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -865,15 +865,15 @@
 
 static int get_active_cq_level(const RATE_CONTROL *rc,
                                const AV1EncoderConfig *const oxcf,
-                               int intra_only, int superres_denom) {
+                               int intra_only, SUPERRES_MODE superres_mode,
+                               int superres_denom) {
   static const double cq_adjust_threshold = 0.1;
   int active_cq_level = oxcf->cq_level;
   (void)intra_only;
   if (oxcf->rc_mode == AOM_CQ || oxcf->rc_mode == AOM_Q) {
     // printf("Superres %d %d %d = %d\n", superres_denom, intra_only,
     //        rc->frames_to_key, !(intra_only && rc->frames_to_key <= 1));
-    if ((oxcf->superres_mode == SUPERRES_QTHRESH ||
-         oxcf->superres_mode == SUPERRES_AUTO) &&
+    if ((superres_mode == SUPERRES_QTHRESH || superres_mode == SUPERRES_AUTO) &&
         superres_denom != SCALE_NUMERATOR) {
       int mult = SUPERRES_QADJ_PER_DENOM_KEYFRAME_SOLO;
       if (intra_only && rc->frames_to_key <= 1) {
@@ -941,8 +941,9 @@
   const RATE_CONTROL *const rc = &cpi->rc;
   const CurrentFrame *const current_frame = &cm->current_frame;
   const AV1EncoderConfig *const oxcf = &cpi->oxcf;
-  const int cq_level = get_active_cq_level(rc, oxcf, frame_is_intra_only(cm),
-                                           cm->superres_scale_denominator);
+  const int cq_level =
+      get_active_cq_level(rc, oxcf, frame_is_intra_only(cm), cpi->superres_mode,
+                          cm->superres_scale_denominator);
   const int bit_depth = cm->seq_params.bit_depth;
 
   if (oxcf->use_fixed_qp_offsets) {
@@ -1216,8 +1217,8 @@
     // Tweak active_best_quality for AOM_Q mode when superres is on, as this
     // will be used directly as 'q' later.
     if (oxcf->rc_mode == AOM_Q &&
-        (oxcf->superres_mode == SUPERRES_QTHRESH ||
-         oxcf->superres_mode == SUPERRES_AUTO) &&
+        (cpi->superres_mode == SUPERRES_QTHRESH ||
+         cpi->superres_mode == SUPERRES_AUTO) &&
         cm->superres_scale_denominator != SCALE_NUMERATOR) {
       active_best_quality =
           AOMMAX(active_best_quality -
@@ -1394,8 +1395,9 @@
   const RATE_CONTROL *const rc = &cpi->rc;
   const AV1EncoderConfig *const oxcf = &cpi->oxcf;
   const GF_GROUP *gf_group = &cpi->gf_group;
-  const int cq_level = get_active_cq_level(rc, oxcf, frame_is_intra_only(cm),
-                                           cm->superres_scale_denominator);
+  const int cq_level =
+      get_active_cq_level(rc, oxcf, frame_is_intra_only(cm), cpi->superres_mode,
+                          cm->superres_scale_denominator);
   const int bit_depth = cm->seq_params.bit_depth;
 
   if (oxcf->use_fixed_qp_offsets) {
diff --git a/av1/encoder/tpl_model.c b/av1/encoder/tpl_model.c
index 7973412..7c34de7 100644
--- a/av1/encoder/tpl_model.c
+++ b/av1/encoder/tpl_model.c
@@ -984,7 +984,7 @@
   EncodeFrameParams this_frame_params = *frame_params;
   TplParams *const tpl_data = &cpi->tpl_data;
 
-  if (cpi->oxcf.superres_mode != SUPERRES_NONE) return 0;
+  if (cpi->superres_mode != SUPERRES_NONE) return 0;
 
   cm->current_frame.frame_type = frame_params->frame_type;
   for (int gf_index = gf_group->index; gf_index < gf_group->size; ++gf_index) {
@@ -1087,7 +1087,7 @@
   const TplDepFrame *const tpl_frame = &tpl_data->tpl_frame[tpl_idx];
 
   if (!tpl_frame->is_valid) return;
-  if (cpi->oxcf.superres_mode != SUPERRES_NONE) return;
+  if (cpi->superres_mode != SUPERRES_NONE) return;
 
   const TplDepStats *const tpl_stats = tpl_frame->tpl_stats_ptr;
   const int tpl_stride = tpl_frame->stride;
@@ -1142,7 +1142,7 @@
   if (tpl_frame->is_valid == 0) return;
   if (!is_frame_tpl_eligible(cpi)) return;
   if (tpl_idx >= MAX_LAG_BUFFERS) return;
-  if (cpi->oxcf.superres_mode != SUPERRES_NONE) return;
+  if (cpi->superres_mode != SUPERRES_NONE) return;
   if (cpi->oxcf.aq_mode != NO_AQ) return;
 
   const int bsize_base = BLOCK_16X16;