H.264學習筆記5——熵編碼之CAVLC


  H.264中,4x4的像素塊經過變換和量化之后,低頻信號集中在左上角,大量高頻信號集中在右下角。左邊的低頻信號相對數值較大,而右下角的大量高頻信號都被量化成0、1和-1;變換量化后的殘差信息有一定的統計特性和規律。

  CAVLC(Context-based Adaptive Variable-Length Code):基於上下文的可變長度編碼,是H.264中進行4x4像素塊進行熵編碼的方法,基本(baseline)檔次中只能使用CAVLC,只有主要檔次和擴展檔次才能使用CABAC(見筆記:熵編碼之CABAC)。

一、對於經過Zigzag掃描(Z掃描)后的4x4像素殘差,編碼過程包括:

A、非零系數數目(TotalCoeffs)和拖尾系數數目(TrailingOnes)的編碼:

  拖尾系數:就是指Z掃描后,末尾高頻信號中出現連續1或-1的個數(中間可以隔任意多個0),拖尾系數最多有5個。當連續1或-1的個數超過3個,只有最后3個1或-1是拖尾系數,其他的當作普通的非零系數。

  TotalCoeffs和TrailingOnes通過查表方式進行編碼,H.264針對TotalCoeffs和TrailingOnes,提供了4張變長表和1張定長表(部分見附表9-5)。編碼表的選擇是由NC確定的,NC的值是由上下文信息確定的。對於色度直流信號,NC=-1;對於其他的NC,根據當前塊左邊4x4塊和上面4x4塊的非零系數的個數A和B決定。如表一:其中X表示該塊與當前塊屬於同一slice且可用。根據NC選擇編碼表的策略如表二:

表一
A(左邊塊) B(上面塊) NC
X   X     (A+B)/2
X   A
X B
0
表二
NC 編碼表編號
0,1 變長表1
2,3 變長表2
4,5,6,7 變長表3
>=8 定長表
-1 變長表4

  通過NC確定所選擇的表之后,將編碼的二進制輸出。

B、每一個拖尾系數的符號正負性編碼(按照Z掃面結果的逆序編碼):

  按照逆序對每一個拖尾系數的符號進行編碼,用0表示1(正)、1表示-1(負),將編碼結果輸出

C、除拖尾系數外的每一個非零系數幅值(Level,包含正負號信息)編碼(按照Z掃描結果的逆序編碼):

  拖尾系數幅值的編碼包括前綴Level_prefix和后綴Level_suffix。另外編碼過程中suffixLength基於上下文信息,根據Level_suffix和Level實時更新。具體過程如下:

  1、設置初始SuffixLength:

    當TotalCoeffs>10且TrailingOnes<=1時,SuffixLength設為1;否則設為0;

  2、將有符號的Level轉換成無符號的LevelCode:

    若Level > 0:LevelCode = (Level << 1)-2;

    若Level < 0:LevelCode = -(Level << 1) - 1;

    這樣解碼時,就可以根據LevelCode的奇偶性判斷Level的正負性,從在根據LevelCode解碼出有符號的Level。

  3、計算Level_prefix 和 Level_suffix:

    Level_prefix = LevelCode / (1 << SuffixLength);

    Level_suffix = LevelCode% (1 << SuffixLength);

  4、編碼Level_prefix和Level_suffix:

    編碼Level_prefix是通過查標准表9-6(部分見附表9-6),編碼得到的是前綴碼,所以解碼時可以即使、唯一譯碼。Level_suffix的編碼就是Level_suffix的二進制無符號形式。然后將Level_prefix和Level_suffix的編碼結果依次輸出,但當SuffixLength=0時,沒有Level_suffix,不需要輸出。

  5、更新SuffixLength的值,回到步驟2繼續編碼下一個非零系數。更新過程可以用下面代碼表示:

1 if(SuffixLength == 0)
2     SuffixLength++;
3 else if (abs(Level) > (3 << (SuffixLength -1)) && SuffixLength < 6)
4     SuffixLength++;

  即:當SuffixLength為0時,SuffixLength加1;當SuffixLength達到6之后不再更新SuffixLength;當SuffixLength在1和6之間,如果當前已編碼的非零系數的絕對值(abs(Level))大於給定的閾值S,那么SuffixLength增1,其中閾值S的大小為:S = 3 * 2 ^ (SuffixLength-1) = 3<<(SuffixLength-1)。

D、最后一個非零系數前0的數目(TotalZeros)編碼:查找標准表9-7(部分見附表9-7)~9-9

E、每一個非零系數前連續0的數目(RunBefore)編碼(按照Z掃面結果的逆序編碼):查找標准表9-10(部分見附表9-10)

  編碼過程中,ZerosLeft表示當前編碼非零系數左邊所有0的個數,對於最后一個(逆序的最后一個)非零系數前0的個數不需要編碼。  

、例如:對於4x4的殘差塊,如下圖:

0 3 -1 0
0 -1 1 0
1 0 0 0
0 0 0 0

  經過Z掃描得到序列:0,3,0,1,-1,-1,0,1,0,0,0,0,0,0,0,0。

  對該序列進行編碼如下:

  1、初始值設定:

    TotalCoeffs = 5;TrailingOnes = 3;TotalZeros = 3;假設 NC = 1;SuffixLength = 0;最終編碼輸出碼流為out。

  2、編碼TotalCoeffs和TrailingOnes:

    查附表9-5得,TotalCoeffs = 5、TrailingOnes = 3和0 <= NC <2時;編碼結果為:0000 100。

    此時out = 0000 100。

  3、編碼拖尾系數符號:

    拖尾系數為1,-1,-1(掃描逆序),對應的符號編碼為0,1,1。所以此時out = 0000 1000 11。

  4、編碼每個非拖尾非零系數的幅值Level:

    需要編碼的非零系數有1,3(Z掃描逆序),初始i=2,過程如下:

    Level[i--] = 1; 得到LevelCode = 0,Level_prefix = 0,沒有Level_suffix(因為SuffixLength=0),查表9-6得編碼結果為1。此時out = 0000 1000 111。

    然后更新SuffixLength,SuffixLength++得SuffixLength=1;

    Level[i--] = 3;得到LevelCode=4,Level_prefix = 2,Level_suffix = 0,查表9-6得Level_prefix編碼結果為001,然后Level_suffix的二進制表示為0。

    out = 0000 1000 1110 010。此時i=0,此步驟編碼結束。

  5、編碼TotalZeros:查表9-7得編碼結果為編碼結果為111,此時out = 0000 1000 1110 0101 11。

  6、編碼每一個非零系數前的連續o的數目:有四個非零系數前連續0的個數要編碼,初始i=5。查表9-10的編碼過程如下:

    ZerosLeft = 3, RunBefore = 1,Level[i--]=1,編碼結果為10;

    ZerosLeft = 2, RunBefore = 0,Level[i--]=-1,編碼結果為1;

    ZerosLeft = 2, RunBefore = 0,Level[i--]=-1,編碼結果為1;

    ZerosLeft = 2, RunBefore = 1,Level[i--]=1,編碼結果為01;

    ZerosLeft = 1, RunBefore = 1,Level[i--]=3,此時對應第一個非零系數,不需要編碼;

  最后輸出結果為 out = 0000 1000 1110 0101 1110 1101。

  相應解碼如下:讀入out = 0000 1000 1110 0101 1110 1101

  1、解碼TotalCoeffs和TrailingOnes:

    初始NC=1,根據表9-5,可以從0000100中解碼得到TotalCoeffs=5;TrailingOnes=3。這里因為表9-5的編碼可以及時、唯一譯碼,所以遇到的第一個合法的01串就是TotalCoeffs和TrailingOnes編碼的結果。

  2、解碼拖尾系數:此時out = 0 1110 0101 1110 1101

    由TrailingOnes=3知,有3個拖尾系數,所以對應的正負號編碼為011,所以3個拖尾系數是1,-1,-1。所以解碼輸出 in是 -1,-1,1(因為編碼是逆序的)。

  3、解碼除拖尾系數外的非零系數:此時out = 10 0101 1110 1101

    由TotalCoeffs=5;TrailingOnes=3知除拖尾系數外,還有兩個非零系數。初始SuffixLength=0,所以根據表9-6(及時、唯一譯碼)解碼如下:

    SuffixLength=0  查表得比特串為1,level_prefix=0,LevelCode=0(偶數),Level=1,沒有Level_suffix;(消耗碼流0)

 

    SuffixLength=1  查表得比特串為001,level_prefix=2,LevelCode=4(偶數),Level=3,Level_suffix=0;(消耗碼流0010)  

    所以輸出 in是 3,1,-1,-1,1

  4、解碼每個非零系數前0的個數:此時out = 1 1110 1101

    TotalCoeffs = 5;根據表9-7解碼得 TotalZeros=3,對應碼流:111。

    然后查表9-10,得到每一個非零系數前連續0的個數,過程如下:此時out = 10 1101

    TotalZeros=3,根據碼流查表得10對應 RunBefore=1,in是 3,1,-1,-1,0,1

      TotalZeros=3-1=2,根據碼流查表得1對應 RunBefore=0,in是 3,1,-1,-1,0,1 

    TotalZeros=2-0=2,根據碼流查表得1對應 RunBefore=0,in是 3,1,-1,-1,0,1

    TotalZeros=2-0=2,根據碼流查表得01對應 RunBefore=1,in是 3,0,1,-1,-1,0,1

    TotalZeros=2-1=1,out碼流解碼完,所以TotalZeros=1表示3之前的0數目,in是 0,3,1,-1,-1,0,1

    然后在結尾補0組成16個殘差系數,得解碼結果0,3,1,-1,-1,0,1,0,0,0,0,0,0,0,0,0

三、附表:

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM