- 熵編碼回顧:利用信息的統(tǒng)一冗余來進行數據壓縮的無損編碼方法
熵編碼:
無損編碼:解碼后可無失真還原信源信息;
利用信源符號的概率特性(不同的信源符號概率不等),使編碼后的信息盡可能接近信源的熵;
常見熵編碼方法:
變長編碼:哈夫曼編碼、香農-費諾編碼泽西、指數哥倫布編碼;(已經實現的解析H264碼流結構中使用的大多數是定長編碼和指數哥倫布編碼)
算數編碼缰趋;
預測殘差數據必須要使用比指數哥倫布編碼壓縮效率更高的編碼方法CABAC( Context-based Adaptive Arithmatic Binary coding),CAVLC( Context-based Adaptive Variable Length Coding)
熵編碼的輸入為幀內幀間預測的殘差經過變換量化后的系數矩陣
對于一個4x4的矩陣捧杉,變換量化后通常呈現以下特性
大部分為0 ,不為0的只是少數部分
2.CAVLC
上下文自適應的變長編碼:
用于亮度和色度預測殘差的編碼秘血,以量化后的變換系數的形式味抖;
變換系數矩陣的特征:
稀疏:矩陣元素以0為主;
非零系數集中于低頻灰粮;
高頻部分的非零系數大部分為±1仔涩;
非零系數個數同相鄰塊有關;
CAVLC的上下文模型:
編碼非零系數的表格索引粘舟;
更新編碼非零系數時的后綴長度
CAVLC的輸入通常是4x4的系數矩陣熔脂,8x8用的較少,針對一整個像素塊的編碼
- CALVC的編碼過程
編碼需要的重要元素:
非零系數的個數(TotalCoeffs):取值范圍為[0, 16]柑肴,即當前系數矩陣中包括多少個非0值的元素霞揉;
拖尾系數的個數(TrailingOnes):取值范圍為[0, 3],表示最高頻的幾個值為±1的系數的個數晰骑。
拖尾系數的符號:以1 bit表示适秩,0表示+,1表示-硕舆;
當前塊值(numberCurrent):用于選擇編碼碼表秽荞,由上方和左側的相鄰塊的非零系數個數計算得到。普通非0系數的幅值(level):幅值的編碼分為prefix和suffix兩個部分進行編碼抚官。編碼過程按照反序編碼扬跋,即從最高頻率非零系數開始。(高頻到低頻反序來編碼)
最后一個非0系數之前的0的個數(TotalZeros);
每個非0系數之前0的個數(RunBefore):按照反序編碼耗式,即從最高頻非零系數開始胁住;對于最后一個非零系數(即最低頻的非零系數)前的0的個數趁猴,以及沒有剩余的0系數需要編碼時刊咳,不需要再繼續(xù)進行編碼彪见。
系數矩陣Z形掃描
CAVLC對一個固定大小的系數矩陣進行編碼,例如:
-
{
3, 2, -1, 0, 1, 0, 1, 0, -1, 0, 0, 0, 0, 0, 0, 0, }
掃描重排之后得到一維數組:[3, 2, 1, -1, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
4.編碼過程
確定當前塊值nC娱挨,選擇coeff_token的碼表余指;
根據非零系數個數TotalCoeffs和拖尾系數個數TrailingOnes,編碼coeff_token跷坝;
編碼拖尾系數的符號酵镜;(拖尾系數總共可能有0,1柴钻,2淮韭,3)個
編碼拖尾系數之外的普通非零系數;(從最高頻到最低頻反向編碼除了拖尾系數之外的普通的每一個非0系數,每一個普通非零系數都需要按照前綴和后綴兩部分來進行編碼)這一部分是整個編碼過程中相對麻煩的
編碼最末非零系數之前0的總個數贴届;
編碼每個非零系數之前的0的個數靠粪;(兩個特殊情況:a,所有的0都被編碼完成毫蚓,b,最低頻的非零系數前面所有的0都是不需要進行編碼的)
還是不清楚普通的非零系數是如何進行編碼實現的占键,level,前綴和后綴如何進行編碼元潘,以下通過實例寫代碼看看編碼后產生什么結果
如何求最后一個非零系數前面的零系數的個數畔乙?
掃描重排之后得到一維數組:[3, 2, 1, -1, 0, -1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0]
從后往前遍歷,得到最后一個不為零的非零系數的下標idx翩概,此處要求的是最后一個非零系數前面的零系數的個數:可以列出1個方程式
//coeff[idx]左邊的零系數的個數為totalZeros,coeff[idx]右邊的零系數的個數為16-idx-1,全部的零系數的個數=16-全部的非零系數的個數totalCoeffs
//16 - totalcoeffs = 16 - idx - 1 + totalZeros
=====> totalZeros = idx - totalCoeffs + 1;
編碼過程:
確定當前塊值nC牲距,選擇coeff_token的碼表;(在H264官方文檔的236頁,先編碼非零系數)
根據非零系數個數TotalCoeffs和拖尾系數個數TrailingOnes钥庇,編碼coeff_token牍鞠;
編碼拖尾系數的符號;
編碼拖尾系數之外的普通非零系數上沐;
編碼最末非零系數之前0的總個數皮服;
編碼每個非零系數之前的0的個數;
分為兩種情況参咙,totalCoeffs的值大于等于3或小于3龄广,值的大小為0-16
編碼前綴和后綴
前綴和codeword的關系在標準文檔Table 9-6 239頁
前綴:是幾后面就補多少個0
體現上下文自適應的閾值公式在標準文檔239頁
//為什么叫做上下文自適應的二進制編碼,除了coeffTokenMap蕴侧,此處會對后綴長度進行更新择同,體現了上下文的思想
//更新的原則是剛剛編碼的levels[idx]大于某一個閾值公式在標準文檔239頁,就suffixLength ++ 自增1
編碼TotalZeros
VlcIndex的值是TotalCoeff(非零系數的個數)
Let the variable tzVlcIndex be equal to TotalCoeff( coeff_token ).
編碼runBefore净宵,也是由協議中定義的表格Table9-10來實現的
矩陣編碼后的碼流輸出結果為
以上是CAVLC的編碼過程敲才,但是還未解決如何在H264碼流中使用CAVLC對系數矩陣進行解析裹纳,以及如何完整的解析一個宏塊
添加類Residual使CMacroblock類可以對殘差數據進行解析和保存
在碼流解析器中繼續(xù)依賴解析residual,官方文檔的76頁
使用CAVLC將一個4x4亮度塊變換矩陣從碼流中解析成原始yuv
色度塊、Intra16x16模式的解析
色度塊紧武、Intra16x16模式塊的解析思想類似4x4亮度塊:
- 依次解析numCoeff剃氧、trailingOnes、trailingSigns阻星、levels朋鞍、totalZeros、runBefore妥箕;
不同之處:
每個單元內系數數量最大值滥酥;
AC/DC是否分別解析;
nC值的計算方法畦幢;
不同分割模式的比較
不同顏色分量的比較
解析色度部分16x16,依據標準文檔236頁坎吻,nC=-1,nC=-1針對的不是4:2:0格式
DC模式