H264 编码基本原理
1 H264 簡介
H.264,同時也是 MPEG-4 第十部分,是由 ITU-T 視頻編碼專家組(VCEG)和 ISO/IEC 動態(tài)圖像專家組(MPEG)聯(lián)合組成的聯(lián)合視頻組(JVT,Joint Video Team)提出的高度壓縮數(shù)字視頻編解碼器標(biāo)準(zhǔn)。這個標(biāo)準(zhǔn)通常被稱之為 H.264/AVC(或者 AVC/H.264 或者 H.264/MPEG-4 AVC 或 MPEG-4/H.264 AVC)。是一種面向塊,基于運動補償?shù)囊曨l編碼標(biāo)準(zhǔn)。
視頻編碼其本質(zhì)就是將數(shù)據(jù)壓縮,主要是去除冗余信息(包括空間上的冗余信息和時間上的冗余信息),從而實現(xiàn)數(shù)據(jù)量的壓縮。
- 空間冗余: 在同一圖像(幀)內(nèi),相近像素之間的差別很小(甚至是相同的),所以就可以用一個特定大小的像素矩陣來表示相鄰的像素。
- 時間冗余: 視頻中連續(xù)的圖像(幀)之間,其中發(fā)生變化的像素占整張圖像像素的比例極其微小,所以就可以用其中一幀來表示相鄰的幀來減少帶寬消耗。
- 編碼冗余: 不同像素出現(xiàn)的概率不同,所以就可以為出現(xiàn)概率高的像素分配盡量少的字節(jié),對出現(xiàn)概率低的像素分配盡量多的字節(jié)。
- 視覺冗余:人眼對很多像素顏色不敏感,所以就可以丟棄這些冗余的信息而并不影響人眼觀看的效果。
- 知識冗余:有許多圖像的理解與某些基礎(chǔ)知識有相當(dāng)大的相關(guān)性。例如,人臉的圖像有固定的結(jié)構(gòu),嘴的上方有鼻子,鼻子的上方有眼睛,鼻子位于正面圖像的中線上等等。這類規(guī)律性的結(jié)構(gòu)可由先驗知識和背景知識得到,我們稱此類冗余為知識冗余。根據(jù)已有知識,對某些圖像中所包含的物體,可以構(gòu)造其基本模型,并創(chuàng)建對應(yīng)各種特征的圖像庫,進(jìn)而圖像的存儲只需要保存一些特征參數(shù),從而可以大大減少數(shù)據(jù)量。
用一個簡單的例子來說明編碼的必要性:
當(dāng)你此刻顯示器正在播放一個視頻,分辨率是1280*720,幀率是25,那么一秒所產(chǎn)生正常的數(shù)據(jù)大小為:
1280*720(位像素)*25(幀) / 8(1字節(jié)8位)(轉(zhuǎn)換結(jié)果:B) / 1024(轉(zhuǎn)換結(jié)果:KB) / 1024
(轉(zhuǎn)換結(jié)果:MB) = 2.74MB
那么90分鐘的電影就要14.8GB,這個數(shù)據(jù)量顯然在當(dāng)前網(wǎng)絡(luò)下是不現(xiàn)實的。
2 H264 功能結(jié)構(gòu)
在 H.264/AVC 視頻編碼標(biāo)準(zhǔn)中,整個系統(tǒng)框架劃分為如下兩個層面:
- 視頻編碼層(Video Coding Layer,VCL):VCL 數(shù)據(jù)即被壓縮編碼后的視頻數(shù)據(jù)序列,負(fù)責(zé)有效表示視頻數(shù)據(jù)的內(nèi)容,主要包括幀內(nèi)預(yù)測,幀間預(yù)測、變換量化、熵編碼等壓縮單元。
- 網(wǎng)絡(luò)抽象層(Network Abstraction Layer,NAL):負(fù)責(zé)將 VCL 數(shù)據(jù)封裝到 NAL 單元中,并提供頭信息,以保證數(shù)據(jù)適合各種信道和存儲介質(zhì)上的傳輸。
如圖所示:
因此平時每幀數(shù)據(jù)就是一個 NAL 單元。NAL 單元的實際格式如下:
每個 NAL 單元都是由 1 字節(jié) NAL header 和 若干整數(shù)字節(jié)的原始字節(jié)序列負(fù)荷(RBSP, Raw Byte Sequence Payload) 構(gòu)成。
3 H264 幀類型
H264 結(jié)構(gòu)中,一個視頻圖像編碼后的數(shù)據(jù)叫做一幀,一幀由一個片(slice)或多個片組成,一個片由一個或多個宏塊(MB)組成,一個宏塊由16x16的 yuv 數(shù)據(jù)組成。宏塊作為 H264 編碼的基本單位。
經(jīng)過壓縮后的幀分為:I幀,P幀 和 B幀:
- I 幀 :關(guān)鍵幀,采用幀內(nèi)壓縮技術(shù)。你可以理解為這一幀畫面的完整保留,解碼時只需要本幀數(shù)據(jù)就可以完成(因為包含完整畫面)。
- P 幀 :向前參考幀,在壓縮時,只參考前面已經(jīng)處理的幀。采用幀間壓縮技術(shù)。P 幀表示的是這一幀跟之前的一個關(guān)鍵幀(或 P 幀)的差別,解碼時需要用之前緩存的畫面疊加上本幀定義的差別,生成最終畫面。(也就是差別幀,P 幀沒有完整畫面數(shù)據(jù),只有與前一幀的畫面差別的數(shù)據(jù))。
- B 幀 :雙向參考幀,在壓縮時,它即參考前而的幀,又參考它后面的幀。采用幀間壓縮技術(shù)。B 幀記錄的是本幀與前后幀的差別,換言之,要解碼 B 幀,不僅要取得之前的緩存畫面,還要解碼之后的畫面,通過前后畫面的與本幀數(shù)據(jù)的疊加取得最終的畫面。B 幀壓縮率高,但是解碼時 CPU 工作量會比較大。
兩個 I 幀之間是一個圖像序列,即 GOP,在一個圖像序列中只有一個I幀。
如下圖所示:
當(dāng)運動變化比較少時,一個序列可以很長,因為運動變化少就代表圖像畫面的內(nèi)容變動很小,所以就可以編一個 I 幀,然后一直 P 幀、B 幀了。當(dāng)運動變化多時,可能一個序列就比較短了。
還有一個概念是,IDR幀:
一個序列的第一個圖像叫做 IDR 圖像(立即刷新圖像),IDR 圖像都是 I 幀圖像。H.264 引入 IDR 圖像是為了解碼的重同步,當(dāng)解碼器解碼到 IDR 圖像時,立即將參考幀隊列清空,將已解碼的數(shù)據(jù)全部輸出或拋棄,重新查找參數(shù)集,開始一個新的序列。這樣,如果前一個序列出現(xiàn)重大錯誤,在這里可以獲得重新同步的機會。IDR 圖像之后的圖像永遠(yuǎn)不會使用 IDR 之前的圖像的數(shù)據(jù)來解碼。IDR 圖像一定是 I 圖像,但 I 圖像不一定是 IDR 圖像。一個序列中可以有很多的I圖像,I 圖像之后的圖像可以引用 I 圖像之間的圖像做運動參考。
還有一點注意的,對于 IDR 幀來說,在 IDR 幀之后的所有幀都不能引用任何 IDR 幀之前的幀的內(nèi)容,與此相反,對于普通的 I 幀來說,位于其之后的 B幀 和 P 幀可以引用位于普通 I 幀之前的 I 幀。從隨機存取的視頻流中,播放器永遠(yuǎn)可以從一個 IDR 幀播放,因為在它之后沒有任何幀引用之前的幀。但是,不能在一個沒有 IDR 幀的視頻中從任意點開始播放,因為后面的幀總是會引用前面的幀。
I、B、P 各幀是根據(jù)壓縮算法的需要,是人為定義的,它們都是實實在在的物理幀。一般來說,I 幀的壓縮率是7(跟JPG差不多),P 幀是20,B 幀可以達(dá)到50。可見使用 B 幀能節(jié)省大量空間,節(jié)省出來的空間可以用來保存多一些 I 幀,這樣在相同碼率下,可以提供更好的畫質(zhì)。
正因為有 B 幀這樣的雙向預(yù)測幀的存在,某一幀的解碼序列和實際的顯示序列是不一樣的。如下圖所示:
DTS: (Decode Time Stamp) 用于視頻的解碼序列
PTS: (Presentation Time Stamp)用于視頻的顯示序列。
4 H264 編碼原理
H264 采用的核心壓縮算法是幀內(nèi)壓縮和幀間壓縮,幀內(nèi)壓縮是生成 I 幀的算法,幀間壓縮是生成 B 幀和 P 幀的算法。
- 幀內(nèi)(Intraframe)壓縮:也稱為空間壓縮(Spatialcompression)。當(dāng)壓縮一幀圖像時,僅考慮本幀的數(shù)據(jù)而不考慮相鄰幀之間的冗余信息,這實際上與靜態(tài)圖像壓縮類似。幀內(nèi)一般采用有損壓縮算法,由于幀內(nèi)壓縮是編碼一個完整的圖像,所以可以獨立的解碼、顯示。幀內(nèi)壓縮一般達(dá)不到很高的壓縮,跟編碼 JPEG 差不多。
- 幀間(Interframe)壓縮:也稱為時間壓縮(Temporalcompression),它通過比較時間軸上不同幀之間的數(shù)據(jù)進(jìn)行壓縮。幀間壓縮一般是無損的。幀差值(Framedifferencing)算法是一種典型的時間壓縮法,相鄰幾幀的數(shù)據(jù)有很大的相關(guān)性,它通過比較本幀與相鄰幀之間的差異,僅記錄本幀與其相鄰幀的差值,這樣可以大大減少數(shù)據(jù)量。
下面就簡單描述下 H264 壓縮數(shù)據(jù)的過程。通過攝像頭采集到的視頻幀(按每秒 30 幀算),被送到 H264 編碼器的緩沖區(qū)中。編碼器先要為每一幅圖片劃分宏塊。
以下面這張圖為例:
劃分宏塊
H264 默認(rèn)是使用 16X16 大小的區(qū)域作為一個宏塊,也可以劃分成 8X8 大小。
劃分好宏塊后,計算宏塊的象素值。
以此類推,計算一幅圖像中每個宏塊的像素值,所有宏塊都處理完后如下面的樣子。
劃分子塊
H264 對比較平坦的圖像使用 16X16 大小的宏塊。但為了更高的壓縮率,還可以在 16X16 的宏塊上更劃分出更小的子塊。子塊的大小可以是 8X16、 16X8、 8X8、 4X8、 8X4、 4X4非常的靈活。
上幅圖中,紅框內(nèi)的 16X16 宏塊中大部分是藍(lán)色背景,而三只鷹的部分圖像被劃在了該宏塊內(nèi),為了更好的處理三只鷹的部分圖像,H264就在 16X16 的宏塊內(nèi)又劃分出了多個子塊。
這樣再經(jīng)過幀內(nèi)壓縮,可以得到更高效的數(shù)據(jù)。下圖是分別使用 mpeg-2 和 H264 對上面宏塊進(jìn)行壓縮后的結(jié)果。其中左半部分為 MPEG-2 子塊劃分后壓縮的結(jié)果,右半部分為 H264 的子塊劃壓縮后的結(jié)果,可以看出 H264 的劃分方法更具優(yōu)勢。
宏塊劃分好后,就可以對 H264 編碼器緩存中的所有圖片進(jìn)行分組了。
幀分組
對于視頻數(shù)據(jù)主要有兩類數(shù)據(jù)冗余,一類是時間上的數(shù)據(jù)冗余,另一類是空間上的數(shù)據(jù)冗余。其中時間上的數(shù)據(jù)冗余是最大的。為什么這么說呢?假設(shè)攝像頭每秒抓取30幀,這30幀的數(shù)據(jù)大部分情況下都是相關(guān)聯(lián)的。也有可能不止30幀的的數(shù)據(jù),可能幾十幀,上百幀的數(shù)據(jù)都是關(guān)聯(lián)特別密切的。
對于這些關(guān)聯(lián)特別密切的幀,其實我們只需要保存一幀的數(shù)據(jù),其它幀都可以通過這一幀再按某種規(guī)則預(yù)測出來,所以說視頻數(shù)據(jù)在時間上的冗余是最多的。
為了達(dá)到相關(guān)幀通過預(yù)測的方法來壓縮數(shù)據(jù),就需要將視頻幀進(jìn)行分組。那么如何判定某些幀關(guān)系密切,可以劃為一組呢?我們來看一下例子,下面是捕獲的一組運動的臺球的視頻幀,臺球從右上角滾到了左下角。
H264 編碼器會按順序,每次取出兩幅相鄰的幀進(jìn)行宏塊比較,計算兩幀的相似度。如下圖:
通過宏塊掃描與宏塊搜索可以發(fā)現(xiàn)這兩個幀的關(guān)聯(lián)度是非常高的。進(jìn)而發(fā)現(xiàn)這一組幀的關(guān)聯(lián)度都是非常高的。因此,上面這幾幀就可以劃分為一組。其算法是:在相鄰幾幅圖像畫面中,一般有差別的像素只有10%以內(nèi)的點,亮度差值變化不超過2%,而色度差值的變化只有1%以內(nèi),我們認(rèn)為這樣的圖可以分到一組。
在這樣一組幀中,經(jīng)過編碼后,我們只保留第一帖的完整數(shù)據(jù),其它幀都通過參考上一幀計算出來。我們稱第一幀為 IDR/I 幀,其它幀我們稱為 P/B 幀,這樣編碼后的數(shù)據(jù)幀組我們稱為 GOP。
運動估計與補償
在 H264 編碼器中將幀分組后,就要計算幀組內(nèi)物體的運動矢量了。還以上面運動的臺球視頻幀為例,我們來看一下它是如何計算運動矢量的。
H264 編碼器首先按順序從緩沖區(qū)頭部取出兩幀視頻數(shù)據(jù),然后進(jìn)行宏塊掃描。當(dāng)發(fā)現(xiàn)其中一幅圖片中有物體時,就在另一幅圖的鄰近位置(搜索窗口中)進(jìn)行搜索。如果此時在另一幅圖中找到該物體,那么就可以計算出物體的運動矢量了。下面這幅圖就是搜索后的臺球移動的位置。
通過上圖中臺球位置相差,就可以計算出臺球運動的方向和距離。H264 依次把每一幀中球移動的距離和方向都記錄下來就成了下面的樣子。
運動矢量計算出來后,將相同部分(也就是綠色部分)減去,就得到了補償數(shù)據(jù)。我們最終只需要將補償數(shù)據(jù)進(jìn)行壓縮保存,以后在解碼時就可以恢復(fù)原圖了。壓縮補償后的數(shù)據(jù)只需要記錄很少的一點數(shù)據(jù)。如下所示:
我們把運動矢量與補償稱為幀間壓縮技術(shù),它解決的是視頻幀在時間上的數(shù)據(jù)冗余。除了幀間壓縮,幀內(nèi)也要進(jìn)行數(shù)據(jù)壓縮,幀內(nèi)數(shù)據(jù)壓縮解決的是空間上的數(shù)據(jù)冗余。下面我們就來介紹一下幀內(nèi)壓縮技術(shù)。
幀內(nèi)預(yù)測
人眼對圖象都有一個識別度,對低頻的亮度很敏感,對高頻的亮度不太敏感。所以基于一些研究,可以將一幅圖像中人眼不敏感的數(shù)據(jù)去除掉。這樣就提出了幀內(nèi)預(yù)測技術(shù)。
H264 的幀內(nèi)壓縮與 JPEG 很相似。一幅圖像被劃分好宏塊后,對每個宏塊可以進(jìn)行 9 種模式的預(yù)測。找出與原圖最接近的一種預(yù)測模式。
下面這幅圖是對整幅圖中的每個宏塊進(jìn)行預(yù)測的過程。
幀內(nèi)預(yù)測后的圖像與原始圖像的對比如下:
然后,將原始圖像與幀內(nèi)預(yù)測后的圖像相減得殘差值。
再將我們之前得到的預(yù)測模式信息一起保存起來,這樣我們就可以在解碼時恢復(fù)原圖了。效果如下:
經(jīng)過幀內(nèi)與幀間的壓縮后,雖然數(shù)據(jù)有大幅減少,但還有優(yōu)化的空間。
對殘差數(shù)據(jù)做 DCT 變換
可以將殘差數(shù)據(jù)做整數(shù)離散余弦變換,去掉數(shù)據(jù)的相關(guān)性,進(jìn)一步壓縮數(shù)據(jù)。如下圖所示,左側(cè)為原數(shù)據(jù)的宏塊,右側(cè)為計算出的殘差數(shù)據(jù)的宏塊。
將殘差數(shù)據(jù)宏塊數(shù)字化后如下圖所示:
將殘差數(shù)據(jù)宏塊進(jìn)行 DCT 轉(zhuǎn)換。
去掉相關(guān)聯(lián)的數(shù)據(jù)后,我們可以看出數(shù)據(jù)被進(jìn)一步壓縮了。
做完 DCT 變換后,還不夠,還要進(jìn)行熵編碼。
熵編碼(CABAC)
上面的幀內(nèi)壓縮是屬于有損壓縮技術(shù),也就是說圖像被壓縮后,無法完全復(fù)原。而熵編碼壓縮是一種無損壓縮,其實現(xiàn)原理是使用新的編碼來表示輸入的數(shù)據(jù),給高頻的詞一個短碼,給低頻詞一個長碼,從而達(dá)到壓縮的效果。常用的熵編碼有游程編碼,哈夫曼編碼和 CAVLC 編碼等。
在 H.264/MPEG-4 AVC 中使用的熵編碼算法是 CABAC(ContextAdaptive Binary Arithmatic Coding)。CABAC 在不同的上下文環(huán)境中使用不同的概率模型來編碼。其編碼過程大致是這樣:首先,將欲編碼的符號用二進(jìn)制 bit 表示;然后對于每個 bit,編碼器選擇一個合適的概率模型,并通過相鄰元素的信息來優(yōu)化這個概率模型;最后,使用算術(shù)編碼壓縮數(shù)據(jù)。
MPEG-2 中使用的 VLC 也是這種算法,我們以 A-Z 作為例子,A屬于高頻數(shù)據(jù),Z屬于低頻數(shù)據(jù)。看看它是如何做的。
CABAC 也是給高頻數(shù)據(jù)短碼,給低頻數(shù)據(jù)長碼。同時還會根據(jù)上下文相關(guān)性進(jìn)行壓縮,這種方式又比 VLC 高效很多。其效果如下:
現(xiàn)在將 A-Z 換成視頻幀,它就成了下面的樣子。
從上面這張圖中明顯可以看出采用 CACBA 的無損壓縮方案要比 VLC 高效的多。
以上就是整個編碼流程,生成的數(shù)據(jù)就是壓縮后的可傳輸?shù)谋忍亓鳌=獯a過程則與之相反。
總結(jié)
以上是生活随笔為你收集整理的H264 编码基本原理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 记录一下自己刷题的错题
- 下一篇: 同轴式二级圆柱齿轮减速器的设计(论文+D