CAVLC算法解析

CAVLC算法解析

writeSyntaxElement_NumCoeffTrailingOnes裏有lentab[3][4][17] codtab[3][4][17]

編碼非零係數數目 (NumCoeff)和拖尾係數數目(TrailingOnes)

writeSyntaxElement_NumCoeffTrailingOnesChromaDC裏有lentab[4][5] codtab[4][5]

與上面的函數功能一樣, 只是這兒特別針對Chroma DC(色度直流係數)

writeSyntaxElement_TotalZeros裏有lentab[TOTRUN_NUM(15)][16] codtab[TOTRUN_NUM][16]

編碼最後一個非零係數前零的數目(TotalZeros)

writeSyntaxElement_TotalZerosChromaDC裏有lentab[3][4] codtab[3][4]

特別針對色度直流係數ChromaDC

writeSyntaxElement_Run裏有lentab[TOTRUN_NUM][16] codtab[TOTRUN_NUM][16]

編碼非零係數前零的個數: write VLC for Run Before Next Coefficient, VLC0

writeSyntaxElement_Level_VLC1, writeSyntaxElement_Level_VLCN

編碼除拖尾係數之外的非零係數的幅值

 

intwriteSyntaxElement_TotalZeros(SyntaxElement *se, DataPartition *this_dataPart);

intwriteSyntaxElement_TotalZerosChromaDC(SyntaxElement *se, DataPartition *this_dataPart);

intwriteSyntaxElement_Run(SyntaxElement *se, DataPartition *this_dataPart);

intwriteSyntaxElement_NumCoeffTrailingOnes(SyntaxElement *se, DataPartition *this_dataPart);

intwriteSyntaxElement_NumCoeffTrailingOnesChromaDC(SyntaxElement *se, DataPartition *this_dataPart);

intwriteSyntaxElement_Level_VLC1(SyntaxElement *se, DataPartition *this_dataPart);

intwriteSyntaxElement_Level_VLCN(SyntaxElement *se, intvlc, DataPartition *this_dataPart);

 

基於內容的自適應變長編碼[CAVLC]

基於內容自適應的變長編碼方式用於編碼zigzag順序掃描的4x4和2x2殘差變換系數塊。

1、             編碼係數個數和零序列(coeff_token):

coeff_token = <TotalCoeff, TrailingOnes>;

TotalCoeff = 編碼非零係數總數; [0 , 16]

TrailingOnes = 特殊處理的+/-1個數; [0 , 3]

2、           編碼每個TrailingOne的符號:

倒序,從高頻開始向前編碼TrailingOne符號,每個符號一位,0爲正,1爲負,最多爲3個。

3、           編碼餘下非零係數的幅值:

編碼順序:倒序,從高頻開始向前編碼直到DC係數,每個幅值碼字level[i]包含一個幅值前綴level_prefix和一個幅值後綴level_suffix。

level[i]: Level爲實際係數的幅值。但有個例外:

當TrailingOnes<3時,那麼被編碼的第一個非T1 幅值肯定不是+/-1(否則將算作T1)。這個幅值如果爲負就加1(如果爲正就減1),例如+/-2 被映射成+/-1, +/-3映射成+/-2進行編碼,這樣可以用較短的變長碼.

levelCode:

         如果level[i]爲正, levelCode = (Level[i] << 1) - 2;

如果 level[i]爲負, levelCode = -(Level[i] << 1) - 1;

計算level_prefix:

編碼時:

level_prefix = levelCode / (1 << suffixLength);

根據level_prefix查標準表9-6得到碼字

解碼時:

從比特流的當前位置開始讀取,計算爲0的leading bits數量。0的長度即爲level_prefix值,對應關係可察看標準文檔中表9-6。

計算suffixLength:

suffixLength爲0-6 比特,其長度是自適應變換的。

suffixLength 增長過程:

1、             初始化suffixLength = 0 ; 如果有超過10個非零係數,並且少於3個TailingOnes,這時suffixLength = 1;

2、           編碼最高頻的非零係數;

3、           如果這個係數的幅值大於一定的閾值,則增長suffixLength

當前suffixLength

增加suffixLength的係數閾值

12 

24 

48 

N/A 

更新suffixLength函數如下:

if(suffixLength == 0)

++suffixLength;

else if(level[i] > (3<<suffixLength-1) && suffixLength < 6)

++suffixLength;

計算levelSuffixSize: (後綴是長度爲levelSuffixSize的無符號整數)

除了以下兩種情況levelSuffixSize等於suffixLength:

1、             level_prefix == 14 && suffixLength == 0 時, levelSuffixSize = 4;

2、           level_prefix >= 15 時,levelSuffixSize = level_prefix – 3;

4、             編碼最後一個非零係數前零的個數

使用VLC編碼最高頻非零係數前所有零的個數

total_zeros:既爲最高非零係數前所有零的個數;編碼表見標準表9-7;表9-8;表9-9

5、             編碼每個零遊程

zerosLeft: 當前係數之前所有的零的個數

run_before: 緊接當前係數前的零個數

CAVLC算法的具體過程(參考Sunrise的總結)

編碼過程:

假設有一個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)求得的,見畢厚傑書P1206.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;

編碼完畢。

 

CAVLC中的前綴和後綴——264小生

H264中的CAVLC在對TrailingOne之後的非零係數編碼時,使用了前綴(prefix)和後綴(suffix)的概念,並且用suffixlength來表示後綴的長度。具體編碼過程是這樣的:

,suffixlength初始化爲0(如果超過10個非零係數,而且少於3TrailingOnes,suffixlength初始化爲1)

,將有符號的level(係數的值),轉化爲無符號數,有三種情況:

(1)如果Level是正的,levelCode = (Level<<1) – 2

(2)如果Level是負的,levelCode = -(Level<<1) – 1

(3)如果TrailingOnes小於3,那麼第一個非TrailingOnes的非零係數必不爲 +1-1,爲了節省編碼比特,將其幅值減1。也就是如果level爲正,level=level-1;否則,level=level+1。然後再按(1)

(2)level轉化爲levelCodeT264,此步驟是通過直接對levelcode2完成的,levelcode=levelcode-2,這和通過對level幅值減1得到的levelcode是一樣的。

,得到level_prefixlevel_suffix

先說明一下,在解碼端,levelcode是這樣被解碼的:

levelcode=(level_prefix<<suffixlength)+level_suffix

知道這一點很重要。從解碼levelcode的公式中可以看出,編碼端的level_prefix就是將levelcode右移suffixlength位得到的,level_suffix直接就是levelcode的低suffixlength位。比如levelcode =13,也就是二進制'1101',而且如果此時的suffixlength=1,那麼level_prefix=13>>1='110',level_suffix直接就是levelcode的最低位'1';再比如levelcode=13='1101', suffixlength=3,這時level_prefix=13>>3='1', level_suffix 就是 levelcode的低3'101'。根據level_prefix 的值查表得到輸出的碼字。

這裏還有三種特殊情況,在解碼端:

(1)如果此時發現suffixlength=0,level_prefix=14,那麼認爲level_suffix4(而不是0)

(2)如果此時發現level_prefix=15,那麼認爲level_suffix12位的。

(3)如果此時發現suffixlength=0,level_prefix=15,那麼經過使用公式levelcode=

(level_prefix<<suffixlength)+level_suffix得到的levelcode還需要再加上15
發佈了17 篇原創文章 · 獲贊 19 · 訪問量 38萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章