resize-refactor: Refactor 2-pass VBR resizing
Replaces resizing's table and index approach to frame sizes with
numerator and denominator integers in the AV1_COMP struct.
This approach is more flexible and will be simpler going forward as it
is much more similar to the 1-pass CBR approach that is also being
refactored. The intention is to merge both approaches and this is the
first step toward that.
Change-Id: I5733c0687390f8a8e2790dcddfa09fb08ab88376
diff --git a/av1/encoder/encoder.c b/av1/encoder/encoder.c
index 35f9f20..c623bdc 100644
--- a/av1/encoder/encoder.c
+++ b/av1/encoder/encoder.c
@@ -2189,9 +2189,15 @@
memset(cm->fc, 0, sizeof(*cm->fc));
memset(cm->frame_contexts, 0, FRAME_CONTEXTS * sizeof(*cm->frame_contexts));
+ cpi->resize_pending = 0;
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;
init_config(cpi, oxcf);
@@ -3047,11 +3053,18 @@
int scale = 0;
assert(frame_is_kf_gf_arf(cpi));
- if (rc->frame_size_selector == UNSCALED &&
+ if (cpi->resize_scale_num == cpi->resize_scale_den &&
q >= rc->rf_level_maxq[gf_group->rf_level[gf_group->index]]) {
+ const int old_num = cpi->resize_scale_num;
+ --cpi->resize_scale_num;
+ if (cpi->resize_scale_num <= 0) {
+ cpi->resize_scale_num = old_num;
+ return 0;
+ }
const int max_size_thresh =
- (int)(rate_thresh_mult[SCALE_STEP1] *
+ (int)(av1_resize_rate_factor(cpi) *
AOMMAX(rc->this_frame_target, rc->avg_frame_bandwidth));
+ cpi->resize_scale_num = old_num;
scale = rc->projected_frame_size > max_size_thresh ? 1 : 0;
}
return scale;
@@ -4332,9 +4345,13 @@
if (cpi->resize_pending == 1) {
// Change in frame size so go back around the recode loop.
- cpi->rc.frame_size_selector =
- SCALE_STEP1 - cpi->rc.frame_size_selector;
- cpi->rc.next_frame_size_selector = cpi->rc.frame_size_selector;
+ // 11/16 is close to the old 2/3, then goes back to 16/16.
+ cpi->resize_scale_num -= 5;
+ if (cpi->resize_scale_num < 8 || cpi->resize_scale_num > 16)
+ cpi->resize_scale_num = 16;
+ cpi->resize_scale_den = 16;
+ cpi->resize_next_scale_num = cpi->resize_scale_num;
+ cpi->resize_next_scale_den = cpi->resize_scale_den;
#if CONFIG_INTERNAL_STATS
++cpi->tot_recode_hits;
diff --git a/av1/encoder/encoder.h b/av1/encoder/encoder.h
index 4e7aef8..68808a7 100644
--- a/av1/encoder/encoder.h
+++ b/av1/encoder/encoder.h
@@ -629,6 +629,8 @@
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;
diff --git a/av1/encoder/firstpass.c b/av1/encoder/firstpass.c
index e35a54e..109de34 100644
--- a/av1/encoder/firstpass.c
+++ b/av1/encoder/firstpass.c
@@ -1235,27 +1235,12 @@
}
}
-void av1_init_subsampling(AV1_COMP *cpi) {
- const AV1_COMMON *const cm = &cpi->common;
- RATE_CONTROL *const rc = &cpi->rc;
- const int w = cm->width;
- const int h = cm->height;
- int i;
-
- for (i = 0; i < FRAME_SCALE_STEPS; ++i) {
- // Note: Frames with odd-sized dimensions may result from this scaling.
- rc->frame_width[i] = (w * 16) / frame_scale_factor[i];
- rc->frame_height[i] = (h * 16) / frame_scale_factor[i];
- }
-
- setup_rf_level_maxq(cpi);
-}
-
-void av1_calculate_coded_size(AV1_COMP *cpi, int *scaled_frame_width,
+void av1_calculate_coded_size(const AV1_COMP *cpi, int *scaled_frame_width,
int *scaled_frame_height) {
- RATE_CONTROL *const rc = &cpi->rc;
- *scaled_frame_width = rc->frame_width[rc->frame_size_selector];
- *scaled_frame_height = rc->frame_height[rc->frame_size_selector];
+ *scaled_frame_width =
+ cpi->oxcf.width * cpi->resize_scale_num / cpi->resize_scale_den;
+ *scaled_frame_height =
+ cpi->oxcf.height * cpi->resize_scale_num / cpi->resize_scale_den;
}
void av1_init_second_pass(AV1_COMP *cpi) {
@@ -1316,7 +1301,7 @@
twopass->last_kfgroup_zeromotion_pct = 100;
if (oxcf->resize_mode != RESIZE_NONE) {
- av1_init_subsampling(cpi);
+ setup_rf_level_maxq(cpi);
}
}
@@ -2300,7 +2285,8 @@
if (oxcf->resize_mode == RESIZE_DYNAMIC) {
// Default to starting GF groups at normal frame size.
- cpi->rc.next_frame_size_selector = UNSCALED;
+ // TODO(afergs): Make a function for this
+ cpi->resize_next_scale_num = cpi->resize_next_scale_den;
}
}
@@ -2646,7 +2632,8 @@
if (oxcf->resize_mode == RESIZE_DYNAMIC) {
// Default to normal-sized frame on keyframes.
- cpi->rc.next_frame_size_selector = UNSCALED;
+ // TODO(afergs): Make a function for this
+ cpi->resize_next_scale_num = cpi->resize_next_scale_den;
}
}
diff --git a/av1/encoder/firstpass.h b/av1/encoder/firstpass.h
index db459cc..cb893d4 100644
--- a/av1/encoder/firstpass.h
+++ b/av1/encoder/firstpass.h
@@ -177,9 +177,8 @@
// Post encode update of the rate control parameters for 2-pass
void av1_twopass_postencode_update(struct AV1_COMP *cpi);
-void av1_init_subsampling(struct AV1_COMP *cpi);
-
-void av1_calculate_coded_size(struct AV1_COMP *cpi, int *scaled_frame_width,
+void av1_calculate_coded_size(const struct AV1_COMP *cpi,
+ int *scaled_frame_width,
int *scaled_frame_height);
#if CONFIG_EXT_REFS
diff --git a/av1/encoder/ratectrl.c b/av1/encoder/ratectrl.c
index 1f2ea36..8500b83 100644
--- a/av1/encoder/ratectrl.c
+++ b/av1/encoder/ratectrl.c
@@ -93,6 +93,11 @@
static int kf_high = 5000;
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);
+}
+
// Functions to compute the active minq lookup table entries based on a
// formulaic approach to facilitate easier adjustment of the Q tables.
// The formulae were derived from computing a 3rd order polynomial best
@@ -384,7 +389,7 @@
else
rcf = rc->rate_correction_factors[INTER_NORMAL];
}
- rcf *= rcf_mult[rc->frame_size_selector];
+ rcf *= av1_resize_rate_factor(cpi);
return fclamp(rcf, MIN_BPB_FACTOR, MAX_BPB_FACTOR);
}
@@ -392,7 +397,7 @@
RATE_CONTROL *const rc = &cpi->rc;
// Normalize RCF to account for the size-dependent scaling factor.
- factor /= rcf_mult[cpi->rc.frame_size_selector];
+ factor /= av1_resize_rate_factor(cpi);
factor = fclamp(factor, MIN_BPB_FACTOR, MAX_BPB_FACTOR);
@@ -1076,7 +1081,8 @@
}
// Modify active_best_quality for downscaled normal frames.
- if (rc->frame_size_selector != UNSCALED && !frame_is_kf_gf_arf(cpi)) {
+ if (cpi->resize_scale_num != cpi->resize_scale_den &&
+ !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 =
@@ -1160,9 +1166,9 @@
// Modify frame size target when down-scaling.
if (cpi->oxcf.resize_mode == RESIZE_DYNAMIC &&
- rc->frame_size_selector != UNSCALED)
- rc->this_frame_target = (int)(rc->this_frame_target *
- rate_thresh_mult[rc->frame_size_selector]);
+ cpi->resize_scale_num != cpi->resize_scale_den)
+ rc->this_frame_target =
+ (int)(rc->this_frame_target * av1_resize_rate_factor(cpi));
// Target rate per SB64 (including partial SB64s.
rc->sb64_target_rate = (int)((int64_t)rc->this_frame_target * 64 * 64) /
@@ -1321,8 +1327,10 @@
// Trigger the resizing of the next frame if it is scaled.
if (oxcf->pass != 0) {
cpi->resize_pending =
- rc->next_frame_size_selector != rc->frame_size_selector;
- rc->frame_size_selector = rc->next_frame_size_selector;
+ (cpi->resize_next_scale_num != cpi->resize_scale_num ||
+ cpi->resize_next_scale_den != cpi->resize_scale_den);
+ cpi->resize_scale_num = cpi->resize_next_scale_num;
+ cpi->resize_scale_den = cpi->resize_next_scale_den;
}
}
diff --git a/av1/encoder/ratectrl.h b/av1/encoder/ratectrl.h
index 93a9b49..61bb0c2 100644
--- a/av1/encoder/ratectrl.h
+++ b/av1/encoder/ratectrl.h
@@ -49,27 +49,6 @@
} RATE_FACTOR_LEVEL;
#endif // CONFIG_EXT_REFS
-// Internal frame scaling level.
-typedef enum {
- UNSCALED = 0, // Frame is unscaled.
- SCALE_STEP1 = 1, // First-level down-scaling.
- FRAME_SCALE_STEPS
-} FRAME_SCALE_LEVEL;
-
-// Frame dimensions multiplier wrt the native frame size, in 1/16ths,
-// specified for the scale-up case.
-// e.g. 24 => 16/24 = 2/3 of native size. The restriction to 1/16th is
-// intended to match the capabilities of the normative scaling filters,
-// giving precedence to the up-scaling accuracy.
-static const int frame_scale_factor[FRAME_SCALE_STEPS] = { 16, 24 };
-
-// Multiplier of the target rate to be used as threshold for triggering scaling.
-static const double rate_thresh_mult[FRAME_SCALE_STEPS] = { 1.0, 2.0 };
-
-// Scale dependent Rate Correction Factor multipliers. Compensates for the
-// greater number of bits per pixel generated in down-scaled frames.
-static const double rcf_mult[FRAME_SCALE_STEPS] = { 1.0, 2.0 };
-
typedef struct {
// Rate targetting variables
int base_frame_target; // A baseline frame target before adjustment
@@ -162,10 +141,6 @@
int q_2_frame;
// Auto frame-scaling variables.
- FRAME_SCALE_LEVEL frame_size_selector;
- FRAME_SCALE_LEVEL next_frame_size_selector;
- int frame_width[FRAME_SCALE_STEPS];
- int frame_height[FRAME_SCALE_STEPS];
int rf_level_maxq[RATE_FACTOR_LEVELS];
} RATE_CONTROL;
@@ -214,6 +189,10 @@
void av1_rc_get_one_pass_vbr_params(struct AV1_COMP *cpi);
void av1_rc_get_one_pass_cbr_params(struct AV1_COMP *cpi);
+// How many times less pixels there are to encode given the current scaling.
+// Temporary replacement for rcf_mult and rate_thresh_mult.
+double av1_resize_rate_factor(const struct AV1_COMP *cpi);
+
// Post encode update of the rate control parameters based
// on bytes used
void av1_rc_postencode_update(struct AV1_COMP *cpi, uint64_t bytes_used);