Commit 883c1ab25b for aom
commit 883c1ab25b51b561b333749d7a840934c618a9a9
Author: Lin Zheng <linzhen@google.com>
Date: Mon Jun 22 16:56:17 2026 +0000
Tweak the rc worst_quality decision
Lowering the qindex on the gf group with higher stationarity and
smaller coded error improves coding efficiency, with a reasonable
iso-quality enc-time trade-off for both ugc1080p and shorts content.
Neutral impact on other testsets.
vbr-mode, speed 0 to speed 4 average:
ssim/psnr1411/vmaf/vmaf_neg/iso-enc-time
ugc1080p -0.67%/-0.63%/-0.58%/-0.50%/0.82%
shorts_608p -0.22%/-0.25%/-0.23%/-0.21%/0.57%
shorts_720p_public -0.03%/-0.02%/-0.15%/-0.12%/0.71%
Change-Id: Ifb2db85bbf29db7c94b2ebd9a3bb6424b59faacc
diff --git a/av1/encoder/pass2_strategy.c b/av1/encoder/pass2_strategy.c
index 19ce429368..7af5bcf540 100644
--- a/av1/encoder/pass2_strategy.c
+++ b/av1/encoder/pass2_strategy.c
@@ -168,8 +168,13 @@ static const double q_pow_term[(QINDEX_RANGE >> 5) + 1] = { 0.65, 0.70, 0.75,
0.80, 0.85, 0.90,
0.95, 0.95, 0.95 };
#define ERR_DIVISOR 96.0
-static double calc_correction_factor(double err_per_mb, int q) {
- const double error_term = err_per_mb / ERR_DIVISOR;
+static double calc_correction_factor(double err_per_mb, int q,
+ double inactive_zone,
+ bool lower_qindex_on_static_frame) {
+ double error_term = err_per_mb / ERR_DIVISOR;
+ if (lower_qindex_on_static_frame) {
+ error_term = error_term * (1 - AOMMIN(0.6, inactive_zone));
+ }
const int index = q >> 5;
// Adjustment to power term based on qindex
const double power_term =
@@ -319,15 +324,17 @@ static int qbpm_enumerator(int rate_err_tol, bool use_smaller_enumerator) {
// calculation of a correction_factor.
static int find_qindex_by_rate_with_correction(
uint64_t desired_bits_per_mb, aom_bit_depth_t bit_depth,
- double error_per_mb, double group_weight_factor, int rate_err_tol,
- int best_qindex, int worst_qindex, bool use_smaller_enumerator) {
+ double error_per_mb, bool lower_qindex_on_static_frame,
+ double group_weight_factor, int rate_err_tol, int best_qindex,
+ int worst_qindex, bool use_smaller_enumerator, double inactive_zone) {
assert(best_qindex <= worst_qindex);
int low = best_qindex;
int high = worst_qindex;
while (low < high) {
const int mid = (low + high) >> 1;
- const double mid_factor = calc_correction_factor(error_per_mb, mid);
+ const double mid_factor = calc_correction_factor(
+ error_per_mb, mid, inactive_zone, lower_qindex_on_static_frame);
const double q = av1_convert_qindex_to_q(mid, bit_depth);
const int enumerator =
qbpm_enumerator(rate_err_tol, use_smaller_enumerator);
@@ -392,12 +399,28 @@ static int get_twopass_worst_quality(AV1_COMP *cpi, const double av_frame_err,
// Update bpm correction factor based on previous GOP rate error.
twopass_update_bpm_factor(cpi, rate_err_tol);
+ int baseline_gf_interval = cpi->ppi->p_rc.baseline_gf_interval - 1;
+ const FIRSTPASS_STATS *cur_arf_stats = av1_firstpass_info_peek(
+ &cpi->ppi->twopass.firstpass_info, baseline_gf_interval);
+
+ bool lower_qindex_on_static_frame = false;
+
+ if (cur_arf_stats != NULL) {
+ // The changes are only applied if the coded_error of the current
+ // gf_group's arf frame does not significantly exceed the group's average
+ // error. It serves as a safeguard for certain corner cases that arf
+ // frames might not be good enough.
+ lower_qindex_on_static_frame =
+ (cur_arf_stats->coded_error < 2 * av_err_per_mb);
+ }
+
// Try and pick a max Q that will be high enough to encode the
// content at the given rate.
int q = find_qindex_by_rate_with_correction(
target_norm_bits_per_mb, cpi->common.seq_params->bit_depth,
- av_err_per_mb, cpi->ppi->twopass.bpm_factor, rate_err_tol,
- rc->best_quality, rc->worst_quality, use_smaller_enumerator);
+ av_err_per_mb, lower_qindex_on_static_frame,
+ cpi->ppi->twopass.bpm_factor, rate_err_tol, rc->best_quality,
+ rc->worst_quality, use_smaller_enumerator, inactive_zone);
// Restriction on active max q for constrained quality mode.
if (rc_cfg->mode == AOM_CQ) q = AOMMAX(q, rc_cfg->cq_level);