frame_superres: Post encode/decode upscaling

This patch implements the post-encode and post-decode upscaling for the
frame superresolution experiment to work.

Upscaling happens after cdef and before loop restoration.

For now, this patch forces on random-superres.

The patch also cleans up some broken rate control hooks from VP9
days, to be brought back later when the resize and superres tools
are stable.

Change-Id: If0a8f69224dfaa0f4ae7703bd429ea2af953c7a6
diff --git a/av1/encoder/aq_cyclicrefresh.c b/av1/encoder/aq_cyclicrefresh.c
index b2b4106..05aa28c 100644
--- a/av1/encoder/aq_cyclicrefresh.c
+++ b/av1/encoder/aq_cyclicrefresh.c
@@ -352,10 +352,7 @@
   // For video conference clips, if the background has high motion in current
   // frame because of the camera movement, set this frame as the golden frame.
   // Use 70% and 5% as the thresholds for golden frame refreshing.
-  // Also, force this frame as a golden update frame if this frame will change
-  // the resolution (av1_resize_pending != 0).
-  if (av1_resize_pending(cpi) ||
-      (cnt1 * 10 > (70 * rows * cols) && cnt2 * 20 < cnt1)) {
+  if (cnt1 * 10 > (70 * rows * cols) && cnt2 * 20 < cnt1) {
     av1_cyclic_refresh_set_golden_update(cpi);
     rc->frames_till_gf_update_due = rc->baseline_gf_interval;
 
diff --git a/av1/encoder/bitstream.c b/av1/encoder/bitstream.c
index c44867b..fb8ab94 100644
--- a/av1/encoder/bitstream.c
+++ b/av1/encoder/bitstream.c
@@ -4172,8 +4172,7 @@
 
 static void write_render_size(const AV1_COMMON *cm,
                               struct aom_write_bit_buffer *wb) {
-  const int scaling_active =
-      cm->width != cm->render_width || cm->height != cm->render_height;
+  const int scaling_active = !av1_resize_unscaled(cm);
   aom_wb_write_bit(wb, scaling_active);
   if (scaling_active) {
     aom_wb_write_literal(wb, cm->render_width - 1, 16);
@@ -4189,7 +4188,6 @@
     aom_wb_write_bit(wb, 0);  // no scaling
   } else {
     aom_wb_write_bit(wb, 1);  // scaling, write scale factor
-    // TODO(afergs): write factor to the compressed header instead
     aom_wb_write_literal(
         wb, cm->superres_scale_numerator - SUPERRES_SCALE_NUMERATOR_MIN,
         SUPERRES_SCALE_BITS);
@@ -4199,13 +4197,15 @@
 
 static void write_frame_size(const AV1_COMMON *cm,
                              struct aom_write_bit_buffer *wb) {
+#if CONFIG_FRAME_SUPERRES
+  aom_wb_write_literal(wb, cm->superres_upscaled_width - 1, 16);
+  aom_wb_write_literal(wb, cm->superres_upscaled_height - 1, 16);
+  write_superres_scale(cm, wb);
+#else
   aom_wb_write_literal(wb, cm->width - 1, 16);
   aom_wb_write_literal(wb, cm->height - 1, 16);
-
-  write_render_size(cm, wb);
-#if CONFIG_FRAME_SUPERRES
-  write_superres_scale(cm, wb);
 #endif  // CONFIG_FRAME_SUPERRES
+  write_render_size(cm, wb);
 }
 
 static void write_frame_size_with_refs(AV1_COMP *cpi,
@@ -4218,20 +4218,26 @@
     YV12_BUFFER_CONFIG *cfg = get_ref_frame_buffer(cpi, ref_frame);
 
     if (cfg != NULL) {
+#if CONFIG_FRAME_SUPERRES
+      found = cm->superres_upscaled_width == cfg->y_crop_width &&
+              cm->superres_upscaled_height == cfg->y_crop_height;
+#else
       found =
           cm->width == cfg->y_crop_width && cm->height == cfg->y_crop_height;
+#endif
       found &= cm->render_width == cfg->render_width &&
                cm->render_height == cfg->render_height;
     }
     aom_wb_write_bit(wb, found);
     if (found) {
+#if CONFIG_FRAME_SUPERRES
+      write_superres_scale(cm, wb);
+#endif  // CONFIG_FRAME_SUPERRES
       break;
     }
   }
 
-  if (!found) {
-    write_frame_size(cm, wb);
-  }
+  if (!found) write_frame_size(cm, wb);
 }
 
 static void write_sync_code(struct aom_write_bit_buffer *wb) {
@@ -4370,11 +4376,6 @@
   }
 #endif
 
-#if CONFIG_FRAME_SUPERRES
-  // TODO(afergs): Remove - this is just to stop superres from breaking
-  cm->superres_scale_numerator = SUPERRES_SCALE_DENOMINATOR;
-#endif  // CONFIG_FRAME_SUPERRES
-
   if (cm->frame_type == KEY_FRAME) {
     write_sync_code(wb);
     write_bitdepth_colorspace_sampling(cm, wb);
diff --git a/av1/encoder/encodeframe.c b/av1/encoder/encodeframe.c
index 4e30d16..a0eed78 100644
--- a/av1/encoder/encodeframe.c
+++ b/av1/encoder/encodeframe.c
@@ -4860,17 +4860,31 @@
 #if CONFIG_TEMPMV_SIGNALING
   if (cm->prev_frame) {
     cm->use_prev_frame_mvs &= !cm->error_resilient_mode &&
-                              cm->width == cm->prev_frame->buf.y_width &&
-                              cm->height == cm->prev_frame->buf.y_height &&
+#if CONFIG_FRAME_SUPERRES
+                              cm->width == cm->last_width &&
+                              cm->height == cm->last_height &&
+#else
+                              cm->width == cm->prev_frame->buf.y_crop_width &&
+                              cm->height == cm->prev_frame->buf.y_crop_height &&
+#endif  // CONFIG_FRAME_SUPERRES
                               !cm->intra_only && !cm->prev_frame->intra_only;
   } else {
     cm->use_prev_frame_mvs = 0;
   }
 #else
-  cm->use_prev_frame_mvs = !cm->error_resilient_mode && cm->prev_frame &&
-                           cm->width == cm->prev_frame->buf.y_crop_width &&
-                           cm->height == cm->prev_frame->buf.y_crop_height &&
-                           !cm->intra_only && cm->last_show_frame;
+  if (cm->prev_frame) {
+    cm->use_prev_frame_mvs = !cm->error_resilient_mode &&
+#if CONFIG_FRAME_SUPERRES
+                             cm->width == cm->last_width &&
+                             cm->height == cm->last_height &&
+#else
+                             cm->width == cm->prev_frame->buf.y_crop_width &&
+                             cm->height == cm->prev_frame->buf.y_crop_height &&
+#endif  // CONFIG_FRAME_SUPERRES
+                             !cm->intra_only && cm->last_show_frame;
+  } else {
+    cm->use_prev_frame_mvs = 0;
+  }
 #endif  // CONFIG_TEMPMV_SIGNALING
 
   // Special case: set prev_mi to NULL when the previous mode info
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index f27928b..e9a27a9 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -2099,10 +2099,6 @@
   cpi->resize_state = 0;
   cpi->resize_avg_qp = 0;
   cpi->resize_buffer_underflow = 0;
-  cpi->resize_scale_num = 16;
-  cpi->resize_scale_den = 16;
-  cpi->resize_next_scale_num = 16;
-  cpi->resize_next_scale_den = 16;
 
   cpi->common.buffer_pool = pool;
 
@@ -2450,6 +2446,8 @@
   av1_loop_filter_init(cm);
 #if CONFIG_FRAME_SUPERRES
   cm->superres_scale_numerator = SUPERRES_SCALE_DENOMINATOR;
+  cm->superres_upscaled_width = oxcf->scaled_frame_width;
+  cm->superres_upscaled_height = oxcf->scaled_frame_height;
 #endif  // CONFIG_FRAME_SUPERRES
 #if CONFIG_LOOP_RESTORATION
   av1_loop_restoration_precal();
@@ -3380,61 +3378,6 @@
 #endif  // DUMP_REF_FRAME_IMAGES
 }
 
-static void loopfilter_frame(AV1_COMP *cpi, AV1_COMMON *cm) {
-  MACROBLOCKD *xd = &cpi->td.mb.e_mbd;
-  struct loopfilter *lf = &cm->lf;
-  if (is_lossless_requested(&cpi->oxcf)) {
-    lf->filter_level = 0;
-  } else {
-    struct aom_usec_timer timer;
-
-    aom_clear_system_state();
-
-    aom_usec_timer_start(&timer);
-
-    av1_pick_filter_level(cpi->source, cpi, cpi->sf.lpf_pick);
-
-    aom_usec_timer_mark(&timer);
-    cpi->time_pick_lpf += aom_usec_timer_elapsed(&timer);
-  }
-
-  if (lf->filter_level > 0) {
-#if CONFIG_VAR_TX || CONFIG_EXT_PARTITION || CONFIG_CB4X4
-    av1_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level, 0, 0);
-#else
-    if (cpi->num_workers > 1)
-      av1_loop_filter_frame_mt(cm->frame_to_show, cm, xd->plane,
-                               lf->filter_level, 0, 0, cpi->workers,
-                               cpi->num_workers, &cpi->lf_row_sync);
-    else
-      av1_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level, 0, 0);
-#endif
-  }
-#if CONFIG_CDEF
-  if (is_lossless_requested(&cpi->oxcf)) {
-    cm->cdef_bits = 0;
-    cm->cdef_strengths[0] = 0;
-    cm->nb_cdef_strengths = 1;
-  } else {
-    // Find cm->dering_level, cm->clpf_strength_u and cm->clpf_strength_v
-    av1_cdef_search(cm->frame_to_show, cpi->source, cm, xd,
-                    cpi->oxcf.speed > 0);
-
-    // Apply the filter
-    av1_cdef_frame(cm->frame_to_show, cm, xd);
-  }
-#endif
-#if CONFIG_LOOP_RESTORATION
-  av1_pick_filter_restoration(cpi->source, cpi, cpi->sf.lpf_pick);
-  if (cm->rst_info[0].frame_restoration_type != RESTORE_NONE ||
-      cm->rst_info[1].frame_restoration_type != RESTORE_NONE ||
-      cm->rst_info[2].frame_restoration_type != RESTORE_NONE) {
-    av1_loop_restoration_frame(cm->frame_to_show, cm, cm->rst_info, 7, 0, NULL);
-  }
-#endif  // CONFIG_LOOP_RESTORATION
-  aom_extend_frame_inner_borders(cm->frame_to_show);
-}
-
 static INLINE void alloc_frame_mvs(AV1_COMMON *const cm, int buffer_idx) {
   RefCntBuffer *const new_fb_ptr = &cm->buffer_pool->frame_bufs[buffer_idx];
   if (new_fb_ptr->mvs == NULL || new_fb_ptr->mi_rows < cm->mi_rows ||
@@ -3789,56 +3732,19 @@
 }
 #endif  // CONFIG_LOOP_RESTORATION
 
-static void set_scaled_size(AV1_COMP *cpi) {
-  AV1_COMMON *const cm = &cpi->common;
-  AV1EncoderConfig *const oxcf = &cpi->oxcf;
-
-  // TODO(afergs): Replace with call to av1_resize_pending? Could replace
-  //               scaled_size_set as well.
-  // TODO(afergs): Realistically, if resize_pending is true, then the other
-  //               conditions must already be satisfied.
-  //               Try this first:
-  //                 av1_resize_pending &&
-  //                 (DYNAMIC && (1 Pass CBR || 2 Pass VBR)
-  //                  STATIC  && FIRST_FRAME)
-  //               Really, av1_resize_pending should just reflect the above.
-  // TODO(afergs): Allow fixed resizing in AOM_CBR mode?
-  // 2 Pass VBR: Resize if fixed resize and first frame, or dynamic resize and
-  //             a resize is pending.
-  // 1 Pass CBR: Resize if dynamic resize and resize pending.
-  if ((oxcf->pass == 2 && oxcf->rc_mode == AOM_VBR &&
-       ((oxcf->resize_mode == RESIZE_FIXED && cm->current_video_frame == 0) ||
-        (oxcf->resize_mode == RESIZE_DYNAMIC && av1_resize_pending(cpi)))) ||
-      (oxcf->pass == 0 && oxcf->rc_mode == AOM_CBR &&
-       oxcf->resize_mode == RESIZE_DYNAMIC && av1_resize_pending(cpi))) {
-    // TODO(afergs): This feels hacky... Should it just set? Should
-    //               av1_set_next_scaled_size be a library function?
-    av1_calculate_next_scaled_size(cpi, &oxcf->scaled_frame_width,
-                                   &oxcf->scaled_frame_height);
-  }
-}
-
 static void set_frame_size(AV1_COMP *cpi, int width, int height) {
-  int ref_frame;
   AV1_COMMON *const cm = &cpi->common;
-  AV1EncoderConfig *const oxcf = &cpi->oxcf;
   MACROBLOCKD *const xd = &cpi->td.mb.e_mbd;
+  int ref_frame;
 
   if (width != cm->width || height != cm->height) {
     // There has been a change in the encoded frame size
     av1_set_size_literal(cpi, width, height);
-
-    // TODO(agrange) Scale cpi->max_mv_magnitude if frame-size has changed.
-    // TODO(afergs): Make condition just (pass == 0) or (rc_mode == CBR) -
-    //               UNLESS CBR starts allowing FIXED resizing. Then the resize
-    //               mode will need to get checked too.
-    if (oxcf->pass == 0 && oxcf->rc_mode == AOM_CBR &&
-        oxcf->resize_mode == RESIZE_DYNAMIC)
-      set_mv_search_params(cpi);  // TODO(afergs): Needed? Caller calls after...
+    set_mv_search_params(cpi);
   }
 
 #if !CONFIG_XIPHRC
-  if (oxcf->pass == 2) {
+  if (cpi->oxcf.pass == 2) {
     av1_set_target_rate(cpi);
   }
 #endif
@@ -3857,6 +3763,7 @@
                        "Failed to allocate frame buffer");
 
 #if CONFIG_LOOP_RESTORATION
+  // TODO(afergs): Use cm->superres_upscaled_(width|height)
   set_restoration_tilesize(cm->width, cm->height, cm->rst_info);
   for (int i = 0; i < MAX_MB_PLANE; ++i)
     cm->rst_info[i].frame_restoration_type = RESTORE_NONE;
@@ -3915,16 +3822,124 @@
 }
 
 static void setup_frame_size(AV1_COMP *cpi) {
-  set_scaled_size(cpi);
-#if CONFIG_FRAME_SUPERRES
   int encode_width;
   int encode_height;
-  av1_calculate_superres_size(cpi, &encode_width, &encode_height);
-  set_frame_size(cpi, encode_width, encode_height);
-#else
-  set_frame_size(cpi, cpi->oxcf.scaled_frame_width,
-                 cpi->oxcf.scaled_frame_height);
+
+  av1_calculate_next_scaled_size(cpi, &encode_width, &encode_height);
+
+#if CONFIG_FRAME_SUPERRES
+  AV1_COMMON *cm = &cpi->common;
+  cm->superres_upscaled_width = encode_width;
+  cm->superres_upscaled_height = encode_height;
+  av1_calculate_next_superres_scale(cpi, encode_width, encode_width);
+  av1_calculate_superres_size(cm, &encode_width, &encode_height);
 #endif  // CONFIG_FRAME_SUPERRES
+
+  set_frame_size(cpi, encode_width, encode_height);
+}
+
+#if CONFIG_FRAME_SUPERRES
+static void superres_post_encode(AV1_COMP *cpi) {
+  AV1_COMMON *cm = &cpi->common;
+
+  if (av1_superres_unscaled(cm)) return;
+
+  assert(cpi->unscaled_source->y_crop_width != cm->superres_upscaled_width);
+  assert(cpi->unscaled_source->y_crop_height != cm->superres_upscaled_height);
+
+  av1_superres_upscale(cm, NULL);
+
+  // If regular resizing is occurring the source will need to be downscaled to
+  // match the upscaled superres resolution. Otherwise the original source is
+  // used.
+  if (av1_resize_unscaled(cm)) {
+    cpi->source = cpi->unscaled_source;
+    if (cpi->last_source != NULL) cpi->last_source = cpi->unscaled_last_source;
+  } else {
+    // Do downscale. cm->(width|height) has been updated by av1_superres_upscale
+    if (aom_realloc_frame_buffer(
+            &cpi->scaled_source, cm->superres_upscaled_width,
+            cm->superres_upscaled_height, cm->subsampling_x, cm->subsampling_y,
+#if CONFIG_HIGHBITDEPTH
+            cm->use_highbitdepth,
+#endif  // CONFIG_HIGHBITDEPTH
+            AOM_BORDER_IN_PIXELS, cm->byte_alignment, NULL, NULL, NULL))
+      aom_internal_error(
+          &cm->error, AOM_CODEC_MEM_ERROR,
+          "Failed to reallocate scaled source buffer for superres");
+    assert(cpi->scaled_source.y_crop_width == cm->superres_upscaled_width);
+    assert(cpi->scaled_source.y_crop_height == cm->superres_upscaled_height);
+#if CONFIG_HIGHBITDEPTH
+    av1_resize_and_extend_frame(cpi->unscaled_source, &cpi->scaled_source,
+                                (int)cm->bit_depth);
+#else
+    av1_resize_and_extend_frame(cpi->unscaled_source, &cpi->scaled_source);
+#endif  // CONFIG_HIGHBITDEPTH
+    cpi->source = &cpi->scaled_source;
+  }
+}
+#endif  // CONFIG_FRAME_SUPERRES
+
+static void loopfilter_frame(AV1_COMP *cpi, AV1_COMMON *cm) {
+  MACROBLOCKD *xd = &cpi->td.mb.e_mbd;
+  struct loopfilter *lf = &cm->lf;
+  if (is_lossless_requested(&cpi->oxcf)) {
+    lf->filter_level = 0;
+  } else {
+    struct aom_usec_timer timer;
+
+    aom_clear_system_state();
+
+    aom_usec_timer_start(&timer);
+
+    av1_pick_filter_level(cpi->source, cpi, cpi->sf.lpf_pick);
+
+    aom_usec_timer_mark(&timer);
+    cpi->time_pick_lpf += aom_usec_timer_elapsed(&timer);
+  }
+
+  if (lf->filter_level > 0) {
+#if CONFIG_VAR_TX || CONFIG_EXT_PARTITION || CONFIG_CB4X4
+    av1_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level, 0, 0);
+#else
+    if (cpi->num_workers > 1)
+      av1_loop_filter_frame_mt(cm->frame_to_show, cm, xd->plane,
+                               lf->filter_level, 0, 0, cpi->workers,
+                               cpi->num_workers, &cpi->lf_row_sync);
+    else
+      av1_loop_filter_frame(cm->frame_to_show, cm, xd, lf->filter_level, 0, 0);
+#endif
+  }
+#if CONFIG_CDEF
+  if (is_lossless_requested(&cpi->oxcf)) {
+    cm->cdef_bits = 0;
+    cm->cdef_strengths[0] = 0;
+    cm->nb_cdef_strengths = 1;
+  } else {
+    // Find cm->dering_level, cm->clpf_strength_u and cm->clpf_strength_v
+    av1_cdef_search(cm->frame_to_show, cpi->source, cm, xd,
+                    cpi->oxcf.speed > 0);
+
+    // Apply the filter
+    av1_cdef_frame(cm->frame_to_show, cm, xd);
+  }
+#endif
+
+#if CONFIG_FRAME_SUPERRES
+  superres_post_encode(cpi);
+#endif  // CONFIG_FRAME_SUPERRES
+
+#if CONFIG_LOOP_RESTORATION
+  av1_pick_filter_restoration(cpi->source, cpi, cpi->sf.lpf_pick);
+  if (cm->rst_info[0].frame_restoration_type != RESTORE_NONE ||
+      cm->rst_info[1].frame_restoration_type != RESTORE_NONE ||
+      cm->rst_info[2].frame_restoration_type != RESTORE_NONE) {
+    av1_loop_restoration_frame(cm->frame_to_show, cm, cm->rst_info, 7, 0, NULL);
+  }
+#endif  // CONFIG_LOOP_RESTORATION
+  // TODO(debargha): Fix mv search range on encoder side
+  // aom_extend_frame_inner_borders(cm->frame_to_show);
+  aom_extend_frame_borders(cm->frame_to_show);
 }
 
 static void reset_use_upsampled_references(AV1_COMP *cpi) {
@@ -3950,30 +3965,24 @@
 
   aom_clear_system_state();
 
-#if CONFIG_FRAME_SUPERRES
-  // TODO(afergs): Figure out when is actually a good time to do superres
-  cm->superres_scale_numerator = SUPERRES_SCALE_DENOMINATOR;
-  // (uint8_t)(rand() % 9 + SUPERRES_SCALE_NUMERATOR_MIN);
-  cpi->superres_pending = cpi->oxcf.superres_enabled && 0;
-#endif  // CONFIG_FRAME_SUPERRES
-
   setup_frame_size(cpi);
-  av1_resize_step(cpi);
+  assert(cm->width == cpi->scaled_source.y_crop_width);
+  assert(cm->height == cpi->scaled_source.y_crop_height);
 
   // For 1 pass CBR under dynamic resize mode: use faster scaling for source.
   // Only for 2x2 scaling for now.
   if (cpi->oxcf.pass == 0 && cpi->oxcf.rc_mode == AOM_CBR &&
       cpi->oxcf.resize_mode == RESIZE_DYNAMIC &&
-      cpi->un_scaled_source->y_width == (cm->width << 1) &&
-      cpi->un_scaled_source->y_height == (cm->height << 1)) {
-    cpi->source = av1_scale_if_required_fast(cm, cpi->un_scaled_source,
+      cpi->unscaled_source->y_width == (cm->width << 1) &&
+      cpi->unscaled_source->y_height == (cm->height << 1)) {
+    cpi->source = av1_scale_if_required_fast(cm, cpi->unscaled_source,
                                              &cpi->scaled_source);
     if (cpi->unscaled_last_source != NULL)
       cpi->last_source = av1_scale_if_required_fast(
           cm, cpi->unscaled_last_source, &cpi->scaled_last_source);
   } else {
     cpi->source =
-        av1_scale_if_required(cm, cpi->un_scaled_source, &cpi->scaled_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);
@@ -4011,11 +4020,6 @@
   // transform / motion compensation build reconstruction frame
   av1_encode_frame(cpi);
 
-#if CONFIG_FRAME_SUPERRES
-  // TODO(afergs): Upscale the frame to show
-  cpi->superres_pending = 0;
-#endif  // CONFIG_FRAME_SUPERRES
-
   // Update some stats from cyclic refresh, and check if we should not update
   // golden reference, for 1 pass CBR.
   if (cpi->oxcf.aq_mode == CYCLIC_REFRESH_AQ && cm->frame_type != KEY_FRAME &&
@@ -4052,11 +4056,7 @@
 
     setup_frame_size(cpi);
 
-#if CONFIG_FRAME_SUPERRES
-    if (loop_count == 0 || av1_resize_pending(cpi) || cpi->superres_pending) {
-#else
-    if (loop_count == 0 || av1_resize_pending(cpi)) {
-#endif  // CONFIG_FRAME_SUPERRES
+    if (loop_count == 0) {
       set_size_dependent_vars(cpi, &q, &bottom_index, &top_index);
 
       // cpi->sf.use_upsampled_references can be different from frame to frame.
@@ -4077,9 +4077,6 @@
       undershoot_seen = 0;
 #endif
 
-      // Advance resize to next state now that updates are done
-      av1_resize_step(cpi);
-
       q_low = bottom_index;
       q_high = top_index;
 
@@ -4094,8 +4091,7 @@
     }
 
     cpi->source =
-        av1_scale_if_required(cm, cpi->un_scaled_source, &cpi->scaled_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);
@@ -4217,8 +4213,6 @@
 #if !CONFIG_XIPHRC
         int retries = 0;
 
-        // TODO(afergs): Replace removed recode when av1_resize_pending is true
-
         // Frame size out of permitted range:
         // Update correction factor & compute new Q to try...
         // Frame is too large
@@ -5532,7 +5526,7 @@
       if ((last_source = av1_lookahead_peek(cpi->lookahead, -1)) == NULL)
         return -1;
     }
-
+    if (cm->current_video_frame > 0) assert(last_source != NULL);
     // Read in the source frame.
     source = av1_lookahead_pop(cpi->lookahead, flush);
 
@@ -5544,11 +5538,9 @@
       check_src_altref(cpi, source);
     }
   }
-
   if (source) {
-    cpi->un_scaled_source = cpi->source =
+    cpi->unscaled_source = cpi->source =
         force_src_buffer ? force_src_buffer : &source->img;
-
     cpi->unscaled_last_source = last_source != NULL ? &last_source->img : NULL;
 
     *time_stamp = source->ts_start;
@@ -5619,7 +5611,6 @@
     av1_rc_get_second_pass_params(cpi);
   } else if (oxcf->pass == 1) {
     setup_frame_size(cpi);
-    av1_resize_step(cpi);
   }
 #endif
 
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index ee1257c..70de507 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -21,6 +21,7 @@
 #include "av1/common/entropymode.h"
 #include "av1/common/thread_common.h"
 #include "av1/common/onyxc_int.h"
+#include "av1/common/resize.h"
 #include "av1/encoder/aq_cyclicrefresh.h"
 #if CONFIG_ANS
 #include "aom_dsp/ans.h"
@@ -372,7 +373,7 @@
 
   YV12_BUFFER_CONFIG *source;
   YV12_BUFFER_CONFIG *last_source;  // NULL for first frame and alt_ref frames
-  YV12_BUFFER_CONFIG *un_scaled_source;
+  YV12_BUFFER_CONFIG *unscaled_source;
   YV12_BUFFER_CONFIG scaled_source;
   YV12_BUFFER_CONFIG *unscaled_last_source;
   YV12_BUFFER_CONFIG scaled_last_source;
@@ -601,18 +602,10 @@
   TileBufferEnc tile_buffers[MAX_TILE_ROWS][MAX_TILE_COLS];
 
   int resize_state;
-  int resize_scale_num;
-  int resize_scale_den;
-  int resize_next_scale_num;
-  int resize_next_scale_den;
   int resize_avg_qp;
   int resize_buffer_underflow;
   int resize_count;
 
-#if CONFIG_FRAME_SUPERRES
-  int superres_pending;
-#endif  // CONFIG_FRAME_SUPERRES
-
   // VARIANCE_AQ segment map refresh
   int vaq_refresh;
 
@@ -831,23 +824,22 @@
   ubufs[new_uidx].ref_count++;
 }
 
-// Returns 1 if a resize is pending and 0 otherwise.
-static INLINE int av1_resize_pending(const struct AV1_COMP *cpi) {
-  return cpi->resize_scale_num != cpi->resize_next_scale_num ||
-         cpi->resize_scale_den != cpi->resize_next_scale_den;
-}
-
 // Returns 1 if a frame is unscaled and 0 otherwise.
-static INLINE int av1_resize_unscaled(const struct AV1_COMP *cpi) {
-  return cpi->resize_scale_num == cpi->resize_scale_den;
+static INLINE int av1_resize_unscaled(const AV1_COMMON *cm) {
+#if CONFIG_FRAME_SUPERRES
+  return cm->superres_upscaled_width == cm->render_width &&
+         cm->superres_upscaled_height == cm->render_height;
+#else
+  return cm->width == cm->render_width && cm->height == cm->render_height;
+#endif  // CONFIG_FRAME_SUPERRES
 }
 
-// Moves resizing to the next state. This is just setting the numerator and
-// denominator to the next numerator and denominator, causing
-// av1_resize_pending to subsequently return false.
-static INLINE void av1_resize_step(struct AV1_COMP *cpi) {
-  cpi->resize_scale_num = cpi->resize_next_scale_num;
-  cpi->resize_scale_den = cpi->resize_next_scale_den;
+static INLINE int av1_frame_unscaled(const AV1_COMMON *cm) {
+#if CONFIG_FRAME_SUPERRES
+  return av1_superres_unscaled(cm) && av1_resize_unscaled(cm);
+#else
+  return av1_resize_unscaled(cm);
+#endif  // CONFIG_FRAME_SUPERRES
 }
 
 #ifdef __cplusplus
diff --git a/av1/encoder/firstpass.c b/av1/encoder/firstpass.c
index 7a0abba..859c60b 100644
--- a/av1/encoder/firstpass.c
+++ b/av1/encoder/firstpass.c
@@ -1231,27 +1231,6 @@
   }
 }
 
-void av1_calculate_next_scaled_size(const AV1_COMP *cpi,
-                                    int *scaled_frame_width,
-                                    int *scaled_frame_height) {
-  *scaled_frame_width =
-      cpi->oxcf.width * cpi->resize_next_scale_num / cpi->resize_next_scale_den;
-  *scaled_frame_height = cpi->oxcf.height * cpi->resize_next_scale_num /
-                         cpi->resize_next_scale_den;
-}
-
-#if CONFIG_FRAME_SUPERRES
-void av1_calculate_superres_size(const AV1_COMP *cpi, int *encoded_width,
-                                 int *encoded_height) {
-  *encoded_width = cpi->oxcf.scaled_frame_width *
-                   cpi->common.superres_scale_numerator /
-                   SUPERRES_SCALE_DENOMINATOR;
-  *encoded_height = cpi->oxcf.scaled_frame_height *
-                    cpi->common.superres_scale_numerator /
-                    SUPERRES_SCALE_DENOMINATOR;
-}
-#endif  // CONFIG_FRAME_SUPERRES
-
 void av1_init_second_pass(AV1_COMP *cpi) {
   const AV1EncoderConfig *const oxcf = &cpi->oxcf;
   TWO_PASS *const twopass = &cpi->twopass;
@@ -2291,12 +2270,6 @@
     twopass->section_intra_rating = calculate_section_intra_ratio(
         start_pos, twopass->stats_in_end, rc->baseline_gf_interval);
   }
-
-  if (oxcf->resize_mode == RESIZE_DYNAMIC) {
-    // Default to starting GF groups at normal frame size.
-    // TODO(afergs): Make a function for this
-    cpi->resize_next_scale_num = cpi->resize_next_scale_den;
-  }
 }
 
 // Threshold for use of the lagging second reference frame. High second ref
@@ -2638,12 +2611,6 @@
   // The count of bits left is adjusted elsewhere based on real coded frame
   // sizes.
   twopass->modified_error_left -= kf_group_err;
-
-  if (oxcf->resize_mode == RESIZE_DYNAMIC) {
-    // Default to normal-sized frame on keyframes.
-    // TODO(afergs): Make a function for this
-    cpi->resize_next_scale_num = cpi->resize_next_scale_den;
-  }
 }
 
 // Define the reference buffers that will be updated post encode.
diff --git a/av1/encoder/firstpass.h b/av1/encoder/firstpass.h
index 4310445..983b3b5 100644
--- a/av1/encoder/firstpass.h
+++ b/av1/encoder/firstpass.h
@@ -177,18 +177,6 @@
 // Post encode update of the rate control parameters for 2-pass
 void av1_twopass_postencode_update(struct AV1_COMP *cpi);
 
-void av1_calculate_next_scaled_size(const struct AV1_COMP *cpi,
-                                    int *scaled_frame_width,
-                                    int *scaled_frame_height);
-
-#if CONFIG_FRAME_SUPERRES
-// This is the size after superress scaling, which could be 1:1.
-// Superres scaling happens after regular downscaling.
-// TODO(afergs): Limit overall reduction to 1/2 of the original size
-void av1_calculate_superres_size(const struct AV1_COMP *cpi, int *encoded_width,
-                                 int *encoded_height);
-#endif  // CONFIG_FRAME_SUPERRES
-
 #if CONFIG_EXT_REFS
 static INLINE int get_number_of_extra_arfs(int interval, int arf_pending) {
   if (arf_pending && MAX_EXT_ARFS > 0)
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 4552c67..ed6e9e6 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -94,8 +94,8 @@
 static int kf_low = 400;
 
 double av1_resize_rate_factor(const AV1_COMP *cpi) {
-  return (double)(cpi->resize_scale_den * cpi->resize_scale_den) /
-         (cpi->resize_scale_num * cpi->resize_scale_num);
+  return (double)(cpi->oxcf.width * cpi->oxcf.height) /
+         (cpi->common.width * cpi->common.height);
 }
 
 // Functions to compute the active minq lookup table entries based on a
@@ -1081,7 +1081,7 @@
   }
 
   // Modify active_best_quality for downscaled normal frames.
-  if (!av1_resize_unscaled(cpi) && !frame_is_kf_gf_arf(cpi)) {
+  if (!av1_frame_unscaled(cm) && !frame_is_kf_gf_arf(cpi)) {
     int qdelta = av1_compute_qdelta_by_rate(
         rc, cm->frame_type, active_best_quality, 2.0, cm->bit_depth);
     active_best_quality =
@@ -1164,7 +1164,7 @@
   rc->this_frame_target = target;
 
   // Modify frame size target when down-scaled.
-  if (cpi->oxcf.resize_mode == RESIZE_DYNAMIC && !av1_resize_unscaled(cpi))
+  if (!av1_frame_unscaled(cm))
     rc->this_frame_target =
         (int)(rc->this_frame_target * av1_resize_rate_factor(cpi));
 
@@ -1663,3 +1663,59 @@
     vbr_rate_correction(cpi, &target_rate);
   av1_rc_set_frame_target(cpi, target_rate);
 }
+
+static unsigned int lcg_rand16(unsigned int *state) {
+  *state = (unsigned int)(*state * 1103515245ULL + 12345);
+  return *state / 65536 % 32768;
+}
+
+void av1_calculate_next_scaled_size(AV1_COMP *cpi, int *width, int *height) {
+  AV1EncoderConfig *oxcf = &cpi->oxcf;
+
+  // TODO(afergs): Get width from frame instead?
+  *width = oxcf->width;
+  *height = oxcf->height;
+
+  if (oxcf->resize_mode == RESIZE_FIXED) {
+    *width = oxcf->scaled_frame_width;
+    *height = oxcf->scaled_frame_height;
+    return;
+  }
+  if (oxcf->resize_mode == RESIZE_DYNAMIC) {
+    // NOTE: RESIZE_DYNAMIC defaults to random now.
+    static unsigned int seed = 56789;
+    if (oxcf->pass == 2 || oxcf->pass == 0) {
+      int scale_num = lcg_rand16(&seed) % 4 + 13;
+      int scale_den = 16;
+      if (!(cpi->oxcf.width * scale_num / scale_den * 2 < oxcf->width ||
+            cpi->oxcf.height * scale_num / scale_den * 2 < oxcf->height)) {
+        *width = cpi->oxcf.width * scale_num / scale_den;
+        *height = cpi->oxcf.height * scale_num / scale_den;
+      }
+    }
+  }
+}
+
+#if CONFIG_FRAME_SUPERRES
+#define RANDOM_SUPERRES 1
+int av1_calculate_next_superres_scale(AV1_COMP *cpi, int width, int height) {
+  const AV1EncoderConfig *oxcf = &cpi->oxcf;
+  (void)width;
+  (void)height;
+  (void)oxcf;
+#if RANDOM_SUPERRES
+  if (cpi->common.frame_type != KEY_FRAME) {
+    if (oxcf->pass == 2 || oxcf->pass == 0) {
+      static unsigned int seed = 34567;
+      int new_num = lcg_rand16(&seed) % 9 + 8;
+      if (new_num * width / SUPERRES_SCALE_DENOMINATOR * 2 < oxcf->width ||
+          new_num * height / SUPERRES_SCALE_DENOMINATOR * 2 < oxcf->height)
+        new_num = SUPERRES_SCALE_DENOMINATOR;
+      cpi->common.superres_scale_numerator = new_num;
+      return new_num;
+    }
+  }
+#endif  // RANDOM_SUPERRES
+  return 16;
+}
+#endif  // CONFIG_FRAME_SUPERRES
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index 61bb0c2..13b1555 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -256,6 +256,12 @@
 
 int av1_resize_one_pass_cbr(struct AV1_COMP *cpi);
 
+void av1_calculate_next_scaled_size(struct AV1_COMP *cpi, int *width,
+                                    int *height);
+#if CONFIG_FRAME_SUPERRES
+int av1_calculate_next_superres_scale(struct AV1_COMP *cpi, int width,
+                                      int height);
+#endif  // CONFIG_FRAME_SUPERRES
 #ifdef __cplusplus
 }  // extern "C"
 #endif