int x264_ratecontrol_new( x264_t *h )
{
x264_ratecontrol_t *rc;
x264_emms();
// 依据线程数, 为h->rc分配内存空间
CHECKED_MALLOCZERO( h->rc, h->param.i_threads * sizeof(x264_ratecontrol_t) );
rc = h->rc;
// 确定是否为自适应码率控制模式
rc->b_abr = h->param.rc.i_rc_method != X264_RC_CQP && !h->param.rc.b_stat_read;
rc->b_2pass = h->param.rc.i_rc_method == X264_RC_ABR && h->param.rc.b_stat_read;
/* FIXME: use integers */
// 计算帧率
if( h->param.i_fps_num > 0 && h->param.i_fps_den > 0 )
rc->fps = (float) h->param.i_fps_num / h->param.i_fps_den;
else
rc->fps = 25.0;
// 如果 mbtree 码率控制, 则pb_factor = 1, 即B帧等同P帧的qp
// 同时, 量化器曲线压缩因子等于 1
if( h->param.rc.b_mb_tree )
{
h->param.rc.f_pb_factor = 1;
rc->qcompress = 1;
}
else
rc->qcompress = h->param.rc.f_qcompress;
rc->bitrate = h->param.rc.i_bitrate * (h->param.i_avcintra_class ? 1024. : 1000.);
// bitrate 容许误差
rc->rate_tolerance = h->param.rc.f_rate_tolerance;
rc->nmb = h->mb.i_mb_count;
rc->last_non_b_pict_type = -1;
// cbr 衰减系数
rc->cbr_decay = 1.0;
if( h->param.rc.i_rc_method == X264_RC_CRF && h->param.rc.b_stat_read )
{
x264_log( h, X264_LOG_ERROR, "constant rate-factor is incompatible with 2pass.\n" );
return -1;
}
// 见 x264_ratecontrol_init_reconfigurable
x264_ratecontrol_init_reconfigurable( h, 1 );
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;
x264_reduce_fraction64( &num, &denom );
rc->hrd_multiply_denom = 180000 / num;
double bits_required = log2( 180000 / rc->hrd_multiply_denom )
+ log2( h->sps->vui.i_time_scale )
+ log2( h->sps->vui.hrd.i_cpb_size_unscaled );
if( bits_required >= 63 )
{
x264_log( h, X264_LOG_ERROR, "HRD with very large timescale and bufsize not supported\n" );
return -1;
}
}
// 容许误差太小
if( rc->rate_tolerance < 0.01 )
{
x264_log( h, X264_LOG_WARNING, "bitrate tolerance too small, using .01\n" );
rc->rate_tolerance = 0.01;
}
// 可变qp标志取决于两个变量的或, b_vbv 和rc.i_aq_mode
h->mb.b_variable_qp = rc->b_vbv || h->param.rc.i_aq_mode;
// 如果自适应码率控制
if( rc->b_abr )
{
/* FIXME ABR_INIT_QP is actually used only in CRF */
#define ABR_INIT_QP (( h->param.rc.i_rc_method == X264_RC_CRF ? h->param.rc.f_rf_constant : 24 ) + QP_BD_OFFSET)
rc->accum_p_norm = .01;
rc->accum_p_qp = ABR_INIT_QP * rc->accum_p_norm;
/* estimated ratio that produces a reasonable QP for the first I-frame */
// 预计复杂度之和
rc->cplxr_sum = .01 * pow( 7.0e5, rc->qcompress ) * pow( h->mb.i_mb_count, 0.5 );
// 分摊到每帧bit数窗口
rc->wanted_bits_window = 1.0 * rc->bitrate / rc->fps;
// 最后非B帧图片类型为I
rc->last_non_b_pict_type = SLICE_TYPE_I;
}
// 缺省 param.rc.f_ip_factor = 1.4
// h->param.rc.f_ip_factor = param.rc.f_ip_factor
// I帧qp偏移 = 6.0 * log2f( h->param.rc.f_ip_factor )
// 缺省 param.rc.f_pb_factor = 1.3
// h->param.rc.f_pb_factor = param.rc.f_pb_factor
// B帧qp偏移 = 6.0 * log2f( h->param.rc.f_pb_factor );
rc->ip_offset = 6.0 * log2f( h->param.rc.f_ip_factor );
rc->pb_offset = 6.0 * log2f( h->param.rc.f_pb_factor );
rc->qp_constant[SLICE_TYPE_P] = h->param.rc.i_qp_constant;
rc->qp_constant[SLICE_TYPE_I] = x264_clip3( h->param.rc.i_qp_constant - rc->ip_offset + 0.5, 0, QP_MAX );
rc->qp_constant[SLICE_TYPE_B] = x264_clip3( h->param.rc.i_qp_constant + rc->pb_offset + 0.5, 0, QP_MAX );
h->mb.ip_offset = rc->ip_offset + 0.5;
// lstep=>每帧qscale的最大变化系数
// 初始化last_qscale
rc->lstep = pow( 2, h->param.rc.i_qp_step / 6.0 );
rc->last_qscale = qp2qscale( 26 );
// 初始化pred, row_preds, lmin, lmax, last_qscale_for
// lmin, lmax 表示与帧类型相关的最小,最大qscale
// last_qscale_for 表示与帧类型相关的上一次的qscale
// 帧(图像类型)
// enum slice_type_e
// {
// SLICE_TYPE_P = 0,
// SLICE_TYPE_B = 1,
// SLICE_TYPE_I = 2,
// };
int num_preds = h->param.b_sliced_threads * h->param.i_threads + 1;
CHECKED_MALLOC( rc->pred, 5 * sizeof(predictor_t) * num_preds );
CHECKED_MALLOC( rc->pred_b_from_p, sizeof(predictor_t) );
for( int i = 0; i < 3; i++ )
{
rc->last_qscale_for[i] = qp2qscale( ABR_INIT_QP );
rc->lmin[i] = qp2qscale( h->param.rc.i_qp_min );
rc->lmax[i] = qp2qscale( h->param.rc.i_qp_max );
for( int j = 0; j < num_preds; j++ )
{
rc->pred[i+j*5].coeff_min = 2.0 / 4;
rc->pred[i+j*5].coeff = 2.0;
rc->pred[i+j*5].count = 1.0;
rc->pred[i+j*5].decay = 0.5;
rc->pred[i+j*5].offset = 0.0;
}
for( int j = 0; j < 2; j++ )
{
rc->row_preds[i][j].coeff_min = .25 / 4;
rc->row_preds[i][j].coeff = .25;
rc->row_preds[i][j].count = 1.0;
rc->row_preds[i][j].decay = 0.5;
rc->row_preds[i][j].offset = 0.0;
}
}
*rc->pred_b_from_p = rc->pred[0];
// 见 parse_zones
if( parse_zones( h ) < 0 )
{
x264_log( h, X264_LOG_ERROR, "failed to parse zones\n" );
return -1;
}
/* Load stat file and init 2pass algo */
if( h->param.rc.b_stat_read )
{
char *p, *stats_in, *stats_buf;
/* read 1st pass stats */
assert( h->param.rc.psz_stat_in );
stats_buf = stats_in = x264_slurp_file( h->param.rc.psz_stat_in );
if( !stats_buf )
{
x264_log( h, X264_LOG_ERROR, "ratecontrol_init: can't open stats file\n" );
return -1;
}
if( h->param.rc.b_mb_tree )
{
char *mbtree_stats_in = x264_strcat_filename( h->param.rc.psz_stat_in, ".mbtree" );
if( !mbtree_stats_in )
return -1;
rc->p_mbtree_stat_file_in = x264_fopen( mbtree_stats_in, "rb" );
x264_free( mbtree_stats_in );
if( !rc->p_mbtree_stat_file_in )
{
x264_log( h, X264_LOG_ERROR, "ratecontrol_init: can't open mbtree stats file\n" );
return -1;
}
}
/* check whether 1st pass options were compatible with current options */
if( strncmp( stats_buf, "#options:", 9 ) )
{
x264_log( h, X264_LOG_ERROR, "options list in stats file not valid\n" );
return -1;
}
float res_factor, res_factor_bits;
{
int i, j;
uint32_t k, l;
char *opts = stats_buf;
stats_in = strchr( stats_buf, '\n' );
if( !stats_in )
return -1;
*stats_in = '\0';
stats_in++;
if( sscanf( opts, "#options: %dx%d", &i, &j ) != 2 )
{
x264_log( h, X264_LOG_ERROR, "resolution specified in stats file not valid\n" );
return -1;
}
else if( h->param.rc.b_mb_tree )
{
rc->mbtree.srcdim[0] = i;
rc->mbtree.srcdim[1] = j;
}
res_factor = (float)h->param.i_width * h->param.i_height / (i*j);
/* Change in bits relative to resolution isn't quite linear on typical sources,
* so we'll at least try to roughly approximate this effect. */
res_factor_bits = powf( res_factor, 0.7 );
if( !( p = strstr( opts, "timebase=" ) ) || sscanf( p, "timebase=%u/%u", &k, &l ) != 2 )
{
x264_log( h, X264_LOG_ERROR, "timebase specified in stats file not valid\n" );
return -1;
}
if( k != h->param.i_timebase_num || l != h->param.i_timebase_den )
{
x264_log( h, X264_LOG_ERROR, "timebase mismatch with 1st pass (%u/%u vs %u/%u)\n",
h->param.i_timebase_num, h->param.i_timebase_den, k, l );
return -1;
}
CMP_OPT_FIRST_PASS( "bitdepth", BIT_DEPTH );
CMP_OPT_FIRST_PASS( "weightp", X264_MAX( 0, h->param.analyse.i_weighted_pred ) );
CMP_OPT_FIRST_PASS( "bframes", h->param.i_bframe );
CMP_OPT_FIRST_PASS( "b_pyramid", h->param.i_bframe_pyramid );
CMP_OPT_FIRST_PASS( "intra_refresh", h->param.b_intra_refresh );
CMP_OPT_FIRST_PASS( "open_gop", h->param.b_open_gop );
CMP_OPT_FIRST_PASS( "bluray_compat", h->param.b_bluray_compat );
if( (p = strstr( opts, "interlaced=" )) )
{
char *current = h->param.b_interlaced ? h->param.b_tff ? "tff" : "bff" : h->param.b_fake_interlaced ? "fake" : "0";
char buf[5];
sscanf( p, "interlaced=%4s", buf );
if( strcmp( current, buf ) )
{
x264_log( h, X264_LOG_ERROR, "different interlaced setting than first pass (%s vs %s)\n", current, buf );
return -1;
}
}
if( (p = strstr( opts, "keyint=" )) )
{
p += 7;
char buf[13] = "infinite ";
if( h->param.i_keyint_max != X264_KEYINT_MAX_INFINITE )
sprintf( buf, "%d ", h->param.i_keyint_max );
if( strncmp( p, buf, strlen(buf) ) )
{
x264_log( h, X264_LOG_ERROR, "different keyint setting than first pass (%.*s vs %.*s)\n",
strlen(buf)-1, buf, strcspn(p, " "), p );
return -1;
}
}
if( strstr( opts, "qp=0" ) && h->param.rc.i_rc_method == X264_RC_ABR )
x264_log( h, X264_LOG_WARNING, "1st pass was lossless, bitrate prediction will be inaccurate\n" );
if( !strstr( opts, "direct=3" ) && h->param.analyse.i_direct_mv_pred == X264_DIRECT_PRED_AUTO )
{
x264_log( h, X264_LOG_WARNING, "direct=auto not used on the first pass\n" );
h->mb.b_direct_auto_write = 1;
}
if( ( p = strstr( opts, "b_adapt=" ) ) && sscanf( p, "b_adapt=%d", &i ) && i >= X264_B_ADAPT_NONE && i <= X264_B_ADAPT_TRELLIS )
h->param.i_bframe_adaptive = i;
else if( h->param.i_bframe )
{
x264_log( h, X264_LOG_ERROR, "b_adapt method specified in stats file not valid\n" );
return -1;
}
if( (h->param.rc.b_mb_tree || h->param.rc.i_vbv_buffer_size) && ( p = strstr( opts, "rc_lookahead=" ) ) && sscanf( p, "rc_lookahead=%d", &i ) )
h->param.rc.i_lookahead = i;
}
/* find number of pics */
p = stats_in;
int num_entries;
for( num_entries = -1; p; num_entries++ )
p = strchr( p + 1, ';' );
if( !num_entries )
{
x264_log( h, X264_LOG_ERROR, "empty stats file\n" );
return -1;
}
rc->num_entries = num_entries;
if( h->param.i_frame_total < rc->num_entries && h->param.i_frame_total > 0 )
{
x264_log( h, X264_LOG_WARNING, "2nd pass has fewer frames than 1st pass (%d vs %d)\n",
h->param.i_frame_total, rc->num_entries );
}
if( h->param.i_frame_total > rc->num_entries )
{
x264_log( h, X264_LOG_ERROR, "2nd pass has more frames than 1st pass (%d vs %d)\n",
h->param.i_frame_total, rc->num_entries );
return -1;
}
CHECKED_MALLOCZERO( rc->entry, rc->num_entries * sizeof(ratecontrol_entry_t) );
/* init all to skipped p frames */
for( int 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;
double total_qp_aq = 0;
for( int i = 0; i < rc->num_entries; i++ )
{
ratecontrol_entry_t *rce;
int frame_number;
char pict_type;
int e;
char *next;
float qp_rc, qp_aq;
int ref;
next= strchr(p, ';');
if( next )
*next++ = 0; //sscanf is unbelievably slow on long strings
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 dur:%"SCNd64" cpbdur:%"SCNd64" q:%f aq:%f tex:%d mv:%d misc:%d imb:%d pmb:%d smb:%d d:%c",
&pict_type, &rce->i_duration, &rce->i_cpb_duration, &qp_rc, &qp_aq, &rce->tex_bits,
&rce->mv_bits, &rce->misc_bits, &rce->i_count, &rce->p_count,
&rce->s_count, &rce->direct_mode );
rce->tex_bits *= res_factor_bits;
rce->mv_bits *= res_factor_bits;
rce->misc_bits *= res_factor_bits;
rce->i_count *= res_factor;
rce->p_count *= res_factor;
rce->s_count *= res_factor;
p = strstr( p, "ref:" );
if( !p )
goto parse_error;
p += 4;
for( ref = 0; ref < 16; ref++ )
{
if( sscanf( p, " %d", &rce->refcount[ref] ) != 1 )
break;
p = strchr( p+1, ' ' );
if( !p )
goto parse_error;
}
rce->refs = ref;
/* find weights */
rce->i_weight_denom[0] = rce->i_weight_denom[1] = -1;
char *w = strchr( p, 'w' );
if( w )
{
int count = sscanf( w, "w:%hd,%hd,%hd,%hd,%hd,%hd,%hd,%hd",
&rce->i_weight_denom[0], &rce->weight[0][0], &rce->weight[0][1],
&rce->i_weight_denom[1], &rce->weight[1][0], &rce->weight[1][1],
&rce->weight[2][0], &rce->weight[2][1] );
if( count == 3 )
rce->i_weight_denom[1] = -1;
else if ( count != 8 )
rce->i_weight_denom[0] = rce->i_weight_denom[1] = -1;
}
if( pict_type != 'b' )
rce->kept_as_ref = 1;
switch( pict_type )
{
case 'I':
rce->frame_type = X264_TYPE_IDR;
rce->pict_type = SLICE_TYPE_I;
break;
case 'i':
rce->frame_type = X264_TYPE_I;
rce->pict_type = SLICE_TYPE_I;
break;
case 'P':
rce->frame_type = X264_TYPE_P;
rce->pict_type = SLICE_TYPE_P;
break;
case 'B':
rce->frame_type = X264_TYPE_BREF;
rce->pict_type = SLICE_TYPE_B;
break;
case 'b':
rce->frame_type = X264_TYPE_B;
rce->pict_type = SLICE_TYPE_B;
break;
default: e = -1; break;
}
if( e < 13 )
{
parse_error:
x264_log( h, X264_LOG_ERROR, "statistics are damaged at line %d, parser out=%d\n", i, e );
return -1;
}
rce->qscale = qp2qscale( qp_rc );
total_qp_aq += qp_aq;
p = next;
}
if( !h->param.b_stitchable )
h->pps->i_pic_init_qp = SPEC_QP( (int)(total_qp_aq / rc->num_entries + 0.5) );
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_strcat_filename( h->param.rc.psz_stat_out, ".temp" );
if( !rc->psz_stat_file_tmpname )
return -1;
rc->p_stat_file_out = x264_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 );
if( p )
fprintf( rc->p_stat_file_out, "#options: %s\n", p );
x264_free( p );
if( h->param.rc.b_mb_tree && !h->param.rc.b_stat_read )
{
rc->psz_mbtree_stat_file_tmpname = x264_strcat_filename( h->param.rc.psz_stat_out, ".mbtree.temp" );
rc->psz_mbtree_stat_file_name = x264_strcat_filename( h->param.rc.psz_stat_out, ".mbtree" );
if( !rc->psz_mbtree_stat_file_tmpname || !rc->psz_mbtree_stat_file_name )
return -1;
rc->p_mbtree_stat_file_out = x264_fopen( rc->psz_mbtree_stat_file_tmpname, "wb" );
if( rc->p_mbtree_stat_file_out == NULL )
{
x264_log( h, X264_LOG_ERROR, "ratecontrol_init: can't open mbtree stats file\n" );
return -1;
}
}
}
if( h->param.rc.b_mb_tree && (h->param.rc.b_stat_read || h->param.rc.b_stat_write) )
{
if( !h->param.rc.b_stat_read )
{
rc->mbtree.srcdim[0] = h->param.i_width;
rc->mbtree.srcdim[1] = h->param.i_height;
}
if( x264_macroblock_tree_rescale_init( h, rc ) < 0 )
return -1;
}
// 对多线程而言,为每个线程分配一个rc
for( int i = 0; i<h->param.i_threads; i++ )
{
h->thread[i]->rc = rc+i;
if( i )
{
对其他rc, 拷贝第一个rc对象
rc[i] = rc[0];
h->thread[i]->param = h->param;
h->thread[i]->mb.b_variable_qp = h->mb.b_variable_qp;
h->thread[i]->mb.ip_offset = h->mb.ip_offset;
}
}
return 0;
fail:
return -1;
}