正所謂工欲善其事,必先利其器;我們下面要解析vps,sps,pps,少不了的會有兩點:1、對照spec看語法元素;2根據描述解析語法元素;那么這里我要總結的是,如何解析這些語法元素;因為vps,sps,pps的信息,單獨看每個有啥含義,在這里看是沒有太多用處的;目前我們只能說了解個大概;因為這些信息是為了后面的解碼服務的;所以這里我們要看具體是怎么解析的;
首先這里我要粘貼一下書上的描述子的描述(這里有點繞。。。但是沒錯):
那么這里面就出現了幾個概念需要理解:
1、基于上下文的自適應的二元算數編碼:ae(v)這里指的是可以理解為對于265就是cabac編碼
2、其他的就是哥倫布編碼以及其他等等;
所以,這節最主要的還是要看熵編碼這一塊的知識,就知道如何進行熵解碼
一、
首先我們應該先看看普通的變長編碼(非定長的,VLC,看一下首字母就知道怎么回事了)是怎么編碼的;來引出我們的概念:
常見的就是哈夫曼編碼,說道哈夫曼編碼,其實在這里了解一下即可;說道哈夫曼編碼就離不開哈夫曼樹,直接舉例,會比較好理解一些:
假設ABCD,加權是0.2,0.3,0.1,0.4,那么我們怎么畫哈夫曼樹呢;首先我們找最小的兩個;也就是A,C。
小概率的放到左邊,大概率的放到右邊,那么就會合成一個E,E就是0.3,然后E再和B對比,然后組成F,F是0.6,然后再和D對比那么D放到左邊,F放到右邊,所以就會有下圖:
畫的太丑了,但是很明顯就是編碼后,A是111,C是110,B是10,D是0,所以比較簡單;
舉例如果是ACBA,那么編碼出來的就是11111010111
二、
上面是代表的是變長編碼;但是算數編碼是不一樣的;變長編碼,如哈夫曼編碼,那么會是要對每個碼字都要進行率先給一個碼字;如A是111,C是110,那么每個字符,至少也得分配一個碼字;但是算數編碼不是的;他是要對整個碼率進行編碼;這就出現了概率空間的概念了舉個例子,比如AA,我可能用1一個bit就代替了,那么如果使用邊長編碼的話,那么就會出現1111116個bit,這樣是不是感覺算數編碼很節???
上面說了這么多,其實沒啥用,如果不舉例,其實什么都看不懂;我們還是按照上面的概率,上面ACBA舉例;那么如果是算數編碼,那么應該是怎么樣的呢?
如下圖:
1、首先我們說,第一個碼字是A,那么就是落在的概率區間就是[0,0.2]
2、然后第二個碼字是C,那么C是在A的基礎之上的,所以C落在[0.1~0.12],C過后,概率區間只有0.02大小了
3、然后是B,那么B是在0.02x0.2以后,所以結合前面就是0.104~0.11之間;此時,概率區間只有0.006大小了
4、最后是A,那么A又是從0開始的,所以輸出的碼率下限就是0.104,那么我們輸出0.104,就能代表是ACBA這個碼字了
我們整理為公式的話輸出的就是0+0.2x0.5+0.2x0.1x0.2 = 0.104
那比如如果我們現在有了一個小數,能否解碼出來呢?答案是必須且唯一的;要不學習算數編碼,無法解碼有什么用呢?
假設是一個0.105,那么0.105在0~0.2之間,也就是說第一個是A
然后我們現在看編碼的這個公式0+0.2x0.5+0.2x0.1x0.2 = 0.104
說明什么呢?說明下一步主要看第二加的內容區間。所以為(0.105-0)/0.2 = 0.525,是C
以此類推,(0.525-0.5)/0.1 = 0.25,是B
(0.25-0.2)/0.3是0.166,是A
也就是最終為ACBA;
那么我們上面編碼不是0.104嘛,為啥0.105也是ACBA呢?
因為ACBA最后一個是落在0.006x0.2 = 0.0012也就是說,在0.104~0.1052之間的任意數都是0可以的;
三、
下面要看一下哥倫布指數編碼;哥倫布指數編碼,屬于變長編碼的范疇;那么我們從上面可以看出我們學習了變長編碼,算數編碼;為什么,我們要回過頭來,看哥倫布指數編碼呢?
首先,我們要看哥倫布指數編碼在265中的作用:
1、slice以上大多會用到哥倫布指數編碼(sps,vps,pps,ue(v),se(v))
2、在slice層,有一個參數要用1階哥倫布指數編碼去二值化
這兩點是不是很暈?其實還好,我大體描述一下是什么意思:
對于那些sps,vps這些,我們需要哥倫布編碼的方式編碼;就是這些值用哥倫布指數編碼編成0101的碼字即可;
但是對于slice編碼的話,就像上面描述的;用變長編碼是不是用的碼字特別多?是不是需要用算數編碼?但是算數編碼需要三步:1、二值化;2、建立概率模型;3、算數編碼;此時,變長編碼。也就是1階哥倫布指數編碼就會用到了
但是這里我得說一句,一階哥倫布指數編碼去二值化,情況很少,大部分我們不用這種方式;slice層只有一個地方會用到;所以了解即可;
終于要進入正題了;就是如何進行哥倫布指數編碼:
首先要看一下,無符號0階哥倫布指數編碼:
這里我是在不想寫那么多了,但是我只是總結一下;其中,圖片中codenum指的是要編碼的語法元素;如果要進行哥倫布指數編碼,那么有兩部分組成:
1、前綴0,前綴0的話,計算就是M那個公式;
2、實際的碼字,就是codenum+1對應的二進制;
如果編程的話,沒有以2為底的函數的話,可以用兩個以10為底的log相除
是不是很簡單,下面還有表格,都是例子;
然后再看有符號的哥倫布指數編碼
其中V是指的要編碼的語法元素;是不是很巧妙?通過奇偶就能區分了正負;可以看出,正數都是變成了奇數后再去編碼,負數和0變成了偶數去編碼;
最后看一下1階哥倫布指數編碼,再強調一點,這個只是為了二值化,所以會用1階哥倫布指數編碼
這里貼了一段程序,如下:
代碼是不是很容易就可以看懂?
其中synval代表的是要編碼的語法元素;要首先求一個絕對值;然后定義個結束的標志位;然后k初始化為1,因為是1階哥倫布指數編碼;然后循環輸出0和1,然后輸出幾個0,或者幾個1,最終結束;
舉例14,按照上述的邏輯輸出為11100000,也就是224
講到這里,我們其實自適應的二元算數編碼還沒有接觸。但是起碼;sps這些你能解析了;因為他們大部分是哥倫布編碼;這節寫的有點多,所以后面再寫cabac