vp8: Change default gf behavior for 1 pass cbr.
In 1 pass CBR, with error_resilience off, allow for special logic to change the default gf behaviour. In this CL: boost is turned off and the gf period is set to a multiple of cyclic refresh period. Change only affect 1 pass CBR mode, i.e, when the flag gf_update_onepass_cbr is set. Including the previous change (3ec8e11: to allow cyclic refresh for error_resilience off), comparing metrics on RTC set for error_resilience off vs on: avgPSNR/SSIM up by ~6%. Change-Id: Id5b3fb62a4f04de5a805bd1b418f2b349574e0bc
This commit is contained in:
@@ -1467,6 +1467,12 @@ void vp8_change_config(VP8_COMP *cpi, VP8_CONFIG *oxcf) {
|
|||||||
cpi->baseline_gf_interval =
|
cpi->baseline_gf_interval =
|
||||||
cpi->oxcf.alt_freq ? cpi->oxcf.alt_freq : DEFAULT_GF_INTERVAL;
|
cpi->oxcf.alt_freq ? cpi->oxcf.alt_freq : DEFAULT_GF_INTERVAL;
|
||||||
|
|
||||||
|
// GF behavior for 1 pass CBR, used when error_resilience is off.
|
||||||
|
if (!cpi->oxcf.error_resilient_mode &&
|
||||||
|
cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER &&
|
||||||
|
cpi->oxcf.Mode == MODE_REALTIME)
|
||||||
|
cpi->baseline_gf_interval = cpi->gf_interval_onepass_cbr;
|
||||||
|
|
||||||
#if (CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING)
|
#if (CONFIG_REALTIME_ONLY & CONFIG_ONTHEFLY_BITPACKING)
|
||||||
cpi->oxcf.token_partitions = 3;
|
cpi->oxcf.token_partitions = 3;
|
||||||
#endif
|
#endif
|
||||||
@@ -1785,6 +1791,23 @@ struct VP8_COMP *vp8_create_compressor(VP8_CONFIG *oxcf) {
|
|||||||
cpi->cyclic_refresh_mode_index = 0;
|
cpi->cyclic_refresh_mode_index = 0;
|
||||||
cpi->cyclic_refresh_q = 32;
|
cpi->cyclic_refresh_q = 32;
|
||||||
|
|
||||||
|
// GF behavior for 1 pass CBR, used when error_resilience is off.
|
||||||
|
cpi->gf_update_onepass_cbr = 0;
|
||||||
|
cpi->gf_noboost_onepass_cbr = 0;
|
||||||
|
if (!cpi->oxcf.error_resilient_mode &&
|
||||||
|
cpi->oxcf.end_usage == USAGE_STREAM_FROM_SERVER && cpi->oxcf.Mode <= 2) {
|
||||||
|
cpi->gf_update_onepass_cbr = 1;
|
||||||
|
cpi->gf_noboost_onepass_cbr = 1;
|
||||||
|
cpi->gf_interval_onepass_cbr =
|
||||||
|
cpi->cyclic_refresh_mode_max_mbs_perframe > 0
|
||||||
|
? (2 * (cpi->common.mb_rows * cpi->common.mb_cols) /
|
||||||
|
cpi->cyclic_refresh_mode_max_mbs_perframe)
|
||||||
|
: 10;
|
||||||
|
cpi->gf_interval_onepass_cbr =
|
||||||
|
VPXMIN(40, VPXMAX(6, cpi->gf_interval_onepass_cbr));
|
||||||
|
cpi->baseline_gf_interval = cpi->gf_interval_onepass_cbr;
|
||||||
|
}
|
||||||
|
|
||||||
if (cpi->cyclic_refresh_mode_enabled) {
|
if (cpi->cyclic_refresh_mode_enabled) {
|
||||||
CHECK_MEM_ERROR(cpi->cyclic_refresh_map,
|
CHECK_MEM_ERROR(cpi->cyclic_refresh_map,
|
||||||
vpx_calloc((cpi->common.mb_rows * cpi->common.mb_cols), 1));
|
vpx_calloc((cpi->common.mb_rows * cpi->common.mb_cols), 1));
|
||||||
|
|||||||
@@ -501,6 +501,11 @@ typedef struct VP8_COMP {
|
|||||||
|
|
||||||
int force_maxqp;
|
int force_maxqp;
|
||||||
|
|
||||||
|
// GF update for 1 pass cbr.
|
||||||
|
int gf_update_onepass_cbr;
|
||||||
|
int gf_interval_onepass_cbr;
|
||||||
|
int gf_noboost_onepass_cbr;
|
||||||
|
|
||||||
#if CONFIG_MULTITHREAD
|
#if CONFIG_MULTITHREAD
|
||||||
/* multithread data */
|
/* multithread data */
|
||||||
int *mt_current_mb_col;
|
int *mt_current_mb_col;
|
||||||
|
|||||||
@@ -885,61 +885,61 @@ static void calc_pframe_target_size(VP8_COMP *cpi) {
|
|||||||
/* Adjust target frame size for Golden Frames: */
|
/* Adjust target frame size for Golden Frames: */
|
||||||
if (cpi->oxcf.error_resilient_mode == 0 &&
|
if (cpi->oxcf.error_resilient_mode == 0 &&
|
||||||
(cpi->frames_till_gf_update_due == 0) && !cpi->drop_frame) {
|
(cpi->frames_till_gf_update_due == 0) && !cpi->drop_frame) {
|
||||||
int Q =
|
if (!cpi->gf_update_onepass_cbr) {
|
||||||
(cpi->oxcf.fixed_q < 0) ? cpi->last_q[INTER_FRAME] : cpi->oxcf.fixed_q;
|
int Q = (cpi->oxcf.fixed_q < 0) ? cpi->last_q[INTER_FRAME]
|
||||||
|
: cpi->oxcf.fixed_q;
|
||||||
|
|
||||||
int gf_frame_useage = 0; /* Golden frame useage since last GF */
|
int gf_frame_useage = 0; /* Golden frame useage since last GF */
|
||||||
int tot_mbs = cpi->recent_ref_frame_usage[INTRA_FRAME] +
|
int tot_mbs = cpi->recent_ref_frame_usage[INTRA_FRAME] +
|
||||||
cpi->recent_ref_frame_usage[LAST_FRAME] +
|
cpi->recent_ref_frame_usage[LAST_FRAME] +
|
||||||
cpi->recent_ref_frame_usage[GOLDEN_FRAME] +
|
cpi->recent_ref_frame_usage[GOLDEN_FRAME] +
|
||||||
cpi->recent_ref_frame_usage[ALTREF_FRAME];
|
cpi->recent_ref_frame_usage[ALTREF_FRAME];
|
||||||
|
|
||||||
int pct_gf_active = (100 * cpi->gf_active_count) /
|
int pct_gf_active = (100 * cpi->gf_active_count) /
|
||||||
(cpi->common.mb_rows * cpi->common.mb_cols);
|
(cpi->common.mb_rows * cpi->common.mb_cols);
|
||||||
|
|
||||||
if (tot_mbs) {
|
if (tot_mbs) {
|
||||||
gf_frame_useage = (cpi->recent_ref_frame_usage[GOLDEN_FRAME] +
|
gf_frame_useage = (cpi->recent_ref_frame_usage[GOLDEN_FRAME] +
|
||||||
cpi->recent_ref_frame_usage[ALTREF_FRAME]) *
|
cpi->recent_ref_frame_usage[ALTREF_FRAME]) *
|
||||||
100 / tot_mbs;
|
100 / tot_mbs;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pct_gf_active > gf_frame_useage) gf_frame_useage = pct_gf_active;
|
if (pct_gf_active > gf_frame_useage) gf_frame_useage = pct_gf_active;
|
||||||
|
|
||||||
/* Is a fixed manual GF frequency being used */
|
/* Is a fixed manual GF frequency being used */
|
||||||
if (cpi->auto_gold) {
|
if (cpi->auto_gold) {
|
||||||
/* For one pass throw a GF if recent frame intra useage is
|
/* For one pass throw a GF if recent frame intra useage is
|
||||||
* low or the GF useage is high
|
* low or the GF useage is high
|
||||||
*/
|
*/
|
||||||
if ((cpi->pass == 0) &&
|
if ((cpi->pass == 0) &&
|
||||||
(cpi->this_frame_percent_intra < 15 || gf_frame_useage >= 5)) {
|
(cpi->this_frame_percent_intra < 15 || gf_frame_useage >= 5)) {
|
||||||
cpi->common.refresh_golden_frame = 1;
|
cpi->common.refresh_golden_frame = 1;
|
||||||
|
|
||||||
/* Two pass GF descision */
|
/* Two pass GF descision */
|
||||||
} else if (cpi->pass == 2) {
|
} else if (cpi->pass == 2) {
|
||||||
cpi->common.refresh_golden_frame = 1;
|
cpi->common.refresh_golden_frame = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
|
|
||||||
/* Debug stats */
|
/* Debug stats */
|
||||||
if (0)
|
if (0) {
|
||||||
{
|
FILE *f;
|
||||||
FILE *f;
|
|
||||||
|
|
||||||
f = fopen("gf_useaget.stt", "a");
|
f = fopen("gf_useaget.stt", "a");
|
||||||
fprintf(f, " %8ld %10ld %10ld %10ld %10ld\n",
|
fprintf(f, " %8ld %10ld %10ld %10ld %10ld\n",
|
||||||
cpi->common.current_video_frame, cpi->gfu_boost, GFQ_ADJUSTMENT, cpi->gfu_boost, gf_frame_useage);
|
cpi->common.current_video_frame, cpi->gfu_boost,
|
||||||
fclose(f);
|
GFQ_ADJUSTMENT, cpi->gfu_boost, gf_frame_useage);
|
||||||
}
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (cpi->common.refresh_golden_frame == 1) {
|
if (cpi->common.refresh_golden_frame == 1) {
|
||||||
#if 0
|
#if 0
|
||||||
|
|
||||||
if (0)
|
if (0) {
|
||||||
{
|
|
||||||
FILE *f;
|
FILE *f;
|
||||||
|
|
||||||
f = fopen("GFexit.stt", "a");
|
f = fopen("GFexit.stt", "a");
|
||||||
@@ -949,61 +949,70 @@ static void calc_pframe_target_size(VP8_COMP *cpi) {
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (cpi->auto_adjust_gold_quantizer) {
|
if (cpi->auto_adjust_gold_quantizer) {
|
||||||
calc_gf_params(cpi);
|
calc_gf_params(cpi);
|
||||||
}
|
|
||||||
|
|
||||||
/* If we are using alternate ref instead of gf then do not apply the
|
|
||||||
* boost It will instead be applied to the altref update Jims
|
|
||||||
* modified boost
|
|
||||||
*/
|
|
||||||
if (!cpi->source_alt_ref_active) {
|
|
||||||
if (cpi->oxcf.fixed_q < 0) {
|
|
||||||
if (cpi->pass == 2) {
|
|
||||||
/* The spend on the GF is defined in the two pass
|
|
||||||
* code for two pass encodes
|
|
||||||
*/
|
|
||||||
cpi->this_frame_target = cpi->per_frame_bandwidth;
|
|
||||||
} else {
|
|
||||||
int Boost = cpi->last_boost;
|
|
||||||
int frames_in_section = cpi->frames_till_gf_update_due + 1;
|
|
||||||
int allocation_chunks = (frames_in_section * 100) + (Boost - 100);
|
|
||||||
int bits_in_section = cpi->inter_frame_target * frames_in_section;
|
|
||||||
|
|
||||||
/* Normalize Altboost and allocations chunck down to
|
|
||||||
* prevent overflow
|
|
||||||
*/
|
|
||||||
while (Boost > 1000) {
|
|
||||||
Boost /= 2;
|
|
||||||
allocation_chunks /= 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Avoid loss of precision but avoid overflow */
|
|
||||||
if ((bits_in_section >> 7) > allocation_chunks) {
|
|
||||||
cpi->this_frame_target =
|
|
||||||
Boost * (bits_in_section / allocation_chunks);
|
|
||||||
} else {
|
|
||||||
cpi->this_frame_target =
|
|
||||||
(Boost * bits_in_section) / allocation_chunks;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
cpi->this_frame_target =
|
|
||||||
(estimate_bits_at_q(1, Q, cpi->common.MBs, 1.0) *
|
|
||||||
cpi->last_boost) /
|
|
||||||
100;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
/* If we are using alternate ref instead of gf then do not apply the
|
||||||
/* If there is an active ARF at this location use the minimum
|
* boost It will instead be applied to the altref update Jims
|
||||||
* bits on this frame even if it is a contructed arf.
|
* modified boost
|
||||||
* The active maximum quantizer insures that an appropriate
|
*/
|
||||||
* number of bits will be spent if needed for contstructed ARFs.
|
if (!cpi->source_alt_ref_active) {
|
||||||
*/
|
if (cpi->oxcf.fixed_q < 0) {
|
||||||
else {
|
if (cpi->pass == 2) {
|
||||||
cpi->this_frame_target = 0;
|
/* The spend on the GF is defined in the two pass
|
||||||
}
|
* code for two pass encodes
|
||||||
|
*/
|
||||||
|
cpi->this_frame_target = cpi->per_frame_bandwidth;
|
||||||
|
} else {
|
||||||
|
int Boost = cpi->last_boost;
|
||||||
|
int frames_in_section = cpi->frames_till_gf_update_due + 1;
|
||||||
|
int allocation_chunks = (frames_in_section * 100) + (Boost - 100);
|
||||||
|
int bits_in_section = cpi->inter_frame_target * frames_in_section;
|
||||||
|
|
||||||
|
/* Normalize Altboost and allocations chunck down to
|
||||||
|
* prevent overflow
|
||||||
|
*/
|
||||||
|
while (Boost > 1000) {
|
||||||
|
Boost /= 2;
|
||||||
|
allocation_chunks /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Avoid loss of precision but avoid overflow */
|
||||||
|
if ((bits_in_section >> 7) > allocation_chunks) {
|
||||||
|
cpi->this_frame_target =
|
||||||
|
Boost * (bits_in_section / allocation_chunks);
|
||||||
|
} else {
|
||||||
|
cpi->this_frame_target =
|
||||||
|
(Boost * bits_in_section) / allocation_chunks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
cpi->this_frame_target =
|
||||||
|
(estimate_bits_at_q(1, Q, cpi->common.MBs, 1.0) *
|
||||||
|
cpi->last_boost) /
|
||||||
|
100;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* If there is an active ARF at this location use the minimum
|
||||||
|
* bits on this frame even if it is a contructed arf.
|
||||||
|
* The active maximum quantizer insures that an appropriate
|
||||||
|
* number of bits will be spent if needed for contstructed ARFs.
|
||||||
|
*/
|
||||||
|
cpi->this_frame_target = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
cpi->current_gf_interval = cpi->frames_till_gf_update_due;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Special case for 1 pass CBR: for now no boost and fixed gf period.
|
||||||
|
// TODO(marpan): Adjust this boost/interval logic.
|
||||||
|
cpi->gf_noboost_onepass_cbr = 1;
|
||||||
|
cpi->baseline_gf_interval = cpi->gf_interval_onepass_cbr;
|
||||||
|
// Skip this update if the zero_mvcount is low.
|
||||||
|
if (cpi->zeromv_count > (cpi->common.MBs >> 1))
|
||||||
|
cpi->common.refresh_golden_frame = 1;
|
||||||
|
cpi->frames_till_gf_update_due = cpi->baseline_gf_interval;
|
||||||
cpi->current_gf_interval = cpi->frames_till_gf_update_due;
|
cpi->current_gf_interval = cpi->frames_till_gf_update_due;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1025,8 +1034,9 @@ void vp8_update_rate_correction_factors(VP8_COMP *cpi, int damp_var) {
|
|||||||
if (cpi->common.frame_type == KEY_FRAME) {
|
if (cpi->common.frame_type == KEY_FRAME) {
|
||||||
rate_correction_factor = cpi->key_frame_rate_correction_factor;
|
rate_correction_factor = cpi->key_frame_rate_correction_factor;
|
||||||
} else {
|
} else {
|
||||||
if (cpi->oxcf.number_of_layers == 1 && (cpi->common.refresh_alt_ref_frame ||
|
if (cpi->oxcf.number_of_layers == 1 && !cpi->gf_noboost_onepass_cbr &&
|
||||||
cpi->common.refresh_golden_frame)) {
|
(cpi->common.refresh_alt_ref_frame ||
|
||||||
|
cpi->common.refresh_golden_frame)) {
|
||||||
rate_correction_factor = cpi->gf_rate_correction_factor;
|
rate_correction_factor = cpi->gf_rate_correction_factor;
|
||||||
} else {
|
} else {
|
||||||
rate_correction_factor = cpi->rate_correction_factor;
|
rate_correction_factor = cpi->rate_correction_factor;
|
||||||
@@ -1102,8 +1112,9 @@ void vp8_update_rate_correction_factors(VP8_COMP *cpi, int damp_var) {
|
|||||||
if (cpi->common.frame_type == KEY_FRAME) {
|
if (cpi->common.frame_type == KEY_FRAME) {
|
||||||
cpi->key_frame_rate_correction_factor = rate_correction_factor;
|
cpi->key_frame_rate_correction_factor = rate_correction_factor;
|
||||||
} else {
|
} else {
|
||||||
if (cpi->oxcf.number_of_layers == 1 && (cpi->common.refresh_alt_ref_frame ||
|
if (cpi->oxcf.number_of_layers == 1 && !cpi->gf_noboost_onepass_cbr &&
|
||||||
cpi->common.refresh_golden_frame)) {
|
(cpi->common.refresh_alt_ref_frame ||
|
||||||
|
cpi->common.refresh_golden_frame)) {
|
||||||
cpi->gf_rate_correction_factor = rate_correction_factor;
|
cpi->gf_rate_correction_factor = rate_correction_factor;
|
||||||
} else {
|
} else {
|
||||||
cpi->rate_correction_factor = rate_correction_factor;
|
cpi->rate_correction_factor = rate_correction_factor;
|
||||||
@@ -1118,7 +1129,6 @@ int vp8_regulate_q(VP8_COMP *cpi, int target_bits_per_frame) {
|
|||||||
cpi->active_worst_quality = cpi->worst_quality;
|
cpi->active_worst_quality = cpi->worst_quality;
|
||||||
return cpi->worst_quality;
|
return cpi->worst_quality;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reset Zbin OQ value */
|
/* Reset Zbin OQ value */
|
||||||
cpi->mb.zbin_over_quant = 0;
|
cpi->mb.zbin_over_quant = 0;
|
||||||
|
|
||||||
@@ -1128,10 +1138,12 @@ int vp8_regulate_q(VP8_COMP *cpi, int target_bits_per_frame) {
|
|||||||
if (cpi->common.frame_type == KEY_FRAME) {
|
if (cpi->common.frame_type == KEY_FRAME) {
|
||||||
Q = cpi->oxcf.key_q;
|
Q = cpi->oxcf.key_q;
|
||||||
} else if (cpi->oxcf.number_of_layers == 1 &&
|
} else if (cpi->oxcf.number_of_layers == 1 &&
|
||||||
cpi->common.refresh_alt_ref_frame) {
|
cpi->common.refresh_alt_ref_frame &&
|
||||||
|
!cpi->gf_noboost_onepass_cbr) {
|
||||||
Q = cpi->oxcf.alt_q;
|
Q = cpi->oxcf.alt_q;
|
||||||
} else if (cpi->oxcf.number_of_layers == 1 &&
|
} else if (cpi->oxcf.number_of_layers == 1 &&
|
||||||
cpi->common.refresh_golden_frame) {
|
cpi->common.refresh_golden_frame &&
|
||||||
|
!cpi->gf_noboost_onepass_cbr) {
|
||||||
Q = cpi->oxcf.gold_q;
|
Q = cpi->oxcf.gold_q;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -1145,7 +1157,7 @@ int vp8_regulate_q(VP8_COMP *cpi, int target_bits_per_frame) {
|
|||||||
if (cpi->common.frame_type == KEY_FRAME) {
|
if (cpi->common.frame_type == KEY_FRAME) {
|
||||||
correction_factor = cpi->key_frame_rate_correction_factor;
|
correction_factor = cpi->key_frame_rate_correction_factor;
|
||||||
} else {
|
} else {
|
||||||
if (cpi->oxcf.number_of_layers == 1 &&
|
if (cpi->oxcf.number_of_layers == 1 && !cpi->gf_noboost_onepass_cbr &&
|
||||||
(cpi->common.refresh_alt_ref_frame ||
|
(cpi->common.refresh_alt_ref_frame ||
|
||||||
cpi->common.refresh_golden_frame)) {
|
cpi->common.refresh_golden_frame)) {
|
||||||
correction_factor = cpi->gf_rate_correction_factor;
|
correction_factor = cpi->gf_rate_correction_factor;
|
||||||
@@ -1199,6 +1211,7 @@ int vp8_regulate_q(VP8_COMP *cpi, int target_bits_per_frame) {
|
|||||||
if (cpi->common.frame_type == KEY_FRAME) {
|
if (cpi->common.frame_type == KEY_FRAME) {
|
||||||
zbin_oqmax = 0;
|
zbin_oqmax = 0;
|
||||||
} else if (cpi->oxcf.number_of_layers == 1 &&
|
} else if (cpi->oxcf.number_of_layers == 1 &&
|
||||||
|
!cpi->gf_noboost_onepass_cbr &&
|
||||||
(cpi->common.refresh_alt_ref_frame ||
|
(cpi->common.refresh_alt_ref_frame ||
|
||||||
(cpi->common.refresh_golden_frame &&
|
(cpi->common.refresh_golden_frame &&
|
||||||
!cpi->source_alt_ref_active))) {
|
!cpi->source_alt_ref_active))) {
|
||||||
|
|||||||
Reference in New Issue
Block a user