http://adam-fish.livejournal.com/1408.html
在网上找到的这篇我觉得写不错http://hi.baidu.com/sahlee/blog/item/879db7d1823c4c0a3af3cf02.html,只是代码讲解部分较少。
下面是我的学习笔记,拿出来和大家分享,有不对的地方希望有心人多多指正
x264中ratecontrol主要过程是;
1.根据前面已经编好的帧计算SATD值来预测当前帧的复杂度(第一帧I帧除外);
2.计算好复杂度之后,根据复杂度和线性量化控制参数(qcomp)来计算qpscale。qpscale会影响最终编码是所用到qp。
3.根据目标码率和之前编码帧所用的比特数可以确定一个rate_factor,若之前编码的比特数多与目标实际产生,则rate_factor小。
这个rate_factor是调整qpscale用的,还有overflow来对qpscale来做溢出补偿处理来控制文件的大小。
4.最后根据计算公式得到qp
主要的函数
1.
x264_ratecontrol_new()函数中的一些关键参数
rc->bitrate = h->param.rc.i_bitrate * 1000.; ///目标码率
rc->rate_tolerance = h->param.rc.f_rate_tolerance; ///允许的误差
rc->nmb = h->mb.i_mb_count; ///要编码的宏块数
rc->cplxr_sum = .01 * pow( 7.0e5, h->param.rc.f_qcompress ) * pow( h->mb.i_mb_count, 0.5 );
rc->wanted_bits_window = /*1.0 **/ rc->bitrate / rc->fps;
///得到ratefactor
2.
在x264_encoder_encode这个函数里面的x264_frame_init_lowres( h, fenc )是对当前帧进行一个下采样,将cif格式的图像下采样为qcif格式。为后面计算SATD做好准备。
x264_ratecontrol_start()
|
rate_estimate_qscale()
rcc->last_satd = x264_stack_align( x264_rc_analyse_slice, h ); ///这个分析之前下采样出来的SATD的函数
q = get_qscale( h, &rce, rcc->wanted_bits_window / rcc->cplxr_sum, h->fenc->i_frame ); ///根据前面已编好帧的比特数计算rate_factor来调整qpscale
|
qpscale2qp() ///将得到的qpscale转换成qp
3.
encode--->Encode_frame--->x264_encoder_encode--->x264_slices_write--->x264_slice_write--->x264_ratecontrol_mb
int b0 = predict_row_size_sum( h, y, rc->qpm );这里是计算将要编码帧的复杂度,此函数内部涉及到了SATD的计算还有一些和论文相符的复杂度计算
///细节没看明白,但感觉是在编宏块的时候调整QP之类的
4.
encode--->Encode_frame--->x264_encoder_encode--->x264_ratecontrol_end /////在编完一帧过后
x264_ratecontrol_end()函数
h->fdec->f_qp_avg_rc = rc->qpa_rc /= h->mb.i_mb_count; ///aq之前的qp 根据变量的字面意思应该根据宏块的个数来计算qp的平均值
h->fdec->f_qp_avg_aq = rc->qpa_aq /= h->mb.i_mb_count; ///aq之后的qp aq是什么?
if( rc->b_abr )
{
rc->cplxr_sum += bits * qp2qscale(rc->qpa_rc) / rc->last_rceq;
rc->cplxr_sum *= rc->cbr_decay;
rc->wanted_bits_window += rc->bitrate / rc->fps;
rc->wanted_bits_window *= rc->cbr_decay;
accum_p_qp_update( h, rc->qpa_rc );
}
////这一段应该是在统计已编好帧的bit数,为编下一帧的qp调整做好准备
5.
x264_ratecontrol_summary和x264_ratecontrol_delete这两个函数不知道为什么没有走到,summary函数不知是做什么用的,delete就很明显是用来释放rc开辟的空间的