H264編碼總結

在目前,無論在各個行只要和視頻相關的,我們都可以看見H264相關的身影,H264作爲目前使用最廣泛的視頻壓縮標準,隨着 x264/openh264以及ffmpeg等開源庫的推出,大多數使用者無需再對H264的細節做過多的研究。但是,爲了在別的開發者面前更好的裝逼,有必要了解一下H264的基本原理和一些常見的概念。
那麼H264有多厲害?

H.264: H.264/AVC項目的目的是爲了創建一個比以前的視頻壓縮標準,在更低的比特率的情況下依然能夠提供良好視頻質量的標準(如,一半或者更少於MPEG-2,H.263,或者MPEG-4 Part2 )。同時,還要不會太大的增加設計的複雜性。
優勢:
1)網絡親和性,即可適用於各種傳輸網絡
2)高的視頻壓縮比,當初提出的指標是比 H.263,MPEG-4,約爲它們的 2 倍,現在都已基 實現;

沒看出H264多厲害?那麼我們來算個數,就拿直播來說,目前作爲國內最多美女的優秀直播APP喵播,如何做到實時傳輸視頻而不卡頓?很大一方面是因爲視頻得高壓縮處理,而這個高壓縮處理就是基於H264來的。大家都知道視頻就是在播連環畫,在一秒內翻過 24 張以上的圖片,就感覺圖像是連續的了,這就是視頻的原理。但是大家有沒有想過,一張圖片有多大呢?我們的屏幕分辨率按 1280 * 720 算的話,一秒鐘的視頻大概就 2.64 MB 了。這麼算,放在以前,大夥省喫儉用去網吧,偷偷摸摸下個xxx電影,發現3分鐘就上百兆,那不是欲哭無淚啊。所以我們要進行壓縮,而 H.264 不僅壓縮比比較高,對網絡的兼容性也非常好,所以大多數人做直播也就選擇了 H.264 作爲編碼格式了。

以下,我就要按照我個人對H264的理解,參考網上大神的文章總結出來的。分別從H264編碼流程中一步一步的講解。
總共分5個部分:

幀間和幀內預測(Estimation)
變換(Transform)和反變換
量化(Quantization)和反量化
環路濾波(Loop Filter)
熵編碼(Entropy Coding)
看名詞是不是很難理解,很高端?沒錯,就是這麼高端,很難理解的。

H264基本結構
H.264 原始碼流(又稱爲裸流),是有一個接一個的 NALU 組成的,而它的功能分爲兩層:視頻編碼層(VCL, Video Coding Layer)和網絡提取層(NAL, Network Abstraction Layer),其中,前者負責有效表示視頻數據的內容,而後者則負責格式化數據並提供頭信息,以保證數據適合各種信道和存儲介質上的傳輸。因此我們平時的每幀數據就是一個NAL單元(SPS與PPS除外)。

在這裏插入圖片描述
圖1.png
在這裏插入圖片描述
RBS.jpg
VCL 數據即編碼處理的輸出,它表示被壓縮編碼後的視頻數據 序列。在 VCL 數據傳輸或存儲之前,這些編碼的 VCL 數據,先被映射或封裝進 NAL 單元(以下簡稱 NALU,Nal Unit) 中。每個 NALU 包括一個原始字節序列負荷(RBSP, Raw Byte Sequence Payload)、一組 對應於視頻編碼的 NALU 頭部信息。RBSP 的基本結構是:在原始編碼數據的後面填加了結尾 比特。一個 bit“1”若干比特“0”,以便字節對齊。

上圖中的 NALU頭 + RBSP 就相當與一個 NALU (Nal Unit), 每個單元都按獨立的 NALU 傳送。說到最後H264的基本結構就是NALU。下面具體分析一下這個東西,它和我們壓縮有着密切聯繫。

NALU的由來
一幀圖片經過 H.264 編碼器之後,就被編碼爲一個或多個片(slice),而裝載着這些片(slice)的載體,就是 NALU 了,我們可以來看看 NALU 跟片的關係(slice)。

在這裏插入圖片描述
圖2.png

幀(frame)是用作描述一張圖片的,一幀(frame)對應一張圖片,而片(slice),是 H.264 中提出的新概念,是通過編碼圖片後切分通過高效的方式整合出來的概念,一張圖片至少有一個或多個片(slice)。

什麼是切片
在這裏插入圖片描述
圖3.png

上圖中可以看出,片(slice)都是又 NALU 裝載並進行網絡傳輸的,但是這並不代表 NALU 內就一定是切片,這是充分不必要條件,因爲 NALU 還有可能裝載着其他用作描述視頻的信息。

片的主要作用是用作宏塊(Macroblock)的載體(ps:下面會介紹到宏塊的概念)。片之所以被創造出來,主要目的是爲限制誤碼的擴散和傳輸。
如何限制誤碼的擴散和傳輸?
每個片(slice)都應該是互相獨立被傳輸的,某片的預測(片(slice)內預測和片(slice)間預測)不能以其它片中的宏塊(Macroblock)爲參考圖像。
在這裏插入圖片描述
圖4.png
我們可以理解爲一 張/幀 圖片可以包含一個或多個分片(Slice),而每一個分片(Slice)包含整數個宏塊(Macroblock),即每片(slice)至少一個 宏塊(Macroblock),最多時每片包 整個圖像的宏塊。

上圖結構中,我們不難看出,每個分片也包含着頭和數據兩部分:

分片頭中包含着分片類型、分片中的宏塊類型、分片幀的數量、分片屬於那個圖像以及對應的幀的設置和參數等信息。
分片數據中則是宏塊,這裏就是我們要找的存儲像素數據的地方。
什麼是宏塊
宏塊是視頻信息的主要承載者,因爲它包含着每一個像素的亮度和色度信息。視頻解碼最主要的工作則是提供高效的方式從碼流中獲得宏塊中的像素陣列。
組成部分:一個宏塊由一個16×16亮度像素和附加的一個8×8 Cb和一個 8×8 Cr 彩色像素塊組成。每個圖象中,若干宏塊被排列成片的形式。
在這裏插入圖片描述
圖5.png
從上圖中,可以看到,宏塊中包含了宏塊類型、預測類型、Coded Block Pattern、Quantization Parameter、像素的亮度和色度數據集等等信息。、

來看看如何劃分宏塊的
編碼器先要爲每一幅圖片劃分宏塊。
以下面這張圖爲例:

在這裏插入圖片描述
圖6.jpeg

H264默認是使用 16X16 大小的區域作爲一個宏塊,也可以劃分成 8X8 大小。

在這裏插入圖片描述
圖7.jpeg
劃分好宏塊後,計算宏塊的象素值。

在這裏插入圖片描述
圖8.jpeg
以此類推,計算一幅圖像中每個宏塊的像素值,所有宏塊都處理完後如下面的樣子。
在這裏插入圖片描述
圖9.jpeg
如何劃分子塊
在說着之前,先了解切片(slice)類型跟宏塊類型的關係

I片:只包 I宏塊,I 宏塊利用從當前片中已解碼的像素作爲參考進行幀內預測(不能取其它片中的已解碼像素作爲參考進行幀內預測)。
P片:可包 P和I宏塊,P 宏塊利用前面已編碼圖象作爲參考圖象進行幀內預測,一個幀內編碼的宏塊可進一步作宏塊的分割:即 16×16、16×8、8×16 或 8×8 亮度像素塊(以及附帶的彩色像素);如果選了 8×8 的子宏塊,則可再分成各種子宏塊的分割,其尺寸爲 8×8、8×4、4×8 或 4×4 亮度像素塊(以及附帶的彩色像素)。
B片:可包 B和I宏塊,B 宏塊則利用雙向的參考圖象(當前和 來的已編碼圖象幀)進行幀內預測。
SP片(切換P):用於不同編碼流之間的切換,包含 P 和/或 I 宏塊
SI片:擴展檔次中必須具有的切換,它包 了一種特殊類型的編碼宏塊,叫做 SI 宏塊,SI 也是擴展檔次中的必備功能。
H264對比較平坦的圖像使用 16X16 大小的宏塊。但爲了更高的壓縮率,還可以在 16X16 的宏塊上更劃分出更小的子塊。子塊的大小可以是 8X16、 16X8、 8X8、 4X8、 8X4、 4X4非常的靈活。

在這裏插入圖片描述
圖10.jpeg
上幅圖中,紅框內的 16X16 宏塊中大部分是藍色背景,而三隻鷹的部分圖像被劃在了該宏塊內,爲了更好的處理三隻鷹的部分圖像,H264就在 16X16 的宏塊內又劃分出了多個子塊。
在這裏插入圖片描述
圖11.jpeg
這樣再經過幀內壓縮,可以得到更高效的數據。下圖是分別使用mpeg-2和H264對上面宏塊進行壓縮後的結果。其中左半部分爲MPEG-2子塊劃分後壓縮的結果,右半部分爲H264的子塊劃壓縮後的結果,可以看出H264的劃分方法更具優勢。

在這裏插入圖片描述
圖12.jpeg
到這裏,H264的基本結構大致就明瞭了。整天應該如下圖:

在這裏插入圖片描述
圖13.png
其實 H.264 的碼流結構並沒有大家想的那麼複雜,編碼後視頻的每一組圖像(GOP,圖像組)都給予了傳輸中的序列(PPS)和本身這個幀的圖像參數(SPS),所以,我們的整體結構,應該如此:
在這裏插入圖片描述
圖14.png
經過壓縮後的幀分爲:I幀,P幀和B幀:

I幀:幀內編碼幀 又稱intra picture,表示關鍵幀,I 幀通常是每個 GOP(MPEG 所使用的一種視頻壓縮技術)的第一個幀,經過適度地壓縮,做爲隨機訪問的參考點,可以當成圖象。I幀可以看成是一個圖像經過壓縮後的產物。你可以理解爲這一幀畫面的完整保留;解碼時只需要本幀數據就可以完成(因爲包含完整畫面)
P幀: 前向預測編碼幀 又稱predictive-frame,通過充分將低於圖像序列中前面已編碼幀的時間冗餘信息來壓縮傳輸數據量的編碼圖像,也叫預測幀;表示的是這一幀跟之前的一個關鍵幀(或P幀)的差別,解碼時需要用之前緩存的畫面(I幀)疊加上本幀定義的差別,生成最終畫面。(也就是差別幀,P幀沒有完整畫面數據,只有與前一幀的畫面差別的數據)
B幀: 雙向預測內插編碼幀(雙向差別幀、雙向預測幀) 又稱bi-directional interpolated prediction frame,既考慮與源圖像序列前面已編碼幀,也顧及源圖像序列後面已編碼幀之間的時間冗餘信息來壓縮傳輸數據量的編碼圖像;也就是B幀記錄的是本幀與前後幀的差別(具體比較複雜,有4種情況),換言之,要解碼B幀,不僅要取得之前的緩存畫面,還要解碼之後的畫面,通過前後畫面的與本幀數據的疊加取得最終的畫面。B幀壓縮率高,但是解碼時CPU會比較累~。
除了I/P/B幀外,還有圖像序列GOP。
GOP:兩個I幀之間是一個圖像序列,在一個圖像序列中只有一個I幀。(圖像組)主要用作形容一個 i 幀 到下一個 i 幀之間的間隔了多少個幀,增大圖片組能有效的減少編碼後的視頻體積,但是也會降低視頻質量,至於怎麼取捨,得看需求了。
I幀是完整的視頻幀,換句話說,客戶端只有在獲得I幀後纔會有完整的視頻。如果直接發送,不等I幀,客戶端得到的畫面會殘缺,但是延遲較低。如果等I幀,客戶端緩衝時間較長,得到畫面會完整,但是延遲至少是一個gop。
I、P、B幀特點分析

I 幀特點:

它是一個全幀壓縮編碼幀。它將全幀圖像信息進行JPEG壓縮編碼及傳輸; 
解碼時僅用I幀的數據就可重構完整圖像; 
I幀描述了圖像背景和運動主體的詳情; 
I幀不需要參考其他畫面而生成; 
I幀是P幀和B幀的參考幀(其質量直接影響到同組中以後各幀的質量); 
I幀是幀組GOP的基礎幀(第一幀),在一組中只有一個I幀; 
I幀不需要考慮運動矢量; 
I幀所佔數據的信息量比較大。 

P幀特點:

P幀是I幀後面相隔1~2幀的編碼幀; 
P幀採用運動補償的方法傳送它與前面的I或P幀的差值及運動矢量(預測誤差); 
解碼時必須將I幀中的預測值與預測誤差求和後才能重構完整的P幀圖像; 
P幀屬於前向預測的幀間編碼。它只參考前面最靠近它的I幀或P幀; 
P幀可以是其後面P幀的參考幀,也可以是其前後的B幀的參考幀; 
由於P幀是參考幀,它可能造成解碼錯誤的擴散; 
由於是差值傳送,P幀的壓縮比較高。 

B幀特點

B幀是由前面的I或P幀和後面的P幀來進行預測的; 
B幀傳送的是它與前面的I或P幀和後面的P幀之間的預測誤差及運動矢量; 
B幀是雙向預測編碼幀; 
B幀壓縮比最高,因爲它只反映丙參考幀間運動主體的變化情況,預測比較準確; 
B幀不是參考幀,不會造成解碼錯誤的擴散。

那麼上面幀類型在實際碼流上面是怎麼判斷的?

在這裏插入圖片描述
圖15.png

如圖中標記:
在實際的H264數據幀中,往往幀前面帶有00 00 00 01 或 00 00 01分隔符,一般來說編碼器編出的首幀數據爲PPS與SPS,接着爲I幀……

第一處:以00 00 00 01 06爲開頭的是SEI信息
第二處:以00 00 00 01 67爲開頭的是SPS
第三處:以00 00 00 01 68爲開頭的是PPS
第四處:以00 00 00 01 65爲開頭的是IDR Slice,這個也就是I幀。
我們看到常用naltype 像sps= 0x07 pps= 0x08 sei = 0x06 I/P/B= 0x01/0x05 也就是說只判斷naltype = 0x01/0x05是判斷不出來I/P/B幀類型的,需要到slice層去判斷用到“熵編碼”具體的“熵編碼”內容請看:“H.264官方中文版.pdf”.

NAL的解碼單元的流程如下:

在這裏插入圖片描述
圖16.jpg
幀內預測
對一特定宏塊兒編碼時,利用周圍的宏塊的預測值和實際值的差進行編碼
人眼對圖象都有一個識別度,對低頻的亮度很敏感,對高頻的亮度不太敏感。所以基於一些研究,可以將一幅圖像中人眼不敏感的數據去除掉。這樣就提出了幀內預測技術。

H264的幀內壓縮與JPEG很相似。一幅圖像被劃分好宏塊後,對每個宏塊可以進行 9 種模式的預測。找出與原圖最接近的一種預測模式。

在這裏插入圖片描述
圖17.jpeg
下面這幅圖是對整幅圖中的每個宏塊進行預測的過程:

在這裏插入圖片描述
圖18.jpeg
幀內預測後的圖像與原始圖像的對比如下:

在這裏插入圖片描述
圖19.jpeg
然後,將原始圖像與幀內預測後的圖像相減得殘差值:

在這裏插入圖片描述
圖20.jpeg
再將我們之前得到的預測模式信息一起保存起來,這樣我們就可以在解碼時恢復原圖了。效果如下:

在這裏插入圖片描述
圖21.jpeg
經過幀內與幀間的壓縮後,雖然數據有大幅減少,但還有優化的空間。

幀間預測
利用連續幀中的時間冗餘來進行運動估計和補償。碼流中增加SP幀,方便在不同碼率的碼流間切換,同時支持隨機接入和快速回放。

幀分組
對於視頻數據主要有兩類數據冗餘,一類是時間上的數據冗餘,另一類是空間上的數據冗餘。其中時間上的數據冗餘是最大的。下面我們就先來說說視頻數據時間上的冗餘問題。

爲什麼說時間上的冗餘是最大的呢?假設攝像頭每秒抓取30幀,這30幀的數據大部分情況下都是相關聯的。也有可能不止30幀的的數據,可能幾十幀,上百幀的數據都是關聯特別密切的。

對於這些關聯特別密切的幀,其實我們只需要保存一幀的數據,其它幀都可以通過這一幀再按某種規則預測出來,所以說視頻數據在時間上的冗餘是最多的。

爲了達到相關幀通過預測的方法來壓縮數據,就需要將視頻幀進行分組。那麼如何判定某些幀關係密切,可以劃爲一組呢?我們來看一下例子,下面是捕獲的一組運動的檯球的視頻幀,檯球從右上角滾到了左下角。

在這裏插入圖片描述
圖22.jpeg
在這裏插入圖片描述
圖23.jpeg
H264編碼器會按順序,每次取出兩幅相鄰的幀進行宏塊比較,計算兩幀的相似度。如下圖:

在這裏插入圖片描述
圖24.jpeg
通過宏塊掃描與宏塊搜索可以發現這兩個幀的關聯度是非常高的。進而發現這一組幀的關聯度都是非常高的。因此,上面這幾幀就可以劃分爲一組。其算法是:在相鄰幾幅圖像畫面中,一般有差別的像素只有10%以內的點,亮度差值變化不超過2%,而色度差值的變化只有1%以內,我們認爲這樣的圖可以分到一組。

在這樣一組幀中,經過編碼後,我們只保留第一帖的完整數據,其它幀都通過參考上一幀計算出來。我們稱第一幀爲IDR/I幀,其它幀我們稱爲P/B幀,這樣編碼後的數據幀組我們稱爲GOP。

運動估計與補償
在H264編碼器中將幀分組後,就要計算幀組內物體的運動矢量了。還以上面運動的檯球視頻幀爲例,我們來看一下它是如何計算運動矢量的。

H264編碼器首先按順序從緩衝區頭部取出兩幀視頻數據,然後進行宏塊掃描。當發現其中一幅圖片中有物體時,就在另一幅圖的鄰近位置(搜索窗口中)進行搜索。如果此時在另一幅圖中找到該物體,那麼就可以計算出物體的運動矢量了。下面這幅圖就是搜索後的檯球移動的位置。

在這裏插入圖片描述
圖25.jpeg
通過上圖中臺球位置相差,就可以計算出臺圖運行的方向和距離。H264依次把每一幀中球移動的距離和方向都記錄下來就成了下面的樣子:

在這裏插入圖片描述
圖26.jpeg
運動矢量計算出來後,將相同部分(也就是綠色部分)減去,就得到了補償數據。我們最終只需要將補償數據進行壓縮保存,以後在解碼時就可以恢復原圖了。壓縮補償後的數據只需要記錄很少的一點數據。如下所示:
在這裏插入圖片描述
圖27.jpeg
我們把運動矢量與補償稱爲幀間壓縮技術,它解決的是視頻幀在時間上的數據冗餘。除了幀間壓縮,幀內也要進行數據壓縮,幀內數據壓縮解決的是空間上的數據冗餘。下面我們就來介紹一下幀內壓縮技術。

#######對殘差數據做DCT(量化和反量化)
步長以12.5%的符合速率遞增,不是固定的常數。變換系數的讀出有兩種:之字掃描和雙掃描。多數用之字掃描,雙掃描僅用於較小量化級的塊內。

可以將殘差數據做整數離散餘弦變換,去掉數據的相關性,進一步壓縮數據。如下圖所示,左側爲原數據的宏塊,右側爲計算出的殘差數據的宏塊。

在這裏插入圖片描述
圖28.jpeg
將殘差數據宏塊數字化後如下圖所示:

在這裏插入圖片描述
圖29.jpeg
將殘差數據宏塊進行 DCT 轉換:

在這裏插入圖片描述
圖30.jpeg
去掉相關聯的數據後,我們可以看出數據被進一步壓縮了:

在這裏插入圖片描述
圖31.jpeg
熵編碼(CABAC)
熵編碼壓縮是一種無損壓縮,其實現原理是使用新的編碼來表示輸入的數據,從而達到壓縮的效果。常用的熵編碼有遊程編碼,哈夫曼編碼和CAVLC編碼等。

CABAC
CABAC(ContextAdaptive Binary Arithmatic Coding)也是 H.264/MPEG-4AVC中使用的熵編碼算法。CABAC在不同的上下文環境中使用不同的概率模型來編碼。其編碼過程大致是這樣:首先,將欲編碼的符號用二進制bit表示;然後對於每個bit,編碼器選擇一個合適的概率模型,並通過相鄰元素的信息來優化這個概率模型;最後,使用算術編碼壓縮數據。

MPEG-2中使用的VLC就是這種算法,我們以 A-Z 作爲例子,A屬於高頻數據,Z屬於低頻數據。看看它是如何做的:

在這裏插入圖片描述
圖32.jpeg
CABAC也是給高頻數據短碼,給低頻數據長碼。同時還會根據上下文相關性進行壓縮,這種方式又比VLC高效很多。其效果如下:
在這裏插入圖片描述
圖33.jpeg
現在將 A-Z 換成視頻幀,它就成了下面的樣子:

在這裏插入圖片描述
圖34.jpeg
最後,本文對H264的基本結構進行了分析,也講述了他的幾大要點。本文參考融合以下兩篇文章(感謝他們的無私奉獻),並且加入自己的一些理解,希望通過這兩篇文章和自己的理解,能讓你更好的理解H264,文中有不足的,留言。
H264基本原理
深入淺出理解視頻編碼H264結構

作者:DramaScript
鏈接:https://www.jianshu.com/p/0c296b05ef2a
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。

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