- 1 CAVLC概念
- 2 CAVLC原理
- 3 CAVLC編碼流程
- 4 CAVLC解碼流程
- 展開全部
CAVLC即基于上下文的自適應變長編碼。H.264標準中使用CAVLC對4*4模塊的亮度和色度殘差數據進行編碼。
CAVLC-CAVLC概念
CAVLC的全稱是Context-Adaptive Varialbe-Length Coding,即基于上下文的自適應變長編碼。CAVLC的本質是變長編碼,它的特性主要體現在自適應能力上,CAVLC可以根據已編碼句法元素的情況動態的選擇編碼中使用的碼表,并且隨時更新拖尾系數后綴的長度,從而獲得極高的壓縮比。H.264標準中使用CAVLC對4×4模塊的亮度和色度殘差數據進行編碼。
CAVLC-CAVLC原理
在H.264標準編碼體系中,視頻圖像在經過了預測、變換及量化編碼后表現出如下的特性:4×4塊殘差數據塊比較稀疏,其中非零系數主要集中在低頻部分,而高頻系數大部分是零;量化后的數據經過zig-zag掃描,DC系數附近的非零系數值較大,而高頻位置上的非零系數值大部分是+1和-1;相鄰的4×4塊的非零系數的數目是相關的。CAVLC就是利用編碼后殘差數據的這些特性,通過自適應對不同碼表的選擇,利用較少的編碼數據對殘差數據進行無損的熵編碼,進一步減少了編碼數據的冗余和相關性,提高了H.264的壓縮效率。
CAVLC-CAVLC編碼流程
視頻圖像在經過預測、變換和量化編碼后,需要經過Zig-zag掃描和重新的排序過程,為后序的CAVLC編碼進行準備。一個殘差數據塊的CAVLC熵編碼的流程如圖所示:

1、TotalCoeffs和TrailingOnes的編碼
從碼流的起始位置開始計算整個編碼塊中非零系數的數目(TotalCoeffs),非零系數的數目為從0-16,非零系數的數目被賦值給變量TotalCoeffs。
拖尾系數是指碼流中正或者負1的個數(+/-1)。拖尾系數的數目(TrailingOnes)被限定在3個以內,如果+/-1的數目超過3個,則只有最后3個被視為拖尾系數,其余的被視為普通的非零系數,拖尾系數的數目被賦值為變量TrailingOnes。?
2、判斷計算nC值
nC(Number Current 當前塊值)值的計算集中體現了CAVLC的基于上下文的思想,通過nC值選擇不同H.264標準附錄CAVLC碼表。?
3、查表獲得coeff_token編碼
根據之前編碼和計算過程所得的變量TotalCoeffs、TrailingOnes和nC值可以查H.264標準附錄CAVLC碼表,即可得出coeff_token編碼序列。
4、編碼每個拖尾系數的符號:前面的coeff_token編碼中已經包含了拖尾系數的總數,還需進一步對拖尾系數的符號進行編碼。由于拖尾系數符合為正(+)或負(-),因此,在H.264標準中規定用0表示正1(+1)、1表示負1(-1)。當拖尾系數的數目超過3個只有最后3個被認定為拖尾系數,因此對符號的編碼順序應按照反向掃描的順序進行。
5、編碼除拖尾系數之外的非零系數的幅值(Levels)
非零系數的幅值(Levels)由兩個部分組成:前綴(level_prefix)和后綴(level_suffix)。levelCode、levelSuffixsSize和suffixLength是編碼過程中需要使用的三個變量,其中levelCode是中間過程中用到的無符號數,levelSuffixsSize表示后綴長度位數,suffixLength代表Level的碼表序號。
6、編碼最后一個非零系數前零的數目(TotalZeros)
TotalZeros指的是在最后一個非零系數前零的數目,此非零系數指的是按照正向掃描的最后一個非零系數。因為非零系數數目(TotalCoeffs)是已知,這就決定了TotalZeros可能的最大值。根據TotalCoeffs值,H.264標準共提供了25個變長表格供查找,其中編碼亮度數據時有15個表格供查找,編碼色度DC 2×2塊(4:2:0格式)有3個表格、編碼色度DC 2×4塊(4:2:2格式)有7個表格。
7、編碼每個非零系數前零的個數(RunBefore)
在CAVLC中,變量 ZerosLeft表示當前非零系數左邊的所有零的個數,ZerosLeft的初始值等于TotalZeros。每個非零系數前零的個數(RunBefore)是按照反序來進行編碼的,從最高頻的非零系數開始。H.264標準中根據不同ZerosLeft和RunBefore,構建了RunBefore編碼表格供編碼查找使用。根據表格每編碼完一個RunBefore,對ZerosLeft的值進行更新,繼續編碼下一個RunBefore,直至全部完成所有非零系數前零的個數的編碼。當ZerosLeft=0即沒有剩余0需要編碼時或者只有一個非零系數時,均不需要再進行RunBefore編碼。
CAVLC-CAVLC解碼流程
CAVLC熵解碼是上述CAVLC熵編碼的逆過程,CAVLC熵解碼的輸入數據是來自片層數據的比特流,解碼的基本單位是一個4×4的像素塊,輸出為包含4×4塊每個像素點所有幅值的序列。CAVLC解碼步驟如下:
1. 初始化所有的系數幅值
2. 解碼非零系數個數(TotalCoeff)和拖尾系數個數(TrailingOnes)。
3. 解碼拖尾系數符號(trailing_ones_sign_flag)
4. 解碼非零系數幅值
5. 解碼total_zeros和run_before
6. 組合非零系數幅值和游程信息,得到整個殘差數據塊
?
CAVLC: Context-Adaptive Variable-Length Coding CAVLC模型選擇主要體現:非零系數編碼所需表格的選擇和拖尾系數后綴長度的更新; 編碼過程 2.編碼非零系數的數目(TotalCoeffs: 0-16)和拖尾系數數目(TrailingOnes: 0-3) 3.編碼每個拖尾系數的符號 4.編碼除了拖尾系數之外的非零系數的幅值Levels 5)更新suffixLength 5.編碼最后一個非零系數前零的數目TotalZeros 6.編碼每個非零系數前零的個數RunBefore
2.確定TotalCoeffs和TrailingOnes 3.根據TrailingOnes確定拖尾1的符號 4.解析除拖尾系數之外的非零系數的幅值(解碼Levels) 2)計算得到Level[i] 3)更新suffixLength 5.根據得到的TotalCoeff數值和TotalZeros編碼值得到TotalZeros數值 6.解析每個非零系數前零的數目(解碼RunBefore) 例子:假定用了Num-VLC0表 Reodered block: 編碼 Decoding: |
?
?
?
?
[轉貼] CAVLC編碼過程詳解——Sunrise
謹以此文獻給QQ群“H.264樂園”和群里那些無私奉獻的同行朋友!
也希望能對剛進入這個領域的朋友有所幫助,歡迎做過CAVLC的同行能批評指正!
編碼過程:
假設有一個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;
編碼完畢。
----------------------------------Sunrise------
[[i] 本帖最后由 firstime 于 2008-9-4 02:49 PM 編輯 [/i]]
請問斑竹,老畢書上120頁表6.10中第2行和第三行的NA和NB是不是給弄反了?
應該是弄反了
請問trailing ones是指所有絕對值為1的系數的個數還是連續絕對值為1的系數的個數。
謝謝。
倒數三個 +/-1
另:可結合本論壇帖子“[url=http://bbs.chinavideo.org/viewthread.php?tid=1057][color=blue][b]CAVLC中的前綴和后綴[/b][/color][/url]”學習。
[[i] 本帖最后由 firstime 于 2008-5-20 09:59 PM 編輯 [/i]]
“如果Level[ i ]是負的,levelCode = - (Level[ i ]<<1) – 1”
假如Level[ i ]=-3,levelCode值是多少啊?
還有能不能詳細講解一下如何確定suffixLength的取值,它跟域值的關系怎么確定?
謝謝!
[[i] 本帖最后由 firstime 于 2007-1-27 10:06 PM 編輯 [/i]]
討論
是JM86運行后的trace記錄
@160? ?Luma # c & tr.1s(0,0) vlc=0 #c=11 #t1=1? ?? ?? ?000000000001110 ( 11)
@175? ?Luma trailing ones sign (0,0)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?0 (??0)
@176? ?Luma lev (0,0) k=9 vlc=1 lev= -2? ?? ?? ?? ?? ?? ?? ?? ?? ???11 ( -1)
@178? ?Luma lev (0,0) k=8 vlc=1 lev= -1? ?? ?? ?? ?? ?? ?? ?? ?? ???11 ( -1)
@180? ?Luma lev (0,0) k=7 vlc=1 lev=??1? ?? ?? ?? ?? ?? ?? ?? ?? ???10 (??1)
@182? ?Luma lev (0,0) k=6 vlc=1 lev= -5? ?? ?? ?? ?? ?? ?? ?? ? 000011 ( -5)
@188? ?Luma lev (0,0) k=5 vlc=2 lev=-11? ?? ?? ?? ?? ?? ?? ???00000101 (-11)
@196? ?Luma lev (0,0) k=4 vlc=3 lev= -3? ?? ?? ?? ?? ?? ?? ?? ?? ?1101 ( -3)
@200? ?Luma lev (0,0) k=3 vlc=3 lev=??3? ?? ?? ?? ?? ?? ?? ?? ?? ?1100 (??3)
@204? ?Luma lev (0,0) k=2 vlc=3 lev=??3? ?? ?? ?? ?? ?? ?? ?? ?? ?1100 (??3)
@208? ?Luma lev (0,0) k=1 vlc=3 lev=-12? ?? ?? ?? ?? ?? ?? ?? ? 001111 (-12)
@214? ?Luma lev (0,0) k=0 vlc=3 lev=??9? ?? ?? ?? ?? ?? ?? ?? ? 001000 (??9)
上面這段是trace.txt中的記錄,根據前面的vlc=0 #c=11 #t1=1,就是trailing_ones 的個數是1個(@175? ?Luma trailing ones sign (0,0)? ?? ???0 (??0) )也能說明,但是在下面的level中,明明還要-1,1可以作為trailing_ones的,為什么不把這兩個數當作trailing_ones呢??而是作為level呢????
回答
接上面的問題,在群里面討論弄明白了
在CAVLC編碼中,從右往左看,算trailing_ones時,在右邊不能有abs()>1的數,還有算trailing_ones的個數的話,也不能被別的abs()>1的數隔斷,如果隔斷的話,只能計數到隔斷數為止,而且要保證個數<=3。例如。。。。2,3,0,0,0,1,1,1,0,0,2 ,這個序列中triailing_ones是沒有的。還有。。。。。1,0,0,-1,3,1,0,0,0,0,算trailing_ones 個數時,只能有一個也就是3后面的“1”算一個,3前面的-1和1由于被3隔斷,所以不能算入其中。
[[i] 本帖最后由 dcfarmer 于 2007-6-7 03:27 PM 編輯 [/i]]
ZerosLeft =1, run_before = 1? ?? ?run_before[0]不需要碼流來表示
請問:為什么不需要碼流來表示?
是因為是最后一位嗎?
查表知:此時 run_before[0]=0
回復 #6 achen 的帖子
Level[ i ]=-3,levelCode值是多少啊?
levelcode應該是3
[size=12px]ZerosLeft =1, run_before = 1? ?? ?run_before[0]不需要碼流來表示
請問:為什么不需要碼流來表示?
是因為是最后一位嗎?
查表知:此時 run_before[0]=0[/size]
[size=12px] [/size]
[size=12px]---------------------------------------------------------[/size]
[size=12px] [/size]
[size=12px]I think it's because can know the vaule based on the value before. :)[/size]
2007-1-28 11:22 AM dcfarmer
討論
是JM86運行后的trace記錄
@160? ?Luma # c & tr.1s(0,0) vlc=0 #c=11 #t1=1? ?? ?? ?000000000001110 ( 11)
@175? ?Luma trailing ones sign (0,0)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?0 (??0)
@176? ?Luma lev (0,0) k=9 vlc=1 lev= -2? ?? ?? ?? ?? ?? ?? ?? ?? ???11 ( -1)
@178? ?Luma lev (0,0) k=8 vlc=1 lev= -1? ?? ?? ?? ?? ?? ?? ?? ?? ???11 ( -1)
@180? ?Luma lev (0,0) k=7 vlc=1 lev=??1? ?? ?? ?? ?? ?? ?? ?? ?? ???10 (??1)
@182? ?Luma lev (0,0) k=6 vlc=1 lev= -5? ?? ?? ?? ?? ?? ?? ?? ? 000011 ( -5)
@188? ?Luma lev (0,0) k=5 vlc=2 lev=-11? ?? ?? ?? ?? ?? ?? ???00000101 (-11)
@196? ?Luma lev (0,0) k=4 vlc=3 lev= -3? ?? ?? ?? ?? ?? ?? ?? ?? ?1101 ( -3)
@200? ?Luma lev (0,0) k=3 vlc=3 lev=??3? ?? ?? ?? ?? ?? ?? ?? ?? ?1100 (??3)
@204? ?Luma lev (0,0) k=2 vlc=3 lev=??3? ?? ?? ?? ?? ?? ?? ?? ?? ?1100 (??3)
@208? ?Luma lev (0,0) k=1 vlc=3 lev=-12? ?? ?? ?? ?? ?? ?? ?? ? 001111 (-12)
@214? ?Luma lev (0,0) k=0 vlc=3 lev=??9? ?? ?? ?? ?? ?? ?? ?? ? 001000 (??9)
請問上面這段TRACE記錄對應的16個系數序列是什么?謝謝
好貼...
回復 #10 timek 的帖子
levelcode應該是5,level先乘2為-6,再取反減1
解碼時因為levelcode為奇數,level = (‐levelCode‐1)/2
剛學習,受用了。謝謝
畢厚杰P123,6.8.6節中所給例子是否有誤?是否應如下編碼?
0? ?? ???0? ?? ???-1? ?? ???0
5? ?? ???2? ?? ???0? ?? ???0
3? ?? ???0? ?? ???0? ?? ???0
1? ?? ???0? ?? ???0? ?? ???0? ?? ???
數據重排:0,0,5,3,2,-1,0,0,0,1……
其中TotalCoeffs = 5, TrailingOnes = 2, Total_zeros = 5, NC = 3
編碼過程:
元素? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?數值? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?編碼
Coeff_token? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???TotalCoeffs = 5, TrailingOnes = 2? ?? ?? ?? ?? ?0000101
Trailingones_sign_flag(1)? ?? ?? ?? ?? ???+? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?0
Tranlingones_sign_flag(0)? ?? ?? ?? ?? ? -? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? 1
Level(2)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???1 (suffixLenth = 0)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? 1
Level(1)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???3 (suffixLength = 1)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???0010
Level(0)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???5 (suffixLength = 1)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???000010
Total_zeros? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ???5? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? 101
Run_before(4)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Zeroleft = 5, run_before = 3? ?? ?? ?? ?? ?? ?? ?? ???010
Run_before(4)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Zeroleft = 2, run_before = 0? ?? ?? ?? ?? ?? ?? ?? ???1
Run_before(4)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Zeroleft = 2, run_before = 0? ?? ?? ?? ?? ?? ?? ?? ???1
Run_before(4)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Zeroleft = 2, run_before = 0? ?? ?? ?? ?? ?? ?? ?? ???1
Run_before(4)? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?Zeroleft = 2, run_before = 2? ?? ?? ?? ?? ?? ?? ?? ?? ?? ? 無
最終編碼輸出:000010110010000010101010111
[[i] 本帖最后由 peiyangpr 于 2009-1-4 09:16 PM 編輯 [/i]]
?
residual_block_cavlc( coeffLevel, maxNumCoeff ) {? C????? Descriptor
??? for( i = 0; i < maxNumCoeff; i++ )??????????
??????? coeffLevel[ i ] = 0?????
??? // coeff_token????? 指明了非零系數的個數,拖尾系數的個數。??????
??? coeff_token?
??? if( TotalCoeff( coeff_token ) > 0 ) {??????????
??????? if( TotalCoeff( coeff_token ) > 10??? &&??? TrailingOnes( coeff_token ) <
3 )
??????????? suffixLength = 1??????????
??????? else??????????
??????????? suffixLength = 0??????????
??????? for( i = 0; i < TotalCoeff( coeff_token ); i++ )??????????
??????????? if( i < TrailingOnes( coeff_token ) ) {???????????
??????????????? // trailing_ones_sign_flag? 拖尾系數的符號
??????????????????? -???? 如果trailing_ones_sign_flag = 0,? 相應的拖尾系數是+1。
??????????????????? -???? 否則,trailing_ones_sign_flag =1,相應的拖尾系數是-1。?
??????????????? trailing_ones_sign_flag??
??????????????? level[ i ] = 1 – 2 * trailing_ones_sign_flag??????????
??????????? } else {??????????
??????????????? // level_prefix and level_suffix? 非零系數值的前綴和后綴。?
??????????????? level_prefix?
??????????????? levelCode = ( level_prefix << suffixLength )??????????
??????????????? if( suffixLength > 0??? | |??? level_prefix >= 14 ) {??????????
??????????????????? level_suffix??
??????????????????? levelCode += level_suffix??????????
??????????????? }??????????
??????????????? if( level_prefix??? = =??? 15??? &&??? suffixLength??? = =??? 0 )??????????
??????????????????? levelCode += 15??????????
??????????????? if( i??? = =??? TrailingOnes( coeff_token )??? &&????
????????????????????? TrailingOnes( coeff_token ) < 3 )
??????????????????? levelCode += 2??????????
??????????????? if( levelCode % 2??? = =??? 0 )??????????
??????????????????? level[ i ] = ( levelCode + 2 ) >> 1??????????
??????????????? else??????????
??????????????????? level[ i ] = ( –levelCode – 1 ) >> 1??????????
??????????????? if( suffixLength??? = =??? 0 )??????????
??????????????????? suffixLength = 1??????????
??????????????? if( Abs( level[ i ] )??? >??? ( 3 << ( suffixLength – 1 ) )??? &&????
????????????????????? suffixLength < 6 )
??????????????????? suffixLength++??????????
??????????? }??????????
??????? if( TotalCoeff( coeff_token ) < maxNumCoeff ) {??????????
??????????? // total_zeros??? 系數中 0 的總個數。
??????????? total_zeros???
??????????? zerosLeft = total_zeros??????????
??????? } else??????????
??????????? zerosLeft = 0??????????
??????? for( i = 0; i < TotalCoeff( coeff_token ) – 1; i++ ) {??????????
??????????? if( zerosLeft > 0 ) {??????????
???????????????
??????????????? run_before???
??????????????? run[ i ] = run_before??????????
??????????? } else??????????
??????????????? run[ i ] = 0??????????
??????????? zerosLeft = zerosLeft – run[ i ]??????????
??????? }??????????
??????? run[ TotalCoeff( coeff_token ) – 1 ] = zerosLeft??????????
??????? coeffNum = -1??????????
??????? for( i = TotalCoeff( coeff_token ) – 1; i >= 0; i-- ) {??????????
??????????? coeffNum += run[ i ] + 1??????????
??????????? coeffLevel[ coeffNum ] = level[ i ]????????????
??????? }??????????
??? }??????????
}
?
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/xfding/archive/2010/04/12/5477464.aspx