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