Refactor q mode to compute quality along with structure

Now constant quality mode will compute the q values for each frame
in a gf group directly after the group structure is determined.
No change in performance.

Change-Id: Ieb7c04ba3626f3916572fa54fb58163cbdb173b6
diff --git a/av1/encoder/firstpass.h b/av1/encoder/firstpass.h
index 7897015..f10ce3f 100644
--- a/av1/encoder/firstpass.h
+++ b/av1/encoder/firstpass.h
@@ -125,6 +125,10 @@
   int ref_frame_gop_idx[MAX_STATIC_GF_GROUP_LENGTH + 1][REF_FRAMES];
   unsigned char pyramid_height;
   unsigned char pyramid_lvl_nodes[MAX_PYRAMID_LVL];
+  // These are currently only populated for AOM_Q mode
+  unsigned char q_val[MAX_STATIC_GF_GROUP_LENGTH + 1];
+  unsigned char q_upper[MAX_STATIC_GF_GROUP_LENGTH + 1];
+  unsigned char q_lower[MAX_STATIC_GF_GROUP_LENGTH + 1];
   int bit_allocation[MAX_STATIC_GF_GROUP_LENGTH + 1];
   int size;
 } GF_GROUP;
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index ac22b68..a0e3548 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -24,6 +24,7 @@
 #include "av1/encoder/encoder.h"
 #include "av1/encoder/firstpass.h"
 #include "av1/encoder/gop_structure.h"
+#include "av1/encoder/ratectrl.h"
 
 // Calculate an active area of the image that discounts formatting
 // bars and partially discounts other 0 energy areas.
@@ -729,6 +730,52 @@
 #endif  // GROUP_ADAPTIVE_MAXQ
 #define MIN_FWD_KF_INTERVAL 8
 
+static void assign_q_and_bounds_q_mode(AV1_COMP *cpi) {
+  AV1_COMMON *const cm = &cpi->common;
+  GF_GROUP *const gf_group = &cpi->twopass.gf_group;
+  const int width = cm->width;
+  const int height = cm->height;
+  RATE_CONTROL *const rc = &cpi->rc;
+  const int last_boosted_q = rc->last_boosted_qindex;
+  const int last_kf_q = rc->last_kf_qindex;
+  const int avg_frame_qindex = rc->avg_frame_qindex[INTER_FRAME];
+  int bottom_index, top_index;
+  int q;
+
+  for (int cur_index = 0; cur_index <= gf_group->size; ++cur_index) {
+    const FRAME_UPDATE_TYPE cur_update_type = gf_group->update_type[cur_index];
+    int arf_q = -1;  // Initialize to invalid value, for sanity check later.
+
+    q = av1_get_q_and_bounds_constant_quality_two_pass(
+        cpi, width, height, &bottom_index, &top_index, &arf_q, cur_index);
+    if (cur_update_type == ARF_UPDATE) {
+      cpi->rc.arf_q = arf_q;
+    }
+    gf_group->q_val[cur_index] = q;
+    gf_group->q_upper[cur_index] = top_index;
+    gf_group->q_lower[cur_index] = bottom_index;
+
+    // Update the rate control state necessary to accuratly compute q for
+    // the next frames.
+    // This is used to help set quality in forced key frames to reduce popping
+    if ((q < rc->last_boosted_qindex) || (cur_update_type == KF_UPDATE) ||
+        (!rc->constrained_gf_group && (cur_update_type == ARF_UPDATE ||
+                                       cur_update_type == INTNL_ARF_UPDATE ||
+                                       cur_update_type == GF_UPDATE))) {
+      rc->last_boosted_qindex = q;
+    }
+    // TODO(sarahparker) Investigate whether or not this is actually needed
+    if (cur_update_type == LF_UPDATE)
+      rc->avg_frame_qindex[INTER_FRAME] =
+          ROUND_POWER_OF_TWO(3 * rc->avg_frame_qindex[INTER_FRAME] + q, 2);
+    if (cur_update_type == KF_UPDATE) rc->last_kf_qindex = q;
+  }
+  // Reset all of the modified state to the original values.
+  rc->last_boosted_qindex = last_boosted_q;
+  rc->last_kf_qindex = last_kf_q;
+  rc->avg_frame_qindex[INTER_FRAME] = avg_frame_qindex;
+}
+
 // Analyse and define a gf/arf group.
 static void define_gf_group(AV1_COMP *cpi, FIRSTPASS_STATS *this_frame,
                             const EncodeFrameParams *const frame_params) {
@@ -1071,6 +1118,8 @@
   // Set up the structure of this Group-Of-Pictures (same as GF_GROUP)
   av1_gop_setup_structure(cpi, frame_params);
 
+  if (cpi->oxcf.rc_mode == AOM_Q) assign_q_and_bounds_q_mode(cpi);
+
   // Allocate bits to each of the frames in the GF group.
   allocate_gf_group_bits(cpi, gf_group_bits, gf_group_error_left, gf_arf_bits,
                          frame_params);
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 9e527d4..e075dc3 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -1029,7 +1029,7 @@
 static void get_intra_q_and_bounds_two_pass(const AV1_COMP *cpi, int width,
                                             int height, int *active_best,
                                             int *active_worst, int *arf_q,
-                                            int cq_level) {
+                                            int cq_level, int is_fwd_kf) {
   const AV1_COMMON *const cm = &cpi->common;
   const RATE_CONTROL *const rc = &cpi->rc;
   const AV1EncoderConfig *const oxcf = &cpi->oxcf;
@@ -1043,7 +1043,7 @@
     // as q.
     active_best_quality = cq_level;
     active_worst_quality = cq_level;
-  } else if (cm->current_frame.frame_type == KEY_FRAME && cm->show_frame == 0) {
+  } else if (is_fwd_kf) {
     // Handle the special case for forward reference key frames.
     // Increase the boost because this keyframe is used as a forward and
     // backward reference.
@@ -1116,12 +1116,12 @@
                  0);
     }
   }
-
   *active_best = active_best_quality;
   *active_worst = active_worst_quality;
 }
 
-// Does some final adjustments to the q value and bounds.
+// Does some final adjustments to the q value and bounds. This does not apply to
+// AOM_Q mode unless it is an INTRA_ONLY_FRAME.
 static void postprocess_q_and_bounds(const AV1_COMP *cpi, int width, int height,
                                      int *active_worst, int *active_best,
                                      int *q_out, int is_intrl_arf_boost) {
@@ -1132,6 +1132,8 @@
   int active_best_quality = *active_best;
   int active_worst_quality = *active_worst;
   int q;
+  assert(IMPLIES(cpi->oxcf.rc_mode == AOM_Q,
+                 cm->current_frame.frame_type == INTRA_ONLY_FRAME));
 
   // Extension to max or min Q if undershoot or overshoot is outside
   // the permitted range.
@@ -1204,6 +1206,106 @@
   *q_out = q;
 }
 
+// Get the value for q and its upper and lower bounds for consant quality mode.
+// This is called for every frame in a gf group right after the gf structure is
+// determined.
+int av1_get_q_and_bounds_constant_quality_two_pass(const AV1_COMP *cpi,
+                                                   int width, int height,
+                                                   int *bottom_index,
+                                                   int *top_index, int *arf_q,
+                                                   int gf_index) {
+  const AV1_COMMON *const cm = &cpi->common;
+  const RATE_CONTROL *const rc = &cpi->rc;
+  const GF_GROUP *gf_group = &cpi->twopass.gf_group;
+  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);
+  int active_best_quality = 0;
+  int active_worst_quality = cpi->twopass.active_worst_quality;
+  int q;
+  const int bit_depth = cm->seq_params.bit_depth;
+
+  const int is_intrl_arf_boost =
+      gf_group->update_type[gf_index] == INTNL_ARF_UPDATE;
+
+  const int is_boosted_frame = gf_group->update_type[gf_index] == GF_UPDATE ||
+                               gf_group->update_type[gf_index] == ARF_UPDATE ||
+                               is_intrl_arf_boost;
+
+  int is_fwd_kf = 0;
+  if (gf_group->update_type[gf_index] == ARF_UPDATE) {
+    assert(is_altref_enabled(cpi));
+    const int arf_src_index = gf_group->arf_src_offset[gf_index];
+    is_fwd_kf = arf_src_index == (rc->frames_to_key - 1);
+  }
+
+  if (gf_group->update_type[gf_index] == KF_UPDATE || is_fwd_kf) {
+    get_intra_q_and_bounds_two_pass(cpi, width, height, &active_best_quality,
+                                    &active_worst_quality, arf_q, cq_level,
+                                    is_fwd_kf);
+  } else if (is_boosted_frame) {
+    // Use the lower of active_worst_quality and recent
+    // average Q as basis for GF/ARF best Q limit unless last frame was
+    // a key frame.
+    if (gf_group->update_type[0] != KF_UPDATE &&
+        rc->avg_frame_qindex[INTER_FRAME] < active_worst_quality) {
+      q = rc->avg_frame_qindex[INTER_FRAME];
+    } else {
+      q = active_worst_quality;
+    }
+    if (gf_group->update_type[gf_index] != ARF_UPDATE && !is_intrl_arf_boost) {
+      active_best_quality = cq_level;
+    } else {
+      if (gf_group->update_type[gf_index] == ARF_UPDATE) {
+        active_best_quality = get_gf_active_quality(rc, q, bit_depth);
+        const int min_boost = get_gf_high_motion_quality(q, bit_depth);
+        const int boost = min_boost - active_best_quality;
+
+        active_best_quality = min_boost - (int)(boost * rc->arf_boost_factor);
+        *arf_q = active_best_quality;
+      } else {
+        assert(rc->arf_q >= 0);  // Ensure it is set to a valid value.
+        assert(is_intrl_arf_boost);
+        active_best_quality = rc->arf_q;
+        int this_height = gf_group->pyramid_level[gf_index];
+        while (this_height < gf_group->pyramid_height) {
+          active_best_quality = (active_best_quality + cq_level + 1) / 2;
+          ++this_height;
+        }
+      }
+    }
+  } else {
+    active_best_quality = cq_level;
+  }
+
+  aom_clear_system_state();
+  // Static forced key frames Q restrictions dealt with elsewhere.
+  if ((gf_group->update_type[gf_index] != KF_UPDATE) ||
+      !rc->this_key_frame_forced ||
+      (cpi->twopass.last_kfgroup_zeromotion_pct < STATIC_MOTION_THRESH)) {
+    const int qdelta = av1_frame_type_qdelta(cpi, active_worst_quality);
+    active_worst_quality =
+        AOMMAX(active_worst_quality + qdelta, active_best_quality);
+  }
+
+  active_best_quality =
+      clamp(active_best_quality, rc->best_quality, rc->worst_quality);
+  active_worst_quality =
+      clamp(active_worst_quality, active_best_quality, rc->worst_quality);
+
+  q = active_best_quality;
+  clamp(q, active_best_quality, active_worst_quality);
+
+  *top_index = active_worst_quality;
+  *bottom_index = active_best_quality;
+
+  assert(*top_index <= rc->worst_quality && *top_index >= rc->best_quality);
+  assert(*bottom_index <= rc->worst_quality &&
+         *bottom_index >= rc->best_quality);
+  assert(q <= rc->worst_quality && q >= rc->best_quality);
+  return q;
+}
+
 static int rc_pick_q_and_bounds_two_pass(const AV1_COMP *cpi, int width,
                                          int height, int *bottom_index,
                                          int *top_index, int *arf_q) {
@@ -1213,7 +1315,7 @@
   const GF_GROUP *gf_group = &cpi->twopass.gf_group;
   const int cq_level = get_active_cq_level(rc, oxcf, frame_is_intra_only(cm),
                                            cm->superres_scale_denominator);
-  int active_best_quality;
+  int active_best_quality = 0;
   int active_worst_quality = cpi->twopass.active_worst_quality;
   int q;
   int *inter_minq;
@@ -1222,9 +1324,38 @@
 
   const int is_intrl_arf_boost =
       gf_group->update_type[gf_group->index] == INTNL_ARF_UPDATE;
+
+  // AOM_Q mode determines quality when the gf structure is created. The only
+  // case in which the q values from this process are unreliable is for an
+  // INTRA_ONLY frame or superres scaled frame.
+  if (oxcf->rc_mode == AOM_Q &&
+      cm->current_frame.frame_type != INTRA_ONLY_FRAME) {
+    // Modify active_best_quality and q for downscaled normal frames.
+    if (av1_frame_scaled(cm) && !frame_is_kf_gf_arf(cpi)) {
+      const int qdelta =
+          av1_compute_qdelta_by_rate(rc, cm->current_frame.frame_type,
+                                     active_best_quality, 2.0, bit_depth);
+      active_best_quality =
+          AOMMAX(active_best_quality + qdelta, rc->best_quality);
+      active_best_quality =
+          clamp(active_best_quality, rc->best_quality, rc->worst_quality);
+
+      *top_index = gf_group->q_upper[gf_group->index];
+      *bottom_index = active_best_quality;
+      // The q value is set to active_best_quality in AOM_Q mode
+      return active_best_quality;
+    }
+    *top_index = gf_group->q_upper[gf_group->index];
+    *bottom_index = gf_group->q_lower[gf_group->index];
+    return gf_group->q_val[gf_group->index];
+  }
+
   if (frame_is_intra_only(cm)) {
+    const int is_fwd_kf =
+        cm->current_frame.frame_type == KEY_FRAME && cm->show_frame == 0;
     get_intra_q_and_bounds_two_pass(cpi, width, height, &active_best_quality,
-                                    &active_worst_quality, arf_q, cq_level);
+                                    &active_worst_quality, arf_q, cq_level,
+                                    is_fwd_kf);
   } else if (!rc->is_src_frame_alt_ref &&
              (cpi->refresh_golden_frame || is_intrl_arf_boost ||
               cpi->refresh_alt_ref_frame)) {
@@ -1261,28 +1392,6 @@
           ++this_height;
         }
       }
-    } else if (oxcf->rc_mode == AOM_Q) {
-      if (!cpi->refresh_alt_ref_frame && !is_intrl_arf_boost) {
-        active_best_quality = cq_level;
-      } else {
-        if (gf_group->update_type[gf_group->index] == ARF_UPDATE) {
-          active_best_quality = get_gf_active_quality(rc, q, bit_depth);
-          const int min_boost = get_gf_high_motion_quality(q, bit_depth);
-          const int boost = min_boost - active_best_quality;
-
-          active_best_quality = min_boost - (int)(boost * rc->arf_boost_factor);
-          *arf_q = active_best_quality;
-        } else {
-          assert(rc->arf_q >= 0);  // Ensure it is set to a valid value.
-          assert(is_intrl_arf_boost);
-          active_best_quality = rc->arf_q;
-          int this_height = gf_group_pyramid_level(cpi);
-          while (this_height < gf_group->pyramid_height) {
-            active_best_quality = (active_best_quality + cq_level + 1) / 2;
-            ++this_height;
-          }
-        }
-      }
     } else {
       active_best_quality = get_gf_active_quality(rc, q, bit_depth);
       const int min_boost = get_gf_high_motion_quality(q, bit_depth);
@@ -1299,16 +1408,12 @@
       }
     }
   } else {
-    if (oxcf->rc_mode == AOM_Q) {
-      active_best_quality = cq_level;
-    } else {
-      active_best_quality = inter_minq[active_worst_quality];
+    active_best_quality = inter_minq[active_worst_quality];
 
-      // For the constrained quality mode we don't want
-      // q to fall below the cq level.
-      if ((oxcf->rc_mode == AOM_CQ) && (active_best_quality < cq_level)) {
-        active_best_quality = cq_level;
-      }
+    // For the constrained quality mode we don't want
+    // q to fall below the cq level.
+    if ((oxcf->rc_mode == AOM_CQ) && (active_best_quality < cq_level)) {
+      active_best_quality = cq_level;
     }
   }
 
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index 1cd5994..39c13cb 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -263,6 +263,12 @@
 
 int av1_resize_one_pass_cbr(struct AV1_COMP *cpi);
 
+int av1_get_q_and_bounds_constant_quality_two_pass(const struct AV1_COMP *cpi,
+                                                   int width, int height,
+                                                   int *bottom_index,
+                                                   int *top_index, int *arf_q,
+                                                   int gf_index);
+
 #ifdef __cplusplus
 }  // extern "C"
 #endif