h264-sps解析&Exp-golomb編解碼

理論

熵編碼

熵編碼是一種無損編碼,按照熵原理不丟失任何信息的編碼。

常見的熵編碼有:香濃(Shannon)編碼、哈夫曼(Huffman)編碼、算術(arithmetic)編碼、指數哥倫布(exponential Golomb)編碼、基於上下文的自適應變長編碼(CAVLC:Context-based Adaptive Variable Length Coding )、基於上下文的自適應二進制算術編碼(CABAC:Context-based Adaptive Binary Arithmetic Coding )。

在H264中,主要使用三種編碼方式,exp-golomb、CAVLC、CABAC。

因爲在項目中,需要解析sps,而sps RBSP語法元素主要用到了0階exp-golomb,下面介紹0階exp-golomb。

指數哥倫布編碼

指數哥倫布碼(Exponential-Golomb coding)是一種無損數據壓縮方法。

Exp-golomb編碼規則(文字描述版本)

說明:

codenum 表示 待編碼的數 x;

codeword 表示 編碼後的數;codeword的構成=[prefix][suffix]

prefix 也叫做 leadingzerobits; 二進制數

suffix 也是二進制數

編碼步驟

  1. codenum+1 並將其值寫成二進制形式,用suffix表示;
  2. 數suffix的位數,用M表示;
  3. prefix 由M-1個0組成;

以codenum=5爲例,

  1. codenum+1=6,即suffix = 0b110;
  2. prefix = 0b00;
  3. codeword = 0b00110;

我們知道,在計算機中,以字節作爲最小存儲單位(字節對齊),而字節由8個bit組成。10進制數5在計算機中的存儲爲0b00000101,可以看出實際的有效位數只有3位,另外的5位沒有用,但還是佔用了5個bit的存儲空間。所以爲了更高效地利用物理存儲空間,工程師們就想,有沒有什麼方式既能正確的表示數據又能更省存儲空間呢?那就需要設計某種“規則”,使用這種“規則”重新表示數據。而這種“規則”用專業術語表達就叫做編碼。
前面提到的指數哥倫布編碼就是萬千編碼方式中的一種,通過exp-golomb coding,將0b00000101壓縮成了0b00110,從8位壓縮到了5位,節省了3位。

從上面講解Exp-golomb編碼規則中,並沒有看到和指數相關的東西。那爲什麼這玩意叫指數哥倫布編碼呢?

其實,上面講解的編碼規則是一種特殊情況(指數k=0)。k階指數哥倫布編碼的一般規則是

  1. x+2k2^k-1 使用 0階指數哥倫布編碼;
  2. 數suffix的位數,用M表示;
  3. prefix 由M-1個0組成;

以codenum=5, k=1爲例,

  1. 5+211=65+2^1-1=6,6的0階指數哥倫布編碼爲00111;
  2. 刪除 1 個前導 0;
  3. codeword 爲 0b0111;
    k階指數哥倫布表

Elias gamma coding

Elias γ code or Elias gamma code is a universal code encoding positive integers developed by Peter Elias.[1]:197, 199 It is used most commonly when coding integers whose upper-bound cannot be determined beforehand.

elias gamma coding 使用 2log2x+12\lfloor log_2^{x}\rfloor + 1個bit來編碼表示數值。例如,數字5 使用 5個bit來表示;數字10使用7個bit來表示。

在這裏插入圖片描述

編碼規則

​ x 爲 待編碼數

  1. 找N,N爲x的2的指數的最大冪次;N=floor(log2x)N=floor(log_2^{x}),即$2^N\le x < 2^{N+1} $;
  2. N個前導0 bits;
  3. 接着將x表示成2進制;
  4. 將#2和#3的二進制數組合 即爲編碼後的數;

以x=5爲例:

  1. N = 2;x=22+1x = 2^2+1
  2. 2個前導0,00;
  3. x = 0b101
  4. codeword = 0b00101

實踐

sps的數據語法格式如下
sps1

sps2

從sps的語法中可以看到,主要使用了4種描述子,u(1),u(n),ue(v),se(v)。

接下來,分別介紹這四種描述子及其代碼實現。

在h264標準中,有一個讀取比特流的語法函數,read_bits(n)

read_bits( n ) reads the next n bits from the bitstream and advances the bitstream pointer by n bit positions. When n is
equal to 0, read_bits( n ) is specified to return a value equal to 0 and to not advance the bitstream pointer

read_bits的作用就是 從當前比特流位置開始,讀取n個比特,同時比特流指針向前移動n位。如果n爲0,read_bits返回0,且比特流指針不移動。

Syntax elements coded as ue(v), me(v), or se(v) are Exp-Golomb-coded. Syntax elements coded as te(v) are truncated ExpGolomb-coded. The parsing process for these syntax elements begins with reading the bits starting at the current location in the bitstream up to and including the first non-zero bit, and counting the number of leading bits that are equal to 0.

This process is specified as follows:
leadingZeroBits = -1
for( b = 0; !b; leadingZeroBits++ )
b = read_bits( 1 )

在h264的語法元素中,ue(v),me(v),se(v)都是使用指數哥倫布編碼;te(v)使用截斷指數哥倫布編碼。解碼過程爲 從當前比特流位置開始讀,直到遇到第一個非0bit位,即1位,然後計算前導0的個數N(注意:比特流的指針移動到了第一個非0bit的下一位);接着再向後讀取N個bit並得到這個N個bit對應的數值;再按照公式codeNum=2leadingZeroBits1+read_bits(leadingZeroBits)codeNum=2^{leadingZeroBits}-1+read\_bits(leadingZeroBits)解出原數值。

例如,5的exp-golomb coded number是 00110,第一個比特值1的前面有2個前導0,即leadingZeroBits=2;接着,第一個比特值1後的兩個比特值爲10,也就是10進制的2;所以codeNum=221+2=5codeNum = 2^2-1+2=5 ,這樣就解出原數值5了。

從table9-1可以看出,"prefix"即是leadingZeroBits對應的前導0個數,"suffix"即是codeNum對應的比特值,由xix_i表示,i的範圍是[0, leadingZeroBits-1],xix_i可以是0也可以是1。

bit_string_prefix_suffix

u(1)

u(1)就相當於 read_bits(1)。它的值是0或1。

bcxt_read_u1

u(n)

unsigned integer using n bits. When n is “v” in the syntax table, the number of bits varies in a manner
dependent on the value of other syntax elements. The parsing process for this descriptor is specified by the return
value of the function read_bits( n ) interpreted as a binary representation of an unsigned integer with most
significant bit written first.

u(n) 就相當於 read_bits(n)。u(n)的返回值是n個bit對應的正整數。注意:most significant bit written first

bcxt_read_u

ue(v)

unsigned integer Exp-Golomb-coded syntax element with the left bit first. The parsing process for this
descriptor is specified in clause 9.1

ue(v)是使用0階指數哥倫布編碼的值,所以解析sps相應的語法元素時,要使用0階指數哥倫布對應的解碼規則進行解碼。ue(v)的實現原理即是前面提到的codeNum=2leadingZeroBits1+read_bits(leadingZeroBits)codeNum=2^{leadingZeroBits}-1+read\_bits(leadingZeroBits)。ue(v)的值即是codeNum。

在這裏插入圖片描述
在這裏插入圖片描述

se(v)

se(v)的值 就是 在ue(v)的值的基礎上,按照(1)k+1Ceil(k/2),k=ue(v)(-1)^{k+1}Ceil(k/2),k=ue(v)計算得到。

更直觀點的描述就是,se(v)對應的語法元素的值 ,從1開始,每相鄰的兩個數爲一對,低序號的值爲正數,高序號的值爲負數,依次升序排列,如下表所示。

se

bcxt_read_se

reference:

https://en.wikipedia.org/wiki/Exponential-Golomb_coding

ITU-T H.264 (V12) 2017-04-13

https://baike.baidu.com/item/%E7%86%B5%E7%BC%96%E7%A0%81/3303605

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章