[x264-devel] Improve HRD conformance
Anton Mitrofanov
git at videolan.org
Sat Dec 20 21:10:50 CET 2014
x264 | branch: master | Anton Mitrofanov <BugMaster at narod.ru> | Wed Aug 29 03:02:27 2012 +0400| [f4a455a43df3088bae5208dcc98b8f6214fdce7d] | committer: Anton Mitrofanov
Improve HRD conformance
> http://git.videolan.org/gitweb.cgi/x264.git/?a=commit;h=f4a455a43df3088bae5208dcc98b8f6214fdce7d
---
encoder/ratecontrol.c | 82 ++++++++++++++++++++++++++++++-------------------
1 file changed, 51 insertions(+), 31 deletions(-)
diff --git a/encoder/ratecontrol.c b/encoder/ratecontrol.c
index 3e92e38..363e81e 100644
--- a/encoder/ratecontrol.c
+++ b/encoder/ratecontrol.c
@@ -96,6 +96,7 @@ struct x264_ratecontrol_t
/* VBV stuff */
double buffer_size;
int64_t buffer_fill_final;
+ int64_t buffer_fill_final_min;
double buffer_fill; /* planned buffer, if all in-progress frames hit their bit budget */
double buffer_rate; /* # of bits added to buffer_fill after each frame */
double vbv_max_rate; /* # of bits added to buffer_fill per second */
@@ -724,7 +725,8 @@ void x264_ratecontrol_init_reconfigurable( x264_t *h, int b_init )
if( h->param.rc.f_vbv_buffer_init > 1. )
h->param.rc.f_vbv_buffer_init = x264_clip3f( h->param.rc.f_vbv_buffer_init / h->param.rc.i_vbv_buffer_size, 0, 1 );
h->param.rc.f_vbv_buffer_init = x264_clip3f( X264_MAX( h->param.rc.f_vbv_buffer_init, rc->buffer_rate / rc->buffer_size ), 0, 1);
- rc->buffer_fill_final = rc->buffer_size * h->param.rc.f_vbv_buffer_init * h->sps->vui.i_time_scale;
+ rc->buffer_fill_final =
+ rc->buffer_fill_final_min = rc->buffer_size * h->param.rc.f_vbv_buffer_init * h->sps->vui.i_time_scale;
rc->b_vbv = 1;
rc->b_vbv_min_rate = !rc->b_2pass
&& h->param.rc.i_rc_method == X264_RC_ABR
@@ -776,11 +778,11 @@ int x264_ratecontrol_new( x264_t *h )
if( h->param.i_nal_hrd )
{
uint64_t denom = (uint64_t)h->sps->vui.hrd.i_bit_rate_unscaled * h->sps->vui.i_time_scale;
- uint64_t num = 180000;
+ uint64_t num = 90000;
x264_reduce_fraction64( &num, &denom );
- rc->hrd_multiply_denom = 180000 / num;
+ rc->hrd_multiply_denom = 90000 / num;
- double bits_required = log2( 180000 / rc->hrd_multiply_denom )
+ double bits_required = log2( 90000 / rc->hrd_multiply_denom )
+ log2( h->sps->vui.i_time_scale )
+ log2( h->sps->vui.hrd.i_cpb_size_unscaled );
if( bits_required >= 63 )
@@ -1914,15 +1916,16 @@ int x264_ratecontrol_end( x264_t *h, int bits, int *filler )
h->fenc->hrd_timing.cpb_removal_time = rc->nrt_first_access_unit + (double)(h->fenc->i_cpb_delay - h->i_cpb_delay_pir_offset) *
h->sps->vui.i_num_units_in_tick / h->sps->vui.i_time_scale;
- double cpb_earliest_arrival_time = h->fenc->hrd_timing.cpb_removal_time - (double)rc->initial_cpb_removal_delay / 90000;
if( h->fenc->b_keyframe )
{
- rc->nrt_first_access_unit = h->fenc->hrd_timing.cpb_removal_time;
- rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay;
- rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset;
+ rc->nrt_first_access_unit = h->fenc->hrd_timing.cpb_removal_time;
+ rc->initial_cpb_removal_delay = h->initial_cpb_removal_delay;
+ rc->initial_cpb_removal_delay_offset = h->initial_cpb_removal_delay_offset;
}
- else
- cpb_earliest_arrival_time -= (double)rc->initial_cpb_removal_delay_offset / 90000;
+
+ double cpb_earliest_arrival_time = h->fenc->hrd_timing.cpb_removal_time - (double)rc->initial_cpb_removal_delay / 90000;
+ if( !h->fenc->b_keyframe )
+ cpb_earliest_arrival_time -= (double)rc->initial_cpb_removal_delay_offset / 90000;
if( h->sps->vui.hrd.b_cbr_hrd )
h->fenc->hrd_timing.cpb_initial_arrival_time = rc->previous_cpb_final_arrival_time;
@@ -2095,7 +2098,7 @@ static int update_vbv( x264_t *h, int bits )
int bitrate = h->sps->vui.hrd.i_bit_rate_unscaled;
x264_ratecontrol_t *rcc = h->rc;
x264_ratecontrol_t *rct = h->thread[0]->rc;
- uint64_t buffer_size = (uint64_t)h->sps->vui.hrd.i_cpb_size_unscaled * h->sps->vui.i_time_scale;
+ int64_t buffer_size = (int64_t)h->sps->vui.hrd.i_cpb_size_unscaled * h->sps->vui.i_time_scale;
if( rcc->last_satd >= h->mb.i_mb_count )
update_predictor( &rct->pred[h->sh.i_type], qp2qscale( rcc->qpa_rc ), rcc->last_satd, bits );
@@ -2103,32 +2106,45 @@ static int update_vbv( x264_t *h, int bits )
if( !rcc->b_vbv )
return filler;
- rct->buffer_fill_final -= (uint64_t)bits * h->sps->vui.i_time_scale;
+ uint64_t buffer_diff = (uint64_t)bits * h->sps->vui.i_time_scale;
+ rct->buffer_fill_final -= buffer_diff;
+ rct->buffer_fill_final_min -= buffer_diff;
- if( rct->buffer_fill_final < 0 )
+ if( rct->buffer_fill_final_min < 0 )
{
- double underflow = (double)rct->buffer_fill_final / h->sps->vui.i_time_scale;
+ double underflow = (double)rct->buffer_fill_final_min / h->sps->vui.i_time_scale;
if( rcc->rate_factor_max_increment && rcc->qpm >= rcc->qp_novbv + rcc->rate_factor_max_increment )
x264_log( h, X264_LOG_DEBUG, "VBV underflow due to CRF-max (frame %d, %.0f bits)\n", h->i_frame, underflow );
else
x264_log( h, X264_LOG_WARNING, "VBV underflow (frame %d, %.0f bits)\n", h->i_frame, underflow );
+ rct->buffer_fill_final =
+ rct->buffer_fill_final_min = 0;
}
- rct->buffer_fill_final = X264_MAX( rct->buffer_fill_final, 0 );
if( h->param.i_avcintra_class )
- rct->buffer_fill_final += buffer_size;
+ buffer_diff = buffer_size;
else
- rct->buffer_fill_final += (uint64_t)bitrate * h->sps->vui.i_num_units_in_tick * h->fenc->i_cpb_duration;
+ buffer_diff = (uint64_t)bitrate * h->sps->vui.i_num_units_in_tick * h->fenc->i_cpb_duration;
+ rct->buffer_fill_final += buffer_diff;
+ rct->buffer_fill_final_min += buffer_diff;
- if( h->param.rc.b_filler && rct->buffer_fill_final > buffer_size )
+ if( rct->buffer_fill_final > buffer_size )
{
- int64_t scale = (int64_t)h->sps->vui.i_time_scale * 8;
- filler = (rct->buffer_fill_final - buffer_size + scale - 1) / scale;
- bits = h->param.i_avcintra_class ? filler * 8 : X264_MAX( (FILLER_OVERHEAD - h->param.b_annexb), filler ) * 8;
- rct->buffer_fill_final -= (uint64_t)bits * h->sps->vui.i_time_scale;
+ if( h->param.rc.b_filler )
+ {
+ int64_t scale = (int64_t)h->sps->vui.i_time_scale * 8;
+ filler = (rct->buffer_fill_final - buffer_size + scale - 1) / scale;
+ bits = h->param.i_avcintra_class ? filler * 8 : X264_MAX( (FILLER_OVERHEAD - h->param.b_annexb), filler ) * 8;
+ buffer_diff = (uint64_t)bits * h->sps->vui.i_time_scale;
+ rct->buffer_fill_final -= buffer_diff;
+ rct->buffer_fill_final_min -= buffer_diff;
+ }
+ else
+ {
+ rct->buffer_fill_final = X264_MIN( rct->buffer_fill_final, buffer_size );
+ rct->buffer_fill_final_min = X264_MIN( rct->buffer_fill_final_min, buffer_size );
+ }
}
- else
- rct->buffer_fill_final = X264_MIN( rct->buffer_fill_final, buffer_size );
return filler;
}
@@ -2139,23 +2155,27 @@ void x264_hrd_fullness( x264_t *h )
uint64_t denom = (uint64_t)h->sps->vui.hrd.i_bit_rate_unscaled * h->sps->vui.i_time_scale / rct->hrd_multiply_denom;
uint64_t cpb_state = rct->buffer_fill_final;
uint64_t cpb_size = (uint64_t)h->sps->vui.hrd.i_cpb_size_unscaled * h->sps->vui.i_time_scale;
- uint64_t multiply_factor = 180000 / rct->hrd_multiply_denom;
+ uint64_t multiply_factor = 90000 / rct->hrd_multiply_denom;
- if( rct->buffer_fill_final < 0 || rct->buffer_fill_final > cpb_size )
+ if( rct->buffer_fill_final < 0 || rct->buffer_fill_final > (int64_t)cpb_size )
{
- x264_log( h, X264_LOG_WARNING, "CPB %s: %.0lf bits in a %.0lf-bit buffer\n",
- rct->buffer_fill_final < 0 ? "underflow" : "overflow", (float)rct->buffer_fill_final/denom, (float)cpb_size/denom );
+ x264_log( h, X264_LOG_WARNING, "CPB %s: %.0f bits in a %.0f-bit buffer\n",
+ rct->buffer_fill_final < 0 ? "underflow" : "overflow",
+ (double)rct->buffer_fill_final / h->sps->vui.i_time_scale, (double)cpb_size / h->sps->vui.i_time_scale );
}
- h->initial_cpb_removal_delay = (multiply_factor * cpb_state + denom) / (2*denom);
- h->initial_cpb_removal_delay_offset = (multiply_factor * cpb_size + denom) / (2*denom) - h->initial_cpb_removal_delay;
+ h->initial_cpb_removal_delay = (multiply_factor * cpb_state) / denom;
+ h->initial_cpb_removal_delay_offset = (multiply_factor * cpb_size) / denom - h->initial_cpb_removal_delay;
+
+ int64_t decoder_buffer_fill = h->initial_cpb_removal_delay * denom / multiply_factor;
+ rct->buffer_fill_final_min = X264_MIN( rct->buffer_fill_final_min, decoder_buffer_fill );
}
// provisionally update VBV according to the planned size of all frames currently in progress
static void update_vbv_plan( x264_t *h, int overhead )
{
x264_ratecontrol_t *rcc = h->rc;
- rcc->buffer_fill = h->thread[0]->rc->buffer_fill_final / h->sps->vui.i_time_scale;
+ rcc->buffer_fill = h->thread[0]->rc->buffer_fill_final_min / h->sps->vui.i_time_scale;
if( h->i_thread_frames > 1 )
{
int j = h->rc - h->thread[0]->rc;
More information about the x264-devel
mailing list