ref: b4ad9b5d5052b54d74c98c2ee71d5236c39a1537
parent: 82d99257f2f2a009bd3f9cde4375e141fbf85827
author: Paul Wilkins <paulwilkins@google.com>
date: Tue Dec 6 09:48:52 EST 2011
Some further QIndex issues with extended Q Resolved or factored out some further issues with Q index. Put in a 3rd order polynomial instead of less accurate power function as the best fit on gf and kf boost adjustment. Added avg_q value to use instead of ni_av_qi. Compute segment delta Q values based on avg_q. Fixed bug in adjust_maxq_qrange(). The extended range Q on the derf set, using standard data rates (which do not extend high enough to get big benefits) still show a shortfall of between 0.5 and 1% though so there would appear to be further issues that need to be tracked down. Change-Id: Icfd49b9f401906ba487ef1bef7d397048295d959
--- a/vp8/encoder/firstpass.c
+++ b/vp8/encoder/firstpass.c
@@ -898,7 +898,7 @@
double correction_factor;
// Adjustment based on actual quantizer to power term.
- power_term = (vp8_convert_qindex_to_q(Q) * 0.01) + 0.36;
+ power_term = (vp8_convert_qindex_to_q(Q) * 0.01) + pt_low;
power_term = (power_term > pt_high) ? pt_high : power_term;
// Adjustments to error term
@@ -919,29 +919,29 @@
// PGW TODO..
// This code removes direct dependency on QIndex to determin the range
// (now uses the actual quantizer) but has not been tuned.
-static double adjust_maxq_qrange(VP8_COMP *cpi, int qindex )
+static double adjust_maxq_qrange(VP8_COMP *cpi)
{
int i;
- double q = vp8_convert_qindex_to_q(qindex);
+ double q;
- // Set the max corresponding to real q * 2.0
+ // Set the max corresponding to cpi->avg_q * 2.0
+ q = cpi->avg_q * 2.0;
cpi->twopass.maxq_max_limit = cpi->worst_quality;
- for ( i = qindex; i < cpi->worst_quality; i++ )
+ for ( i = cpi->best_quality; i <= cpi->worst_quality; i++ )
{
- if ( vp8_convert_qindex_to_q(qindex) >= (q * 2.0) )
- {
- cpi->twopass.maxq_max_limit = i;
- }
+ cpi->twopass.maxq_max_limit = i;
+ if ( vp8_convert_qindex_to_q(i) >= q )
+ break;
}
- // Set the min corresponding to real q * 0.5
+ // Set the min corresponding to cpi->avg_q * 0.5
+ q = cpi->avg_q * 0.5;
cpi->twopass.maxq_min_limit = cpi->best_quality;
- for ( i = qindex; i > cpi->best_quality; i-- )
+ for ( i = cpi->worst_quality; i >= cpi->best_quality; i-- )
{
- if ( vp8_convert_qindex_to_q(qindex) <= (q * 0.5) )
- {
- cpi->twopass.maxq_min_limit = i;
- }
+ cpi->twopass.maxq_min_limit = i;
+ if ( vp8_convert_qindex_to_q(i) <= q )
+ break;
}
}
@@ -1018,7 +1018,7 @@
// Error per MB based correction factor
err_correction_factor =
- calc_correction_factor(err_per_mb, 150.0, 0.40, 0.90, Q);
+ calc_correction_factor(err_per_mb, 150.0, 0.36, 0.90, Q);
bits_per_mb_at_this_q =
vp8_bits_per_mb(INTER_FRAME, Q) + overhead_bits_per_mb;
@@ -1054,7 +1054,7 @@
((unsigned int)cpi->twopass.total_stats->count >> 8)) &&
(cpi->ni_frames > 150) )
{
- adjust_maxq_qrange( cpi, cpi->ni_av_qi );
+ adjust_maxq_qrange( cpi );
}
return Q;
@@ -1120,7 +1120,7 @@
// Error per MB based correction factor
err_correction_factor =
- calc_correction_factor(err_per_mb, 100.0, 0.40, 0.90, Q);
+ calc_correction_factor(err_per_mb, 100.0, 0.36, 0.90, Q);
bits_per_mb_at_this_q =
vp8_bits_per_mb(INTER_FRAME, Q) + overhead_bits_per_mb;
@@ -1181,7 +1181,7 @@
// Error per MB based correction factor
err_correction_factor =
- calc_correction_factor(err_per_mb, 150.0, 0.40, 0.90, Q);
+ calc_correction_factor(err_per_mb, 150.0, 0.36, 0.90, Q);
bits_per_mb_at_this_q =
(int)( .5 + ( err_correction_factor *
@@ -2329,6 +2329,46 @@
cpi->per_frame_bandwidth = target_frame_size; // Per frame bit target for this frame
}
+// Make a damped adjustment to the active max q.
+int adjust_active_maxq( int old_maxqi, int new_maxqi )
+{
+ int i;
+ int ret_val = new_maxqi;
+ double old_q;
+ double new_q;
+ double target_q;
+
+ old_q = vp8_convert_qindex_to_q( old_maxqi );
+ new_q = vp8_convert_qindex_to_q( new_maxqi );
+
+ target_q = ((old_q * 7.0) + new_q) / 8.0;
+
+ if ( target_q > old_q )
+ {
+ for ( i = old_maxqi; i <= new_maxqi; i++ )
+ {
+ if ( vp8_convert_qindex_to_q( i ) >= target_q )
+ {
+ ret_val = i;
+ break;
+ }
+ }
+ }
+ else
+ {
+ for ( i = old_maxqi; i >= new_maxqi; i-- )
+ {
+ if ( vp8_convert_qindex_to_q( i ) <= target_q )
+ {
+ ret_val = i;
+ break;
+ }
+ }
+ }
+
+ return ret_val;
+}
+
void vp8_second_pass(VP8_COMP *cpi)
{
int tmp_q;
@@ -2480,15 +2520,16 @@
(int)(cpi->twopass.bits_left / frames_left),
overhead_bits );
+ cpi->active_worst_quality = tmp_q;
+ cpi->ni_av_qi = tmp_q;
+ cpi->avg_q = vp8_convert_qindex_to_q( tmp_q );
+
// Limit the maxq value returned subsequently.
// This increases the risk of overspend or underspend if the initial
// estimate for the clip is bad, but helps prevent excessive
// variation in Q, especially near the end of a clip
// where for example a small overspend may cause Q to crash
- adjust_maxq_qrange(cpi, tmp_q);
-
- cpi->active_worst_quality = tmp_q;
- cpi->ni_av_qi = tmp_q;
+ adjust_maxq_qrange(cpi);
}
// The last few frames of a clip almost always have to few or too many
@@ -2509,14 +2550,9 @@
(int)(cpi->twopass.bits_left / frames_left),
overhead_bits );
- // Move active_worst_quality but in a damped way
- if (tmp_q > cpi->active_worst_quality)
- cpi->active_worst_quality ++;
- else if (tmp_q < cpi->active_worst_quality)
- cpi->active_worst_quality --;
-
+ // Make a damped adjustment to active max Q
cpi->active_worst_quality =
- ((cpi->active_worst_quality * 3) + tmp_q + 2) / 4;
+ adjust_active_maxq( cpi->active_worst_quality, tmp_q );
}
cpi->twopass.frames_to_key --;
--- a/vp8/encoder/onyx_if.c
+++ b/vp8/encoder/onyx_if.c
@@ -416,6 +416,35 @@
}
+// Computes a q delta (in "q index" terms) to get from a starting q value
+// to a target value
+// target q value
+static int compute_qdelta( VP8_COMP *cpi, double qstart, double qtarget )
+{
+ int i;
+ int start_index = cpi->worst_quality;
+ int target_index = cpi->worst_quality;
+ int retval = 0;
+
+ // Convert the average q value to an index.
+ for ( i = cpi->best_quality; i < cpi->worst_quality; i++ )
+ {
+ start_index = i;
+ if ( vp8_convert_qindex_to_q(i) >= qstart )
+ break;
+ }
+
+ // Convert the q target to an index
+ for ( i = cpi->best_quality; i < cpi->worst_quality; i++ )
+ {
+ target_index = i;
+ if ( vp8_convert_qindex_to_q(i) >= qtarget )
+ break;
+ }
+
+ return target_index - start_index;
+}
+
//#if CONFIG_SEGFEATURES
static void init_seg_features(VP8_COMP *cpi)
{
@@ -422,7 +451,8 @@
VP8_COMMON *cm = &cpi->common;
MACROBLOCKD *xd = &cpi->mb.e_mbd;
- int high_q = ((int)vp8_convert_qindex_to_q(cpi->ni_av_qi) > 32);
+ int high_q = (int)(cpi->avg_q > 32.0);
+ int qi_delta;
// For now at least dont enable seg features alongside cyclic refresh.
if ( cpi->cyclic_refresh_mode_enabled ||
@@ -471,7 +501,8 @@
xd->update_mb_segmentation_map = 1;
xd->update_mb_segmentation_data = 1;
- set_segdata( xd, 1, SEG_LVL_ALT_Q, -(3+(cpi->ni_av_qi >> 3)) );
+ qi_delta = compute_qdelta( cpi, cpi->avg_q, (cpi->avg_q * 0.875) );
+ set_segdata( xd, 1, SEG_LVL_ALT_Q, (qi_delta - 2) );
set_segdata( xd, 1, SEG_LVL_ALT_LF, -2 );
enable_segfeature(xd, 1, SEG_LVL_ALT_Q);
@@ -495,7 +526,10 @@
xd->update_mb_segmentation_data = 1;
xd->mb_segement_abs_delta = SEGMENT_DELTADATA;
- set_segdata( xd, 1, SEG_LVL_ALT_Q, 5 );
+ qi_delta = compute_qdelta( cpi, cpi->avg_q,
+ (cpi->avg_q * 1.125) );
+ set_segdata( xd, 1, SEG_LVL_ALT_Q, (qi_delta + 2) );
+ set_segdata( xd, 1, SEG_LVL_ALT_Q, 0 );
enable_segfeature(xd, 1, SEG_LVL_ALT_Q);
set_segdata( xd, 1, SEG_LVL_ALT_LF, -2 );
@@ -2242,6 +2276,8 @@
cpi->ni_av_qi = cpi->oxcf.worst_allowed_q;
cpi->ni_tot_qi = 0;
cpi->ni_frames = 0;
+ cpi->tot_q = 0.0;
+ cpi->avg_q = vp8_convert_qindex_to_q( cpi->oxcf.worst_allowed_q );
cpi->total_byte_count = 0;
cpi->drop_frame = 0;
@@ -4601,6 +4637,8 @@
if ((cm->frame_type != KEY_FRAME) && !cm->refresh_golden_frame && !cm->refresh_alt_ref_frame)
{
cpi->ni_frames++;
+ cpi->tot_q += vp8_convert_qindex_to_q(Q);
+ cpi->avg_q = cpi->tot_q / (double)cpi->ni_frames;
// Calculate the average Q for normal inter frames (not key or GFU
// frames).
@@ -4732,7 +4770,7 @@
if (cpi->twopass.total_left_stats->coded_error != 0.0)
fprintf(f, "%10d %10d %10d %10d %10d %10d %10d"
- "%6.2f %6.2f %6.2f %6.2f %6.2f %6.2f"
+ "%6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f"
"%6d %5d %5d %5d %8d %8.2f %10d %10.3f"
"%10.3f %8d\n",
cpi->common.current_video_frame, cpi->this_frame_target,
@@ -4749,6 +4787,7 @@
#endif
vp8_convert_qindex_to_q(cpi->active_best_quality),
vp8_convert_qindex_to_q(cpi->active_worst_quality),
+ cpi->avg_q,
vp8_convert_qindex_to_q(cpi->ni_av_qi),
vp8_convert_qindex_to_q(cpi->cq_target_quality),
cpi->zbin_over_quant,
@@ -4763,7 +4802,7 @@
cpi->tot_recode_hits);
else
fprintf(f, "%10d %10d %10d %10d %10d %10d %10d"
- "%6.2f %6.2f %6.2f %6.2f %6.2f %6.2f"
+ "%6.2f %6.2f %6.2f %6.2f %6.2f %6.2f %6.2f"
"%6d %5d %5d %5d %8d %8.2f %10d %10.3f"
"%8d\n",
cpi->common.current_video_frame,
@@ -4780,6 +4819,7 @@
#endif
vp8_convert_qindex_to_q(cpi->active_best_quality),
vp8_convert_qindex_to_q(cpi->active_worst_quality),
+ cpi->avg_q,
vp8_convert_qindex_to_q(cpi->ni_av_qi),
vp8_convert_qindex_to_q(cpi->cq_target_quality),
cpi->zbin_over_quant,
--- a/vp8/encoder/onyx_int.h
+++ b/vp8/encoder/onyx_int.h
@@ -391,6 +391,8 @@
int ni_tot_qi;
int ni_frames;
int avg_frame_qindex;
+ double tot_q;
+ double avg_q;
int zbin_over_quant;
int zbin_mode_boost;
--- a/vp8/encoder/ratectrl.c
+++ b/vp8/encoder/ratectrl.c
@@ -125,12 +125,26 @@
int vp8_gfboost_qadjust( int qindex )
{
- return (50.0 * pow(vp8_convert_qindex_to_q(qindex), 0.25) + 0.5);
+ int retval;
+ double q;
+
+ q = vp8_convert_qindex_to_q(qindex);
+ retval = (int)( ( 0.00000828 * q * q * q ) +
+ ( -0.0055 * q * q ) +
+ ( 1.32 * q ) + 79.3 );
+ return retval;
}
int kfboost_qadjust( int qindex )
{
- return (91.0 * pow(vp8_convert_qindex_to_q(qindex), 0.165) + 0.5);
+ int retval;
+ double q;
+
+ q = vp8_convert_qindex_to_q(qindex);
+ retval = (int)( ( 0.00000973 * q * q * q ) +
+ ( -0.00613 * q * q ) +
+ ( 1.316 * q ) + 121.2 );
+ return retval;
}
int vp8_bits_per_mb( FRAME_TYPE frame_type, int qindex )
--- a/vp8/encoder/rdopt.c
+++ b/vp8/encoder/rdopt.c
@@ -253,7 +253,7 @@
#if CONFIG_EXTEND_QRANGE
q = (int)pow(vp8_dc_quant(QIndex,0)>>2, 1.25);
q = q << 2;
- cpi->RDMULT *= 16;
+ cpi->RDMULT = cpi->RDMULT << 4;
#else
q = (int)pow(vp8_dc_quant(QIndex,0), 1.25);
#endif