H264编码-码率控制原理以及JM代码分析
碼率控制的主要目的是控制每一幀圖像編碼輸出的比特?cái)?shù),并在總比特?cái)?shù)一定的約束條件下使圖像失真最小。當(dāng)然,由于視頻圖像質(zhì)量及其編碼復(fù)雜性,碼率控制的目標(biāo)并不是單一的。常見(jiàn)的控制目標(biāo)包括:提高輸出碼率控制精度使其最大程度的接近目標(biāo)碼率;提高編碼后輸出比特流的峰值信噪比;減少碼率波動(dòng);提高編碼速度等。碼率控制是一個(gè)多約束條件、多目標(biāo)的優(yōu)化問(wèn)題。
碼率控制涉及視頻質(zhì)量和信道帶寬的折衷。減少碼率會(huì)犧牲質(zhì)量,質(zhì)量提高就會(huì)增加碼率。常用的碼率調(diào)節(jié)手段包括:
1. 典型碼率控制過(guò)程
2. H264的碼率控制模型
H264參考軟件JM實(shí)現(xiàn)的碼率控制算法基于JVT-G102,是一個(gè)多層次的CBR碼率控制算法。碼率控制由三個(gè)層次組成:GOP層碼率控制、圖像層碼率控制以及宏塊層碼率控制。
JM編碼流程如下圖所示,綠色框?yàn)榇a率控制模塊。
GOP層碼率控制主要在rc_init_GOP函數(shù)中實(shí)現(xiàn);
對(duì)于GOP中每一幀圖像調(diào)用rc_init_frame實(shí)現(xiàn)圖像層碼率控制;
圖像中的每一個(gè)宏塊編碼前調(diào)用rc_handle_mb實(shí)現(xiàn)宏塊層碼率控制,更新RQ模型系數(shù),并得到編碼宏塊QP
2.1 GOP層碼率控制
GOP層碼率控制主要目的是:1.確定當(dāng)前GOP中尚未編碼圖像的目標(biāo)比特?cái)?shù);2.GOP中第一個(gè)IDR圖像的量化參數(shù)。JM對(duì)應(yīng)實(shí)現(xiàn)在rc_init_GOP函數(shù)中
2.1.1 目標(biāo)比特?cái)?shù)
目標(biāo)比特?cái)?shù)的計(jì)算滿足以下原則:
當(dāng)編碼到第i個(gè)GOP的第j幀圖像時(shí),當(dāng)前GOP剩余圖像的目標(biāo)比特?cái)?shù)按照如下公式更新:
其中,f為幀率,Ni為當(dāng)前GOP的幀數(shù),Vi(j)為虛擬緩存區(qū)占用bit數(shù)。Ri(j)為當(dāng)前可用的信道帶寬(bit/s),也就是設(shè)置的輸出碼率,在網(wǎng)絡(luò)傳輸時(shí),該值需要根據(jù)當(dāng)前網(wǎng)絡(luò)狀況動(dòng)態(tài)調(diào)節(jié)。bi(j-1)為前一圖像編碼后的實(shí)際比特?cái)?shù)。在CBR時(shí),Ri(j)=Ri(j-1),此使顯然:
Bi(j)=Bi(j-1)-bi(j-1)
每編碼完一幀圖像后,需要按照下式更新虛擬緩存區(qū)大小:
2.1.2 量化參數(shù)
對(duì)于視頻序列第一個(gè)GOP,其IDR圖像的量化參數(shù)根據(jù)設(shè)置的輸出碼率確定。根據(jù)每個(gè)像素分配的bpp(bits per pixel)將初始QP值分為4個(gè)等級(jí)。
if (bpp<= L1)qp = 35; else if(bpp<=L2)qp = 25;zh else if(bpp<=L3)qp = 20; elseqp = 10;其中,Bpp由下式確定:
Bpp=R1(1)/(fxN)
對(duì)于QCIF視頻(176x144)推薦L1 = 0.1,L2 = 0.3,L3 = 0.6;對(duì)于CIF視頻(352x288)推薦L1 = 0.2,L2 = 0.6,L3 = 1.2;其他情況L1 = 0.6,L2 = 1.4,L3 = 2.4;
對(duì)于視頻序列其他GOP的IDR圖像,則根據(jù)前一個(gè)GOP的統(tǒng)計(jì)數(shù)據(jù)計(jì)算確定其量化參數(shù)。公式如下:
QPi(1)=max(QPi?1(1),min(QPi?1(1)+2,SumPQP(i?1)Np(i?1)?min(2,Ni?115)))QP_i(1)=max(QP_{i-1}(1),min(QP_{i-1}(1)+2, \frac {SumPQP(i-1)} {N_p(i-1)} - min(2,\frac {N_{i-1} } {15} ) )) QPi?(1)=max(QPi?1?(1),min(QPi?1?(1)+2,Np?(i?1)SumPQP(i?1)??min(2,15Ni?1??)))
其中,Np(i?1)表示第i?1個(gè)GOP中P幀幀數(shù),SumPQP(i?1)表示這些P幀量化參數(shù)的和。其中, N_p(i-1)表示第i-1個(gè)GOP中P幀幀數(shù), SumPQP(i-1)表示這些P幀量化參數(shù)的和。其中,Np?(i?1)表示第i?1個(gè)GOP中P幀幀數(shù),SumPQP(i?1)表示這些P幀量化參數(shù)的和。
2.2 圖像層碼率控制
圖像層碼率控制可分為兩個(gè)部分:編碼前控制和編碼后控制。其中編碼前控制的目的是確定該GOP中每一幀圖像的量化參數(shù)。編碼后控制的目的是根據(jù)當(dāng)前圖像的編碼結(jié)果,更新RDO模型參數(shù)。
2.2.1 編碼前控制
編碼前控制對(duì)于參考圖像(也就是P slice)和非參考圖像(B slice)由不同的處理方式,每個(gè)GOP中第一個(gè)I slice在GOP層碼率控制中已經(jīng)確定。
JM中對(duì)應(yīng)代碼在rc_quadratic.c中的updateQPRC0函數(shù)(根據(jù)參數(shù)RCUpdateMode選擇不同函數(shù)調(diào)用,RCUpdateMode默認(rèn)方式為0)。
- 對(duì)于非參考圖像(B slice)的QP根據(jù)相鄰的兩幀參考圖像使用簡(jiǎn)單的插值方式處理。計(jì)算過(guò)程如下:
假設(shè)j和j+L+1是相鄰的兩幀參考圖像,QP(j)和QP(j+L+1)分別對(duì)應(yīng)他們的量化參數(shù),根據(jù)L是否大于1,分兩種情況計(jì)算兩者間非參考幀的量化參數(shù)。
1)L=1時(shí),兩幀參考幀之間只有一個(gè)非參考幀。此使QP(j+1)按下式計(jì)算:
2)L>1時(shí),兩幀參考幀之間只有多個(gè)非參考幀。此使QP(j+k)按下式計(jì)算:
其中,k=1,2,…,L。a由QP(j+L+1)和QP(j)的差值確定:
- 對(duì)于參考圖像(P slice)的QP,編碼前控制由兩個(gè)步驟組成:確定每一個(gè)參考圖像的目標(biāo)比特?cái)?shù);確定參考圖像的量化參數(shù)并進(jìn)行RDO。JM中對(duì)應(yīng)代碼在rc_quadratic.c中的rc_init_pict函數(shù)。
1)確定參考圖像的目標(biāo)比特?cái)?shù)主要考慮以下幾個(gè)因素:不同類型圖像分配比特?cái)?shù)的比例有差異;編碼圖像的復(fù)雜度;GOP中不同位置的圖像對(duì)清空緩存區(qū)的貢獻(xiàn)不同。
首先,計(jì)算圖像復(fù)雜度,圖像復(fù)雜度與編碼比特?cái)?shù)和QP值正相關(guān):
AveWp(k)=Wp(k)/8+7?AveWp(k?1)/8AveWp(k) = Wp(k)/8+7 * AveWp(k-1)/8AveWp(k)=Wp(k)/8+7?AveWp(k?1)/8
AveWb(l)=Wb(l)/8+7?AveWb(l?1)/8AveWb(l) = Wb(l)/8+7 * AveWb(l-1)/8AveWb(l)=Wb(l)/8+7?AveWb(l?1)/8
Wp(k)=b(k)?QP(k)Wp(k) = b(k) * QP(k)Wp(k)=b(k)?QP(k)
Wb(l)=b(l)?QP(l)/1.3636Wb(l) = b(l) * QP(l)/1.3636Wb(l)=b(l)?QP(l)/1.3636
其中,AveWp(k)為P slice的平均復(fù)雜度,AveWb(k)為B slice的平均復(fù)雜度。
其次,需要確定當(dāng)前圖像的目標(biāo)緩存級(jí)別(target buffer level)Si(j)。這個(gè)變量用于修正待編碼圖像對(duì)清空緩存區(qū)的權(quán)重,基本原理時(shí)清空緩存區(qū)的工作應(yīng)該更多由非參考幀來(lái)承擔(dān)。當(dāng)編碼完IDR圖像后,目標(biāo)緩存級(jí)別設(shè)置為當(dāng)前緩存區(qū)的占用程度:
p_quad->TargetBufferLevel = (double) p_gen->CurrentBufferFullness;
以后,每編碼完一個(gè)參考圖像,當(dāng)前圖像目標(biāo)緩存按照下式進(jìn)行更新:
考慮目標(biāo)緩存級(jí)別、幀率、可用帶寬以及緩存區(qū)的實(shí)際占用情況,可以得到一個(gè)計(jì)算參考幀比特?cái)?shù)的公式:
tmp_T = imax(0, (int) floor(p_quad->bit_rate / p_quad->frame_rate - p_quad->GAMMAP * (p_gen->CurrentBufferFullness-p_quad->TargetBufferLevel) + 0.5));其中,如果P slice間沒(méi)有B slice時(shí),常量GAMMAP=0.5;其他情況下GAMMAP=0.25.
同樣如果從GOP剩余比特?cái)?shù)考慮,可以得到另一個(gè)計(jì)算目標(biāo)比特?cái)?shù)的公式:
p_quad->Target = (int) floor( p_quad->Wp * p_gen->RemainingBits / (p_quad->Np * p_quad->Wp + p_quad->Nb * p_quad->Wb) + 0.5);綜合考慮這兩種計(jì)算方法,得到如下計(jì)算目標(biāo)比特?cái)?shù)的公式:
p_quad->Target = (int) floor(p_quad->BETAP * (p_quad->Target - tmp_T) + tmp_T + 0.5);其中,如果P slice間沒(méi)有B slice時(shí),常量BETAP=0.5;其他情況下BETAP=0.9
接下來(lái)需要確定參考圖像的量化參數(shù)并進(jìn)行RDO。主要實(shí)現(xiàn)參考JM代碼updateQPRC0。
首先,根據(jù)線性模型,根據(jù)前一個(gè)已編碼P幀的MAD預(yù)測(cè)當(dāng)前幀MAD;
其中兩個(gè)線性模型參數(shù)MADPictureC1、MADPictureC2在編碼當(dāng)前圖像后,需要用線性回歸法對(duì)它們進(jìn)行更新。
然后,根據(jù)二次RQ模型確定圖像的量化參數(shù),計(jì)算過(guò)程參考JM代碼updateModelQPFrame函數(shù)實(shí)現(xiàn)。
通過(guò)對(duì)一元二次方程m_Bits = m_X1 * MAD / QStep + m_X2 * MAD / (QStep * QStep)求解得到量化步長(zhǎng)QStep。
void updateModelQPFrame( RCQuadratic *p_quad, int m_Bits ) {double dtmp, m_Qstep;// ax*x+bx+c=0 的判別式 b*b-4acdtmp = p_quad->CurrentFrameMAD * p_quad->m_X1 * p_quad->CurrentFrameMAD * p_quad->m_X1+ 4 * p_quad->m_X2 * p_quad->CurrentFrameMAD * m_Bits; // 退化為一階方程if ((p_quad->m_X2 == 0.0) || (dtmp < 0) || ((sqrt (dtmp) - p_quad->m_X1 * p_quad->CurrentFrameMAD) <= 0.0)) // fall back 1st order modem_Qstep = (float) (p_quad->m_X1 * p_quad->CurrentFrameMAD / (double) m_Bits);else // 2nd order modem_Qstep = (float) ((2 * p_quad->m_X2 * p_quad->CurrentFrameMAD) / (sqrt (dtmp) - p_quad->m_X1 * p_quad->CurrentFrameMAD));p_quad->m_Qc = Qstep2QP(m_Qstep, p_quad->bitdepth_qp_scale); }2.2.2. 編碼后處理
在圖像級(jí)編碼前控制中,我們確定了每幀圖像的量化參數(shù)。在該層次的編碼后控制階段主要完成以下兩件事情:根據(jù)當(dāng)前幀(或宏塊)的編碼情況更新MAD預(yù)測(cè)模型(線性模型)和二次RQ模型;更新緩存區(qū)狀態(tài),處理緩存區(qū)溢出。
1.更新碼率控制模型:在編碼完當(dāng)前幀/宏塊后,編碼器需要更新RQ和MAD預(yù)測(cè)模型。這里使用線性回歸算法來(lái)更新模型的參數(shù)。更新過(guò)程由下面三步組成(這部分代碼實(shí)現(xiàn)參考JM的updateRCModel函數(shù)):
1)選擇數(shù)據(jù)集:模型的準(zhǔn)確度依賴于做線性回歸的數(shù)據(jù)集大小及其質(zhì)量。一般來(lái)說(shuō),選擇的數(shù)據(jù)量越多,越能反映出平均情況,但難以反映出實(shí)時(shí)情況。例如在場(chǎng)景切換時(shí),需要根據(jù)最近的情況及時(shí)更新模型。
使用滑動(dòng)窗機(jī)制來(lái)確定數(shù)據(jù)集大小。其基本原則是在平穩(wěn)情況下,選擇較大窗口。提高模型準(zhǔn)確度,在場(chǎng)景切換時(shí),選擇較小窗口,以及時(shí)反映新場(chǎng)景對(duì)模型的影響。
JM代碼中使用圖像的MAD來(lái)表示圖像發(fā)生場(chǎng)景切換的強(qiáng)度。通過(guò)當(dāng)前圖像的MAD和前一幀圖像的MAD的比值來(lái)調(diào)整滑動(dòng)窗大小,如下:
n_windowSize = (p_quad->CurrentFrameMAD>p_quad->PreviousFrameMAD)? (int)(p_quad->PreviousFrameMAD/p_quad->CurrentFrameMAD * (RC_MODEL_HISTORY-1) ): (int)(p_quad->CurrentFrameMAD/p_quad->PreviousFrameMAD *(RC_MODEL_HISTORY-1));n_windowSize=iClip3(1, m_Nc, n_windowSize); //確定窗口上界n_windowSize=imin(n_windowSize,p_quad->m_windowSize+1); // 防止窗口階躍過(guò)大n_windowSize=imin(n_windowSize,(RC_MODEL_HISTORY-1));2)計(jì)算模型參數(shù):根據(jù)滑動(dòng)窗內(nèi)數(shù)據(jù)集(QStep、MAD、編碼bit數(shù)),使用線性回歸法更新RQ模型參數(shù)。計(jì)算過(guò)程在JM的RCModelEstimator函數(shù).
具體推導(dǎo)過(guò)程參考RQ模型參數(shù)推導(dǎo)過(guò)程
3)移除滑動(dòng)窗內(nèi)誤差太大的數(shù)據(jù)樣本,并重新計(jì)算RQ模型參數(shù)。使用上一步驟計(jì)算得到的RQ模型參數(shù)計(jì)算每個(gè)樣本的均方差,均方差超過(guò)閾值K的樣本則認(rèn)為該數(shù)據(jù)是錯(cuò)誤數(shù)據(jù),應(yīng)該從數(shù)據(jù)集剔除。然后再根據(jù)步驟2重新計(jì)算一次RQ模型參數(shù)。
//計(jì)算誤差是看參數(shù)估計(jì)后模型計(jì)算結(jié)果表現(xiàn)怎么樣for (i = 0; i < (int) n_windowSize; i++){error[i] = p_quad->m_X1 / p_quad->m_rgQp[i] + p_quad->m_X2 / (p_quad->m_rgQp[i] * p_quad->m_rgQp[i]) - p_quad->m_rgRp[i];std += error[i] * error[i];}threshold = (n_windowSize == 2) ? 0 : sqrt (std / n_windowSize); //均方誤差for (i = 0; i < (int) n_windowSize; i++){//* 對(duì)預(yù)測(cè)誤差較大的幀,標(biāo)記為限制訪問(wèn)if (fabs(error[i]) > threshold)m_rgRejected[i] = TRUE;}// always include the last data pointm_rgRejected[0] = FALSE; //默認(rèn)第一幀圖像無(wú)條件保留,防止數(shù)據(jù)集為空2.3 基本編碼單元層碼率控制
基本編碼單元(basic unit)是碼率控制的基本單元,由連續(xù)編碼的一組n個(gè)宏塊構(gòu)成。如果n和圖像的宏塊個(gè)數(shù)相等,則變成圖像層碼率控制;如果n等于1,則相當(dāng)于宏塊層的碼率控制。
如果當(dāng)前圖像為IDR幀或非參考幀,則該幀所有編碼單元使用相同的量化參數(shù)QP。
基本編碼單元層碼率控制的目標(biāo)是為每一幀圖像中的每個(gè)基本單元選擇合適的量化參數(shù),使得圖像編碼比特?cái)?shù)盡可能接近目標(biāo)值。算法分為5步:
總結(jié)
以上是生活随笔為你收集整理的H264编码-码率控制原理以及JM代码分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 女孩的问题,男孩的回答
- 下一篇: LM317稳压芯片在工程中的应用