本節(jié)內(nèi)容整理自:H264–1–編碼原理以及I幀B幀P幀戴已,作者:dxpqxb
H264是一種高壓縮率的編碼標(biāo)準(zhǔn)固额,如何壓縮嘞头谜?一般的視頻采集都是25幀/秒狐蜕,也就是每秒截圖25次宠纯,其實(shí)每一張圖片的內(nèi)容都相差不大,壓縮的辦法就是利用算法层释,只將每張圖片變動(dòng)差異化的部分保存下來(lái)婆瓜,這樣視頻文件就小多了。
三種幀
在H264協(xié)議里定義了三種幀湃累,完整編碼的幀叫I幀勃救,參考之前的I幀生成的只包含差異部分編碼的幀叫P幀,還有一種參考前后的幀編碼的幀叫B幀治力。
H264采用的核心算法是幀內(nèi)壓縮和幀間壓縮蒙秒,幀內(nèi)壓縮是生成I幀的算法,幀間壓縮是生成B幀和P幀的算法宵统。
I幀:幀內(nèi)編碼幀 晕讲,I幀表示關(guān)鍵幀覆获,你可以理解為這一幀畫(huà)面的完整保留;解碼時(shí)只需要本幀數(shù)據(jù)就可以完成(因?yàn)榘暾?huà)面)
P幀:前向預(yù)測(cè)編碼幀瓢省。P幀表示的是這一幀跟之前的一個(gè)關(guān)鍵幀(或P幀)的差別弄息,解碼時(shí)需要用之前緩存的畫(huà)面疊加上本幀定義的差別,生成最終畫(huà)面勤婚。(也就是差別幀摹量,P幀沒(méi)有完整畫(huà)面數(shù)據(jù),只有與前一幀的畫(huà)面差別的數(shù)據(jù))
B幀:雙向預(yù)測(cè)內(nèi)插編碼幀馒胆。B幀是雙向差別幀缨称,也就是B幀記錄的是本幀與前后幀的差別(具體比較復(fù)雜,有4種情況祝迂,但我這樣說(shuō)簡(jiǎn)單些)睦尽,換言之,要解碼B幀型雳,不僅要取得之前的緩存畫(huà)面当凡,還要解碼之后的畫(huà)面,通過(guò)前后畫(huà)面的與本幀數(shù)據(jù)的疊加取得最終的畫(huà)面纠俭。B幀壓縮率高沿量,但是解碼時(shí)CPU會(huì)比較累。
序列的概念
在H264中圖像以序列為單位進(jìn)行組織柑晒,一個(gè)序列是一段圖像編碼后的數(shù)據(jù)流欧瘪,以I幀開(kāi)始,到下一個(gè)I幀結(jié)束匙赞。
一個(gè)序列的第一個(gè)圖像叫做 IDR 圖像(立即刷新圖像)佛掖,IDR 圖像都是 I 幀圖像。H.264 引入 IDR 圖像是為了解碼的重同步涌庭,當(dāng)解碼器解碼到 IDR 圖像時(shí)芥被,立即將參考幀隊(duì)列清空,將已解碼的數(shù)據(jù)全部輸出或拋棄坐榆,重新查找參數(shù)集拴魄,開(kāi)始一個(gè)新的序列。這樣席镀,如果前一個(gè)序列出現(xiàn)重大錯(cuò)誤匹中,在這里可以獲得重新同步的機(jī)會(huì)。IDR圖像之后的圖像永遠(yuǎn)不會(huì)使用IDR之前的圖像的數(shù)據(jù)來(lái)解碼豪诲。
一個(gè)序列就是一段內(nèi)容差異不太大的圖像編碼后生成的一串?dāng)?shù)據(jù)流顶捷。當(dāng)運(yùn)動(dòng)變化比較少時(shí),一個(gè)序列可以很長(zhǎng)屎篱,因?yàn)檫\(yùn)動(dòng)變化少就代表圖像畫(huà)面的內(nèi)容變動(dòng)很小服赎,所以就可以編一個(gè)I幀葵蒂,然后一直P(pán)幀、B幀了重虑。當(dāng)運(yùn)動(dòng)變化多時(shí)践付,可能一個(gè)序列就比較短了,比如就包含一個(gè)I幀和3缺厉、4個(gè)P幀永高。
片、場(chǎng)芽死、幀乏梁、片的概念
H264結(jié)構(gòu)中,一個(gè)視頻圖像編碼后的數(shù)據(jù)叫做一幀关贵,一幀由一個(gè)片(slice)或多個(gè)片組成,一個(gè)片由一個(gè)或多個(gè)宏塊(MB)組成卖毁,一個(gè)宏塊由16×16的yuv數(shù)據(jù)組成揖曾。宏塊作為H264編碼的基本單位。
1幀 = n個(gè)片
1片 = n個(gè)宏塊
1宏塊 = 16x16yuv數(shù)據(jù)
場(chǎng)和幀:視頻的一場(chǎng)或一幀可用來(lái)產(chǎn)生一個(gè)編碼圖像亥啦。在電視中炭剪,為減少大面積閃爍現(xiàn)象,把一幀分成兩個(gè)隔行的場(chǎng)翔脱。
宏塊:一個(gè)編碼圖像通常劃分成若干宏塊組成奴拦,一個(gè)宏塊由一個(gè)16×16亮度像素和附加的一個(gè)8×8 Cb和一個(gè)8×8 Cr彩色像素塊組成。
片:每個(gè)圖象中届吁,若干宏塊被排列成片的形式错妖。片分為I片、B片疚沐、P片和其他一些片暂氯。
- I片只包含I宏塊,P片可包含P和I宏塊亮蛔,而B(niǎo)片可包含B和I宏塊痴施。
- I宏塊利用從當(dāng)前片中已解碼的像素作為參考進(jìn)行幀內(nèi)預(yù)測(cè)。
- P宏塊利用前面已編碼圖象作為參考圖象進(jìn)行幀內(nèi)預(yù)測(cè)究流。
- B宏塊則利用雙向的參考圖象(前一幀和后一幀)進(jìn)行幀內(nèi)預(yù)測(cè)辣吃。
數(shù)據(jù)結(jié)構(gòu)
H264編碼后的數(shù)據(jù)分為兩層:
- VCL(video coding layer)視頻編碼層:它是對(duì)核心算法引擎,塊芬探,宏塊及片的語(yǔ)法級(jí)別的定義神得,最終輸出編碼完的數(shù)據(jù) SODB。
- NAL(network abstraction layer)網(wǎng)絡(luò)提取層:定義片級(jí)以上的語(yǔ)法級(jí)別(如序列參數(shù)集和圖像參數(shù)集灯节,針對(duì)網(wǎng)絡(luò)傳輸)循头,同時(shí)支持以下功能:獨(dú)立片解碼绵估,起始碼唯一保證,SEI以及流格式編碼數(shù)據(jù)傳送卡骂,NAL層將SODB打包成RBSP然后加上NAL頭国裳,組成一個(gè)NALU(NAL單元)。
分層的好處顯而易見(jiàn)全跨,對(duì)于RTMP傳輸數(shù)據(jù)缝左,我們只需了解NAL層就足夠了。
H264在網(wǎng)絡(luò)傳輸?shù)氖荖ALU浓若,NALU的結(jié)構(gòu)是:NAL頭+RBSP渺杉,如圖所示:
從前面的分析我們知道,VCL層出來(lái)的是編碼完的視頻幀數(shù)據(jù)挪钓,這些幀可能是I是越、B、P幀碌上,而且這些幀可能屬于不同的序列倚评,再者同一個(gè)序列還有相對(duì)應(yīng)的一套序列參數(shù)集和圖片參數(shù)集等等,所以要完成視頻的解碼馏予,不僅需要傳輸VCL層編碼出來(lái)的視頻幀數(shù)據(jù)天梧,還需要傳輸序列參數(shù)集、圖像參數(shù)集等數(shù)據(jù)霞丧。
NALU頭用來(lái)標(biāo)識(shí)后面的RBSP是什么類型的數(shù)據(jù)呢岗,他是否會(huì)被其他幀參考以及網(wǎng)絡(luò)傳輸是否有錯(cuò)誤。
RBSP用來(lái)存放下表中的一種:
RBSP類型 | 所寫(xiě) | 描述 |
---|---|---|
參數(shù)集 | PS | 序列的全局信息蛹尝,如圖像尺寸后豫,視頻格式等 |
增強(qiáng)信息 | SEI | 視頻序列解碼的增強(qiáng)信息 |
圖像界定符 | PD | 視頻圖像的邊界 |
編碼片 | SLICE | 編碼片的頭信息和數(shù)據(jù) |
數(shù)據(jù)分割 | DP | 片層的數(shù)據(jù),用于錯(cuò)誤恢復(fù)解碼 |
序列結(jié)束符 | 表明一個(gè)序列的結(jié)束箩言,下一個(gè)圖像為IDR圖像 | |
流結(jié)束符 | 表明該流中已沒(méi)有圖像 | |
填充數(shù)據(jù) | 亞元數(shù)據(jù)硬贯,用于填充字節(jié) |
其中參數(shù)集包括:序列參數(shù)集 SPS 和圖像參數(shù)集 PPS
- SPS 包含的是針對(duì)一連續(xù)編碼視頻序列的參數(shù),如標(biāo)識(shí)符 seq_parameter_set_id陨收、幀數(shù)及 POC 的約束饭豹、參考幀數(shù)目、解碼圖像尺寸和幀場(chǎng)編碼模式選擇標(biāo)識(shí)等等务漩。
- PPS 對(duì)應(yīng)的是一個(gè)序列中某一幅圖像或者某幾幅圖像拄衰,其參數(shù)如標(biāo)識(shí)符 pic_parameter_set_id、可選的 seq_parameter_set_id饵骨、熵編碼模式選擇標(biāo)識(shí)翘悉、片組數(shù)目、初始量化參數(shù)和去方塊濾波系數(shù)調(diào)整標(biāo)識(shí)等等居触。
這里 SPS 和 PPS 的含義可以不用深入追究妖混,需要明白的是老赤,在視頻發(fā)送時(shí),這兩個(gè)參數(shù)需要作為第一幀發(fā)送出去制市,這樣后邊的I抬旺、B、P 幀才能順利解碼播放祥楣。
數(shù)據(jù)分割:組成片的編碼數(shù)據(jù)存放在 3 個(gè)獨(dú)立的 DP(數(shù)據(jù)分割开财,A、B误褪、C)中责鳍,各自包含一個(gè)編碼片的子集。分割A包含片頭和片中每個(gè)宏塊頭數(shù)據(jù)兽间。分割B包含幀內(nèi)和 SI 片宏塊的編碼殘差數(shù)據(jù)历葛。分割 C包含幀間宏塊的編碼殘差數(shù)據(jù)。每個(gè)分割可放在獨(dú)立的 NAL 單元并獨(dú)立傳輸渡八。(這個(gè)還沒(méi)搞明白啃洋,先知道有這么回事)
轉(zhuǎn)載自 Tony's blog