音视频 H.264格式介绍
名字解釋:
- GOP (圖像組)主要用作形容一個 i 幀 到下一個 i 幀之間的間隔了多少個幀。
增大圖片組(GOP)能有效的減少編碼后的視頻體積,但是也會降低視頻質量。 - 編碼后視頻的每一組圖像(GOP,圖像組)都給予了傳輸中的序列(PPS)和本身這個幀的圖像參數(shù)(SPS)。
- SPS(Sequence Parameter Set)序列參數(shù)集、PPS(Picture Parameter Set)圖像參數(shù)集,包含了圖像編碼的各種參數(shù)信息,是作為解碼器初始化所必須的參數(shù)信息。
- IDR(Instantaneous Decoding Refresh)幀,也就是即時解碼刷新幀,直觀意思就是解碼器在接收到IDR幀后會刷新參考幀緩存。IDR幀前后的視頻幀不會有任何參考關系,解碼器可以從任何一個IDR幀開始解碼。
H.264句法和語義
H.264 中,句法元素共被組織成 序列、圖像、片、宏塊、子宏塊五個層次。
其中每一幀都是NALU,理解了 NALU,就理解 H.264 的結構了。
- 句法元素被組織成有層次的結構,分別描述各個層次的信息。
以往標準中句法元素的分層結構
在這樣的結構中,每一層的頭部和它的數(shù)據(jù)部分形成管理與被管理的強依賴關系,頭部的句法元素是該層數(shù)據(jù)的核心,而一旦頭部丟失,數(shù)據(jù)部分的信息幾乎不可能再被正確解碼出來。尤其在序列層及圖像層,由于網絡中 MTU(最大傳輸單元)大小的限制,不可能將整個層的句法元素全部放入同一個分組中,這個時候如果頭部所在的分組丟失,該層其他分組即使能被正確接收也無法解碼,造成資源浪費。
H.264 中句法元素的分層結構
在 H.264 中,分層結構最大的不同是取消了序列層和圖像層,并將原本屬于序列和圖像頭部的大部分句法元素游離出來形成序列和圖像兩級參數(shù)集,其余的部分則放入片層。參數(shù)集是一個獨立 的數(shù)據(jù)單位,不依賴于參數(shù)集外的其他句法元素。
碼流模型
一種簡化的碼流結構模型
一個序列的第一個圖像叫做 IDR 圖像(立即刷新圖像),IDR 圖像都是 I圖像。
H.264 引入 IDR 圖像是為了解碼的重同步,當解碼器解碼到 IDR 圖像時,立即將參考幀隊列清空,將已解碼的數(shù)據(jù)全部輸出或拋棄,重新查找參數(shù)集,開始一個新的序列。
這樣,如果在前一個序列的傳輸中發(fā)生重大錯誤,如嚴重的丟包,或其他原因引起數(shù)據(jù)錯位,在這里可以獲得重新同步。
IDR 圖像之后的圖像永遠不會引用 IDR 圖像之前的圖像的數(shù)據(jù)來解碼。
IDR 圖像和 I 圖像的區(qū)別,IDR 圖像一定是 I 圖像,但 I 圖像不一定是 IDR 圖像。一個序列中可以有很多的 I 圖像,I 圖像之后的圖像可以引用 I 圖像之間的圖像做運動參考。
H.264基本流NALU
H.264 的基本流(elementary stream,ES)的結構分為兩層,包括視頻編碼層(VCL)和網絡適配層(NAL)。
視頻編碼層VCL負責高效的視頻內容表示,是對核心算法引擎,塊,宏塊及片的語法級別的定義,他最終輸出編碼完的數(shù)據(jù) SODB。
網絡適配層NAL負責以網絡所要求的恰當?shù)姆绞綄?shù)據(jù)進行打包和傳送,將SODB打包成RBSP然后加上NAL頭,組成一個NALU(NAL單元、Nal Unit)。
-
引入NAL并使之與VCL分離帶來的好處包括兩方面:
- 使信號處理和網絡傳輸分離,VCL 和NAL 可以在不同的處理平臺上實現(xiàn);
- VCL 和NAL 分離設計,使得在不同的網絡環(huán)境內,網關不需要因為網絡環(huán)境不同而對VCL比特流進行重構和重編碼。
-
名詞介紹
SODB(String Of Data Bits):原始數(shù)據(jù)比特流, 長度不一定是8的倍數(shù),故需要補齊
RBSP(Raw Byte Sequence Payload):原始數(shù)據(jù)字節(jié)流,SODB+RBSP trailing bits=RBSP,添加加trailing bits是為了使一個RBSP為整字節(jié)數(shù),字節(jié)對齊 -
H.264 的基本流由一系列NALU (Network Abstraction Layer Unit )組成,不同的NALU數(shù)據(jù)量各不相同,每個NALU中可能是IDR圖像、SPS、PPS、non-IDR圖像等。
-
H.264 草案指出,當數(shù)據(jù)流是儲存在介質上時,在每個NALU 前添加起始碼:0x000001或0x00000001,用來指示一個NALU 的起始和終止位置。在這樣的機制下,在碼流中檢測起始碼,作為一個NALU得起始標識,當檢測到下一個起始碼時,當前NALU結束。
H.264 碼流中每個幀的開頭的3~4個字節(jié)是H.264 的start_code(起始碼),0x00000001或0x000001。
3字節(jié)的0x000001只有一種場合下使用,就是一個完整的幀被編為多個slice(片)的時候,從第二個slice開始,包含這些slice的NALU 使用3字節(jié)起始碼。也就是說,如果NALU對應的slice為一幀的開始就用0x00000001,否則就用0x000001。
-
一個視頻幀中可能包含多個NALU, 此時可以稱該視頻幀為多slice視頻幀(一個NALU中包含該視頻幀的一個slice)
碼流格式:Annex-B和AVCC
H.264碼流分Annex-B和AVCC兩種格式。
H.265碼流是Annex-B和HVCC格式。
Android硬解碼 MediaCodec只接受AnnexB格式的數(shù)據(jù),Apple的VideoToolBox,只支AVCC的格式。
區(qū)別有兩點:一個是參數(shù)集(SPS, PPS)組織格式;一個是分隔。
- Annex-B:使用start code分隔NAL(start code為三字節(jié)或四字節(jié),0x000001或0x00000001,一般是四字節(jié));SPS和PPS按流的方式寫在頭部。
- AVCC:使用NALU長度(固定字節(jié),通常為4字節(jié))分隔NAL;在頭部包含extradata(或sequence header)的結構體。
ANNXT-B格式
Annex-B 附錄B, 指ITU-T的 Recommendation(h.264和h.265)在附錄B中規(guī)定碼流格式。
使用start code分隔NAL(start code為三字節(jié)或四字節(jié),0x000001或0x00000001,一般是四字節(jié));SPS和PPS按流的方式寫在頭部。在 AnnexB 中,SPS 和 PPS 被當做了普通的 NALU 進行處理;而在 avcC 中,SPS 和 PPS 信息被當做了特殊的信息進行了處理。
- 防競爭字節(jié) (Emulation Prevention Bytes)
所謂防競爭字節(jié)(Emulation Prevention Bytes),就是在給 NALU 添加起始碼之前,先對碼流進行一次遍歷,查找碼流里面的存在的 0 0 0,0 0 1,0 0 2,0 0 3 的字節(jié),然后對其進行如下修改;在解碼過程中,通過起始碼成功分割 NALU 數(shù)據(jù)之后,還要將防競爭字節(jié)去掉。
0 0 => 0 0 3 0
0 0 1 => 0 0 3 1
0 0 2 => 0 0 3 2
0 0 3 => 0 0 3 3
AVCC格式
在一路采用 AVCC 打包的 H.264 流之中,我們首先看到的將是一段被稱之為 extradata 的數(shù)據(jù),這段數(shù)據(jù)定義了這個 H.264 流的基本屬性數(shù)據(jù),當然,也包含了 SPS 和 PPS 數(shù)據(jù)。
8 version ( always 0x01 ) 8 avc profile ( sps[0][1] ) 8 avc compatibility ( sps[0][2] ) 8 avc level ( sps[0][3] ) 6 reserved ( all bits on ) 2 NALULengthSizeMinusOne // 這個值是(前綴長度-1) 3 reserved ( all bits on ) 5 number of SPS NALUs (usually 1) repeated once per SPS: 16 SPS size variable SPS NALU data 8 number of PPS NALUs (usually 1) repeated once per PPS 16 PPS size variable PPS NALU dataNALULengthSizeMinusOne如果是3,那么每個 NALU 前面前綴的長度就是 4 個字節(jié)。在AVCC格式中,每個NAL前面都會有NAL size字段。NAL size可能是1字節(jié)、2字節(jié)或4字節(jié)(4字節(jié)較常見),解析extradata重要目的就是確認這個值。(而Annex-B格式,要split NAL,只要去探測0x000001就可以了)。
參考ff_h264_decode_extradata()
轉換
-
Annex-B 轉 AVCC
start code 轉為4字節(jié) NAL size
SPS, PPS創(chuàng)建 extradata -
AVCC 轉 Annex-B
FFmpeg “extract_extradata” bitstream filter;
結構
NALU結構
- NALU,即 NAL頭+RBSP
NALU頭結構
-
長度:1Byte,orbidden_bit(1bit) + nal_reference_bit(2bit) + nal_unit_type(5bit)
F(forbidden_zero_bit):1 位,初始為0。當網絡識別此單元存在比特錯誤時,可將其設為 1,以便接收方丟掉該單元
NRI(nal_ref_idc):2 位,用來指示該NALU 的重要性等級。值越大,表示當前NALU越重要。具體大于0 時取何值,沒有明確規(guī)定
Type(nal_unit_type):5 位,指出NALU 的類型
-
NALU 解碼流程
-
nal_unit_type=5:表示當前NAL是IDR圖像的一個片,在這種情況下,IDR圖像中的每個片的nal_unit_type都應該等于5。注意,IDR圖像不能使用分區(qū)。
-
nal_unit_type=7或8:每個SPS 或者PPS 僅對應一個NALU。
RBSP結構
- 典型的 RBSP 單元序列如圖所示。每個單元都按獨立的 NAL 單元傳送。NAL 單元
的頭信息(一個字節(jié))定義了 RBSP 單元的類型,NAL 單元的其余部分則為 RBSP 數(shù)據(jù)。
這里是RBSP序列,需要NAL打包加上NAL頭后進行傳輸。
片
-
片(slice):
一幀圖像可編碼成一個或者多個片,每片包含整數(shù)個宏塊(macro block),即每片至少一個宏塊,最多時包含整個圖像的宏塊。
分片的目的是為了限制誤碼的擴散和傳輸,使編碼片相互間保持獨立。 -
片的語法結構
片頭規(guī)定了片的類型,該片屬于哪個圖像,有關的參考圖像等,片的數(shù)據(jù)包含一系列的編碼宏塊,和或跳編碼(不編碼)數(shù)據(jù)。每個 宏塊包含頭單元和殘差數(shù)據(jù)。
-
片類型
IDR 圖像時, slice_type 等于 2, 4, 7, 9。
宏塊
- 宏塊(Macro Block):
一個編碼圖像通常劃分成若干宏塊組成,一個宏塊由一個 16×16 亮度像素和附加的一個 8×8 Cb和一個 8×8 Cr 彩色像素塊組成。每個圖象中,若干宏塊被排列成片的形式。
I 片只包含 I 宏塊,P 片可包含 P 和 I 宏塊,而 B 片可包含 B 和 I 宏塊。
I 宏塊利用從當前片中已解碼的像素作為參考進行幀內預測(不能取其它片中的已解碼像素作為
參考進行幀內預測)。
P 宏塊利用前面已編碼圖象作為參考圖象進行幀內預測,一個幀內編碼的宏塊可進一步作宏塊的分割:即 16×16、16×8、8×16 或 8×8 亮度像素塊(以及附帶的彩色像素);如果選了 8×8 的子宏塊,則可再分成各種子宏塊的分割,其尺寸為 8×8、8×4、4×8 或 4×4 亮度像素塊(以及附帶的彩色像素)。
B 宏塊則利用雙向的參考圖象(當前和未來的已編碼圖象幀)進行幀內預測。
實際使用例子
【技術干貨】移動端硬解關鍵流程梳理
總結
H.264 的基本流由一系列NALU (Network Abstraction Layer Unit )組成,不同的NALU數(shù)據(jù)量各不相同,每個NALU中可能是IDR圖像、SPS、PPS、non-IDR圖像等。
H.264 中,句法元素共被組織成 序列、圖像、片、宏塊、子宏塊五個層次。
其中每一幀都是NALU,理解了 NALU,就理解 H.264 的結構了。
參考:
H264官方發(fā)布
新一代視頻壓縮編碼標準H.264
深入淺出理解視頻編碼 H264 結構
H.264格式分析
解碼中的AnnexB和avcC兩種分割數(shù)據(jù)方式
碼流格式: Annex-B, AVCC(H.264)與HVCC(H.265), extradata詳解
移動端硬解關鍵流程梳理
x264源碼解析
H264筆記
H264幀格式解析
ffmpeg編碼H.264幀類型判斷
總結
以上是生活随笔為你收集整理的音视频 H.264格式介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C#反混淆脱壳工具de4dot的使用(转
- 下一篇: [css] 行内元素和块级元素有什么区