【H.264/AVC視訊編解碼技術詳解】二十二、熵編碼(7):語法元素的CABAC解析
《H.264/AVC視訊編解碼技術詳解》視訊教程已經在“CSDN學院”上線,視訊中詳述了H.264的背景、標準協議和實現,並通過一個實戰工程的形式對H.264的標準進行解析和實現,歡迎觀看!
“紙上得來終覺淺,絕知此事要躬行”,只有自己按照標準文件以程式碼的形式操作一遍,才能對視訊壓縮編碼標準的思想和方法有足夠深刻的理解和體會!
連結地址:H.264/AVC視訊編解碼技術詳解
GitHub程式碼地址:點選這裡
在本系列的博文18中,我們討論了算術編碼的基本原理,以及實現一個簡單的算術編碼器核心的方法:
而在博文19和21中我們根據H.264對於CABAC的規定,討論了語法元素二值化以及上下文概率模型的相關演算法:
通過前面的研究我們已經瞭解,由於視訊資料特殊的統計特性和對編碼效能的高指標要求,CABAC的演算法遠遠比博文18中描述的基本模型更加複雜。儘管如此,CABAC在算術編碼的最核心層面依然遵循了博文18中所講的根本原理,這一點在本文對標準協議文件的解讀中也可以獲得明確的證實。
一、CABAC解析(解碼)的總流程
CABAC的解碼過程定義與標準協議文件的9.3.3.2節。CABAC解碼過程所需要的輸入資料包括前一章所推匯出的上下文模型索引ctxIdx、旁路模式標誌bypassFlag,以及解碼器引擎的狀態。下圖表示了CABAC解碼過程的概念框圖:
在上圖中可以看出,根據引數的不同,CABAC解碼總共可能有三種執行流程:
- DecodeBypass: 當旁路模式標誌bypassFlag為1時執行,表示旁路模式的解析過程;
- DecodeDecision: 當bypassFlag為0且ctxIdx不為276時執行,表示CABAC解析過程;
- DecodeTerminate
在這三種執行流程中最重要的就是第二種——DecodeDecision。接下來本文將從DecodeDecision開始分析這三種解析過程。
二、CABAC算術編碼的解碼(解析)過程
本節描述的即是DecodeDecision部分的方法。這一部分也是CABAC演算法中最為重要的部分,H.264的main、high profile中的多數語法元素都是通過該過程進行解析的。該部分在標準協議文件的9.3.3.2.1中定義。
從標準協議中的該節內容中可知,該過程所需要的資料有ctxIdx, codIRange 和 codIOffset,其中ctxIdx由前一章《CABAC的上下文概率模型》中的方法推導,codIRange 和 codIOffset的初始值由CABAC解碼器引擎的初始化確定。輸出的資料包括解析出來的語法元素位元位值binVal,以及更新過的codIRange 和 codIOffset。
該過程的整體流程如下圖所示:
2.1 計算 codIRangeLPS
計算 codIRangeLPS 的過程遵循以下流程:
- 根據當前的codIRange值,計算qCodIRangeIdx的值:
- qCodIRangeIdx =( codIRange >> 6 ) & 3
- 通過 qCodIRangeIdx 和 pStateIdx,計算 codIRangeLPS 的值:
- 通過查表獲取:codIRangeLPS = rangeTabLPS[ pStateIdx ][ qCodIRangeIdx ]
- rangeTabLPS為預定義的表,在表9-44中指定;
2.2 更新 codIRange
更新 codIRange 的方法為:
codIRange = codIRange - codIRangeLPS;
更新完成後,判斷 codIOffset,如果 codIOffset >= codIRange,輸出位元位值binVal賦值為1 - valMPS,並且codIOffset自減去codIRange的值,然後codIRange的值賦值為codIRangeLPS;否則,輸出位元位值binVal賦值為valMPS。
2.3 狀態轉移過程
在CABAC編碼或解碼語法元素的某一個bit,編碼/解碼器將隨之更新編解碼器的狀態。狀態轉移過程定義於標準的9.3.3.2.1.1節。該過程根據當前的上下文模型索引和解碼的位元值,來更新上下文模型索引以及LPS/MPS的定義。
狀態轉移過程可以下式表示:
if( binVal = = valMPS )
pStateIdx = transIdxMPS( pStateIdx )
else {
if( pStateIdx = = 0 ) {
valMPS = 1 − valMPS
}
pStateIdx = transIdxLPS( pStateIdx )
}
在編碼過程中上下文模型索引的更新同樣以查表的形式實現,該表格在9-45中規定。
2.4 歸一化過程
在第18篇博文“算術編碼的基本原理中”已經討論過算術編碼器的歸一化。在H.264實際定義的CABAC演算法中,歸一化同樣也是必備過程。CABAC的歸一化過程定義於9.3.3.2.2節,流程圖以下圖表示:
進行歸一化的本質含義是更新codIRange和codIOffset的值,所需要的資料包括當前CABAC的codIRange和codIOffset以及當前的二進位制位元流資料。主要步驟為:
- 判斷如果codIRange不小於256,那麼不需要進行歸一化;
- 如果codIRange小於256,則進行歸一化過程,方法為:
- codIRange和codIOffset分別自乘以2;
- 在碼流中讀取 1 bit,並與codIOffset按位取或運算並更新到codIOffset;
三、CABAC的bypass解析方法
本節描述的是CABAC的DecodeBypass方法,即旁路解析模式,在bypass值設為1時執行。DecodeBypass相比DecodeDecision方法的特點是編碼效率較低但運算遠比DecodeDecision簡單。與DecodeDecision過程相比,DecodeBypass不需要ctxIdx,只需要codIRange和codIOffset兩個值。
DecodeBypass過程的流程圖如下:
解析過程為:
- 首先codIOffset自增一倍,並且從碼流中讀取1 bit與之求按位或操作;
- codIOffset與codIRange對比:
- 若codIOffset小於codIRange,輸出二進位制位0;
- 否則,輸出二進位制位1,且codIOffset自減去codIRange的值;
四、CABAC的終止符解析
CABAC的終止符解析即DecodeTerminate過程,主要用於解析end_of_slice和ctxIdx值為276的元素。解析的方法類似於DecodeBypass過程,流程如下:
- 首先codIOffset自減2;
- codIOffset與codIRange對比:
- 若codIOffset小於codIRange,輸出二進位制位0,並執行解碼器的歸一化過程;
- 否則,輸出二進位制位1;