Commit e378a89b authored by Deb Mukherjee's avatar Deb Mukherjee

Support a constant quality mode in VP9

Adds a new end-usage option for constant quality encoding in vpx. This
first version implemented for VP9, encodes all regular inter frames
using the quality specified in the --cq-level= option, while encoding
all key frames and golden/altref frames at a quality better than that.

The current performance on derfraw300 is +0.910% up from bitrate control,
but achieved without multiple recode loops per frame.

The decision for qp for each altref/golden/key frame will be improved
in subsequent patches based on better use of stats from the first pass.
Further, the qp for regular inter frames may also be varied around the
provided cq-level.

Change-Id: I6c4a2a68563679d60e0616ebcb11698578615fb3
parent e4e86458
...@@ -41,7 +41,8 @@ extern "C" ...@@ -41,7 +41,8 @@ extern "C"
{ {
USAGE_STREAM_FROM_SERVER = 0x0, USAGE_STREAM_FROM_SERVER = 0x0,
USAGE_LOCAL_FILE_PLAYBACK = 0x1, USAGE_LOCAL_FILE_PLAYBACK = 0x1,
USAGE_CONSTRAINED_QUALITY = 0x2 USAGE_CONSTRAINED_QUALITY = 0x2,
USAGE_CONSTANT_QUALITY = 0x3
} END_USAGE; } END_USAGE;
......
...@@ -153,7 +153,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, ...@@ -153,7 +153,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx,
#else #else
RANGE_CHECK_HI(cfg, g_lag_in_frames, 25); RANGE_CHECK_HI(cfg, g_lag_in_frames, 25);
#endif #endif
RANGE_CHECK(cfg, rc_end_usage, VPX_VBR, VPX_CQ); RANGE_CHECK(cfg, rc_end_usage, VPX_VBR, VPX_Q);
RANGE_CHECK_HI(cfg, rc_undershoot_pct, 1000); RANGE_CHECK_HI(cfg, rc_undershoot_pct, 1000);
RANGE_CHECK_HI(cfg, rc_overshoot_pct, 1000); RANGE_CHECK_HI(cfg, rc_overshoot_pct, 1000);
RANGE_CHECK_HI(cfg, rc_2pass_vbr_bias_pct, 100); RANGE_CHECK_HI(cfg, rc_2pass_vbr_bias_pct, 100);
...@@ -204,7 +204,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx, ...@@ -204,7 +204,7 @@ static vpx_codec_err_t validate_config(vpx_codec_alg_priv_t *ctx,
RANGE_CHECK_HI(vp8_cfg, arnr_strength, 6); RANGE_CHECK_HI(vp8_cfg, arnr_strength, 6);
RANGE_CHECK(vp8_cfg, arnr_type, 1, 3); RANGE_CHECK(vp8_cfg, arnr_type, 1, 3);
RANGE_CHECK(vp8_cfg, cq_level, 0, 63); RANGE_CHECK(vp8_cfg, cq_level, 0, 63);
if(finalize && cfg->rc_end_usage == VPX_CQ) if (finalize && (cfg->rc_end_usage == VPX_CQ || cfg->rc_end_usage == VPX_Q))
RANGE_CHECK(vp8_cfg, cq_level, RANGE_CHECK(vp8_cfg, cq_level,
cfg->rc_min_quantizer, cfg->rc_max_quantizer); cfg->rc_min_quantizer, cfg->rc_max_quantizer);
...@@ -327,17 +327,14 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf, ...@@ -327,17 +327,14 @@ static vpx_codec_err_t set_vp8e_config(VP8_CONFIG *oxcf,
oxcf->resample_up_water_mark = cfg.rc_resize_up_thresh; oxcf->resample_up_water_mark = cfg.rc_resize_up_thresh;
oxcf->resample_down_water_mark = cfg.rc_resize_down_thresh; oxcf->resample_down_water_mark = cfg.rc_resize_down_thresh;
if (cfg.rc_end_usage == VPX_VBR) if (cfg.rc_end_usage == VPX_VBR) {
{ oxcf->end_usage = USAGE_LOCAL_FILE_PLAYBACK;
oxcf->end_usage = USAGE_LOCAL_FILE_PLAYBACK; } else if (cfg.rc_end_usage == VPX_CBR) {
} oxcf->end_usage = USAGE_STREAM_FROM_SERVER;
else if (cfg.rc_end_usage == VPX_CBR) } else if (cfg.rc_end_usage == VPX_CQ) {
{ oxcf->end_usage = USAGE_CONSTRAINED_QUALITY;
oxcf->end_usage = USAGE_STREAM_FROM_SERVER; } else if (cfg.rc_end_usage == VPX_Q) {
} oxcf->end_usage = USAGE_CONSTANT_QUALITY;
else if (cfg.rc_end_usage == VPX_CQ)
{
oxcf->end_usage = USAGE_CONSTRAINED_QUALITY;
} }
oxcf->target_bandwidth = cfg.rc_target_bitrate; oxcf->target_bandwidth = cfg.rc_target_bitrate;
......
...@@ -46,7 +46,8 @@ extern "C" ...@@ -46,7 +46,8 @@ extern "C"
typedef enum { typedef enum {
USAGE_STREAM_FROM_SERVER = 0x0, USAGE_STREAM_FROM_SERVER = 0x0,
USAGE_LOCAL_FILE_PLAYBACK = 0x1, USAGE_LOCAL_FILE_PLAYBACK = 0x1,
USAGE_CONSTRAINED_QUALITY = 0x2 USAGE_CONSTRAINED_QUALITY = 0x2,
USAGE_CONSTANT_QUALITY = 0x3,
} END_USAGE; } END_USAGE;
......
...@@ -1092,7 +1092,6 @@ static int estimate_cq(VP9_COMP *cpi, ...@@ -1092,7 +1092,6 @@ static int estimate_cq(VP9_COMP *cpi,
return q; return q;
} }
extern void vp9_new_framerate(VP9_COMP *cpi, double framerate); extern void vp9_new_framerate(VP9_COMP *cpi, double framerate);
void vp9_init_second_pass(VP9_COMP *cpi) { void vp9_init_second_pass(VP9_COMP *cpi) {
...@@ -2079,63 +2078,71 @@ void vp9_second_pass(VP9_COMP *cpi) { ...@@ -2079,63 +2078,71 @@ void vp9_second_pass(VP9_COMP *cpi) {
vp9_clear_system_state(); vp9_clear_system_state();
// Special case code for first frame. if (cpi->oxcf.end_usage == USAGE_CONSTANT_QUALITY) {
if (cpi->common.current_video_frame == 0) { cpi->active_worst_quality = cpi->oxcf.cq_level;
cpi->twopass.est_max_qcorrection_factor = 1.0; } else {
// Special case code for first frame.
// Set a cq_level in constrained quality mode. if (cpi->common.current_video_frame == 0) {
if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) { int section_target_bandwidth =
int est_cq = estimate_cq(cpi, &cpi->twopass.total_left_stats, (int)(cpi->twopass.bits_left / frames_left);
(int)(cpi->twopass.bits_left / frames_left)); cpi->twopass.est_max_qcorrection_factor = 1.0;
cpi->cq_target_quality = cpi->oxcf.cq_level; // Set a cq_level in constrained quality mode.
if (est_cq > cpi->cq_target_quality) if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) {
cpi->cq_target_quality = est_cq; int est_cq = estimate_cq(cpi, &cpi->twopass.total_left_stats,
} section_target_bandwidth);
cpi->cq_target_quality = cpi->oxcf.cq_level;
if (est_cq > cpi->cq_target_quality)
cpi->cq_target_quality = est_cq;
}
// guess at maxq needed in 2nd pass // guess at maxq needed in 2nd pass
cpi->twopass.maxq_max_limit = cpi->worst_quality; cpi->twopass.maxq_max_limit = cpi->worst_quality;
cpi->twopass.maxq_min_limit = cpi->best_quality; cpi->twopass.maxq_min_limit = cpi->best_quality;
tmp_q = estimate_max_q(cpi, &cpi->twopass.total_left_stats, tmp_q = estimate_max_q(cpi, &cpi->twopass.total_left_stats,
(int)(cpi->twopass.bits_left / frames_left)); section_target_bandwidth);
cpi->active_worst_quality = tmp_q; cpi->active_worst_quality = tmp_q;
cpi->ni_av_qi = tmp_q; cpi->ni_av_qi = tmp_q;
cpi->avg_q = vp9_convert_qindex_to_q(tmp_q); cpi->avg_q = vp9_convert_qindex_to_q(tmp_q);
#ifndef ONE_SHOT_Q_ESTIMATE #ifndef ONE_SHOT_Q_ESTIMATE
// Limit the maxq value returned subsequently. // Limit the maxq value returned subsequently.
// This increases the risk of overspend or underspend if the initial // This increases the risk of overspend or underspend if the initial
// estimate for the clip is bad, but helps prevent excessive // estimate for the clip is bad, but helps prevent excessive
// variation in Q, especially near the end of a clip // variation in Q, especially near the end of a clip
// where for example a small overspend may cause Q to crash // where for example a small overspend may cause Q to crash
adjust_maxq_qrange(cpi); adjust_maxq_qrange(cpi);
#endif #endif
} }
#ifndef ONE_SHOT_Q_ESTIMATE #ifndef ONE_SHOT_Q_ESTIMATE
// The last few frames of a clip almost always have to few or too many // The last few frames of a clip almost always have to few or too many
// bits and for the sake of over exact rate control we dont want to make // bits and for the sake of over exact rate control we dont want to make
// radical adjustments to the allowed quantizer range just to use up a // radical adjustments to the allowed quantizer range just to use up a
// few surplus bits or get beneath the target rate. // few surplus bits or get beneath the target rate.
else if ((cpi->common.current_video_frame < else if ((cpi->common.current_video_frame <
(((unsigned int)cpi->twopass.total_stats.count * 255) >> 8)) && (((unsigned int)cpi->twopass.total_stats.count * 255) >> 8)) &&
((cpi->common.current_video_frame + cpi->baseline_gf_interval) < ((cpi->common.current_video_frame + cpi->baseline_gf_interval) <
(unsigned int)cpi->twopass.total_stats.count)) { (unsigned int)cpi->twopass.total_stats.count)) {
if (frames_left < 1) int section_target_bandwidth =
frames_left = 1; (int)(cpi->twopass.bits_left / frames_left);
if (frames_left < 1)
tmp_q = estimate_max_q( frames_left = 1;
cpi,
&cpi->twopass.total_left_stats, tmp_q = estimate_max_q(
(int)(cpi->twopass.bits_left / frames_left)); cpi,
&cpi->twopass.total_left_stats,
// Make a damped adjustment to active max Q section_target_bandwidth);
cpi->active_worst_quality =
adjust_active_maxq(cpi->active_worst_quality, tmp_q); // Make a damped adjustment to active max Q
} cpi->active_worst_quality =
adjust_active_maxq(cpi->active_worst_quality, tmp_q);
}
#endif #endif
}
vp9_zero(this_frame); vp9_zero(this_frame);
if (EOF == input_stats(cpi, &this_frame)) if (EOF == input_stats(cpi, &this_frame))
return; return;
......
...@@ -2714,9 +2714,9 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, ...@@ -2714,9 +2714,9 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
if (cm->frame_type == KEY_FRAME) { if (cm->frame_type == KEY_FRAME) {
#if !CONFIG_MULTIPLE_ARF #if !CONFIG_MULTIPLE_ARF
// Special case for key frames forced because we have reached // Special case for key frames forced because we have reached
// the maximum key frame interval. Here force the Q to a range // the maximum key frame interval. Here force the Q to a range
// based on the ambient Q to reduce the risk of popping // based on the ambient Q to reduce the risk of popping
if (cpi->this_key_frame_forced) { if (cpi->this_key_frame_forced) {
int delta_qindex; int delta_qindex;
int qindex = cpi->last_boosted_qindex; int qindex = cpi->last_boosted_qindex;
...@@ -2725,7 +2725,8 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, ...@@ -2725,7 +2725,8 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
delta_qindex = compute_qdelta(cpi, last_boosted_q, delta_qindex = compute_qdelta(cpi, last_boosted_q,
(last_boosted_q * 0.75)); (last_boosted_q * 0.75));
cpi->active_best_quality = MAX(qindex + delta_qindex, cpi->best_quality); cpi->active_best_quality = MAX(qindex + delta_qindex,
cpi->best_quality);
} else { } else {
int high = 5000; int high = 5000;
int low = 400; int low = 400;
...@@ -2746,7 +2747,6 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, ...@@ -2746,7 +2747,6 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
cpi->active_best_quality = kf_low_motion_minq[q] + adjustment; cpi->active_best_quality = kf_low_motion_minq[q] + adjustment;
} }
// Allow somewhat lower kf minq with small image formats. // Allow somewhat lower kf minq with small image formats.
if ((cm->width * cm->height) <= (352 * 288)) { if ((cm->width * cm->height) <= (352 * 288)) {
q_adj_factor -= 0.25; q_adj_factor -= 0.25;
...@@ -2755,14 +2755,14 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, ...@@ -2755,14 +2755,14 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
// Make a further adjustment based on the kf zero motion measure. // Make a further adjustment based on the kf zero motion measure.
q_adj_factor += 0.05 - (0.001 * (double)cpi->kf_zeromotion_pct); q_adj_factor += 0.05 - (0.001 * (double)cpi->kf_zeromotion_pct);
// Convert the adjustment factor to a qindex delta on active_best_quality. // Convert the adjustment factor to a qindex delta
// on active_best_quality.
q_val = vp9_convert_qindex_to_q(cpi->active_best_quality); q_val = vp9_convert_qindex_to_q(cpi->active_best_quality);
cpi->active_best_quality += cpi->active_best_quality +=
compute_qdelta(cpi, q_val, (q_val * q_adj_factor)); compute_qdelta(cpi, q_val, (q_val * q_adj_factor));
} }
#else #else
double current_q; double current_q;
// Force the KF quantizer to be 30% of the active_worst_quality. // Force the KF quantizer to be 30% of the active_worst_quality.
current_q = vp9_convert_qindex_to_q(cpi->active_worst_quality); current_q = vp9_convert_qindex_to_q(cpi->active_worst_quality);
cpi->active_best_quality = cpi->active_worst_quality cpi->active_best_quality = cpi->active_worst_quality
...@@ -2779,13 +2779,11 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, ...@@ -2779,13 +2779,11 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
cpi->avg_frame_qindex < cpi->active_worst_quality) { cpi->avg_frame_qindex < cpi->active_worst_quality) {
q = cpi->avg_frame_qindex; q = cpi->avg_frame_qindex;
} }
// For constrained quality dont allow Q less than the cq level // For constrained quality dont allow Q less than the cq level
if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY && if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY &&
q < cpi->cq_target_quality) { q < cpi->cq_target_quality) {
q = cpi->cq_target_quality; q = cpi->cq_target_quality;
} }
if (cpi->gfu_boost > high) { if (cpi->gfu_boost > high) {
cpi->active_best_quality = gf_low_motion_minq[q]; cpi->active_best_quality = gf_low_motion_minq[q];
} else if (cpi->gfu_boost < low) { } else if (cpi->gfu_boost < low) {
...@@ -2802,29 +2800,71 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, ...@@ -2802,29 +2800,71 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
// Constrained quality use slightly lower active best. // Constrained quality use slightly lower active best.
if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY)
cpi->active_best_quality = cpi->active_best_quality * 15 / 16; cpi->active_best_quality = cpi->active_best_quality * 15 / 16;
// TODO(debargha): Refine the logic below
if (cpi->oxcf.end_usage == USAGE_CONSTANT_QUALITY) {
if (!cpi->refresh_alt_ref_frame) {
if (cpi->gfu_boost > high) {
cpi->active_best_quality = cpi->cq_target_quality * 14 / 16;
} else if (cpi->gfu_boost < low) {
cpi->active_best_quality = cpi->cq_target_quality;
} else {
const int gap = high - low;
const int offset = high - cpi->gfu_boost;
const int qdiff = cpi->cq_target_quality * 2 / 16;
const int adjustment = ((offset * qdiff) + (gap >> 1)) / gap;
cpi->active_best_quality = cpi->cq_target_quality * 14 / 16
+ adjustment;
}
} else {
if (cpi->frames_since_key > 1) {
if (cpi->gfu_boost > high) {
cpi->active_best_quality = cpi->cq_target_quality * 6 / 16;
} else if (cpi->gfu_boost < low) {
cpi->active_best_quality = cpi->cq_target_quality * 10 / 16;
} else {
const int gap = high - low;
const int offset = high - cpi->gfu_boost;
const int qdiff = cpi->cq_target_quality * 4 / 16;
const int adjustment = ((offset * qdiff) + (gap >> 1)) / gap;
cpi->active_best_quality = cpi->cq_target_quality * 6 / 16
+ adjustment;
}
}
}
}
} else { } else {
if (cpi->oxcf.end_usage == USAGE_CONSTANT_QUALITY) {
cpi->active_best_quality = cpi->cq_target_quality;
} else {
#ifdef ONE_SHOT_Q_ESTIMATE #ifdef ONE_SHOT_Q_ESTIMATE
#ifdef STRICT_ONE_SHOT_Q #ifdef STRICT_ONE_SHOT_Q
cpi->active_best_quality = q; cpi->active_best_quality = q;
#else #else
cpi->active_best_quality = inter_minq[q]; cpi->active_best_quality = inter_minq[q];
#endif #endif
#else #else
cpi->active_best_quality = inter_minq[q]; cpi->active_best_quality = inter_minq[q];
#endif #endif
// For the constant/constrained quality mode we don't want // For the constant/constrained quality mode we don't want
// q to fall below the cq level. // q to fall below the cq level.
if ((cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) && if ((cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY) &&
(cpi->active_best_quality < cpi->cq_target_quality)) { (cpi->active_best_quality < cpi->cq_target_quality)) {
// If we are strongly undershooting the target rate in the last // If we are strongly undershooting the target rate in the last
// frames then use the user passed in cq value not the auto // frames then use the user passed in cq value not the auto
// cq value. // cq value.
if (cpi->rolling_actual_bits < cpi->min_frame_bandwidth) if (cpi->rolling_actual_bits < cpi->min_frame_bandwidth)
cpi->active_best_quality = cpi->oxcf.cq_level; cpi->active_best_quality = cpi->oxcf.cq_level;
else else
cpi->active_best_quality = cpi->cq_target_quality; cpi->active_best_quality = cpi->cq_target_quality;
}
} }
/*
if (cm->current_video_frame == 1)
printf("q/active_best/worst_quality = %d %d %d\n",
q, cpi->active_best_quality, cpi->active_worst_quality);
*/
} }
// Clip the active best and worst quality values to limits // Clip the active best and worst quality values to limits
...@@ -2841,7 +2881,9 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, ...@@ -2841,7 +2881,9 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
cpi->active_worst_quality = cpi->active_best_quality; cpi->active_worst_quality = cpi->active_best_quality;
// Special case code to try and match quality with forced key frames // Special case code to try and match quality with forced key frames
if ((cm->frame_type == KEY_FRAME) && cpi->this_key_frame_forced) { if (cpi->oxcf.end_usage == USAGE_CONSTANT_QUALITY) {
q = cpi->active_best_quality;
} else if ((cm->frame_type == KEY_FRAME) && cpi->this_key_frame_forced) {
q = cpi->last_boosted_qindex; q = cpi->last_boosted_qindex;
} else { } else {
// Determine initial Q to try // Determine initial Q to try
...@@ -2853,7 +2895,8 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, ...@@ -2853,7 +2895,8 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
#if CONFIG_MULTIPLE_ARF #if CONFIG_MULTIPLE_ARF
// Force the quantizer determined by the coding order pattern. // Force the quantizer determined by the coding order pattern.
if (cpi->multi_arf_enabled && (cm->frame_type != KEY_FRAME)) { if (cpi->multi_arf_enabled && (cm->frame_type != KEY_FRAME) &&
cpi->oxcf.end_usage != USAGE_CONSTANT_QUALITY) {
double new_q; double new_q;
double current_q = vp9_convert_qindex_to_q(cpi->active_worst_quality); double current_q = vp9_convert_qindex_to_q(cpi->active_worst_quality);
int level = cpi->this_frame_weight; int level = cpi->this_frame_weight;
...@@ -2988,124 +3031,130 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi, ...@@ -2988,124 +3031,130 @@ static void encode_frame_to_data_rate(VP9_COMP *cpi,
active_worst_qchanged = 0; active_worst_qchanged = 0;
// Special case handling for forced key frames // Special case handling for forced key frames
if ((cm->frame_type == KEY_FRAME) && cpi->this_key_frame_forced) { if (cpi->oxcf.end_usage == USAGE_CONSTANT_QUALITY) {
int last_q = q; loop = 0;
int kf_err = vp9_calc_ss_err(cpi->Source, } else {
&cm->yv12_fb[cm->new_fb_idx]); if ((cm->frame_type == KEY_FRAME) && cpi->this_key_frame_forced) {
int last_q = q;
int high_err_target = cpi->ambient_err; int kf_err = vp9_calc_ss_err(cpi->Source,
int low_err_target = cpi->ambient_err >> 1; &cm->yv12_fb[cm->new_fb_idx]);
// Prevent possible divide by zero error below for perfect KF int high_err_target = cpi->ambient_err;
kf_err += !kf_err; int low_err_target = cpi->ambient_err >> 1;
// The key frame is not good enough or we can afford // Prevent possible divide by zero error below for perfect KF
// to make it better without undue risk of popping. kf_err += !kf_err;
if ((kf_err > high_err_target &&
cpi->projected_frame_size <= frame_over_shoot_limit) || // The key frame is not good enough or we can afford
(kf_err > low_err_target && // to make it better without undue risk of popping.
cpi->projected_frame_size <= frame_under_shoot_limit)) { if ((kf_err > high_err_target &&
// Lower q_high cpi->projected_frame_size <= frame_over_shoot_limit) ||
q_high = q > q_low ? q - 1 : q_low; (kf_err > low_err_target &&
cpi->projected_frame_size <= frame_under_shoot_limit)) {
// Adjust Q // Lower q_high
q = (q * high_err_target) / kf_err; q_high = q > q_low ? q - 1 : q_low;
q = MIN(q, (q_high + q_low) >> 1);
} else if (kf_err < low_err_target && // Adjust Q
cpi->projected_frame_size >= frame_under_shoot_limit) { q = (q * high_err_target) / kf_err;
// The key frame is much better than the previous frame q = MIN(q, (q_high + q_low) >> 1);
// Raise q_low } else if (kf_err < low_err_target &&
q_low = q < q_high ? q + 1 : q_high; cpi->projected_frame_size >= frame_under_shoot_limit) {
// The key frame is much better than the previous frame
// Adjust Q // Raise q_low
q = (q * low_err_target) / kf_err; q_low = q < q_high ? q + 1 : q_high;
q = MIN(q, (q_high + q_low + 1) >> 1);
} // Adjust Q
q = (q * low_err_target) / kf_err;
// Clamp Q to upper and lower limits: q = MIN(q, (q_high + q_low + 1) >> 1);
q = clamp(q, q_low, q_high); }
loop = q != last_q;
}
// Is the projected frame size out of range and are we allowed to attempt to recode.
else if (recode_loop_test(cpi,
frame_over_shoot_limit, frame_under_shoot_limit,
q, top_index, bottom_index)) {
int last_q = q;
int retries = 0;
// Frame size out of permitted range: // Clamp Q to upper and lower limits:
// Update correction factor & compute new Q to try... q = clamp(q, q_low, q_high);
loop = q != last_q;
} else if (recode_loop_test(
cpi, frame_over_shoot_limit, frame_under_shoot_limit,
q, top_index, bottom_index)) {
// Is the projected frame size out of range and are we allowed
// to attempt to recode.
int last_q = q;
int retries = 0;
// Frame size out of permitted range:
// Update correction factor & compute new Q to try...
// Frame is too large
if (cpi->projected_frame_size > cpi->this_frame_target) {
// Raise Qlow as to at least the current value
q_low = q < q_high ? q + 1 : q_high;
if (undershoot_seen || loop_count > 1) {
// Update rate_correction_factor unless
// cpi->active_worst_quality has changed.
if (!active_worst_qchanged)
vp9_update_rate_correction_factors(cpi, 1);
q = (q_high + q_low + 1) / 2;
} else {
// Update rate_correction_factor unless
// cpi->active_worst_quality has changed.
if (!active_worst_qchanged)
vp9_update_rate_correction_factors(cpi, 0);
// Frame is too large q = vp9_regulate_q(cpi, cpi->this_frame_target);
if (cpi->projected_frame_size > cpi->this_frame_target) {
// Raise Qlow as to at least the current value
q_low = q < q_high ? q + 1 : q_high;
if (undershoot_seen || loop_count > 1) { while (q < q_low && retries < 10) {
// Update rate_correction_factor unless cpi->active_worst_quality vp9_update_rate_correction_factors(cpi, 0);
// has changed. q = vp9_regulate_q(cpi, cpi->this_frame_target);
if (!active_worst_qchanged) retries++;
vp9_update_rate_correction_factors(cpi, 1); }
}
q = (q_high + q_low + 1) / 2; overshoot_seen = 1;
} else { } else {
// Update rate_correction_factor unless cpi->active_worst_quality has changed. // Frame is too small
if (!active_worst_qchanged) q_high = q > q_low ? q - 1 : q_low;
vp9_update_rate_correction_factors(cpi, 0);
if (overshoot_seen || loop_count > 1) {
// Update rate_correction_factor unless
// cpi->active_worst_quality has changed.
if (!active_worst_qchanged)
vp9_update_rate_correction_factors(cpi, 1);
q = (q_high + q_low) / 2;
} else {
// Update rate_correction_factor unless
// cpi->active_worst_quality has changed.
if (!active_worst_qchanged)
vp9_update_rate_correction_factors(cpi, 0);
q = vp9_regulate_q(cpi, cpi->this_frame_target);
while (q < q_low && retries < 10) {
vp9_update_rate_correction_factors(cpi, 0);
q = vp9_regulate_q(cpi, cpi->this_frame_target); q = vp9_regulate_q(cpi, cpi->this_frame_target);
retries++;
}
}
overshoot_seen = 1;
} else {
// Frame is too small
q_high = q > q_low ? q - 1 : q_low;
if (overshoot_seen || loop_count > 1) { // Special case reset for qlow for constrained quality.
// Update rate_correction_factor unless cpi->active_worst_quality has changed. // This should only trigger where there is very substantial
if (!active_worst_qchanged) // undershoot on a frame and the auto cq level is above
vp9_update_rate_correction_factors(cpi, 1); // the user passsed in value.
if (cpi->oxcf.end_usage == USAGE_CONSTRAINED_QUALITY && q < q_low) {
q_low = q;
}