H264编码器13(CAVLC和CABAC简介)
來自:https://blog.csdn.net/jubincn/article/details/6948334
?
CABAC/CAVLCin H.264
 什么是熵編碼?
 熵編碼壓縮是一種無損壓縮,其實現原理是使用新的編碼來表示輸入的數據,從而達到壓縮的效果。常用的熵編碼有游程編碼,哈夫曼編碼和CAVLC編碼等。
?
第一部分
?
CAVLC
 CAVLC(Context Adaptive VariableLength Coding)是在H.264/MPEG-4AVC中使用的熵編碼方式。在H.264中,CAVLC以zig-zag順序用于對變換后的殘差塊進行編碼。CAVLC是CABAC的替代品,雖然其壓縮效率不如CABAC,但CAVLC實現簡單,并且在所有的H.264profile中都支持。
?
CAVLC的編碼過程如下:
?
1 計算非零系數(TotalCoeffs)和拖尾系數(TrailingOnes)的數目。
拖尾系數指值為+1/-1的系數,最大數目為3。如果超過3個,那么只有最后三個被視為拖尾系數。拖尾系數的數目被賦值到變量TrailingOnes。
 非零系數包括所有的拖尾系數,其數目被賦值到變量TotalCoeffs)。
2 計算nC(numberCurrent,當前塊值)。
nC值由左邊塊的非零系數nA和上面塊非零系數nB來確定,計算公式為:nC=round((nA+nB)/2);若nA存在nB不存在,則nC=nA;若nA不存在而nB存在,則nC=nB;若nA和nB都不存在,則nC=0。
 nC值用于選擇VLC編碼表,如下圖所示。這里體現了上下文相關(contextadaptive)的特性,例如當nC值較小即周圍塊的非零系數較少時,就會選擇比較短的碼,從而實現了數據壓縮。
?
3 查表獲得coff_token的編碼。
根據之前編碼和計算過程所得的變量TotalCoeffs、TrailingOnes和nC值可以查H.264標準附錄CAVLC碼表,即可得出coeff_token編碼序列。
4 編碼每個拖尾系數的符號,按zig-zag的逆序進行編碼。
每個符號用1個bit位來表示,0表示“+”,1表示“—”。
 當拖尾系數超過三個時只有最后三個被認定為拖尾系數,引詞編碼順序為從后向前編碼。
?
5 編碼除拖尾系數之外非零系數的level(Levels)。
每個非零系數的level包括sign和magnitude,掃描順序是逆zig-zag序。
 level的編碼由前綴(level_prefix)和后綴(level_suffix)組成。前綴的長度在0到6之間,后綴的長度則可通過下面的步驟來確定:
 將后綴初始化為0。(若非零系數的總數超過10且拖尾系數不到3,則初始化為1)。
 編碼頻率最高(即按掃描序最后)的除拖尾系數之外的非零系數。
 若這個系數的magnitude超過某個門檻值(threshold),則增加后綴的長度。下表是門檻值的列表:
6 編碼最后一個非零系數之前0的個數(totalZeos)。
TotalZeros指的是在最后一個非零系數前零的數目,此非零系數指的是按照正向掃描的最后一個非零系數
 根據TotalCoeffs值,H.264標準共提供了25個變長表格供查找,其中編碼亮度數據時有15個表格供查找,編碼色度DC2×2塊(4:2:0格式)有3個表格、編碼色度DC2×4塊(4:2:2格式)有7個表格。
?
7 編碼每個系數前面0的數目(run_before)。
掃描順序為zig-zag的逆序。
 若∑[run_before]== total_zeros,則不需再計算run_before
 掃描序中的最后一個元素不需要計算run_before
 每個run_before的VLC編碼取決于run_before自身及未編碼的0的個數ZerosLeft。例如若ZerosLeft== 2,那么run_before只可能是0,1或2,因此使用兩個bit即可表示。
 ?
第二部分?CAVLC之手把手教你編碼
轉自:http://blog.csdn.net/sunshine1314/article/details/1685948
這篇博客使用實例對上述過程做了詳細的說明,尤其是有關Levels的計算方面做了重要的補充。下面是全文的轉載:
首先聲明本文并不是我寫的,文章來自本人同學(Sunrise),都是一起做的H264,比較了解,文章內容都是自己整理的,比較可信,因此整理到一起,我也偷個懶哈
再次聲明:文中用的標準是BS的正式標準,如果大家發現序號不對,參考著改過來就是了!
編碼過程:
 假設有一個4*4數據塊
 {
 ???0,???3,???-1,???0,
 ???0,???-1,???1,???0,
 ???1,???0,???0,???0,
 ???0,???0,????0,???0
 }
 數據重排列:0,3,0,1,-1,-1,0,1,0……
?
1)初始值設定:
 非零系數的數目(TotalCoeffs)?=?5;
 拖尾系數的數目(TrailingOnes)=?3;
 最后一個非零系數前零的數目(Total_zeros)?=?3;
 變量NC=1;
 (說明:NC值的確定:色度的直流系數NC=-1;其他系數類型NC值是根據當前塊左邊4*4塊的非零系數數目(NA)當前塊上面4*4塊的非零系數數目(NB)求得的,見畢厚杰書P120表6.10)
 suffixLength?=?0;
 i?=?TotalCoeffs?=?5;
 2)編碼coeff_token:
 查標準(BS?ISO/IEC?14496-10:2003)Table?9-5,可得:
 If?(TotalCoeffs?==?5?&&?TrailingOnes?==?3?&&?0?<=?NC?<?2)
 ??????coeff_token?=?0000?100;
 ??????Code?=?0000?100;
 3)編碼所有TrailingOnes的符號:
 逆序編碼,三個拖尾系數的符號依次是+(0),-(1),-(1);
 即:
 TrailingOne?sign[i--]?=?0;
 TrailingOne?sign[i--]?=?1;
 TrailingOne?sign[i--]?=?1;
 Code?=?0000?1000?11;
 4)編碼除了拖尾系數以外非零系數幅值Levels:
 過程如下:
 (1)將有符號的Level[i]轉換成無符號的levelCode;
 如果Level[i]是正的,levelCode?=?(Level[i]<<1)?–?2;?
 如果Level[i]是負的,levelCode?=?-?(Level[i]<<1)?–?1;
 (2)計算level_prefix:level_prefix?=?levelCode?/?(1<<suffixLength);
 ???????查表9-6可得所對應的bit?string;
 (3)計算level_suffix:level_suffix?=?levelCode?%?(1<<suffixLength);
 (4)根據suffixLength的值來確定后綴的長度;
 (5)suffixLength?updata:
 If?(?suffixLength?==?0?)
 suffixLength++;
 ?????????else?if?(?levelCode?>?(3<<suffixLength-1)?&&?suffixLength?<6)
 ????????????suffixLength++;
回到例子中,依然按照逆序,Level[i--]?=?1;(此時i?=?1)
 levelCode?=?0;level_prefix?=?0;
 查表9-6,可得level_prefix?=?0時對應的bit?string?=?1;
 因為suffixLength初始化為0,故該Level沒有后綴;
 因為suffixLength?=?0,故suffixLength++;
 Code?=?0000?1000?111;
 編碼下一個Level:Level[0]?=?3;
 levelCode?=?4;level_prefix?=?2;查表得bit?string?=?001;
 level_suffix?=?0;suffixLength?=?1;故碼流為0010;
 Code?=?0000?1000?1110?010;
 i?=?0,編碼Level結束。
 5)編碼最后一個非零系數前零的數目(TotalZeros):
 ???查表9-7,當TotalCoeffs?=?5,total_zero?=?3時,bit?string?=?111;
 ???Code?=?0000?1000?1110?0101?11;
 6)對每個非零系數前零的個數(RunBefore)進行編碼:
 i?=?TotalCoeffs?=?5;ZerosLeft?=?Total_zeros?=?3;查表9-10:
 依然按照逆序編碼
 ZerosLeft?=3,?run_before?=?1?????????run_before[4]=10;
 ZerosLeft?=2,?run_before?=?0?????????run_before[3]=1;
 ZerosLeft?=2,?run_before?=?0?????????run_before[2]=1;
 ZerosLeft?=2,?run_before?=?1?????????run_before[1]=01;
 ZerosLeft?=1,?run_before?=?1?????????run_before[0]不需要碼流來表示
 Code?=?0000?1000?1110?0101?1110?1101;
 編碼完畢。
?
第三部分 CABAC
 簡介
 CABAC(ContextAdaptive Binary Arithmatic Coding)也是?H.264/MPEG-4AVC中使用的熵編碼算法。CABAC在不同的上下文環境中使用不同的概率模型來編碼。其編碼過程大致是這樣:首先,將欲編碼的符號用二進制bit表示;然后對于每個bit,編碼器選擇一個合適的概率模型,并通過相鄰元素的信息來優化這個概率模型;最后,使用算術編碼壓縮數據。
?
CABAC編碼詳情
 CABAC編碼之所以能取得很高的壓縮比,是因為:a)根據每一個語法元素的上下文來選取預測模型;b)使用本地的統計數據來估計概率;c)使用算術編碼而不是變長編碼。編碼一個符號需要經過下面幾步:
?
1 二值化。
CABAC使用的算術編碼是基于二進制的算術編碼,因此非二進制形式的編碼首先要轉化為二進制的形式表示。
?
下面的2、3、4步
2 選擇上下文模型。
“上下文模型”是指對二值化后的符號中的bit位進行編碼時使用的概率模型。概率模型與最近編碼的符號相關,會有多個概率模型可供選擇。
?
3 算術編碼。
算術編碼器根據第2步選擇的概率模型對每個bit進行編碼。需要注意的是每個bit的子范圍只有兩個數:0和1。
?
4 更新預測模型。
根據實際編碼的值來更新所選擇的預測模型。例如,如果所編碼的二進制bit為1,則預測模型中的1計數要增加。
?
?編碼過程
 下面將以mxdx為例解釋編碼過程,mxdx是motionvector difference in the x-direction的簡寫,通過宏塊的子塊之間運算獲得。
?
1 二值化。
對于|mvdx|<9的數,使用下表進行編碼,超過9的數使用Exp-Golomb編碼。在這里,我們稱編碼后的第一個bit為bin1,第二個bit為bin2,以此推之,可以得到bin3,bin4等。
?
2 為每個bin選擇一個上下文模型。
bin1可以在三個模型之間進行選擇,選擇的依據是相鄰的兩個mxdx的絕對值之和,ek:
ek = mxdxA+ mxdxB(A和B分別是當前塊的上方塊和左邊塊)
根據ek值從下表中為bin1選擇上下文模型:
除bin1之外的其它bit的上下文模型的選擇根據下表進行:
?
3 編碼每個bin。
所選的預測模型中有0和1的概率,從而為算術編碼器提供了概率范圍,算術編碼器使用這個概率范圍對此bin進行算術編碼。
?
4 更新上下文模型。
例如,若bin1使用上下文模型2,而bin1的值是1,那么上下文模型2中1的計數就要增加,1的概率和0的概率需要重新計算。當上下文模型中的總數超過門檻值后,0和1的計數就要除以某個值,從而使得新加入的0和1在模型中產生更大的影響。
 ?
總結
以上是生活随笔為你收集整理的H264编码器13(CAVLC和CABAC简介)的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 企业级微服务构建-01搭建和使用Mave
- 下一篇: 计算机二级access知识点题库,计算机
