Bootstrap

HM码控详解

1.首先是在gop层面,每组gop的初始时都分配了一个目标的gop码率以及gop内的每帧图像的目标码率。其中每帧图像的目标码率是通过递归收敛的方式先找到一个baselamda,通过这个baselamda以及已经定义好的alpha以及beta得到每一帧的bits数,然后将当前gop中所有的帧的bits数求和,就能求出每一帧应该占有的比特数的比例了。主要是求出这个比例,然后利用这个比例对gop的目标码率进行分配,从而得出了gop内每帧图像的目标码率。

2.在pic层。也就是帧一级的层面,首先根据gop的剩余比特数,再对当前帧的比特数做重新预测,获得一个新的目标比特数。利用这个目标比特数以及在gop层面算出来的每帧图像的目标码率做一个结合,算出一个当前帧的目标比特数。这个结合的比例为1:9,也就是说主要是利用在gop层算出来的每帧比特数,次要是利用在pic层算出来的比特数来做微调。

3.计算lamda。上一步预测出来的目标码率,计算每个像素的目标码率数。Lambda由下式计算所得: 

λ=α*bppβ

其中bpp就是每个像素的目标码率数。

当然,这个lambda还要做一个处理。首先是用上一个相同层级的帧的lambda做约束。另外是用上一张编码图片的lambda做约束。

4.计算QP。使用以下公式计算得出:

qp=int(4.2005*logλ+13.7122+0.5)

其中λ是上一步计算出来的。

计算出来的QP值跟lambda一样,也要利用上一个相同层级的帧的QP以及上一帧编码图片的QP来做约束。

5.在每一帧的图像编码结束后,还要做一个重要的步骤——数据更新。更新的包括gop的比特剩余数量、整个序列的比特剩余数量以及当前帧所在时间层级的帧的alpha以及beta值。其中比特数量的更新很好理解,也就是减去当前帧已编码的比特数。下面具体讲讲alpha以及beta的更新。

  •        
            //对于I帧的更新:
            double lnbpp = log(pow(m_picCfg.totalCostIntra / (double)m_seqCfg.numberOfPixel, HM_BETA1));
            double diffLambda = beta*(log((double)totalBits) - log((double)m_picCfg.targetBits));
    
            diffLambda = x265_clip3(-0.125, 0.125, 0.25*diffLambda);
            alpha = alpha * exp(diffLambda);
            beta = beta + diffLambda / lnbpp;
    对于非I帧的更新:
            // update parameters
            double picActualBpp = totalBits / (double)m_seqCfg.numberOfPixel;
            double calLambda = alpha * pow(picActualBpp, beta);
            double inputLambda = averageLambda;
            double lnbpp = log(picActualBpp);
    //当lambda很小或者当前帧用的bit数很少时,减小alpha以及beta
            if (inputLambda < 0.01 || calLambda < 0.01 || picActualBpp < 0.0001)
            {
                alpha *= (1.0 - m_seqCfg.alphaUpdate / 2.0);
    
                beta *= (1.0 - m_seqCfg.betaUpdate / 2.0);
    
    
    
                m_seqCfg.picPara[m_picCfg.frameLevel].alpha = x265_clip3(g_RCAlphaMinValue, g_RCAlphaMaxValue, alpha);
    
                m_seqCfg.picPara[m_picCfg.frameLevel].beta = x265_clip3(g_RCBetaMinValue, g_RCBetaMaxValue, beta);
    
                return;
    
            }
    
    //正常情况的话,就是对alpha以及beta增大
    
            calLambda = x265_clip3(inputLambda / 10.0, inputLambda * 10.0, calLambda);
    
            alpha += m_seqCfg.alphaUpdate * (log(inputLambda) - log(calLambda)) * alpha;
    
            lnbpp = x265_clip3(-5.0, -0.1, lnbpp);
    
            beta += m_seqCfg.betaUpdate * (log(inputLambda) - log(calLambda)) * lnbpp;
    
    
    
            alpha = x265_clip3(g_RCAlphaMinValue, g_RCAlphaMaxValue, alpha);
    
            beta = x265_clip3(g_RCBetaMinValue, g_RCBetaMaxValue, beta);

;