zoukankan      html  css  js  c++  java
  • h.264码率控制

    h.264的码流传输是基于目前有限的网络带宽来进行的,以目前的压缩效率来说,运动不算剧烈、细节不多的影像,在720p的情况下,1000kbps压缩损耗较少(psnr较大),能达到比较好的观赏效果,1080p则需要2000kbps。当然,随着图像运动剧烈程度加大,细节增多的情况,则需要更大的bps来保证图像效果。

    另外由于图像序列中,并非所有的图像都有相同的细节,因此应该在细节多的图像上分配更多的bit,而细节少的图像则分配更少的bit。同一道理,在一张图像上,可能某些位置的细节较多,那就应该在那里分配跟多的bit,否则分配更少的bit。

    h.264的编码码率控制就是考虑到以上的这些情况,制定了码率控制标准。以下以JVT-H017r3为例,分析h.264码率控制模块。

    码率控制三个阶段

    如前面所说,h.264码率控制可以分为三个阶段:

    1. GOP级码率控制
    2. Picture级码率控制
    3. Basic Unit级码率控制

    GOP级的码率控制

    h.264的码流控制是建立在存在虚拟参考解码器的基础上的,即希望通过码率控制做到:编码端编码出来的码流,在经过设定好的bps传输后,解码端解码播放时是同步的(不延迟),下面的outflow可以看做是传输到解码端。

    可以通过上图加以理解,途中为某个GOP在某一时刻的编码状态,Not coded 为未编码图像,coded为已编码图像,图像编码后会以Bit Stream(码流)的形式输出到Virtual Buffer中,这里的Virtual Buffer 并不一定实际存在于实际编码器中,而是算法虚拟出来的缓存区,主要是维护码流的输入与输出,在缓冲区中的码流会以某一速率进行输出(outflow)。

    1. Virtual Buffer

    对于Virtual Buffer的大小,是可计算的

    $egin{align*}
    &V_i(1) = left{egin{matrix}
    0 & i=1\ 
    V_{i-1}(N_{i-1}) & other 
    end{matrix} ight.\ 
    & V_i(j) = V_i(j-1) + b_i(j-1) - frac{R_i(j-1)}{f} qquad j=2,3,...,N_i 
    end{align*}$

    $i$表示第$i$个GOP,$j$表示第$i$个GOP的第$j$幅图像,

    • 如果是视频序列的第一帧,那么以编码数为$0$,缓存区大小肯定为$0$,
    • 如果是其他GOP的第一帧,那么缓存区大小则为上一个GOP剩下来的大小。
    • 在其他情况下,缓存区大小为上一帧的缓存区大小加上上一帧编码后码流大小,减去码流流出的大小。

    2. Remain Picture Bit

    对于当前GOP未编码的图像的bit大小,是未知的,因此需要进行预测

    $B_i(j) = left{egin{matrix}
    frac{R_i(j)}{f} imes N_i - V_i(j) & j=1\ 
    B_i(j-1) + frac{R_i(j)-R_i(j-1)}{f} imes (N_i-j+1) - b_i(j-1) & j=2,3,...,N_i 
    end{matrix} ight.\$

     

    在设定初始值的时候,请注意$-Vi(j)$,这么做其实是为了清空缓存区。$B_i(j) + V_i(j) = frac{R_i(j)}{f} imes N_i$,设定左右两边相等,也就是说希望在码流流出为$N_i$帧的时间里,能把当前GOP中所有的bit以及原本Virtual Buffer中存放的bit一同清空,减少接受端的延迟。

    在其他情况下,预测值B受到上一帧的预测值影像,也受到带宽的变化影响,最后当然要减去上一帧编码所用的bit数。

    在码率没有变化的情况下,会被简化成:

    $B_i(j) = B_i(j-1) - b_i(j-1)$

    3. 设定I帧QP

    对于一个GOP,首当其冲是要设定好它第一帧(I、IDR)的QP,如果是视频序列的第一帧,也就是第一个GOP的第一帧:

    $QP_1(1)=left{egin{matrix}
    40 & bpp leqslant l_1\ 
    30 & qquad l_1 < bpp leqslant l_2\ 
    20 & qquad l_2 < bpp leqslant l_3\ 
    10 & bpp > l_3
    end{matrix} ight.$

     

    $bpp = frac{R_1(1)}{f imes N_{pixel}}$

    $N_{pixel}$是一张图像的像素点个数。

    对于QCIF/CIF,$l_1=0.15, l_2=0.45, l_3=0.9$

    对于大于CIF的图像,$l_1=0.6, l_2=1.4, l_3=2.4$

     

    而对于其他GOP,有

    $QP_i(1)=max{ QP_{i-1}(1) - 2, min{ QP_{i-1}(1)+2, frac{SumPQP(i-1)}{N_p(i-1)} - min{ 2, frac{N_{i-1}}{15} }} }$

    平滑处理:

    $QP_i(1) = QP_i(1)-1 quad if quad QP_i(1) > QP_{i-1}(N_{i-1}-L)-2$

    Picture级码率控制

    1. 设定B帧QP

    对于B帧,都是以B帧两端的参考帧的QP来计算当前B帧QP值。分两种情况,假设两个参考帧间的B帧数为$L$。

    当$L = 1$,

    $QP_i(j+1)=left{egin{matrix}
    frac{QP_i(j)+QP_i(j+2)+2}{2} & if QP_i(j) eq QP_i(j+2) \ 
    QP_i(j)+2 & Otherwise
    end{matrix} ight.$

     

    当$L > 1$,

    $QP_i(j+k)=QP_i(j)+alpha +max{ min{ frac{QP_i(j+L+1)-QP_i(j)}{L-1}, 2 imes(k-1)}, -2 imes(k-1) }$

    $alpha = left{egin{matrix}
    -3 & QP_i(j+L+1)-QP_i(j) leqslant & -2 imes L-3\ 
    -2 & QP_i(j+L+1)-QP_i(j) leqslant & -2 imes L-2\ 
    -1 & QP_i(j+L+1)-QP_i(j) leqslant & -2 imes L-1\ 
    0 & QP_i(j+L+1)-QP_i(j) leqslant & -2 imes L\ 
    1 & QP_i(j+L+1)-QP_i(j) leqslant & -2 imes L+1\ 
    2 & Otherwise
    end{matrix} ight.$

    2. 设定P帧QP

    P帧码率控制主要分为三步:

    1. 算出当前P帧的目标bit
    2. 通过目标bit算出当前帧QP
    3. 把当前帧QP与前面帧的QP进行对比,做平滑处理

     

    为了算出当前P帧的目标bit,需要的参数有三个:Virtual Buffer,Remain Picture Bit,Target Buffer Level。其中前两个参数在前面的GOP级的码率控制中已经获得,下面来引入讨论一个新的概念,目标缓存级别(Target Buffer Level)

    这个级别(Level)用来修正待编码图像对清空缓存区的贡献,基本思想是清空缓存区的工作应该更多由非参考图像来承担,由于B帧的QP普遍会比两端的P帧大,也就是相对来说会占用更小的缓存区域,那么P帧就可以降低QP来提高图像编码质量,那么P帧编码为码流后占用的缓存区会更大。Target Buffer Level 代表的就是P帧在缓存区的占用情况,当有B帧时的Target Buffer Level 会比没有B帧时的大。

    计算方式如下:

    $S_i(2)=V_i(2)$

    $S_i(j+1)=S_i(j)-frac{S_i(2)}{N_p(i)-1}+frac{ar{W}_{p,i}(j) imes(L+1) imes R_i(j)}{f imes (ar{W}_{p,i}(j) + ar{W}_{b,i}(j) imes L)} - frac{R_i(j)}{f}$

    $egin{align*}
    ar{W}_{p,i}(j) &= frac{W_{p,i}(j)}{8} + frac{7 imes ar{W}_{p,i}(j-1)}{8} \
    ar{W}_{b,i}(j) &= frac{W_{b,i}(j)}{8} + frac{7 imes ar{W}_{b,i}(j-1)}{8} \
    W_{p,i}(j) &= b_i(j) imes QP_{p,i}(j) \
    W_{b,i}(j) &= frac{b_i(j) imes QP_{b,i}(j)}{1.3636}
    end{align*}$

    $W_p$是P帧的权重,$W_b$是B帧的权重。

    当没有B帧时,可以简化为:

    $S_i(j+1)=S_i(j)-frac{S_i(2)}{N_p(i)-1}$

    这表明Target Buffer Level会越来越小,在当前GOP末尾会趋向于$0$。

     

    最后结合Virtual buffer,Remain Picture bit,Target Buffer Level三者求出当前P帧的目标bit。

    $egin{align*}
    ilde{T}_i(j) &= frac{R_i(j)}{f} + gamma imes (S_i(j) - V_i(j)) \
    hat{T}_i(j) &= frac{W_{p,i}(j-1) imes B_i(j)}{W_{p,i}(j-1) imes N_{p,gamma} + W_{b,i}(j-1) imes N_{b,gamma}} \
    T_i(j) &= eta imes hat{T}_i(j) + (1-eta) imes ilde{T}_i(j)
    end{align*}$

    当然还有上下界判断(略)。

     

    得到目标bit后就可以求当前P帧的量化步长(求解下面一元二次方程),然后通过量化步长得到量化参数,

    $T_i(j) = c_1 imes frac{ ilde{sigma}_i(j)}{Q_{step,i}(j)} + c_2 imes frac{ ilde{sigma}_i(j)}{Q_{step,i}^2(j)} - m_{h,i}(j)$

    $ ilde{sigma}_i(j) = a_1 imes sigma_i(j-1-L) + a_2$

    其中,$sigma_i(j-l-L)$为上一P帧的复杂度,$ ilde{sigma}_i(j)$为当前P帧复杂度的预测值,$m_{h,i}(j)$则是当前P帧的运动向量以及头部大小。

    最后也少不了对比上一P帧进行平滑QP的处理(略)。

    Basic Unit级码率控制

    这个其实跟“设定P帧QP”有同样的三个步骤,只是把Picture分开了成Basic Unit然后再一一计算,对当前Basic Unit进行码率控制、编码,然后轮到下一个Basic Unit。

    首先需要求当前basic unit的目标bit数,

    $ ilde{b_l} = T_{r} imes frac{ ilde{sigma}_{l,i}^2(l)}{displaystyle{sum_{k=l}^{N_{unit}} ilde{sigma}_{l,i}^2(k)}}$

    其中,$ ilde{sigma}_i(j)$为当前Basic Unit复杂度的预测值,该预测值是通过上一P帧的对应Basic Unit位置来进行预测的,预测方法同上方P帧,采用线性预测,$T_{r}$则是用当前帧未编码的Basic Unit的目标bit数,初始值为$T_i(j)$

    第二步要预测当前P帧的Basic Unit平均的头部大小(包括mv等)。

    $egin{align*}
    ilde{m}_{hdr,l} &= ilde{m}_{hdr,l-1} imes (1-frac{1}{l}) + frac{hat{m}_{hdr,l}}{l} \
    m_{hdr,l} &= ilde{m}_{hdr,l} imes frac{l}{N_{unit}} + m_{hdr,1} imes (1 - frac{l}{N_{unit}});1 leqslant l leqslant N_{unit}
    end{align*}$

     

    其中,$ ilde{m}_{hdr,l}$是序号为$l$的Basic Unit的header bit初步预测值,$hat{m}_{hdr,l}$是当前Basic Unit已经产生的header bit数,$m_{hdr,1}$是上一个P帧的Basic Unit的header bit的平均值。那么上面的式子可以这样理解:等式1是用前一个Basic Unit的header bit初步预测值与当前Basic Unit已产生的header bit来预测当前Basic Unit的初步预测值;等式2是用上一张P帧的Basic Unit的header bit平均值对当前Basic Unit初步预测值进行修正。

    然后用目标bit减去header bit得到预测的纹理bit数。

    $hat{b}_l = ilde{b}_l - m_{hdr,l}$

    最后就是求量化参数了,这个跟上面Picture级的一样,只是把复杂度换成了以Basic Unit为单位。

    还有就是平滑(略)。

     

  • 相关阅读:
    开发者和设计师:为何我们不能好好相处?(转载)
    PHP ACCESS
    来自腾讯的session跨域,跨服代码
    php大括号妙用。
    php mysql 记录集的操作
    开始我的代码笔记
    收藏一个php用的一个页码按钮类
    修改过后的数字英文字符生成图片代码
    搜藏一点php session 常用方法
    php包含漏洞收集程序代码
  • 原文地址:https://www.cnblogs.com/TaigaCon/p/3593036.html
Copyright © 2011-2022 走看看