x264中通过satd和qscale估计bits的模型为线性模型:
bits * qscale = A * satd + B
其中A即coeff,B即offset,则有
coeff = (bits * qscale - coeff) / satd
offset = bits * qscale - coeff * satd
bits估计模型结构体:
typedef struct
{
float coeff_min;//系数A的下界
float coeff; //线性模型的系数A
float count; //
float decay; //衰变系数
float offset; //线性模型的偏移量B
} predictor_t;
帧级bits估计:predict_size()
/*
根据帧的satd和qscale来估计帧的bits开销
p:一组用于satd=>bits的参数
q:qscale
var:satd
过程:
bits = (coeff * satd +offset) / (qscale * count)
*/
static float predict_size( predictor_t *p, float q, float var )
{
return (p->coeff*var + p->offset) / (q*p->count);
}
行级bits估计:predict_row_size()
/*
根据qscale来预测第y行的bits开销
过程:
1.根据第y行的satd和qscale来预测行的bits开销pred_s
2.调整
·若是Islice,或当前帧行的qscale >= 前向参考帧行的qscale,则
·若当前帧&&前向参考帧都Pslice,且两帧satd差 < 当前帧satd一半,则
1.等coeff系数计算当前帧bits开销pred_t
2.求pred_s和pred_t的平均,返回
·若当前帧&&前向参考帧不都是Pslice,或两帧satd差 >= 当前帧satd一半,则直接返回pred_s
·若P/Bslice,且当前帧行的qscale < 前向参考帧行的qscale,则
1.单独根据行的帧内satd预测帧内的bits开销pred_intra
2.返回pred_intra+pred_s
*/
static float predict_row_size( x264_t *h, int y, float qscale )
{
/* average between two predictors:
* absolute SATD, and scaled bit cost of the colocated row in the previous frame */
x264_ratecontrol_t *rc = h->rc;
//根据行bits预测参数结构体、qscale和行satd来预测当前行(第y行)的bits
float pred_s = predict_size( &rc->row_pred[0], qscale, h->fdec->i_row_satd[y] );
if( h->sh.i_type == SLICE_TYPE_I || qscale >= h->fref[0][0]->f_row_qscale[y] )
{ //若是Islice,或当前帧qscale > 前向参考帧对应行的qscale
if( h->sh.i_type == SLICE_TYPE_P
&& h->fref[0][0]->i_type == h->fdec->i_type
&& h->fref[0][0]->f_row_qscale[y] > 0
&& h->fref[0][0]->i_row_satd[y] > 0
&& (abs(h->fref[0][0]->i_row_satd[y] - h->fdec->i_row_satd[y]) < h->fdec->i_row_satd[y]/2))
{ /* 前向参考帧与当前帧类型都为Pslice &&
前向参考帧与当前帧对应行的satd之差在当前帧satd的一半以内
则表明两帧对应行很相似,可以相似计算:
ref_bits * ref_qscale cur_bits * cur_qscale
----------------------- = ------------------- = coeff
ret_satd cur_satd
ref_bits * ref_qscale * cur_satd
=> cur_bits = ----------------------------------------
ref_satd * cur_qscale */
float pred_t = h->fref[0][0]->i_row_bits[y] * h->fdec->i_row_satd[y] / h->fref[0][0]->i_row_satd[y]
* h->fref[0][0]->f_row_qscale[y] / qscale;
//取之前预测的bits 与 相似计算的bits 的均值
return (pred_s + pred_t) * 0.5f;
}
return pred_s;
}
/* Our QP is lower than the reference! */
else //当前帧qscale < 前向参考帧对应行的qscale
{
//根据帧内的行satd、qscale来预测行尺寸
//注意i_row_satd[y]包含行内所有的帧间/帧内satd,而i_row_satds[0][0][y]只包含行帧内satd
float pred_intra = predict_size( &rc->row_pred[1], qscale, h->fdec->i_row_satds[0][0][y] );
/* Sum: better to overestimate than underestimate by using only one of the two predictors. */
//返回和,我不是很明白这个用意
return pred_intra + pred_s;
}
}
bits估计参数结构体更新:update_predictor()
/*
更新predictor_t结构体内的数据,
其中predictor_t p是一组通过帧satd来估计其bits开销所需的参数
p:要更新的一组参数
q:qscale
var:satd
bits:帧的bits开销
*/
static void update_predictor( predictor_t *p, float q, float var, float bits )
{
float range = 1.5;
if( var < 10 )
return;
float old_coeff = p->coeff / p->count;
float old_offset = p->offset / p->count;
/* 计算新的coeff,即 (bits*q - old_offset)/satd
新的coeff有一个下限,且其必须在旧coeff的一定范围内上下波动,不能波动太大 */
float new_coeff = X264_MAX( (bits*q - old_offset) / var, p->coeff_min );
float new_coeff_clipped = x264_clip3f( new_coeff, old_coeff/range, old_coeff*range );
//计算新的offset,即 bits*q - offset*satd
float new_offset = bits*q - new_coeff_clipped * var;
if( new_offset >= 0 )
new_coeff = new_coeff_clipped;
else
new_offset = 0;
//count coeff offset先衰变
p->count *= p->decay;
p->coeff *= p->decay;
p->offset *= p->decay;
//count coeff offset再更新
p->count ++;
p->coeff += new_coeff;
p->offset += new_offset;
}