q = qp2qscale( ABR_INIT_QP ) / fabs( h->param.rc.f_ip_factor ); //qscale = qp2qscale ,将初始化的qp转换成qp值。
#define ABR_INIT_QP (( h->param.rc.i_rc_method == X264_RC_CRF ? h->param.rc.f_rf_constant : 24 ) + QP_BD_OFFSET) //CRF模式,QP初始化值为CRF值
q = clip_qscale( h, pict_type, q );// 传入初始qscale值开始调整,直至predict_size符合vbv 码率控制。
vbv-buffersize 码率控制,实现主循环
Int terminate = 0;
For (int iterations = 0; iterations < 1000 && terminate != 3; iterations ++)
{
Double frame_q[3];
frame_q[0] = h->sh.i_type == SLICE_TYPE_I ? q * h->param.rc.f_ip_factor : q;
frame_q[1] = frame_q[0] * h->param.rc.f_pb_factor;
frame_q[2] = frame_q[0] / h->param.rc.f_ip_factor;
//初始化不同帧类型qp
Double cur_bits = predict_size( &rcc->pred[h->sh.i_type], q, rcc->last_satd);
/* Loop over the planned future frames. */
int j = 0;
double acc_cost = cur_cost;
for( j = 0; buffer_fill_cur >= 0 && buffer_fill_cur <= rcc->buffer_size; j++ )
{
total_duration += last_duration;
buffer_fill_cur += rcc->vbv_max_rate * last_duration;
int i_type = h->fenc->i_planned_type[j];// 每一帧帧类型
int i_satd = h->fenc->i_planned_satd[j]; //每一帧的satd
if( i_type == X264_TYPE_AUTO )// slice type 未确定
break;
i_type = IS_X264_TYPE_I( i_type ) ? SLICE_TYPE_I : IS_X264_TYPE_B( i_type ) ? SLICE_TYPE_B : SLICE_TYPE_P;
cur_bits = predict_size( &rcc->pred[i_type], frame_q[i_type], i_satd ); //不同的帧类型,选用不同的qp值, pred[i_type] 预测因子
acc_cost += h->fenc->i_planned_cost[j];// acc cost
buffer_fill_cur -= cur_bits;
last_duration = h->fenc->f_planned_cpb_duration[j]; //在当前bufsize下预测 duration
}
cur_avg_cost = acc_cost/(j + 1);
target_fill = X264_MIN( rcc->buffer_fill + total_duration * rcc->vbv_max_rate * 0.5, rcc->buffer_size * buffer_used_ration );
if( buffer_fill_cur < target_fill )//和预期的duration 消耗bits对比
{
q *= 1.01;
terminate |= 1;
continue;
}
/* Try to get the buffer no more than 80% filled, but don't set an impossible goal. */
target_fill = x264_clip3f( rcc->buffer_fill - total_duration * rcc->vbv_max_rate * 0.5, rcc->buffer_size * 0.8, rcc->buffer_size ); //按照预测的时长计算的 fill size
if( rcc->b_vbv_min_rate && buffer_fill_cur > target_fill )
{
q /= 1.01;
terminate |= 2;
continue;
}
break;
}