📄 ratecontrol.c
字号:
memset(rc->entry, 0, rc->num_entries * sizeof(ratecontrol_entry_t));
/* init all to skipped p frames */
for(i=0; i<rc->num_entries; i++){
ratecontrol_entry_t *rce = &rc->entry[i];
rce->pict_type = SLICE_TYPE_P;
rce->qscale = rce->new_qscale = qp2qscale(20);
rce->misc_bits = rc->nmb + 10;
rce->new_qp = 0;
}
/* read stats */
p = stats_in;
for(i=0; i < rc->num_entries - h->param.i_bframe; i++){
ratecontrol_entry_t *rce;
int frame_number;
char pict_type;
int e;
char *next;
float qp;
next= strchr(p, ';');
if(next){
(*next)=0; //sscanf is unbelievably slow on looong strings
next++;
}
e = sscanf(p, " in:%d ", &frame_number);
if(frame_number < 0 || frame_number >= rc->num_entries)
{
x264_log(h, X264_LOG_ERROR, "bad frame number (%d) at stats line %d\n", frame_number, i);
return -1;
}
rce = &rc->entry[frame_number];
rce->direct_mode = 0;
e += sscanf(p, " in:%*d out:%*d type:%c q:%f itex:%d ptex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d d:%c",
&pict_type, &qp, &rce->i_tex_bits, &rce->p_tex_bits,
&rce->mv_bits, &rce->misc_bits, &rce->i_count, &rce->p_count,
&rce->s_count, &rce->direct_mode);
switch(pict_type){
case 'I': rce->kept_as_ref = 1;
case 'i': rce->pict_type = SLICE_TYPE_I; break;
case 'P': rce->pict_type = SLICE_TYPE_P; break;
case 'B': rce->kept_as_ref = 1;
case 'b': rce->pict_type = SLICE_TYPE_B; break;
default: e = -1; break;
}
if(e < 10){
x264_log(h, X264_LOG_ERROR, "statistics are damaged at line %d, parser out=%d\n", i, e);
return -1;
}
rce->qscale = qp2qscale(qp);
p = next;
}
x264_free(stats_buf);
if(h->param.rc.i_rc_method == X264_RC_ABR)
{
if(init_pass2(h) < 0) return -1;
} /* else we're using constant quant, so no need to run the bitrate allocation */
}
/* Open output file */
/* If input and output files are the same, output to a temp file
* and move it to the real name only when it's complete */
if( h->param.rc.b_stat_write )
{
char *p;
rc->psz_stat_file_tmpname = x264_malloc( strlen(h->param.rc.psz_stat_out) + 6 );
strcpy( rc->psz_stat_file_tmpname, h->param.rc.psz_stat_out );
strcat( rc->psz_stat_file_tmpname, ".temp" );
rc->p_stat_file_out = fopen( rc->psz_stat_file_tmpname, "wb" );
if( rc->p_stat_file_out == NULL )
{
x264_log(h, X264_LOG_ERROR, "ratecontrol_init: can't open stats file\n");
return -1;
}
p = x264_param2string( &h->param, 1 );
fprintf( rc->p_stat_file_out, "#options: %s\n", p );
x264_free( p );
}
return 0;
}
static int parse_zones( x264_t *h )
{
x264_ratecontrol_t *rc = h->rc;
int i;
if( h->param.rc.psz_zones && !h->param.rc.i_zones )
{
char *p;
h->param.rc.i_zones = 1;
for( p = h->param.rc.psz_zones; *p; p++ )
h->param.rc.i_zones += (*p == '/');
h->param.rc.zones = x264_malloc( h->param.rc.i_zones * sizeof(x264_zone_t) );
p = h->param.rc.psz_zones;
for( i = 0; i < h->param.rc.i_zones; i++)
{
x264_zone_t *z = &h->param.rc.zones[i];
if( 3 == sscanf(p, "%u,%u,q=%u", &z->i_start, &z->i_end, &z->i_qp) )
z->b_force_qp = 1;
else if( 3 == sscanf(p, "%u,%u,b=%f", &z->i_start, &z->i_end, &z->f_bitrate_factor) )
z->b_force_qp = 0;
else
{
char *slash = strchr(p, '/');
if(slash) *slash = '\0';
x264_log( h, X264_LOG_ERROR, "invalid zone: \"%s\"\n", p );
return -1;
}
p = strchr(p, '/') + 1;
}
}
if( h->param.rc.i_zones > 0 )
{
for( i = 0; i < h->param.rc.i_zones; i++ )
{
x264_zone_t z = h->param.rc.zones[i];
if( z.i_start < 0 || z.i_start > z.i_end )
{
x264_log( h, X264_LOG_ERROR, "invalid zone: start=%d end=%d\n",
z.i_start, z.i_end );
return -1;
}
else if( !z.b_force_qp && z.f_bitrate_factor <= 0 )
{
x264_log( h, X264_LOG_ERROR, "invalid zone: bitrate_factor=%f\n",
z.f_bitrate_factor );
return -1;
}
}
rc->i_zones = h->param.rc.i_zones;
rc->zones = x264_malloc( rc->i_zones * sizeof(x264_zone_t) );
memcpy( rc->zones, h->param.rc.zones, rc->i_zones * sizeof(x264_zone_t) );
}
return 0;
}
void x264_ratecontrol_summary( x264_t *h )
{
x264_ratecontrol_t *rc = h->rc;
if( rc->b_abr && h->param.rc.i_rc_method == X264_RC_ABR && !h->param.rc.i_vbv_max_bitrate )
{
double base_cplx = h->mb.i_mb_count * (h->param.i_bframe ? 120 : 80);
x264_log( h, X264_LOG_INFO, "final ratefactor: %.2f\n",
qscale2qp( pow( base_cplx, 1 - h->param.rc.f_qcompress )
* rc->cplxr_sum / rc->wanted_bits_window ) );
}
}
void x264_ratecontrol_delete( x264_t *h )
{
x264_ratecontrol_t *rc = h->rc;
if( rc->p_stat_file_out )
{
fclose( rc->p_stat_file_out );
if( h->i_frame >= rc->num_entries - h->param.i_bframe )
if( rename( rc->psz_stat_file_tmpname, h->param.rc.psz_stat_out ) != 0 )
{
x264_log( h, X264_LOG_ERROR, "failed to rename \"%s\" to \"%s\"\n",
rc->psz_stat_file_tmpname, h->param.rc.psz_stat_out );
}
x264_free( rc->psz_stat_file_tmpname );
}
x264_free( rc->entry );
x264_free( rc->zones );
x264_free( rc );
}
/* Before encoding a frame, choose a QP for it */
void x264_ratecontrol_start( x264_t *h, int i_slice_type, int i_force_qp )
{
x264_ratecontrol_t *rc = h->rc;
ratecontrol_entry_t *rce = NULL;
/// x264_cpu_restore( h->param.cpu );
rc->qp_force = i_force_qp;
rc->slice_type = i_slice_type;
if( h->param.rc.b_stat_read )
{
int frame = h->fenc->i_frame;
assert( frame >= 0 && frame < rc->num_entries );
rce = h->rc->rce = &h->rc->entry[frame];
if( i_slice_type == SLICE_TYPE_B
&& h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO )
{
h->sh.b_direct_spatial_mv_pred = ( rce->direct_mode == 's' );
h->mb.b_direct_auto_read = ( rce->direct_mode == 's' || rce->direct_mode == 't' );
}
}
if( h->fdec->i_row_bits )
{
memset( h->fdec->i_row_bits, 0, h->sps->i_mb_height * sizeof(int) );
}
if( i_slice_type != SLICE_TYPE_B )
{
rc->bframe_bits = 0;
rc->bframes = 0;
while( h->frames.current[rc->bframes] && IS_X264_TYPE_B(h->frames.current[rc->bframes]->i_type) )
rc->bframes++;
}
rc->qpa = 0;
if( i_force_qp )
{
rc->qpm = rc->qp = i_force_qp - 1;
}
else if( rc->b_abr )
{
rc->qpm = rc->qp =
x264_clip3( (int)(qscale2qp( rate_estimate_qscale( h, i_slice_type ) ) + .5), 0, 51 );
}
else if( rc->b_2pass )
{
rce->new_qscale = rate_estimate_qscale( h, i_slice_type );
rc->qpm = rc->qp = rce->new_qp =
x264_clip3( (int)(qscale2qp(rce->new_qscale) + 0.5), 0, 51 );
}
else /* CQP */
{
int q;
if( i_slice_type == SLICE_TYPE_B && h->fdec->b_kept_as_ref )
q = ( rc->qp_constant[ SLICE_TYPE_B ] + rc->qp_constant[ SLICE_TYPE_P ] ) / 2;
else
q = rc->qp_constant[ i_slice_type ];
rc->qpm = rc->qp = q;
}
}
double predict_row_size( x264_t *h, int y, int qp )
{
/* average between two predictors:
* absolute SATD, and scaled bit cost of the colocated row in the previous frame */
x264_ratecontrol_t *rc = h->rc;
double pred_s = predict_size( rc->row_pred, qp2qscale(qp), h->fdec->i_row_satd[y] );
double pred_t = 0;
if( rc->slice_type != SLICE_TYPE_I
&& h->fref0[0]->i_type == h->fdec->i_type
&& h->fref0[0]->i_row_satd[y] > 0 )
{
pred_t = h->fref0[0]->i_row_bits[y] * h->fdec->i_row_satd[y] / h->fref0[0]->i_row_satd[y]
* qp2qscale(h->fref0[0]->i_row_qp[y]) / qp2qscale(qp);
}
if( pred_t == 0 )
pred_t = pred_s;
return (pred_s + pred_t) / 2;
}
double predict_row_size_sum( x264_t *h, int y, int qp )
{
int i;
double bits = 0;
for( i = h->rc->first_row; i <= y; i++ )
bits += h->fdec->i_row_bits[i];
for( i = y+1; i <= h->rc->last_row; i++ )
bits += predict_row_size( h, i, qp );
return bits;
}
void x264_ratecontrol_mb( x264_t *h, int bits )
{
x264_ratecontrol_t *rc = h->rc;
const int y = h->mb.i_mb_y;
/// x264_cpu_restore( h->param.cpu );
h->fdec->i_row_bits[y] += bits;
rc->qpa += rc->qpm;
if( h->mb.i_mb_x != h->sps->i_mb_width - 1 || !h->mb.b_variable_qp )
return;
h->fdec->i_row_qp[y] = rc->qpm;
if( rc->slice_type == SLICE_TYPE_B )
{
/* B-frames shouldn't use lower QP than their reference frames */
if( y < rc->last_row )
{
rc->qpm = X264_MAX( rc->qp,
X264_MIN( h->fref0[0]->i_row_qp[y+1],
h->fref1[0]->i_row_qp[y+1] ));
}
}
else
{
update_predictor( rc->row_pred, qp2qscale(rc->qpm), h->fdec->i_row_satd[y], h->fdec->i_row_bits[y] );
/* tweak quality based on difference from predicted size */
if( y < rc->last_row && h->stat.i_slice_count[rc->slice_type] > 0 )
{
int prev_row_qp = h->fdec->i_row_qp[y];
int b0 = predict_row_size_sum( h, y, rc->qpm );
int b1 = b0;
int i_qp_max = X264_MIN( prev_row_qp + h->param.rc.i_qp_step, h->param.rc.i_qp_max );
int i_qp_min = X264_MAX( prev_row_qp - h->param.rc.i_qp_step, h->param.rc.i_qp_min );
float buffer_left_planned = rc->buffer_fill - rc->frame_size_planned;
while( rc->qpm < i_qp_max
&& (b1 > rc->frame_size_planned * 1.15
|| (rc->buffer_fill - b1 < buffer_left_planned * 0.5)))
{
rc->qpm ++;
b1 = predict_row_size_sum( h, y, rc->qpm );
}
while( rc->qpm > i_qp_min
&& buffer_left_planned > rc->buffer_size * 0.4
&& ((b1 < rc->frame_size_planned * 0.8 && rc->qpm <= prev_row_qp)
|| b1 < (rc->buffer_fill - rc->buffer_size + rc->buffer_rate) * 1.1) )
{
rc->qpm --;
b1 = predict_row_size_sum( h, y, rc->qpm );
}
}
}
}
int x264_ratecontrol_qp( x264_t *h )
{
return h->rc->qpm;
}
/* In 2pass, force the same frame types as in the 1st pass */
int x264_ratecontrol_slice_type( x264_t *h, int frame_num )
{
x264_ratecontrol_t *rc = h->rc;
if( h->param.rc.b_stat_read )
{
if( frame_num >= rc->num_entries )
{
/* We could try to initialize everything required for ABR and
* adaptive B-frames, but that would be complicated.
* So just calculate the average QP used so far. */
h->param.rc.i_qp_constant = (h->stat.i_slice_count[SLICE_TYPE_P] == 0) ? 24
: 1 + h->stat.i_slice_qp[SLICE_TYPE_P] / h->stat.i_slice_count[SLICE_TYPE_P];
rc->qp_constant[SLICE_TYPE_P] = x264_clip3( h->param.rc.i_qp_constant, 0, 51 );
rc->qp_constant[SLICE_TYPE_I] = x264_clip3( (int)( qscale2qp( qp2qscale( h->param.rc.i_qp_constant ) / fabs( h->param.rc.f_ip_factor )) + 0.5 ), 0, 51 );
rc->qp_constant[SLICE_TYPE_B] = x264_clip3( (int)( qscale2qp( qp2qscale( h->param.rc.i_qp_constant ) * fabs( h->param.rc.f_pb_factor )) + 0.5 ), 0, 51 );
x264_log(h, X264_LOG_ERROR, "2nd pass has more frames than 1st pass (%d)\n", rc->num_entries);
x264_log(h, X264_LOG_ERROR, "continuing anyway, at constant QP=%d\n", h->param.rc.i_qp_constant);
if( h->param.b_bframe_adaptive )
x264_log(h, X264_LOG_ERROR, "disabling adaptive B-frames\n");
rc->b_abr = 0;
rc->b_2pass = 0;
h->param.rc.i_rc_method = X264_RC_CQP;
h->param.rc.b_stat_read = 0;
h->param.b_bframe_adaptive = 0;
if( h->param.i_bframe > 1 )
h->param.i_bframe = 1;
return X264_TYPE_P;
}
switch( rc->entry[frame_num].pict_type )
{
case SLICE_TYPE_I:
return rc->entry[frame_num].kept_as_ref ? X264_TYPE_IDR : X264_TYPE_I;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -