音視頻 (一) —— H.264 中的 NAL 技術
音視頻 (二) —— H.264中相關參數(shù)理解
音視頻 (三) —— 視頻相關參數(shù)的理解
了解H.264
H.264,同時也是MPEG-4第十部分,是由ITU-T視頻編碼專家組(VCEG)和ISO/IEC動態(tài)圖像專家組(MPEG)聯(lián)合組成的聯(lián)合視頻組(JVT,Joint Video Team)提出的高度壓縮數(shù)字視頻編解碼器標準。這個標準通常被稱之為H.264/AVC(或者AVC/H.264或者H.264/MPEG-4 AVC或MPEG-4/H.264 AVC)而明確的說明它兩方面的開發(fā)者。
H264標準各主要部分有Access Unit delimiter(訪問單元分割符),SEI(附加增強信息),primary coded picture(基本圖像編碼),Redundant Coded Picture(冗余圖像編碼)。還有Instantaneous Decoding Refresh(IDR,即時解碼刷新)、Hypothetical Reference Decoder(HRD,假想?yún)⒖冀獯a)、Hypothetical Stream Scheduler(HSS,假想碼流調(diào)度器)。
H.264基本數(shù)據(jù)結構
H264碼流可以分為兩層,VCL層和NAL層,NAL的全稱是Network abstraction layer,叫網(wǎng)絡抽象層,它保存了H264相關的參數(shù)信息和圖像信息,NAL層由多個單元NALU組成,NALU由了NALU頭(00 00 00 01或者00 00 01)sps(序列參數(shù)集 Sequence Parameter Set)、pps(圖像參數(shù)集合 picture parameter set)、SEI(增強信息 set enhance information)。

H264編碼出的NALU規(guī)律
第一個I幀 第一幀包括
SPS【00 00 00 01 0x67】PPS【00 00 00 01 0x68】SEI【00 00 00 01 0x06】IDR【00 00 00 01 0x65】P幀
P【00 00 00 01 0x61】I幀包括
SPS【00 00 00 01 0x67】PPS【00 00 00 01 0x68】IDR【00 00 00 01 0x65】
如何判斷幀類型是圖像參考幀還是I、B、P等?
NALU類型是我們判斷幀類型的利器,從官方文檔中得出如下圖:

00 00 00 01分割之后的下一個字節(jié)就是NALU類型,將其轉為二進制數(shù)據(jù)后,解讀順序為從左往右算,如下:
(1)第1位禁止位,值為1表示語法出錯
(2)第2~3位為參考級別
(3)第4~8為是nal單元類型
例如上面00 00 00 01后有67、68以及65
其中
0x67的二進制碼為:
0110 0111
4-8為00111,轉為十進制7,參考第二幅圖:7對應序列參數(shù)集SPS,即0x67開始直到下個00000001之間的數(shù)據(jù)為SPS其中
0x68的二進制碼為:
0110 1000
4-8為01000,轉為十進制8,參考第二幅圖:8對應圖像參數(shù)集PPS,即0x68開始直到下個00000001之間的數(shù)據(jù)為PPS其中0x65的二進制碼為:
0110 0101
4-8為00101,轉為十進制5,參考第二幅圖:5對應IDR圖像中的片(I幀),即0x65開始直到下個00 00 00 01之間的數(shù)據(jù)為I幀
所以判斷是否為I幀的算法為: (NALU類型 & 0001 1111)= 5 即 NALU類型 & 31 = 5
比如0x65 & 31 = 5
更多NALU類型值參考下表

H.264編碼原理
H.264是新一代的編碼標準,以高壓縮高質(zhì)量和支持多種網(wǎng)絡的流媒體傳輸著稱,在編碼方面,我理解的他的理論依據(jù)是:參照一段時間內(nèi)圖像的統(tǒng)計結果表明,在相鄰幾幅圖像畫面中,一般有差別的像素只有10%以內(nèi)的點,亮度差值變化不超過2%,而色度差值的變化只有1%以內(nèi)。所以對于一段變化不大圖像畫面,我們可以先編碼出一個完整的圖像幀A,隨后的B幀就不編碼全部圖像,只寫入與A幀的差別,這樣B幀的大小就只有完整幀的1/10或更小!B幀之后的C幀如果變化不大,我們可以繼續(xù)以參考B的方式編碼C幀,這樣循環(huán)下去。這段圖像我們稱為一個序列(序列就是有相同特點的一段數(shù)據(jù)),當某個圖像與之前的圖像變化很大,無法參考前面的幀來生成,那我們就結束上一個序列,開始下一段序列,也就是對這個圖像生成一個完整幀A1,隨后的圖像就參考A1生成,只寫入與A1的差別內(nèi)容。
在H264協(xié)議里定義了三種幀,完整編碼的幀叫I幀,參考之前的I幀生成的只包含差異部分編碼的幀叫P幀,還有一種參考前后的幀編碼的幀叫B幀。
H264采用的核心算法是幀內(nèi)壓縮和幀間壓縮,幀內(nèi)壓縮是生成I幀的算法,幀間壓縮是生成B幀和P幀的算法。
對序列的說明
在H.264中圖像以序列為單位進行組織,一個序列是一段圖像編碼后的數(shù)據(jù)流,以I幀開始,到下一個I幀結束。
一個序列的第一個圖像叫做 IDR 圖像(立即刷新圖像),IDR 圖像都是 I 幀圖像。H.264 引入 IDR 圖像是為了解碼的重同步,當解碼器解碼到 IDR 圖像時,立即將參考幀隊列清空,將已解碼的數(shù)據(jù)全部輸出或拋棄,重新查找參數(shù)集,開始一個新的序列。這樣,如果前一個序列出現(xiàn)重大錯誤,在這里可以獲得重新同步的機會。IDR圖像之后的圖像永遠不會使用IDR之前的圖像的數(shù)據(jù)來解碼。
一個序列就是一段內(nèi)容差異不太大的圖像編碼后生成的一串數(shù)據(jù)流。當運動變化比較少時,一個序列可以很長,因為運動變化少就代表圖像畫面的內(nèi)容變動很小,所以就可以編一個I幀,然后一直P幀、B幀了。當運動變化多時,可能一個序列就比較短了,比如就包含一個I幀和3、4個P幀。
對三種幀的介紹
I幀
為了更好地理解I幀的概念,我羅列了兩種解釋:
- 幀內(nèi)編碼幀 ,I幀表示關鍵幀,你可以理解為這一幀畫面的完整保留;解碼時只需要本幀數(shù)據(jù)就可以完成(因為包含完整畫面)。
- 幀內(nèi)編碼幀 又稱intra picture,I 幀通常是每個 GOP(MPEG 所使用的一種視頻壓縮技術)的第一個幀,經(jīng)過適度地壓縮,做為隨機訪問的參考點,可以當成圖象。I幀可以看成是一個圖像經(jīng)過壓縮后的產(chǎn)物。
I幀的特點:
- 它是一個全幀壓縮編碼幀。它將全幀圖像信息進行JPEG壓縮編碼及傳輸
- 解碼時僅用I幀的數(shù)據(jù)就可重構完整圖像
- I幀描述了圖像背景和運動主體的詳情
- I幀不需要參考其他畫面而生成
- I幀是P幀和B幀的參考幀(其質(zhì)量直接影響到同組中以后各幀的質(zhì)量)
- I幀是幀組GOP的基礎幀(第一幀),在一組中只有一個I幀
- I幀不需要考慮運動矢量
- I幀所占數(shù)據(jù)的信息量比較大
P幀
為了更好地理解P幀的概念,我也羅列了兩種解釋:
- 前向預測編碼幀。P幀表示的是這一幀跟之前的一個關鍵幀(或P幀)的差別,解碼時需要用之前緩存的畫面疊加上本幀定義的差別,生成最終畫面。(也就是差別幀,P幀沒有完整畫面數(shù)據(jù),只有與前一幀的畫面差別的數(shù)據(jù))
- 前向預測編碼幀 又稱predictive-frame,通過充分將低于圖像序列中前面已編碼幀的時間冗余信息來壓縮傳輸數(shù)據(jù)量的編碼圖像,也叫預測幀
P幀的預測與重構:P幀是以I幀為參考幀,在I幀中找出P幀“某點”的預測值和運動矢量,取預測差值和運動矢量一起傳送。在接收端根據(jù)運動矢量從I幀中找出P幀“某點”的預測值并與差值相加以得到P幀“某點”樣值,從而可得到完整的P幀。
P幀特點:
- P幀是I幀后面相隔1~2幀的編碼幀
- P幀采用運動補償?shù)姆椒▊魉退c前面的I或P幀的差值及運動矢量(預測誤差)
- 解碼時必須將I幀中的預測值與預測誤差求和后才能重構完整的P幀圖像
- P幀屬于前向預測的幀間編碼。它只參考前面最靠近它的I幀或P幀
- P幀可以是其后面P幀的參考幀,也可以是其前后的B幀的參考幀
- 由于P幀是參考幀,它可能造成解碼錯誤的擴散
- 由于是差值傳送,P幀的壓縮比較高
B幀
為了更好地理解P幀的概念,我依然羅列了兩種解釋:
- 雙向預測內(nèi)插編碼幀。B幀是雙向差別幀,也就是B幀記錄的是本幀與前后幀的差別(具體比較復雜,有4種情況,但我這樣說簡單些),換言之,要解碼B幀,不僅要取得之前的緩存畫面,還要解碼之后的畫面,通過前后畫面的與本幀數(shù)據(jù)的疊加取得最終的畫面。B幀壓縮率高,但是解碼時CPU會比較累。
- 雙向預測內(nèi)插編碼幀 又稱bi-directional interpolated prediction frame,既考慮與源圖像序列前面已編碼幀,也顧及源圖像序列后面已編碼幀之間的時間冗余信息來壓縮傳輸數(shù)據(jù)量的編碼圖像,也叫雙向預測幀;
B幀的預測與重構: B幀以前面的I或P幀和后面的P幀為參考幀,“找出”B幀“某點”的預測值和兩個運動矢量,并取預測差值和運動矢量傳送。接收端根據(jù)運動矢量在兩個參考幀中“找出(算出)”預測值并與差值求和,得到B幀“某點”樣值,從而可得到完整的B幀。
B幀的特點:
- B幀是由前面的I或P幀和后面的P幀來進行預測的
- B幀傳送的是它與前面的I或P幀和后面的P幀之間的預測誤差及運動矢量
- B幀是雙向預測編碼幀
- B幀壓縮比最高,因為它只反映丙參考幀間運動主體的變化情況,預測比較準確
- B幀不是參考幀,不會造成解碼錯誤的擴散
I、B、P各幀是根據(jù)壓縮算法的需要,是人為定義的,它們都是實實在在的物理幀。一般來說,I幀的壓縮率是7(跟JPG差不多),P幀是20,B幀可以達到50??梢娛褂肂幀能節(jié)省大量空間,節(jié)省出來的空間可以用來保存多一些I幀,這樣在相同碼率下,可以提供更好的畫質(zhì)。
對壓縮算法的說明
h264的壓縮方法:
- 分組:把幾幀圖像分為一組(GOP,也就是一個序列),為防止運動變化,幀數(shù)不宜取多。
- 定義幀:將每組內(nèi)各幀圖像定義為三種類型,即I幀、B幀和P幀;
- 預測幀:以I幀做為基礎幀,以I幀預測P幀,再由I幀和P幀預測B幀;
- 數(shù)據(jù)傳輸:最后將I幀數(shù)據(jù)與預測的差值信息進行存儲和傳輸。
幀內(nèi)(Intraframe)壓縮也稱為空間壓縮(Spatial compression)。當壓縮一幀圖像時,僅考慮本幀的數(shù)據(jù)而不考慮相鄰幀之間的冗余信息,這實際上與靜態(tài)圖像壓縮類似。幀內(nèi)一般采用有損壓縮算法,由于幀內(nèi)壓縮是編碼一個完整的圖像,所以可以獨立的解碼、顯示。幀內(nèi)壓縮一般達不到很高的壓縮,跟編碼jpeg差不多。
幀間(Interframe)壓縮的原理是:相鄰幾幀的數(shù)據(jù)有很大的相關性,或者說前后兩幀信息變化很小的特點。也即連續(xù)的視頻其相鄰幀之間具有冗余信息,根據(jù)這一特性,壓縮相鄰幀之間的冗余量就可以進一步提高壓縮量,減小壓縮比。幀間壓縮也稱為時間壓縮(Temporal compression),它通過比較時間軸上不同幀之間的數(shù)據(jù)進行壓縮。幀間壓縮一般是無損的。幀差值(Frame differencing)算法是一種典型的時間壓縮法,它通過比較本幀與相鄰幀之間的差異,僅記錄本幀與其相鄰幀的差值,這樣可以大大減少數(shù)據(jù)量。
順便說下有損(Lossy )壓縮和無損(Lossy less)壓縮。無損壓縮也即壓縮前和解壓縮后的數(shù)據(jù)完全一致。多數(shù)的無損壓縮都采用RLE行程編碼算法。有損壓縮意味著解壓縮后的數(shù)據(jù)與壓縮前的數(shù)據(jù)不一致。在壓縮的過程中要丟失一些人眼和人耳所不敏感的圖像或音頻信息,而且丟失的信息不可恢復。幾乎所有高壓縮的算法都采用有損壓縮,這樣才能達到低數(shù)據(jù)率的目標。丟失的數(shù)據(jù)率與壓縮比有關,壓縮比越小,丟失的數(shù)據(jù)越多,解壓縮后的效果一般越差。此外,某些有損壓縮算法采用多次重復壓縮的方式,這樣還會引起額外的數(shù)據(jù)丟失。
三種幀的不同
- I frame:自身可以通過視頻解壓算法解壓成一張單獨的完整的圖片。
- P frame:需要參考其前面的一個I frame 或者B frame來生成一張完整的圖片。
- B frame:則要參考其前一個I或者P幀及其后面的一個P幀來生成一張完整的圖片。
- 兩個I frame之間形成一個GOP,在x264中同時可以通過參數(shù)來設定bf的大小,即:I 和p或者兩個P之間B的數(shù)量。
- 通過上述基本可以說明如果有B frame 存在的情況下一個GOP的最后一個frame一定是P.
DTS和PTS的不同
概念
DTS(Decoding Time Stamp) : 即解碼時間戳,是解碼器進行解碼時相對于SCR(系統(tǒng)參考時間)的時間戳。它主要標識讀入內(nèi)存的bit流在什么時候開始送入解碼器中進行解碼。
PTS(Presentation Time Stamp) : 即顯示時間戳,是顯示幀時相對于SCR的時間戳。它主要是度量解碼后的視頻什么時候被顯示出來。
DTS主要用于視頻的解碼,在解碼階段使用.PTS主要用于視頻的同步和輸出.在display的時候使用.在沒有B frame的情況下.DTS和PTS的輸出順序是一樣的。
例子:
下面給出一個GOP為15的例子,其解碼的參照frame及其解碼的順序都在里面:

如上圖:I frame 的解碼不依賴于任何的其它的幀.而p frame的解碼則依賴于其前面的I frame或者P frame.B frame的解碼則依賴于其前的最近的一個I frame或者P frame 及其后的最近的一個P frame.