建議收藏 | H.265編碼原理入門
視頻編碼的目的是為了壓縮原始視頻,壓縮的主要思路是從空間、時間、編碼、視覺等幾個主要角度去除冗余信息。由于 H.264 出色的數(shù)據(jù)壓縮比率和視頻質(zhì)量,成為當(dāng)前市場上最為流行的編解碼標(biāo)準。而 H.265 是在 H.264 的基礎(chǔ)上,保證相同視頻質(zhì)量的同時,視頻流的碼率還可以減少50%。隨著H.265編碼格式越來越流行,本文將主要介紹 H.265 的編碼原理,以下是 H.265 的編碼框架流程圖。

01
編碼結(jié)構(gòu)
VCL:Video Coding Layer,主要包括視頻壓縮引擎和圖像分塊的語法定義,原始視頻在 VCL 層,被編碼成視頻數(shù)據(jù)。簡單版本的編碼過程如下:
將每一幀的圖像分塊,將塊信息添加到碼流中;
對單元塊進行預(yù)測編碼,幀內(nèi)預(yù)測生成殘差,幀間預(yù)測進行運動估計和運動補償;
對殘差進行變換,對變換系數(shù)進行量化、掃描。
對量化后的變換系數(shù)、運動信息、預(yù)測信息等進行熵編碼,形成壓縮的視頻碼流輸出。
NAL:Network Abstraction Layer,主要定義數(shù)據(jù)的封裝格式,把 VCL 產(chǎn)生的視頻數(shù)據(jù)封裝成一個個 NAL 單元的數(shù)據(jù)包,適配不同的網(wǎng)絡(luò)環(huán)境并傳輸。
02
分塊
從編碼順序和結(jié)構(gòu)上講,H.265首先將一個視頻劃分成若干個序列,一個序列劃分成若干個圖像組(GOP),每一個GOP代表一組連續(xù)的視頻幀。H.265 在對圖像做預(yù)測編碼和變換編碼時,會先對圖像進行劃分,劃分方式是四叉樹。在劃分四叉樹時,會將整個視頻幀劃分成若干個正方形的編碼樹塊(CTB),CTB 可以繼續(xù)劃分成編碼塊(CB),CB 還可以劃分為預(yù)測塊(PB)和變換塊(TB)。因此,H.265對視頻的結(jié)構(gòu)劃分如下圖所示:

同一位置處的一個亮度 CB 和兩個色度 CB ,加上一些相應(yīng)的語法元素,組成一個編碼單元(CU)。CU 是決定進行幀內(nèi)預(yù)測、幀間預(yù)測、Skip/Merge模式的單元。
同一位置處的一個亮度 CTB 和兩個色度 CTB ,加上一些相應(yīng)的語法元素,和包含的 CU ,組成一個編碼樹單元(CTU)。CTU 相當(dāng)于 H.264 中的宏塊,區(qū)別是 CTU 的尺寸是由編碼器制定,最大可以支持到 64x64,最小可以支持到 16x16。而宏塊的大小固定為 16x16。
一個 CTU 在進行編碼時,按照深度優(yōu)先的順序進行 CU 編碼,像數(shù)據(jù)結(jié)構(gòu)中的四叉樹一樣,一個大的方塊代表父節(jié)點,里面有四個小方塊分別代表四個子節(jié)點。

03
預(yù)測
視頻的本質(zhì)是由一系列連續(xù)的視頻幀組成,在單個視頻幀內(nèi)部和多個視頻幀之間都存在大量的冗余。從空間的角度看,單個視頻幀內(nèi)部的像素點之間的像素值相差很小。從時間的角度看,兩個連續(xù)的視頻幀之間也有很多相同的像素點。預(yù)測編碼就是基于圖像統(tǒng)計特性進行數(shù)據(jù)壓縮的一種方法,利用了圖像在時間和空間上的相關(guān)性,通過已經(jīng)重建的像素數(shù)據(jù)預(yù)測當(dāng)前正在編碼的像素。
3.1 幀內(nèi)預(yù)測
幀內(nèi)預(yù)測是指用于預(yù)測的像素和當(dāng)前正在編碼的像素都在同一個視頻幀內(nèi),并且一般都在鄰近的區(qū)域內(nèi)。由于鄰近的像素之間有很強的相關(guān)性,像素值一般都非常接近,發(fā)生突變的概率非常小,差值都是0或者非常小的數(shù)。所以,幀內(nèi)預(yù)測編碼后傳輸?shù)氖穷A(yù)測值和真實值之間的差值,即0附近的值,叫做預(yù)測誤差或殘差,這樣就用較少的比特傳輸,達到壓縮的效果。
H.265幀內(nèi)預(yù)測編碼以塊為單位,使用相鄰已經(jīng)重建的塊的重建值對正在編碼的塊進行預(yù)測。預(yù)測分量分為亮度和色度兩個,對應(yīng)的預(yù)測塊分別是亮度預(yù)測塊和色度預(yù)測塊。為了適應(yīng)高清視頻的內(nèi)容特征,提高預(yù)測精度,H.265采用了更加豐富的預(yù)測塊尺寸和預(yù)測模式。
H.265亮度預(yù)測塊的尺寸在4*4到32*32之間,所有尺寸的預(yù)測塊都有35種預(yù)測模式,這些預(yù)測模式可以分為3類:平面(Planar)模式、直流(DC)模式和角度(Angular)模式。
Planar模式:亮度模式0,適用于像素值變換緩慢的區(qū)域,例如像素漸變的場景。對預(yù)測塊中的每個像素都使用不同的預(yù)測值。預(yù)測值等于:該像素在水平和垂直兩個方向線性插值的平均值。
DC模式:亮度模式1,適用于圖像的大面積平坦區(qū)域,該模式對預(yù)測塊中的所有像素都使用相同的預(yù)測值。
如果預(yù)測塊是正方形,預(yù)測值等于左邊和上邊的參考像素的平均值;
如果預(yù)測塊是長方形,預(yù)測值等于長的那一邊的平均值;
角度模式:亮度模式2~34,總共33個預(yù)測方向,其中模式10是水平方向,模式26是垂直方向。角度模式每個像素的預(yù)測值都是從對應(yīng)預(yù)測方向前已經(jīng)重建的像素集的樣值進行水平或垂直方向偏移角度預(yù)測。

由于彩色視頻中,相同位置的色度信號和亮度信號的特征類似,因此色度預(yù)測塊和亮度預(yù)測塊的預(yù)測模式也類似。H.265中色度預(yù)測塊的預(yù)測模式有Planar模式、垂直模式、水平模式、DC模式和導(dǎo)出模式5種:
Planar模式:色度模式0,和亮度模式0一樣。
垂直模式:色度模式1,和亮度模式26一樣。
水平模式:色度模式2,和亮度模式10一樣。
DC模式:色度模式3,和亮度模式1一樣。
導(dǎo)出模式:色度模式4,采用和對應(yīng)亮度預(yù)測塊相同的預(yù)測模式。如果對應(yīng)的亮度預(yù)測塊模式是0、1、10、26中的一種,則替換為模式34。
3.2 幀間預(yù)測
幀間預(yù)測是指用于預(yù)測的像素和當(dāng)前正在編碼的像素不在同一個視頻幀內(nèi),但是一般在相鄰或附近的位置。一般情況下,幀間預(yù)測編碼的壓縮效果要比幀內(nèi)預(yù)測好,主要原因是視頻幀之間的相關(guān)性非常強。如果視頻幀中的運動物體變化速度很慢,那么視頻幀之間的像素差值也就很小,時間冗余度就非常大。
幀間預(yù)測評估運動物體運動狀況的方法是運動估計,它的主要思想就是對預(yù)測塊從參考幀的給定范圍中搜索匹配塊,計算匹配塊和預(yù)測塊之間的相對位移,該相對位移就是運動矢量。得到運動矢量后,需要對預(yù)測修正,也就是運動補償。將運動矢量輸入到運動補償模塊,"補償"參考幀,即可得到當(dāng)前編碼幀的預(yù)測幀。預(yù)測幀和當(dāng)前幀的差,就是幀間預(yù)測誤差。
如果幀間預(yù)測只用到了前一幀圖像,就稱為前向幀間預(yù)測或單向預(yù)測。該預(yù)測幀也就是P幀,P幀可以參考前面的I幀或者P幀。
如果幀間預(yù)測不僅用到了前一幀圖像預(yù)測當(dāng)前塊,還用到了后一幀圖像,那么就是雙向預(yù)測。該預(yù)測幀也就是B幀,B幀可以參考前面的I幀或P幀和后面的P幀。
由于P幀需要參考前面的I幀或P幀,而B幀需要參考前面I幀或P幀和后面的P幀,如果在一個視頻流中,先到了B幀,而依賴的I幀、P幀還沒有到,那么該B幀還不能立即解碼,那么應(yīng)該怎么保證播放順序呢?其實,在視頻編碼時,會生成PTS和DTS。通常情況下,編碼器在生成一個I幀后,會向后跳過幾個幀,用前面的I幀作為參考幀對P幀編碼,I幀和P幀之間的幀被編碼為B幀。推流的視頻幀順序在編碼的時候就已經(jīng)按照I幀、P幀、B幀的依賴順序編好了,收到數(shù)據(jù)后直接解碼即可。所以,不可能先收到B幀,再收到依賴的I幀和P幀。
PTS:Presentation Time Stamp,顯示時間戳,告訴播放器在什么時間顯示這一幀。
DTS:Decoding Time Stamp,解碼時間戳,告訴播放器在什么時間解碼這一幀。
04
變換
變換編碼是指將圖像中的空間域信號映射變換到頻域(頻率域),然后對生成的變換系數(shù)編碼。由于在空間域中,數(shù)據(jù)之間的相關(guān)性比較大,經(jīng)過預(yù)測編碼后的殘差變化較小,存在大量的數(shù)據(jù)冗余,在圖像中亮度值變化緩慢的平坦區(qū)域特別明顯。而變換為頻域后,會將空間域分散分布的殘差數(shù)據(jù)轉(zhuǎn)換成集中分布,可以降低相關(guān)性,減少數(shù)據(jù)冗余,從而達到去除空間冗余的目的。
在H.265中,一個編碼塊(CB)可以通過四叉樹劃分成若干個預(yù)測塊(PB)和變換塊(TB)。由于從 CB 到 TB 之間的四叉樹劃分主要是為了殘差的變換運算,因此這種四叉樹又稱為殘差四叉樹(RQT)。如下圖所示,就是一個 RQT 劃分實例,將一個 32*32 的殘差 CB 劃分成13個不同大小的 TB 。

每個 TB 的大小有四種,分別是從 4*4、8*8、16*16、32*32,每個 TB 都對應(yīng)一個整數(shù)變換系數(shù)矩陣。大尺寸的 TB 適用于圖像亮度值變化緩慢的平坦區(qū)域,小尺寸的 TB 適用于圖像亮度值變化劇烈的復(fù)雜區(qū)域。所有尺寸都可以使用離散余弦變換(DCT)變換。另外,對于 4*4 的幀內(nèi)預(yù)測亮度殘差塊,還可以使用離散正弦變換(DST)。
由于幀內(nèi)預(yù)測編碼是基于左邊和上邊已經(jīng)編碼塊的數(shù)據(jù),因此預(yù)測塊距離已編碼塊越近,相關(guān)性越強,預(yù)測誤差越??;距離已編碼塊越遠,相關(guān)性越小,預(yù)測誤差越大。預(yù)測誤差的這種數(shù)據(jù)分布特征和 DST 的正弦基函數(shù) sin 非常相似,起始點最小,然后逐漸變大。但是因為 DST 計算量比 DCT 大,需要增加更多的變換類型標(biāo)識,因此 DST 僅用于 4*4的幀內(nèi)預(yù)測亮度殘差塊。
05
量化
由于變換編碼只是將圖像數(shù)據(jù)從空間域矩陣轉(zhuǎn)換為頻域的變換系數(shù)矩陣,矩陣的系數(shù)個數(shù)和數(shù)據(jù)量都沒有減少。要想壓縮數(shù)據(jù),還需要對頻域中的統(tǒng)計特征進行量化和熵編碼。
常見的量化方法可以分為**標(biāo)量量化(SQ)和矢量量化(VQ)**兩類:
標(biāo)量量化:將圖像中的數(shù)據(jù)劃分成若干個區(qū)間,然后在每個區(qū)間用一個值代表這個區(qū)間內(nèi)所有樣點的取值。
矢量量化:將圖像中的數(shù)據(jù)劃分成若干個區(qū)間,然后在每個區(qū)間用一個代表矢量代表這個區(qū)間的所有矢量取值。
由于矢量量化引入了多個像素之間的關(guān)聯(lián),并且使用了概率的方法,一般壓縮率比標(biāo)量量化高。但是由于其計算復(fù)雜度高,所以目前廣泛使用的量化方法是標(biāo)量量化。
量化的壓縮率取決于劃分的區(qū)間大小,即量化步長。量化步長越大,表示量化越粗,對應(yīng)的視頻碼率越低,失真越大;量化步長越小,表示量化越細,對應(yīng)的視頻碼率越高,失真越小。
H.265量化時是以**變換單元(TU)為基本單位,處理對象包括 TU 中的亮度分量和色度分量。H.265采用了非線性標(biāo)量量化,通過量化參數(shù)(QP)**控制每個編碼塊的量化步長,QP 和量化步長的關(guān)系近似呈指數(shù)關(guān)系。QP 是個整數(shù),亮度分量的 QP 值范圍是 0~51,色度分量的亮度 QP 值范圍是0~45。QP 值在0~29范圍時,亮度分量和色度分量的量化步長相等,從QP=30開始,兩者開始產(chǎn)生差異。QP 和量化步長的關(guān)系如下圖所示:

編碼端的量化過程可以簡單理解為是每個 DCT 變換系數(shù)除以量化步長得到量化值。在解碼端對應(yīng)的反量化過程就是量化值乘以量化步長得到 DCT 變化系數(shù)值。
06
熵編碼
熵編碼是指在編碼過程中按熵原理不丟失任何信息的編碼。量化是一種有損的壓縮方式,而熵編碼是用更緊湊的方式標(biāo)記和原數(shù)據(jù)之間的映射關(guān)系,屬于無損壓縮。常見的熵編碼有香農(nóng)(Shannon)編碼、哈夫曼(Huffman)編碼、算術(shù)(Arithmetic)編碼、游程編碼等。
6.1 哈夫曼編碼
哈夫曼編碼是一種變長編碼,即不同字符的編碼長度是變化的。該編碼利用字符出現(xiàn)的概率構(gòu)造哈夫曼二叉樹,目標(biāo)是讓出現(xiàn)概率大的字符編碼時用短碼(距離根節(jié)點近),概率小的字符編碼時用長碼(距離根節(jié)點遠),從而讓平均碼字長度最短。
碼字:字符經(jīng)過哈夫曼編碼后得到的編碼。
例:字符A、B、C、D、E、F對應(yīng)的出現(xiàn)的概率分別是0.32、0.22、0.18、0.16、0.08、0.04。哈夫曼樹的構(gòu)造過程如下:
選擇概率最小的 E、F 作為葉子節(jié)點,計算 E、F 的概率和作為它們父節(jié)點;
將父節(jié)點的值與剩下的 A、B、C、D 概率值排序,再選擇最小的兩個樹求和;
重復(fù)以上過程;
最終構(gòu)造出來的哈夫曼二叉樹如下圖所示:

左節(jié)點的路徑為0,右節(jié)點的路徑為1,求得A、B、C、D、E、F的編碼結(jié)果:
字符 | A | B | C | D | E | F |
概率 | 0.32 | 0.22 | 0.18 | 0.16 | 0.08 | 0.04 |
碼字 | 11 | 01 | 00 | 101 | 1001 | 1000 |
碼字長度 | 2 | 2 | 2 | 3 | 4 | 4 |
平均碼字長度 = 0.32*2 + 0.22*2 + 0.18*2 + 0.16*3 + 0.08*4 + 0.04*4 = 2.4bit
6.2 算術(shù)編碼
雖然哈夫曼編碼在理論上可以獲得最佳編碼結(jié)果,但是在實際編碼中,由于計算機處理的最小數(shù)據(jù)單位是1bit,對于包含小數(shù)點的碼字長度只能按照整數(shù)處理,所以實際編碼效果往往略遜于理論編碼效果。在圖像壓縮領(lǐng)域,通常使用算術(shù)編碼代替哈夫曼編碼。不過,算術(shù)編碼的理論基礎(chǔ)和哈夫曼編碼是一致的,都是概率大的字符用短碼,概率小的字符用長碼。
算術(shù)編碼分為固定模式算術(shù)編碼、自適應(yīng)算術(shù)編碼(AAC)、二進制算術(shù)編碼、自適應(yīng)二進制算術(shù)編碼(CABAC)等,H.265 中使用了 CABAC 。此處將只介紹固定模式算術(shù)編碼流程:
統(tǒng)計輸入的符號序列中各個字符和出現(xiàn)的概率;
按照概率分布,將[0, 1)區(qū)間劃分成多個子區(qū)間,每個子區(qū)間代表一個字符,子區(qū)間的大小代表字符出現(xiàn)的概率;所有子區(qū)間大小的和等于1;假設(shè)該字符的區(qū)間范圍為 [L, H);
設(shè)置初始變量low=0, high=1,不斷讀取符號序列中的每個字符,找到該字符對應(yīng)的區(qū)間范圍 [L, H),更新low和high的值:
low = low + (high - low) * L
high = low + (high - low) * H
遍歷完符號序列后,得到最終的low和high,轉(zhuǎn)換二進制形式輸出得到編碼數(shù)據(jù);
例:輸入符號序列是 ADBCD,統(tǒng)計各個字符出現(xiàn)的概率:
字符 | 出現(xiàn)次數(shù) | 出現(xiàn)概率 | 概率區(qū)間 |
A | 1 | 0.2 | [0, 0.2) |
B | 1 | 0.2 | [0.2, 0.4) |
C | 1 | 0.2 | [0.4, 0.6) |
D | 2 | 0.4 | [0.6, 1) |
遍歷第一個字符 A 時,low = 0, high = 1, L = 0, H = 0.2
low = low + (high - low) * L = 0
high = low + (high - low) * H = 0.2
遍歷第二個字符 D 時,low = 0, high = 0.2, L = 0.6, H = 1
low = low + (high - low) * L = 0.12(注:此處計算的low不代入下面計算high值的公式中)
high = low + (high - low) * H = 0.2
遍歷第三個字符 B 時,low = 0.12,high = 0.2,L = 0.2,H = 0.4
low = low + (high - low) * L = 0.136
high = low + (high - low) * H = 0.152
遍歷第四個字符 C 時,low = 0.136,high = 0.152,L = 0.4,H = 0.6
low = low + (high - low) * L = 0.1424
high = low + (high - low) * H = 0.1456
遍歷第五個字符D時,low = 0.1424,high = 0.1456,L = 0.6,H = 1
low = low + (high - low) * L = 0.14432
high = low + (high - low) * H = 0.1456
得到最后的[low, high)區(qū)間是[0.14432, 0.1456),在這個區(qū)間內(nèi)取任意值轉(zhuǎn)二進制后都是對 "ADBCD"的算術(shù)編碼。對應(yīng)的編碼流程可以簡化到下面這張圖中:

07
環(huán)路濾波
由于 H.265 采用分塊編碼,在圖像反量化、反變換重建的時候,會存在一些失真效應(yīng),例如塊效應(yīng)、振鈴效應(yīng)。為了解決這些問題,H.265 采用了環(huán)路濾波技術(shù),其中包括去方塊濾波(DBF)和樣點自適應(yīng)補償(SAO)。
DBF 作用于邊界像素,用于解決塊效應(yīng)。塊效應(yīng)是指一些相鄰編碼塊邊界處的灰度值存在明顯的不連續(xù)性,產(chǎn)生塊效應(yīng)主要有兩個原因:
編碼器對殘差的DCT變換和量化是基于塊的,忽略了塊與塊之間的相關(guān)性,導(dǎo)致塊之間的處理不一致;
幀間預(yù)測運動補償塊的不完全匹配,存在誤差;而編碼時的預(yù)測參考幀通常來自這些重建圖像,導(dǎo)致待預(yù)測圖像失真;
DBF 針對邊界類型采用強濾波、弱濾波或者不處理,邊界類型的判定是由邊界像素梯度閾值和邊界塊的量化參數(shù)決定的。DBF 處理時,先對整個圖像的垂直邊緣進行水平濾波,然后對水平邊緣進行垂直濾波。濾波過程實際上就是對像素值進行修正的過程,讓方塊看起來不那么明顯。H.264 中也存在 DBF 技術(shù),但是應(yīng)用于 4*4 大小的處理塊,而 H.265 中應(yīng)用于 8*8 大小的處理塊。
SAO 是 H.265 新引入的對重建圖像的誤差補償機制,用于改善振鈴效應(yīng)。振鈴效應(yīng)是指圖像的灰度值劇烈變化產(chǎn)生的震蕩,產(chǎn)生振鈴效應(yīng)主要原因是DCT變換后高頻信息丟失。SAO 的原理就是通過對重構(gòu)曲線的波峰像素添加負值補償,波谷添加正值補償,從而減小高頻信息的失真。和 DBF 只作用于邊界像素不同,SAO 作用于塊中所有的像素。
08
小結(jié)
本文從 H.265 整體編碼流程的角度,介紹了 H.265 編碼涉及到的分塊、預(yù)測、變換、量化、編碼、環(huán)路濾波等技術(shù)點。通過了解這些編碼原理,為我們后續(xù)進一步學(xué)習(xí)音視頻開發(fā)技術(shù)奠定扎實的基礎(chǔ)。
最后歡迎大家加入 音視頻開發(fā)進階 知識星球 ,這里有知識干貨、編程答疑、開發(fā)教程,還有很多精彩分享。
更多內(nèi)容可以在星球菜單中找到,隨著時間推移,干貨也會越來越多?。?!

給出 10元 優(yōu)惠券,漲價在即,目前還是白菜價,基本上提幾個問題就回本,投資自己就是最好的投資!??!

加我微信 ezglumes ,拉你進技術(shù)交流群
推薦閱讀:
開通專輯 | 細數(shù)那些年寫過的技術(shù)文章專輯
Android NDK 免費視頻在線學(xué)習(xí)?。?!
覺得不錯,點個在看唄~

