Rate control on static scenes plus Y2dc delta Q fix.

A problem can arise on static clips with force key frames where
attempts to avoid popping lead to a progressive reduction in key
frame Q that ultimately may lead to unexpected overspend against
the  rate target.

The changes in this patch help to insure that in such clips the
quality of the key frames across the clip is more uniform (rather
than starting bad and getting better - especially at low target rates).

This patch also includes a fix that removes a delta on the Y2DC
when the baseline q index < 4 as this is no longer needed.

There is also a fix to try and prevent repeat single step Q adjustment in
the recode loop leading to lots of recodes, especially where the use
of forced skips as part of segmentation has made the impact of Q on
the number of bits generated much smaller.

Patch 2: Amend "last_boosted_qindex" calculation for arf overlay frames.

Change-Id: Ia1feeb79ed8ed014e4239994fcf5e58e68fd9459
This commit is contained in:
Paul Wilkins 2012-01-11 14:05:57 +00:00
parent 483b262bab
commit cf561bad1d
6 changed files with 106 additions and 48 deletions

View File

@ -3032,10 +3032,26 @@ static void find_next_key_frame(VP8_COMP *cpi, FIRSTPASS_STATS *this_frame)
// We do three calculations for kf size.
// The first is based on the error score for the whole kf group.
// The second (optionaly) on the key frames own error if this is smaller than the average for the group.
// The final one insures that the frame receives at least the allocation it would have received based on its own error score vs the error score remaining
allocation_chunks = ((cpi->twopass.frames_to_key - 1) * 100) + kf_boost; // cpi->twopass.frames_to_key-1 because key frame itself is taken care of by kf_boost
// The second (optionaly) on the key frames own error if this is
// smaller than the average for the group.
// The final one insures that the frame receives at least the
// allocation it would have received based on its own error score vs
// the error score remaining
// Special case if the sequence appears almost totaly static
// as measured by the decay accumulator. In this case we want to
// spend almost all of the bits on the key frame.
// cpi->twopass.frames_to_key-1 because key frame itself is taken
// care of by kf_boost.
if ( decay_accumulator >= 0.99 )
{
allocation_chunks =
((cpi->twopass.frames_to_key - 1) * 10) + kf_boost;
}
else
{
allocation_chunks =
((cpi->twopass.frames_to_key - 1) * 100) + kf_boost;
}
// Normalize Altboost and allocations chunck down to prevent overflow
while (kf_boost > 1000)

View File

@ -477,12 +477,16 @@ void separate_arf_mbs
//if ( ncnt[1] && (ncnt[0] / ncnt[1] < 10) )
if ( 1 )
{
cpi->mbgraph_use_arf_segmentation = ncnt[1];
// Note % of blocks that are marked as static
cpi->static_mb_pct =
(ncnt[1] * 100) / cm->MBs;
vp8_enable_segmentation((VP8_PTR) cpi);
}
else
{
cpi->mbgraph_use_arf_segmentation = 0;
cpi->static_mb_pct = 0;
vp8_disable_segmentation((VP8_PTR) cpi);
}

View File

@ -492,6 +492,7 @@ static void init_seg_features(VP8_COMP *cpi)
vpx_memset( cpi->segmentation_map, 0, (cm->mb_rows * cm->mb_cols));
xd->update_mb_segmentation_map = 0;
xd->update_mb_segmentation_data = 0;
cpi->static_mb_pct = 0;
// Disable segmentation
vp8_disable_segmentation((VP8_PTR)cpi);
@ -507,6 +508,7 @@ static void init_seg_features(VP8_COMP *cpi)
vpx_memset( cpi->segmentation_map, 0, (cm->mb_rows * cm->mb_cols));
xd->update_mb_segmentation_map = 0;
xd->update_mb_segmentation_data = 0;
cpi->static_mb_pct = 0;
// Disable segmentation and individual segment features by default
vp8_disable_segmentation((VP8_PTR)cpi);
@ -557,7 +559,7 @@ static void init_seg_features(VP8_COMP *cpi)
set_segdata( xd, 1, SEG_LVL_ALT_LF, -2 );
enable_segfeature(xd, 1, SEG_LVL_ALT_LF);
if ( high_q )
if ( high_q || (cpi->static_mb_pct == 100) )
{
set_segref(xd, 1, ALTREF_FRAME);
enable_segfeature(xd, 1, SEG_LVL_REF_FRAME);
@ -1973,6 +1975,8 @@ static void init_config(VP8_PTR ptr, VP8_CONFIG *oxcf)
cpi->total_actual_bits = 0;
cpi->total_target_vs_actual = 0;
cpi->static_mb_pct = 0;
#if VP8_TEMPORAL_ALT_REF
{
int i;
@ -2233,6 +2237,7 @@ void vp8_change_config(VP8_PTR ptr, VP8_CONFIG *oxcf)
{
cpi->last_q[0] = cpi->oxcf.fixed_q;
cpi->last_q[1] = cpi->oxcf.fixed_q;
cpi->last_boosted_qindex = cpi->oxcf.fixed_q;
}
cpi->Speed = cpi->oxcf.cpu_used;
@ -2694,6 +2699,9 @@ void vp8_remove_compressor(VP8_PTR *ptr)
fprintf(f, "%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t%8.0f\n",
dr, cpi->total / cpi->count, total_psnr, cpi->totalp / cpi->count, total_psnr2, total_ssim,
total_encode_time);
// fprintf(f, "%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t%7.3f\t%8.0f %10ld\n",
// dr, cpi->total / cpi->count, total_psnr, cpi->totalp / cpi->count, total_psnr2, total_ssim,
// total_encode_time, cpi->tot_recode_hits);
}
if (cpi->b_calculate_ssimg)
@ -2702,6 +2710,9 @@ void vp8_remove_compressor(VP8_PTR *ptr)
fprintf(f, "%7.3f\t%6.4f\t%6.4f\t%6.4f\t%6.4f\t%8.0f\n", dr,
cpi->total_ssimg_y / cpi->count, cpi->total_ssimg_u / cpi->count,
cpi->total_ssimg_v / cpi->count, cpi->total_ssimg_all / cpi->count, total_encode_time);
// fprintf(f, "%7.3f\t%6.4f\t%6.4f\t%6.4f\t%6.4f\t%8.0f %10ld\n", dr,
// cpi->total_ssimg_y / cpi->count, cpi->total_ssimg_u / cpi->count,
// cpi->total_ssimg_v / cpi->count, cpi->total_ssimg_all / cpi->count, total_encode_time, cpi->tot_recode_hits);
}
fclose(f);
@ -4134,10 +4145,15 @@ static void encode_frame_to_data_rate
// based on the ambient Q to reduce the risk of popping
if ( cpi->this_key_frame_forced )
{
if ( cpi->active_best_quality > cpi->avg_frame_qindex * 7/8)
cpi->active_best_quality = cpi->avg_frame_qindex * 7/8;
else if ( cpi->active_best_quality < cpi->avg_frame_qindex >> 2 )
cpi->active_best_quality = cpi->avg_frame_qindex >> 2;
int delta_qindex;
int qindex = cpi->last_boosted_qindex;
delta_qindex = compute_qdelta( cpi, qindex,
(qindex * 0.75) );
cpi->active_best_quality = qindex + delta_qindex;
if (cpi->active_best_quality < cpi->best_quality)
cpi->active_best_quality = cpi->best_quality;
}
}
// One pass more conservative
@ -4248,8 +4264,16 @@ static void encode_frame_to_data_rate
if ( cpi->active_worst_quality < cpi->active_best_quality )
cpi->active_worst_quality = cpi->active_best_quality;
// Determine initial Q to try
Q = vp8_regulate_q(cpi, cpi->this_frame_target);
// Specuial case code to try and match quality with forced key frames
if ( (cm->frame_type == KEY_FRAME) && cpi->this_key_frame_forced )
{
Q = cpi->last_boosted_qindex;
}
else
{
// Determine initial Q to try
Q = vp8_regulate_q(cpi, cpi->this_frame_target);
}
last_zbin_oq = cpi->zbin_over_quant;
// Set highest allowed value for Zbin over quant
@ -4527,23 +4551,32 @@ static void encode_frame_to_data_rate
&cm->yv12_fb[cm->new_fb_idx],
IF_RTCD(&cpi->rtcd.variance));
int high_err_target = cpi->ambient_err;
int low_err_target = ((cpi->ambient_err * 3) >> 2);
// The key frame is not good enough
if ( kf_err > ((cpi->ambient_err * 7) >> 3) )
if ( (kf_err > high_err_target) &&
(cpi->projected_frame_size <= frame_over_shoot_limit) )
{
// Lower q_high
q_high = (Q > q_low) ? (Q - 1) : q_low;
// Adjust Q
Q = (q_high + q_low) >> 1;
Q = (Q * high_err_target) / kf_err;
if ( Q < ((q_high + q_low) >> 1))
Q = (q_high + q_low) >> 1;
}
// The key frame is much better than the previous frame
else if ( kf_err < (cpi->ambient_err >> 1) )
else if ( (kf_err < low_err_target) &&
(cpi->projected_frame_size >= frame_under_shoot_limit) )
{
// Raise q_low
q_low = (Q < q_high) ? (Q + 1) : q_high;
// Adjust Q
Q = (q_high + q_low + 1) >> 1;
Q = (Q * low_err_target) / kf_err;
if ( Q > ((q_high + q_low + 1) >> 1))
Q = (q_high + q_low + 1) >> 1;
}
// Clamp Q to upper and lower limits:
@ -4569,14 +4602,12 @@ static void encode_frame_to_data_rate
// Frame is too large
if (cpi->projected_frame_size > cpi->this_frame_target)
{
//if ( cpi->zbin_over_quant == 0 )
q_low = (Q < q_high) ? (Q + 1) : q_high; // Raise Qlow as to at least the current value
if (cpi->zbin_over_quant > 0) // If we are using over quant do the same for zbin_oq_low
zbin_oq_low = (cpi->zbin_over_quant < zbin_oq_high) ? (cpi->zbin_over_quant + 1) : zbin_oq_high;
//if ( undershoot_seen || (Q == MAXQ) )
if (undershoot_seen)
if ( undershoot_seen || (loop_count > 1) )
{
// Update rate_correction_factor unless cpi->active_worst_quality has changed.
if (!active_worst_qchanged)
@ -4619,7 +4650,7 @@ static void encode_frame_to_data_rate
else // else lower zbin_oq_high
zbin_oq_high = (cpi->zbin_over_quant > zbin_oq_low) ? (cpi->zbin_over_quant - 1) : zbin_oq_low;
if (overshoot_seen)
if ( overshoot_seen || (loop_count > 1) )
{
// Update rate_correction_factor unless cpi->active_worst_quality has changed.
if (!active_worst_qchanged)
@ -4845,6 +4876,20 @@ static void encode_frame_to_data_rate
cpi->last_q[cm->frame_type] = cm->base_qindex;
// Keep record of last boosted (KF/KF/ARF) Q value.
// If the current frame is coded at a lower Q then we also update it.
// If all mbs in this group are skipped only update if the Q value is
// better than that already stored.
// This is used to help set quality in forced key frames to reduce popping
if ( (cm->base_qindex < cpi->last_boosted_qindex) ||
( (cpi->static_mb_pct < 100) &&
( (cm->frame_type == KEY_FRAME) ||
cm->refresh_alt_ref_frame ||
(cm->refresh_golden_frame && !cpi->is_src_frame_alt_ref) ) ) )
{
cpi->last_boosted_qindex = cm->base_qindex;
}
if (cm->frame_type == KEY_FRAME)
{
vp8_adjust_key_frame_context(cpi);
@ -4991,7 +5036,7 @@ static void encode_frame_to_data_rate
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"
"%7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f"
"%6d %5d %5d %5d %8d %8.2f %10d %10.3f"
"%10.3f %8d\n",
cpi->common.current_video_frame, cpi->this_frame_target,
@ -5023,7 +5068,7 @@ static void encode_frame_to_data_rate
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"
"%7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f"
"%6d %5d %5d %5d %8d %8.2f %10d %10.3f"
"%8d\n",
cpi->common.current_video_frame,

View File

@ -383,6 +383,7 @@ typedef struct VP8_COMP
int this_frame_target;
int projected_frame_size;
int last_q[2]; // Separate values for Intra/Inter
int last_boosted_qindex; // Last boosted GF/KF/ARF q
double rate_correction_factor;
double key_frame_rate_correction_factor;
@ -483,11 +484,7 @@ typedef struct VP8_COMP
#endif
MBGRAPH_FRAME_STATS mbgraph_stats[MAX_LAG_BUFFERS];
int mbgraph_n_frames; // number of frames filled in the above
int mbgraph_use_arf_segmentation; // set if part of an ARF is considered to be a
// poor predictor, and thus coeffs are skipped
// or coded at a higher Q using MB-segmentation
// this value is the number of MBs that are
// poor predictors (> 0 and < common.MBs)
int static_mb_pct; // % forced skip mbs by segmentation
int decimation_factor;
int decimation_count;

View File

@ -1271,30 +1271,18 @@ void vp8cx_frame_init_quantizer(VP8_COMP *cpi)
void vp8_set_quantizer(struct VP8_COMP *cpi, int Q)
{
VP8_COMMON *cm = &cpi->common;
int update = 0;
int new_delta_q;
cm->base_qindex = Q;
/* if any of the delta_q values are changing update flag has to be set */
/* currently only y2dc_delta_q may change */
// if any of the delta_q values are changing update flag will
// have to be set.
cm->y1dc_delta_q = 0;
cm->y2ac_delta_q = 0;
cm->uvdc_delta_q = 0;
cm->uvac_delta_q = 0;
cm->y2dc_delta_q = 0;
if (Q < 4)
{
new_delta_q = 4-Q;
}
else
new_delta_q = 0;
update |= cm->y2dc_delta_q != new_delta_q;
cm->y2dc_delta_q = new_delta_q;
/* quantizer has to be reinitialized for any delta_q changes */
if(update)
vp8cx_init_quantizer(cpi);
// quantizer has to be reinitialized if any delta_q changes.
// As there are not any here for now this is inactive code.
//if(update)
// vp8cx_init_quantizer(cpi);
}

View File

@ -24,7 +24,7 @@
#include "encodemv.h"
#define MIN_BPB_FACTOR 0.01
#define MIN_BPB_FACTOR 0.005
#define MAX_BPB_FACTOR 50
extern const MB_PREDICTION_MODE vp8_mode_order[MAX_MODES];
@ -1477,6 +1477,14 @@ void vp8_compute_frame_size_bounds(VP8_COMP *cpi, int *frame_under_shoot_limit,
}
}
}
// For very small rate targets where the fractional adjustment
// (eg * 7/8) may be tiny make sure there is at least a minimum
// range.
*frame_over_shoot_limit += 200;
*frame_under_shoot_limit -= 200;
if ( *frame_under_shoot_limit < 0 )
*frame_under_shoot_limit = 0;
}
}