熵編碼:CABAC

基於上下文的二進制算術編碼(Context-Based Adaptive Binary Arithmetic Coding,CABAC)將自適應二進制算術編碼和上下文模型相結合。是H.265/HEVC的主要熵編碼方案。

主要包括三個步驟:

  1. 二進制化;

  2. 上下文建模;

  3. 二進制算術編碼;

其流程如下:

 

二進制化

二進制化就是將輸入的語法元素轉化爲二進制形式,如果語法元素以及是二進制形式則跳過該步驟。

H.265/HEVC中的二進制化方法有截斷萊斯二元化(Truncated Rice binarization,TR),K階指數哥倫布二元化(k-th order Exp-Golomb binarization,EGK)和定長二元化(Fixed-length binarization,FL)。K階指數哥倫布編碼前面已經介紹過。下面介紹TR和FL。

(1)截斷萊斯二元化TR

設閾值爲cMax,萊斯參數R,待二元化的語法元素爲V。

截斷萊斯碼由前綴串和後綴串拼接成,前綴值P由下式計算得到:P = V >> R

則前綴串獲取過程爲:若P值小於(cMax >> R),則前綴串由P個1和一個0組成,長度爲P+1;若P值大於等於(cMax >> R),則前綴串由(cMax >> R)個1組成,長度爲(cMax >> R)。

當語法元素V小於cMax時,後綴值S爲:S = V - (P << R)

後綴串爲S的二元化串,長度爲R。當語法元素V大於等於cMax時,無後綴串。

(2)定長二元化FL

當語法元素均勻分佈時,可採用定長二元化。假設語法元素值爲x,且x在[0,Max]間,則直接將x從十進制轉爲二進制得到二元化串。

上下文建模

一般情況下,不同語法元素間有一定相關性,且相同語法元素自身也具有一定記憶性。因此根據已編碼元素進行條件編碼可以提高編碼性能。這些已編碼元素就是當前待編碼元素的上下文。

語法元素使用的上下文模型包括兩個概率模型變量:最大概率符號MPS和概率狀態索引pStateIdx。

MPS表示待編碼的Bin最可能出現的符號,取值爲1或0;與之對應,LPS爲最小概率符號。在CABAC中,依據先驗知識爲LPS預設了64個概率值,如下表。

 

在對第一個二元位編碼前需要對概率模型參數進行初始化。在H.265/HEVC中,爲每個概率模型分配一個初始值V,通過V計算上下文模型初始變量MPS和pStateIdx。

 

HM中相關代碼如下:

/**
 - initialize context model with respect to QP and initialization value
 .
 \param  qp         input QP value
 \param  initValue  8 bit initialization value
 */
Void ContextModel::init( Int qp, Int initValue )
{
  qp = Clip3(0, 51, qp);
​
  Int  slope      = (initValue>>4)*5 - 45;
  Int  offset     = ((initValue&15)<<3)-16;
  Int  initState  =  min( max( 1, ( ( ( slope * qp ) >> 4 ) + offset ) ), 126 );
  UInt mpState    = (initState >= 64 );
    //!<m_ucState最後1位存放MPS值
  m_ucState       = ( (mpState? (initState - 64):(63 - initState)) <<1) + mpState;
}

獲得上下文模型初始參數後即可對輸入二元符號進行二元算術編碼和模型參數更新,實現上下文自適應的編碼。概率模型在每個二元位編碼後都要更新。

概率狀態pStateIdx更新方法爲:

若編碼的二元符號值等於MPS,則通過查上面的表更新pStateIdx_new=transIdxMps(pStateIdx)

若編碼的二元符號值等於LPS,如果pStateIdx爲0則互換MPS和LPS,更新pStateIdx;否則不互換MPS和LPS,只更新pStateIdx;pStateIdx更新也是通過查表pStateIdx_new=transIdxLps(pStateIdx)

HM16中相關代碼如下:

  Void updateLPS ()
  {
    m_ucState = m_aucNextStateLPS[ m_ucState ];
  }
​
  Void updateMPS ()
  {
    m_ucState = m_aucNextStateMPS[ m_ucState ];
  }

從概率模型更新過程可以看出:若當前編碼Bin等於MPS,更新後的概率索引值變大,表示下一個符號是MPS的概率變大;若當前編碼Bin等於LPS,更新後的概率索引值變小,表示下一個符號是LPS的概率變大;當概率索引值pStateIdx爲0時,表示MPS和LPS的概率相同,若再出現LPS符號則MPS和LPS需要交換。

二進制算術編碼

二進制算術編碼也是算術編碼的一種,只不過算術編碼過程中的區間和編碼輸出等都用二進制表示。當前語法元素完成二進制化後,對每個Bin根據其概率模型進行二進制算術編碼。二進制算術編碼是基於遞歸區間劃分方式,在遞歸過程中保存編碼區間的長度和區間下限。包括兩種編碼方式:常規編碼和旁路編碼。常規編碼利用自適應的概率模型進行編碼。旁路編碼以等概率方式進行,概率狀態無需更新。

常規編碼

編碼器輸入是上下文模型變量和待編碼Bin,編碼器的狀態是當前編碼區間長度ivlCurrRange和區間下限ivlLow。

編碼流程如下:

 

算術編碼首先需要估計每個符號概率然後進行區間劃分。在CABAC中總是估計LPS的概率(P_lps<0.5),且LPS的概率通過64個離散值表示可以通過查表得到概率索引pStateIdx(見上一節)。

區間劃分通常需要多位乘法運算(區間長度x概率),CABAC爲了降低其複雜度通過查表獲得區間長度。

首先計算索引:qRangeIdx=(ivlCurrRange >> 6) & 3

通過查下表LPS對應的子區間長度爲:ivlLpsRange = rangeTabLps[pStateIdx] [qRangeIdx]

則MPS的子區間長度爲:ivlCurrRange = ivlCurrRange - ivlLpsRange

因爲二進制編碼只有兩個符號0和1,所有區間總是被分爲兩個子區間,且MPS總是在左側,LPS總是在右側。

 

如果當前Bin等於MPS,則MPS的區間長度R_mps作爲下一個符號編碼的區間長度R,區間下限L不變;如果當前Bin等於LPS,則LPS的區間長度R_lps作爲下一個符號編碼的區間長度R,區間下限L變爲L+R_mps;編碼完一個Bin後根據該Bin值更新上下文模型。

區間重歸一化

上面區間劃分後得到的新區間長度可能不在[256,512]間(HM中區間長度初始化爲510),這就需要進行重歸一化。

 

 

當區間長度小於256時就需要進行重歸一化。

設歸一化時用區間[0,102)表示[0,1);

1、當R<256&L<256時,區間落在[0,512)間,即[0,0.5)間(0.5二進制表示爲0.1)。此時輸出0(PutBit(0)),因爲此區間內的數都是0.0x(二進制)。

2、當R<256&L>=512時,區間落在[512,1024)間,即[0.5,1)間。此時輸出1(PutBit(1)),因爲此區間內的數都是0.1x(二進制)。

3、當R<256&L<512時,區間落在[0,512)間或同時跨越[0,512)和[512,1024)。此時既可能是0.01x也可能是0.10x。暫緩輸出,保存這個比特進入下一個重歸一化循環。

4、當R>=256時,無法判斷編碼區間,需要通過輸入下一個符號對R和L進行更新後繼續判斷,因此當前符號編碼流程結束。由於這個原因,因此在一個符號編碼結束後,另一個符號編碼開始前,總是256<=R<512。

PutBit(B)用來輸出編碼符號0或1,從重歸一化可以看出:

1、當滿足條件1時執行PutBit(0),輸出0;

2、當滿足條件2時執行PutBit(1),輸出1;

3、當滿足條件3時,輸出可能爲“10”或者“01”,因此不能直接輸出,走bitsOutstanding++的步驟。在下一次編碼符號時,符合情況2,走PutBit(1),此時bitsOutstanding = 1,因此輸出“10”。符合情況1,走PutBit(0),此時bitsOutstanding = 1,因此輸出“01”;

另外,PutBit(B)不會編碼第一個bit。原因是CABAC在初始化的時候,會以[0,1024)表示區間[0,1),而在初始化區間時R=510,L=0,這意味着已經進行了第一次區間選擇,區間爲[0,0.5),需要輸出“0”。PutBit(B)在此阻止這個“0”的輸出,這樣就能得到正確的算術編碼結果了。

WriteBits( B, N ) 表示將值B以N比特寫入碼流,然後將碼流指針往前移動N個位置。

旁路編碼

旁路編碼不需要對概率模型進行更新,而是採用0和1概率各1/2的方式進行編碼。當bypassFlag標誌位爲1時採用旁路編碼。爲了使區間劃分更加簡單,不採用直接對區間長度二等分的方法,而是採用保持編碼區間長度不變使區間下限L加倍的方法實現區間劃分。隨後進行重歸一化操作。旁路編碼流程如下:

 

參考

新一代高效視頻編碼H.265/HEVC:原理、標準與實現

ITU-T H.265 (V5)

https://www.cnblogs.com/TaigaCon/p/5304563.html

感興趣的請關注微信公衆號Video Coding

 

發佈了97 篇原創文章 · 獲贊 174 · 訪問量 26萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章