H.264碼流結構 (H.264 Data Structure)

--------------------------------------------------------

簡書地址 : H.264 Data Structure

博客地址 : H.264 Data Structure

掘金地址 : H.264 Data Structure

--------------------------------------------------------

Why ?

相信在你的電腦裏,必定存有一些已經下載好的視頻文件,若是你硬說沒有,那我相信你曾經總有吧?曾經也沒有?那我想對你說曾經免費的時候你不下載,直到電影都收費才後悔那些年錯過下載的大片。html

好了,言歸正傳,在平常咱們必定見過不少後綴爲avi, mp4, rmvb, flv等格式的視頻文件。而不多有人真正挖掘這些文件究竟是什麼?其實以上格式都是封裝視頻的封裝格式。ios

什麼是封裝格式 ?git

把音頻數據和視頻數據打包成一個文件的規範。不用封裝格式差距不大, 各有千秋。github

從視頻播放器播放一個互聯網上的視頻文件算法

須要通過如下幾個步驟:解協議,解封裝,解碼視音頻,視音頻同步。若是播放本地文件則不須要解協議,其餘步驟相同。小程序

play process.jpeg

  • 解協議:流媒體協議的數據,解析爲標準的相應的封裝格式數據
  • 解封裝:將輸入的封裝格式的數據,分離成爲音頻流壓縮編碼數據和視頻流壓縮編碼數據。
  • 解碼:就是將視頻/音頻壓縮編碼數據,解碼成爲非壓縮的視頻/音頻原始數據。
  • 視音頻同步:就是根據解封裝模塊處理過程當中獲取到的參數信息,同步解碼出來的視頻和音頻數據,並將視頻音頻數據送至系統的顯卡和聲卡播放出來。

爲何要對視頻數據進行編碼bash

視頻編碼的主要做用是將視頻像素數據(RGB,YUV等)壓縮成視頻碼流,從而下降視頻的數據量。舉個例子:好比當前手機的屏幕分辨率是1280 * 720(即咱們平時在視頻軟件中可選的720P),假設一秒鐘30幀(即1秒鐘傳輸30張圖片),那麼一秒鐘的數據爲 1280 * 720(位像素)*30(張) / 8(1字節8位)(結果B),也就是一秒鐘的數據量爲3.456M數據量,一分鐘就是207.36M,那麼咱們日常看一部電影就是大約18G的流量,試想下若是是這樣對於存儲即網絡傳輸是件多麼恐怖的事情。網絡

正是由於以上緣由,咱們須要對視頻數據進行編碼,以最小程序減少清晰度與最大程序下降數據量,而H264正是目前普遍使用的一種編碼格式,下面咱們將主要介紹下H264的碼流結構。post

碼流結構

刷新圖像概念編碼

在咱們的印象中,一張圖片就是一張圖像,而在H264中圖像是個集合的概念。

幀、頂場、底場均可以稱爲圖像。一幀一般就是一幅完整的圖像。當採集視頻信號時,若是採用逐行掃描,則每次掃描獲得的信號就是一副圖像,也就是一幀。當採集視頻信號時,若是採用隔行掃描(奇、偶數行),則掃描下來的一幀圖像就被分爲了兩個部分,這每一部分就稱爲「場」,根據次序分爲:「頂場」和「底場」。「幀」和「場」的概念又帶來了不一樣的編碼方式:幀編碼、場編碼。逐行掃描適合於運動圖像,因此對於運動圖像採用幀編碼更好;隔行掃描適合於非運動圖像,因此對於非運動圖像採用場編碼更好。

逐行掃描與隔行掃描.png

幀與場.png

H264原始碼流

  • 結構:由一個接一個的 NALU 組成的,而它的功能分爲兩層,VCL(視頻編碼層)和 NAL(網絡提取層).
    • VCL:包括核心壓縮引擎和塊,宏塊和片的語法級別定義,設計目標是儘量地獨立於網絡進行高效的編碼。
    • NAL:負責將VCL產生的比特字符串適配到各類各樣的網絡和多元環境中,覆蓋了全部片級以上的語法級別。

H264碼流.png

  • 組成:NALU (Nal Unit) = NALU頭 + RBSP 在 VCL 數據傳輸或存儲以前,這些編碼的 VCL 數據,先被映射或封裝進 NAL 單元(如下簡稱 NALU,Nal Unit) 中。每一個 NALU 包括一個原始字節序列負荷(RBSP, Raw Byte Sequence Payload)、一組 對應於視頻編碼的 NALU 頭部信息。RBSP 的基本結構是:在原始編碼數據的後面填加告終尾 比特。一個 bit「1」若干比特「0」,以便字節對齊。
一個原始的H.264 NALU 單元常由 [StartCode] [NALU Header] [NALU Payload] 三部分組成

NALU組成.jpeg

  • StartCode : Start Code 用於標示這是一個NALU 單元的開始,必須是」00 00 00 01」 或」00 00 01」

  • NALU Header 下表爲 NAL Header Type

NAL Header Type.png

例如:

00 00 00 01 06:  SEI信息   
00 00 00 01 07:  SPS
00 00 00 01 08:  PPS
00 00 00 01 05:  IDR Slice

複製代碼
  • RBSP :NAL包將其負載數據存儲在 RBSP(Raw Byte Sequence Payload) 中,RBSP 是一系列的 SODB(String Of Data Bits)。

RBSP.png

  • 一幀圖片跟NALU的關聯: 一幀圖片通過 H.264 編碼器以後,就被編碼爲一個或多個片(slice),而裝載着這些片(slice)的載體,就是 NALU 了。 注意:片(slice)的概念不一樣與幀(frame),幀(frame)是用做描述一張圖片的,一幀(frame)對應一張圖片,而片(slice),是 H.264 中提出的新概念,是經過編碼圖片後切分經過高效的方式整合出來的概念,一張圖片至少有一個或多個片(slice)。片(slice)都是又 NALU 裝載並進行網絡傳輸的,可是這並不表明 NALU 內就必定是切片,這是充分沒必要要條件,由於 NALU 還有可能裝載着其餘用做描述視頻的信息。

什麼是切片(slice)?

片的主要做用是用做宏塊(Macroblock)的載體(ps:下面會介紹到宏塊的概念)。片之因此被創造出來,主要目的是爲限制誤碼的擴散和傳輸。

那麼片(slice)的具體結構,咱們用一張圖來直觀說明吧:

slice.png

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

  • 分片頭中包含着分片類型、分片中的宏塊類型、分片幀的數量、分片屬於那個圖像以及對應的幀的設置和參數等信息。
  • 分片數據中則是宏塊,這裏就是咱們要找的存儲像素數據的地方。

什麼是宏塊?

  • 宏塊是視頻信息的主要承載者,它包含着每個像素的亮度和色度信息。視頻解碼的主要工做則是提供高效的方式從碼流中得到宏塊中的像素陣列。

  • 宏塊的組成:一個宏塊由一個16*16亮度像素和附加的一個8 * 8Cb和一個8 * 8Cr彩色像素塊組成。每一個圖像中,若干宏塊被排列成片的形式。

下面是宏塊的結構圖:

宏塊.png

切片(slice)類型跟宏塊類型的關係

切片(slice)來說,分爲如下幾種類型:

  • P-slice. Consists of P-macroblocks (each macro block is predicted using one reference frame) and / or I-macroblocks.

  • B-slice. Consists of B-macroblocks (each macroblock is predicted using one or two reference frames) and / or I-macroblocks.

  • I-slice. Contains only I-macroblocks. Each macroblock is predicted from previously coded blocks of the same slice.

  • SP-slice. Consists of P and / or I-macroblocks and lets you switch between encoded streams.

  • SI-slice. It consists of a special type of SI-macroblocks and lets you switch between encoded streams.

  • I片:只包 I宏塊,I 宏塊利用從當前片中已解碼的像素做爲參考進行幀內預測(不能取其它片中的已解碼像素做爲參考進行幀內預測)。

  • P片:可包 P和I宏塊,P 宏塊利用前面已編碼圖象做爲參考圖象進行幀內預測,一個幀內編碼的宏塊可進一步做宏塊的分割:即 16×1六、16×八、8×16 或 8×8 亮度像素塊(以及附帶的彩色像素);若是選了 8×8 的子宏塊,則可再分紅各類子宏塊的分割,其尺寸爲 8×八、8×四、4×8 或 4×4 亮度像素塊(以及附帶的彩色像素)。

  • B片:可包 B和I宏塊,B 宏塊則利用雙向的參考圖象(當前和 來的已編碼圖象幀)進行幀內預測。

  • SP片(切換P):用於不一樣編碼流之間的切換,包含 P 和/或 I 宏塊

  • SI片:擴展檔次中必須具備的切換,它包含了一種特殊類型的編碼宏塊,叫作 SI 宏塊,SI 也是擴展檔次中的必備功能。

總體結構

總體結構.png

H.264的碼流結構並無那麼複雜,編碼後視頻的每一組圖像(GOP,圖片組)都給予了傳輸的序列(PPS)和自己這個幀的圖像參數(SPS),因此,總體給夠以下

一幀圖像.png

GOP 圖像組主要形容一個I幀到下一個I幀之間間隔了多少幀,增大圖片組能有效的減小編碼後視頻的體積,可是也會下降視頻質量,至於怎麼取捨,得看需求。

NALU頭部的類型

enum nal_unit_type_e
{
NAL_UNKNOWN = 0, // 未使用
NAL_SLICE = 1, // 不分區、非 IDR 圖像的片(片的頭信息和數據)
NAL_SLICE_DPA = 2, // 片分區 A
NAL_SLICE_DPB = 3, // 片分區 B
NAL_SLICE_DPC = 4, // 片分區 C
NAL_SLICE_IDR = 5, / ref_idc != 0 / // IDR 圖像中的片
NAL_SEI = 6, / ref_idc == 0 / // 補充加強信息單元
-
參數集是 H.264 標準的一個新概念,是一種經過改進視頻碼流結構加強錯誤恢復能力的方法。
NAL_SPS = 7, // 序列參數集 (包括一個圖像序列的全部信息,即兩個 IDR 圖像間的全部圖像信息,如圖像尺寸、視頻格式等)
NAL_PPS = 8, // 圖像參數集 (包括一個圖像的全部分片的全部相關信息, 包括圖像類型、序列號等,解碼時某些序列號的丟失可用來檢驗信息包的丟失與否)
-
NAL_AUD = 9, // 分界符
NAL_FILLER = 12, // 填充(啞元數據,用於填充字節)
/ ref_idc == 0 for 6,9, 10 (代表下一圖像爲 IDR 圖像),11(代表該流中已沒有圖像),12 /
};
ps: 以上括號()中的爲類型描述


複製代碼

補充說明

  • I,P,B 幀 與 pts / dts
I幀 P幀 B幀
幀內編碼幀 前向預測編碼幀 雙向預測編碼幀
I幀一般是每一個GOP的第一幀,通過適度壓縮,做爲隨機訪問的參考點,可當作一個圖片通過壓縮後的產物 經過充分低於圖像序列中前面已編碼幀的時間冗餘信息來壓縮傳輸數據編碼圖像,也叫預測幀 既考慮與源圖像序列前面已編碼幀,也顧及源圖像序列後面已編碼幀之間的時間冗餘信息來壓縮傳輸數據量的編碼圖像,也叫雙向預測幀
I,P,B幀
  • I frame : 自身能夠經過視頻解壓算法解壓成一張單獨完整的圖片
  • P frame : 須要參考其前面的一個I frame 或者B frame來生成一張完整圖片
  • B frame : 既要參考其前一個I frame 或者 P frame以及其後一個P frame來生成一張完整的圖片。
DTS,PTS
  • PTS :PTS主要用於度量解碼後的視頻何時被顯示
  • DTS :DTS主要是標識內存中的Bit流何時開始送入解碼器進行解碼
GOP

GOP是畫面組,一個GOP是一組連續的畫面。 GOP通常有兩個數字,如M=3,N=12.M制定I幀與P幀之間的距離,N指定兩個I幀之間的距離。那麼如今的GOP結構是 I BBP BBP BBP BB I

IDR

一個序列的第一個圖像叫作 IDR 圖像(當即刷新圖像),IDR 圖像都是 I 幀圖像。

I和IDR幀都使用幀內預測。I幀不用參考任何幀,可是以後的P幀和B幀是有可能參考這個I幀以前的幀的。IDR就不容許這樣。

  • 核心做用 : H.264 引入 IDR 圖像是爲了解碼的重同步,當解碼器解碼到 IDR 圖像時,當即將參考幀隊列清空,將已解碼的數據所有輸出或拋棄,從新查找參數集,開始一個新的序列。這樣,若是前一個序列出現重大錯誤,在這裏能夠得到從新同步的機會。IDR圖像以後的圖像永遠不會使用IDR以前的圖像的數據來解碼。
幀內預測和幀間預測
  • 幀內預測(也叫幀內壓縮)

幀內預測.png

咱們能夠經過第 一、二、三、四、5 塊的編碼來推測和計算第 6 塊的編碼,所以就不須要對第 6 塊進行編碼了,從而壓縮了第 6 塊,節省了空間

幀間壓縮11.jpg

能夠看到先後兩幀的差別實際上是很小的,這時候用幀間壓縮就頗有意義。 這裏涉及到幾個重要的概念:塊匹配,殘差,運動搜索(運動估計),運動補償. 幀間壓縮最經常使用的方式就是塊匹配(Block Matching)。找找看前面已經編碼的幾幀裏面,和我當前這個塊最相似的一個塊,這樣我不用編碼當前塊的內容了,只須要編碼當前塊和我找到的快的差別(殘差)便可。找最想的塊的過程叫運動搜索(Motion Search),又叫運動估計。用殘差和原來的塊就能推算出當前塊的過程叫運動補償(Motion Compensation).

參考文章:深刻淺出理解H264, 從零瞭解H264結構, 音視頻基礎

相關文章
相關標籤/搜索