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的大小,是可计算的

    Vi(1)={0Vi1(Ni1)i=1otherVi(j)=Vi(j1)+bi(j1)Ri(j1)fj=2,3,...,NiVi(1)={0i=1Vi−1(Ni−1)otherVi(j)=Vi(j−1)+bi(j−1)−Ri(j−1)fj=2,3,...,Ni

    ii表示第ii个GOP,jj表示第ii个GOP的第jj幅图像,

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

    2. Remain Picture Bit

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

    Bi(j)=⎧⎩⎨⎪⎪Ri(j)f×NiVi(j)Bi(j1)+Ri(j)Ri(j1)f×(Nij+1)bi(j1)j=1j=2,3,...,NiBi(j)={Ri(j)f×Ni−Vi(j)j=1Bi(j−1)+Ri(j)−Ri(j−1)f×(Ni−j+1)−bi(j−1)j=2,3,...,Ni

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

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

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

    Bi(j)=Bi(j1)bi(j1)Bi(j)=Bi(j−1)−bi(j−1)

    3. 设定I帧QP

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

    QP1(1)=⎧⎩⎨⎪⎪⎪⎪⎪⎪40302010bppl1l1<bppl2l2<bppl3bpp>l3QP1(1)={40bpp⩽l130l1<bpp⩽l220l2<bpp⩽l310bpp>l3

    bpp=R1(1)f×Npixelbpp=R1(1)f×Npixel

    NpixelNpixel是一张图像的像素点个数。

    对于QCIF/CIF,l1=0.15,l2=0.45,l3=0.9l1=0.15,l2=0.45,l3=0.9

    对于大于CIF的图像,l1=0.6,l2=1.4,l3=2.4l1=0.6,l2=1.4,l3=2.4

     

    而对于其他GOP,有

    QPi(1)=max{QPi1(1)2, min{QPi1(1)+2, SumPQP(i1)Np(i1)min{2, Ni115}}}QPi(1)=max{QPi−1(1)−2, min{QPi−1(1)+2, SumPQP(i−1)Np(i−1)−min{2, Ni−115}}}

    平滑处理:

    QPi(1)=QPi(1)1ifQPi(1)>QPi1(Ni1L)2QPi(1)=QPi(1)−1ifQPi(1)>QPi−1(Ni−1−L)−2

    Picture级码率控制

    1. 设定B帧QP

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

    L=1L=1,

    QPi(j+1)={QPi(j)+QPi(j+2)+22QPi(j)+2if QPi(j)QPi(j+2)OtherwiseQPi(j+1)={QPi(j)+QPi(j+2)+22if QPi(j)≠QPi(j+2)QPi(j)+2Otherwise

    L>1L>1,

    QPi(j+k)=QPi(j)+α+max{min{QPi(j+L+1)QPi(j)L1,2×(k1)},2×(k1)}QPi(j+k)=QPi(j)+α+max{min{QPi(j+L+1)−QPi(j)L−1,2×(k−1)},−2×(k−1)}

    α=⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪321012QPi(j+L+1)QPi(j)QPi(j+L+1)QPi(j)QPi(j+L+1)QPi(j)QPi(j+L+1)QPi(j)QPi(j+L+1)QPi(j)Otherwise2×L32×L22×L12×L2×L+1α={−3QPi(j+L+1)−QPi(j)⩽−2×L−3−2QPi(j+L+1)−QPi(j)⩽−2×L−2−1QPi(j+L+1)−QPi(j)⩽−2×L−10QPi(j+L+1)−QPi(j)⩽−2×L1QPi(j+L+1)−QPi(j)⩽−2×L+12Otherwise

    2. 设定P帧QP

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

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

    为了算出当前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帧时的大。

    计算方式如下:

    Si(2)=Vi(2)Si(2)=Vi(2)

    Si(j+1)=Si(j)Si(2)Np(i)1+W¯p,i(j)×(L+1)×Ri(j)f×(W¯p,i(j)+W¯b,i(j)×L)Ri(j)fSi(j+1)=Si(j)−Si(2)Np(i)−1+W¯p,i(j)×(L+1)×Ri(j)f×(W¯p,i(j)+W¯b,i(j)×L)−Ri(j)f

    W¯p,i(j)W¯b,i(j)Wp,i(j)Wb,i(j)=Wp,i(j)8+7×W¯p,i(j1)8=Wb,i(j)8+7×W¯b,i(j1)8=bi(j)×QPp,i(j)=bi(j)×QPb,i(j)1.3636W¯p,i(j)=Wp,i(j)8+7×W¯p,i(j−1)8W¯b,i(j)=Wb,i(j)8+7×W¯b,i(j−1)8Wp,i(j)=bi(j)×QPp,i(j)Wb,i(j)=bi(j)×QPb,i(j)1.3636

    WpWp是P帧的权重,WbWb是B帧的权重。

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

    Si(j+1)=Si(j)Si(2)Np(i)1Si(j+1)=Si(j)−Si(2)Np(i)−1

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

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

    T~i(j)T^i(j)Ti(j)=Ri(j)f+γ×(Si(j)Vi(j))=Wp,i(j1)×Bi(j)Wp,i(j1)×Np,γ+Wb,i(j1)×Nb,γ=β×T^i(j)+(1β)×T~i(j)T~i(j)=Ri(j)f+γ×(Si(j)−Vi(j))T^i(j)=Wp,i(j−1)×Bi(j)Wp,i(j−1)×Np,γ+Wb,i(j−1)×Nb,γTi(j)=β×T^i(j)+(1−β)×T~i(j)

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

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

    Ti(j)=c1×σ~i(j)Qstep,i(j)+c2×σ~i(j)Q2step,i(j)mh,i(j)Ti(j)=c1×σ~i(j)Qstep,i(j)+c2×σ~i(j)Qstep,i2(j)−mh,i(j)

    σ~i(j)=a1×σi(j1L)+a2σ~i(j)=a1×σi(j−1−L)+a2

    其中,σi(jlL)σi(j−l−L)为上一P帧的复杂度,σ~i(j)σ~i(j)为当前P帧复杂度的预测值,mh,i(j)mh,i(j)则是当前P帧的运动向量以及头部大小。

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

    Basic Unit级码率控制

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

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

    bl~=Tr×σ~2l,i(l)k=lNunitσ~2l,i(k)bl~=Tr×σ~l,i2(l)∑k=lNunitσ~l,i2(k)

    其中,σ~i(j)σ~i(j)为当前Basic Unit复杂度的预测值,该预测值是通过上一P帧的对应Basic Unit位置来进行预测的,预测方法同上方P帧,采用线性预测,TrTr则是用当前帧的目标bit数Ti(j)Ti(j)。

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

    m~hdr,lmhdr,l=m~hdr,l1×(11l)+m^hdr,ll=m~hdr,l×lNunit+mhdr,1×(1lNunit);1lNunitm~hdr,l=m~hdr,l−1×(1−1l)+m^hdr,llmhdr,l=m~hdr,l×lNunit+mhdr,1×(1−lNunit);1⩽l⩽Nunit

    其中,m~hdr,lm~hdr,l是序号为ll的Basic Unit的header bit初步预测值,m^hdr,lm^hdr,l是当前Basic Unit已经产生的header bit数,mhdr,1mhdr,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数。

    b^l=b~lmhdr,lb^l=b~l−mhdr,l

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

    还有就是平滑(略)。

  • 相关阅读:
    躺着的人
    (转载)CentOS查看系统信息|CentOS查看命令
    (转载)重新介绍 JavaScript(JS 教程)
    (转载)Java 容器 & 泛型:四、Colletions.sort 和 Arrays.sort 的算法
    (转载)Java 容器 & 泛型:三、HashSet,TreeSet 和 LinkedHashSet比较
    (转载)Java 容器 & 泛型:二、ArrayList 、LinkedList和Vector比较
    (转载)Java 容器 & 泛型:一、认识容器
    (转载)Python IDLE reload(sys)后无法正常执行命令的原因
    jmete 取配置文件的行数(二)
    jmete 取配置文件的行数(一)
  • 原文地址:https://www.cnblogs.com/xumaojun/p/8523475.html
Copyright © 2011-2022 走看看