x265中码率控制算法貌似与x264的码率控制算法基本相同,基本上是经验性的,与ITU-T/MPEG各类标准推荐的码率控制算法均不同。
x265的率控应该只是帧级率控,虽然有与CU相关的率控参数,但其实那是块级的率失真优化技术,并非块级率控。x265支持三种率控模式:
/* rate tolerance method */
typedef enum
{
X265_RC_ABR, // average bit rate
X265_RC_CQP, // constant QP
X265_RC_CRF // constant rate fator
} X265_RC_METHODS;
X265_RC_ABR应该就对应学界的CBR;CQP对应HM不开率控时的配置;X265_RC_CRF是“Quality-controlled VBR”,学界叫做consistent quality的码率控制。在函数x265_param_default中设置的默认的码率控制类型是X265_RC_CRF。在学界,CBR是码率控制研究的重点;在x264/x265中,CRF模式是重点。
在输入参数类型x265_param中定义了一个包含码率控制输入参数的成员rc,rc是一个定义在类型x265_param中的匿名结构体类型的对象。
下面是与计算QP有关的四个主要函数,它们被调用的顺序与下面的列表排列顺序相同:
// to be called for each curFrame to process RateControl and set QP
int rateControlStart(Frame* curFrame, RateControlEntry* rce, Encoder* enc);
// main logic for calculating QP based on ABR
double rateEstimateQscale(Frame* pic, RateControlEntry *rce);
/* modify the bitrate curve from pass1 for one frame */
double getQScale(RateControlEntry *rce, double rateFactor);
double tuneAbrQScaleFromFeedback(double qScale);
函数rateControlStart中,CQP模式下QP的计算与帧类型有关:
else // CQP
{
if (m_sliceType == B_SLICE && IS_REFERENCED(curFrame))
m_qp = (m_qpConstant[B_SLICE] + m_qpConstant[P_SLICE]) / 2;
else
m_qp = m_qpConstant[m_sliceType];
curEncData.m_avgQpAq = curEncData.m_avgQpRc = m_qp;
x265_zone* zone = getZone();
if (zone)
{
if (zone->bForceQp)
m_qp += zone->qp - m_qpConstant[P_SLICE];
else
m_qp -= 6.0 * X265_LOG2(zone->bitrateFactor);
}
}
CRF和ABR模式时,B帧的QP由前后两个参考的P帧的QP插值而来,I帧、P帧的QP主要用getQScale中的下面这条语句计算:
if (m_param->rc.cuTree)
{
// Scale and units are obtained from rateNum and rateDenom for videos with fixed frame rates.
double timescale = (double)m_param->fpsDenom / (2 * m_param->fpsNum);
q = pow(BASE_FRAME_DURATION / CLIP_DURATION(2 * timescale), 1 - m_param->rc.qCompress);
}
else
q = pow(rce->blurredComplexity, 1 - m_param->rc.qCompress);
上面的rc.qCompress默认是0.6,也就是说量化步长是blurredComplexity的0.4次幂,blurredComplexity越大,量化步长越大。blurredComplexity是图像的预测残差的SATD。
根据图像复杂度初步计算出QScale后,还须除以ratefactor。CRF和ABR调用getQScale时给的rateFactor的参数不同,CBF时是常数,ABR等于m_wantedBitsWindow / m_cplxrSum
,使得计算得到的QScale与已编码视频的复杂度成正比。代码如下:
if (m_param->rc.rateControlMode == X265_RC_CRF)
{
q = getQScale(rce, m_rateFactorConstant);
}
else
{
if (!m_param->rc.bStatRead)
checkAndResetABR(rce, false);
double initialQScale = getQScale(rce, m_wantedBitsWindow / m_cplxrSum);
q = tuneAbrQScaleFromFeedback(initialQScale);
overflow = q / initialQScale;
}
变量overflow等于比特误差除以abrBuffer,X265_RC_ABR模式下,getQScale还需要除以overflow;X265_RC_CRF模式下,“no overflow compensation is done”。
x265中的rc.cuTree,类似于x264中的MBTree,不是空域划分的树结构,而是时域的参考树结构,在结构体对象rc中的定义和注释如下:
struct
{
...
/* Enable CUTree ratecontrol. This keeps track of the CUs that propagate temporally
* across frames and assigns more bits to these CUs. Improves encode efficiency.
* Default: enabled */
int cuTree;
...
}
MBTree的百度百科:http://baike.baidu.com/item/Macroblock%20Tree
此外,在ABR模式下还可以设置为二次编码,CRF和CQP模式下不兼容二次编码。设置编码次数的命令如下:
--pass <integer>
客观质量不是他们考虑的因素,他们考虑主观质量,他们认为CBR模式的主观质量最好。