視頻編碼最重要目的就是為了進(jìn)行數(shù)據(jù)壓縮,以此來降低數(shù)據(jù)傳輸和存儲的成本,用一個簡單的例子來說明視頻編碼的重要性。我們計(jì)算一段 10
秒鐘1080p
(1920*1080)、30fps
的 yuv420p
像素格式(每個像素占用1.5
字節(jié))原始視頻的體積:
1920 * 1080 * 30 * 10 * 1.5 = 933120000 字節(jié) ≈ 889.89MB
僅僅是一段 10
秒鐘的1080p
原始視頻的體積就達(dá)到了 889.89MB
,如果傳輸沒有壓縮的視頻數(shù)據(jù),1 秒鐘需要約 88.99MB
的帶寬,顯然這是一個很大的數(shù)據(jù)量,應(yīng)用于現(xiàn)在的網(wǎng)絡(luò),網(wǎng)絡(luò)壓力會很大。但是有了視頻編碼的存在,大幅的減少了視頻流所需要的比特,讓現(xiàn)在的網(wǎng)絡(luò)可以無壓力的播放,甚至在某些低碼率的情況下,我們依然可以看到高清的視頻。當(dāng)前視頻編碼標(biāo)準(zhǔn)很多,最主流的還是 H.264 編碼。
一、H.264簡介
國際上制定視頻編解碼技術(shù)的組織有兩個,一個是“國際電聯(lián)(ITU-T)”,它制定的標(biāo)準(zhǔn)有 H.261、H.263、H.263+ 等,另一個是“國際標(biāo)準(zhǔn)化組織(ISO)”它制定的標(biāo)準(zhǔn)有 MPEG-1、MPEG-2、MPEG-4 等。而 H.264 則是由兩個組織聯(lián)合組建的聯(lián)合視頻組(JVT)共同制定的新數(shù)字視頻編碼標(biāo)準(zhǔn),所以它既是 ITU-T 的 H.264,又是 ISO/IEC 的 MPEG-4 高級視頻編碼(Advanced Video Coding,AVC)的第 10 部分。
H.264 是迄今為止視頻錄制、壓縮和分發(fā)的最常用格式。截至 2019 年 9 月,已有 91% 的視頻開發(fā)人員使用了該格式。H.264 提供了明顯優(yōu)于以前任何標(biāo)準(zhǔn)的壓縮性能,在同樣的畫質(zhì)下,擁有更高的壓縮率(低碼率),同時擁有更好的網(wǎng)絡(luò)親和性,可適用于各種傳輸網(wǎng)絡(luò)。H.264 因其是藍(lán)光盤的其中一種編解碼標(biāo)準(zhǔn)而著名,所有藍(lán)光盤播放器都必須能解碼 H.264。
二、編碼過程及原理
H.264 的編程過程比較復(fù)雜,本文只介紹大體的框架和脈絡(luò),具體細(xì)節(jié)就不展開了。大體可以歸納為以下幾個主要步驟(如下圖):劃分幀類型、幀內(nèi)/幀間編碼、變換 + 量化、濾波、熵編碼。
1、劃分幀類型
視頻壓縮主要是壓縮視頻冗余數(shù)據(jù),對于視頻數(shù)據(jù)主要有兩類冗余數(shù)據(jù),一類是空間上的冗余,一類是時間上的冗余。其中時間上的冗余是最大的。為什么說時間上的冗余是最大的呢?我們使用 YuvEye 查看視頻的每一幀會發(fā)現(xiàn),有很多連續(xù)的幀是相似的(如下圖的 3853~3864 幀是非常相似的),連續(xù)相似的幀有可能有幾十幀,也有可能有幾百幀。對于這些連續(xù)相似的幀,其實(shí)我們只需要保存一幀數(shù)據(jù),其他幀可以通過這一幀按照某種規(guī)則預(yù)測出來,所以說視頻數(shù)據(jù)在時間上的冗余是最多的。
有統(tǒng)計(jì)結(jié)果表明,在連續(xù)的幾幀圖像中,一般只有10%以內(nèi)的像素有差別,亮度的差值變化不超過2%,而色度的差值變化只在1%以內(nèi)。為了達(dá)到連續(xù)相似的相關(guān)幀通過預(yù)測的方法來壓縮數(shù)據(jù),就需要將視頻幀進(jìn)行分組。那么如何對相似幀進(jìn)行分組呢?H.264 編碼器會按順序,每次取出兩幅相鄰的幀進(jìn)行宏塊比較,計(jì)算兩幀的相似度。通過宏塊掃描與宏塊搜索可以發(fā)現(xiàn)這兩個幀的關(guān)聯(lián)度是非常高的。進(jìn)而發(fā)現(xiàn)這一組幀的關(guān)聯(lián)度都是非常高的,這些幀就可以劃分到一個圖像群組,我們簡稱 GOP(Group Of Pictures)。
接下來就要對 GOP 中的每一幀確定一個類型,H.264 協(xié)議中定義了 I 幀
、P 幀
和 B 幀
共 3 種類型:
I 幀
(I Picture、I Frame、Intra Coded Picture),譯為:幀內(nèi)編碼圖像,也叫做關(guān)鍵幀(Keyframe),是視頻的第一幀,也是 GOP 的第一幀,一個 GOP 只有一個I 幀
。I 幀
是一種自帶全部信息的完整獨(dú)立幀,不會依賴其他幀的信息,也就是自我進(jìn)行參考的幀,可以簡單理解為一張靜態(tài)圖像。在編碼時對整幀圖像數(shù)據(jù)進(jìn)行編碼。在解碼時僅用當(dāng)前I 幀
的編碼數(shù)據(jù)就可以解碼出完整的圖像。
P 幀
(P Picture、P Frame、Predictive Coded Picture),譯為:預(yù)測編碼圖像。編碼時并不會對整幀圖像數(shù)據(jù)進(jìn)行編碼,以前面的 I 幀
或 P 幀
作為參考幀,只編碼當(dāng)前 P 幀
與參考幀的差異數(shù)據(jù)。解碼時需要先解碼出前面的參考幀,再結(jié)合差異數(shù)據(jù)解碼出當(dāng)前 P 幀
完整的圖像。在較早的視頻編碼標(biāo)準(zhǔn)(例如MPEG-2)中,P 幀
只能使用一個參考幀,而一些現(xiàn)代視頻編碼標(biāo)準(zhǔn)(比如 H.264),允許使用多個參考幀。
B 幀
(B Picture、B Frame、Bipredictive Coded Picture),譯為:前后預(yù)測編碼圖像。
編碼時并不會對整幀圖像數(shù)據(jù)進(jìn)行編碼,同時以前面、后面的 I 幀
或 P 幀
作為參考幀,只編碼當(dāng)前 B 幀
與前后參考幀的差異數(shù)據(jù),因?yàn)榭蓞⒖嫉膸兌嗔耍灾恍枰鎯Ω俚牟町悢?shù)據(jù)。解碼時需要先解碼出前后的參考幀,再結(jié)合差異數(shù)據(jù)解碼出當(dāng)前 B 幀
完整的圖像。
不難看出,編碼后的數(shù)據(jù)大小:I 幀
> P 幀
> B 幀
。
1.1、幀的編解碼順序
以下圖為例,在播放時站在用戶角度看到的幀的順序是 I0->B2->B3->P1->B5->B6->P4->B8->B9->I7->B11->B12->P10
。編碼時同樣首先編碼 I0
幀,按照顯示順序接下來應(yīng)該編碼 B2
幀,但是由于 B2
幀需要參考后面的 P1
幀,所以要優(yōu)先編碼 P1
幀,接下來才能編碼 B2
幀,然后是 B3
幀,再后面就是 P4
幀、B5
幀、B6
幀,緊接著由于 B8
幀和 B9
幀需要參考 GOP #1 的 I7
幀,在 B8
幀和 B9
幀編碼之前要先編碼 I7
幀,總結(jié)下來編碼的順序是 I0->P1->B2->B3->P4->B5->B6->I7->B8->B9->P10->B11->B12
。解碼順序和編碼順序是一樣的。
1.2、GOP 長度
GOP 的長度表示 GOP 的幀數(shù)。GOP 的長度需要控制在合理范圍,以平衡視頻質(zhì)量、視頻大小(網(wǎng)絡(luò)帶寬)和seek 效果(拖動、快進(jìn)的響應(yīng)速度)等。加大 GOP 長度有利于減小視頻文件大小,但也不宜設(shè)置過大,太大則會導(dǎo)致 GOP 后部幀的畫面失真,影響視頻質(zhì)量。由于 P 幀
、B 幀
的復(fù)雜度大于 I 幀
,GOP 值過大,過多的P 幀
、B 幀
會影響編碼效率,使編碼效率降低。如果設(shè)置過小的 GOP 值,視頻文件會比較大,則需要提高視頻的輸出碼率,以確保畫面質(zhì)量不會降低,故會增加網(wǎng)絡(luò)帶寬。GOP 長度也是影響視頻 seek 響應(yīng)速度的關(guān)鍵因素,seek 時播放器需要定位到離指定位置最近的前一個I 幀
,如果 GOP 太大意味著距離指定位置可能越遠(yuǎn)(需要解碼的參考幀就越多)、seek 響應(yīng)的時間(緩沖時間)也越長。
1.3、GOP 類型
GOP 又可以分為 Open(開放)、Closed(封閉)兩種。Open 類型:前一個 GOP 的 B 幀
可以參考下一個 GOP 的 I 幀
。Closed 類型:前一個 GOP 的 B 幀
不能參考下一個 GOP 的 I 幀
,并且 GOP 不能以 B 幀
結(jié)尾。
需要注意的是,由于 P 幀
、B 幀
都對前面的參考幀(P 幀
、I 幀
)有依賴性,因此,一旦前面的參考幀出現(xiàn)數(shù)據(jù)錯誤,就會導(dǎo)致后面的 P 幀
、B 幀
也出現(xiàn)數(shù)據(jù)錯誤,而且這種錯誤還會繼續(xù)向后傳播。對于普通的 I 幀
,其后的P 幀
和B 幀
可以參考該普通 I 幀
之前的其他 I 幀
。
在 Closed GOP 中,有一種特殊的 I 幀
,叫做 IDR 幀
(Instantaneous Decoder Refresh,譯為:即時解碼刷新)。在編碼解碼中為了方便,將 GOP 中首個 I 幀
要和其他I幀區(qū)別開,把第一個 I 幀
叫 IDR 幀
,這樣方便控制編碼和解碼流程,所以 IDR 幀
一定是 I 幀
,但 I 幀
不一定是 IDR 幀
。當(dāng)遇到 IDR 幀
時,會清空參考幀隊(duì)列。如果前一個序列出現(xiàn)重大錯誤,在這里可以獲得重新同步的機(jī)會,使錯誤不會繼續(xù)往下傳播。一個 IDR 幀
之后的所有幀,永遠(yuǎn)都不會參考該 IDR 幀之前的幀。視頻播放時,播放器一般都支持隨機(jī) seek(拖動)到指定位置,而播放器直接選擇到指定位置附近的 IDR 幀
進(jìn)行播放最為便捷,因?yàn)榭梢悦鞔_知道該 IDR 幀
之后的所有幀都不會參考其之前的其他 I 幀
,從而避免較為復(fù)雜的反向解析。
2、幀內(nèi)/幀間編碼
I 幀
采用的是幀內(nèi)(Intra Frame)編碼,處理的是空間冗余。P 幀
、B 幀
采用的是幀間(Inter Frame)編碼,處理的是時間冗余。
2.1、劃分宏塊
在進(jìn)行編碼之前,編碼器會通過算法將一張完整的幀切割成多個宏塊(Macroblock),然后逐塊進(jìn)行后續(xù)的壓縮處理。H.264 中的宏塊大小通常是 16x16
,宏塊是 H.264 中最大的塊。宏塊可以進(jìn)一步拆分為多個更小的變換塊(Transform blocks)、預(yù)測塊(Prediction blocks)。變換塊的尺寸有:16x16
、8x8
、4x4
。預(yù)測塊的尺寸有:16×16
、16×8
、8×16
、8×8
、8×4
、4×8
、4×4
。
2.2、幀內(nèi)編碼
幀內(nèi)編碼,也稱幀內(nèi)預(yù)測。 假設(shè)當(dāng)前的塊不在圖像邊緣,我們可以用上方相鄰塊邊界鄰近值作為基礎(chǔ)值,也就是上面一行中的每一個值,都垂直向下做拷貝,構(gòu)建出和源 YUV 塊一樣大小的預(yù)測塊,這種構(gòu)建預(yù)測塊的方式,我們叫做垂直預(yù)測模式,屬于幀內(nèi)預(yù)測模式的一種。緊接著,以 4x4
的預(yù)測塊為例,用源 YUV 的數(shù)據(jù)和預(yù)測 YUV 的數(shù)據(jù)做差值,得到殘差塊,這樣我們在碼流中,就直接傳輸當(dāng)前 4x4
塊的預(yù)測模式的標(biāo)志位和殘差數(shù)據(jù)就行,這樣極大地節(jié)省了碼流。編碼器會選取最佳預(yù)測模式,使預(yù)測幀更加接近原始幀,減少相互間的差異,提高編碼的壓縮效率。
與垂直預(yù)測模式相似的,還有水平預(yù)測模式、均值預(yù)測模式(也就是 4x4
的均值填充整個 4x4
)等 9 種可選的預(yù)測模式,:
2.3、幀間編碼
幀間編碼,也稱幀間預(yù)測,用到了運(yùn)動補(bǔ)償(Motion compensation)技術(shù)。編碼器利用塊匹配算法,嘗試在先前已編碼的幀(稱為參考幀)上搜索與正在編碼的塊相似的塊。如果編碼器搜索成功,則可以使用稱為運(yùn)動矢量的向量對塊進(jìn)行編碼,該向量指向匹配塊在參考幀處的位置。在大多數(shù)情況下,編碼器將成功執(zhí)行,但是找到的塊可能與它正在編碼的塊不完全匹配,這時編碼器將計(jì)算它們之間殘差值。這些殘差值稱為預(yù)測誤差,需要進(jìn)行變換并將其發(fā)送給編碼器。綜上所述,如果編碼器在參考幀上成功找到匹配塊,它將獲得指向匹配塊的運(yùn)動矢量和預(yù)測誤差。使用這兩個元素以及幀間預(yù)測模式標(biāo)志位,解碼器將能夠恢復(fù)該塊的原始像素。如果一切順利,該算法將能夠找到一個幾乎沒有預(yù)測誤差的匹配塊,因此,一旦進(jìn)行變換,運(yùn)動矢量加上預(yù)測誤差的總大小將小于原始編碼的大小。如果塊匹配算法未能找到合適的匹配,則預(yù)測誤差將是可觀的。因此,運(yùn)動矢量的總大小加上預(yù)測誤差將大于原始編碼。在這種情況下,編碼器將產(chǎn)生異常,并為該特定塊發(fā)送原始編碼。
3、變換 + 量化
把經(jīng)過預(yù)測后得到的殘差值經(jīng)過 DCT 變換(Discrete Cosine Transform,譯為離散余弦變換),目的是把直流和低頻(相對平坦,圖像或塊中大部分占比)能量集中在左上,高頻(細(xì)節(jié),圖像或塊中少部分占比)能量集中在右下。DCT 本身雖然沒有壓縮作用,僅僅是去掉了數(shù)據(jù)的相關(guān)性,卻為后面進(jìn)一步壓縮數(shù)據(jù)時的取舍,奠定了必不可少的基礎(chǔ)。
變換后直流分量 DC 都集中在左上角,是整塊像素的求和的均值。由于人眼對高頻信號不敏感,我們可以定義這樣一個變量 QP = 5,將變換塊中所有的值都除以 QP,這樣做進(jìn)一步節(jié)省傳輸碼流位寬,同時主要去掉了高頻分量的值,在解碼端只需要將變換塊中所有的值在乘 QP 就可以基本還原低頻分量。
我們將 QP 運(yùn)算的過程稱為量化,可見量化值越大,丟掉的高頻信息就越多,再加上編碼器中都是用整形變量代表像素值,所以量化值最大還原的低頻信息也會越不準(zhǔn)確,即造成的失真就越大,塊效應(yīng)也會越大,視頻編碼的質(zhì)量損失主要來源于此。
4、濾波
---- 后續(xù)更新 ----
5、熵編碼
熵的大小與信源的概率模型有著密切的關(guān)系,各個符號出現(xiàn)的概率不同,信源的熵也不同。當(dāng)信源中各事件是等概率分布時,熵具有極大值。信源的熵與其可能達(dá)到的最大值之間的差值反映了該信源所含有的冗余度。信源的冗余度越小,即每個符號所獨(dú)立攜帶的信息量越大,那么傳送相同的信息量所需要的序列長度越短,符號位越少。因此,數(shù)據(jù)壓縮的一個基本的途徑是去除信源的符號之間的相關(guān)性,盡可能地使序列成為無記憶的,即前一符號的出現(xiàn)不影響以后任何一個符號出現(xiàn)的概率。
利用信源的統(tǒng)計(jì)特性進(jìn)行碼率壓縮的編碼就稱為熵編碼,也叫統(tǒng)計(jì)編碼。熵編碼是無損壓縮編碼方法,它生成的碼流可以經(jīng)解碼無失真地恢復(fù)出原數(shù)據(jù)。熵編碼是建立在隨機(jī)過程的統(tǒng)計(jì)特性基礎(chǔ)上的。
視頻編碼常用的有兩種:變長編碼(哈夫曼編碼)、算術(shù)編碼。
H.264 最后將結(jié)果進(jìn)行熵編碼,分為上下文自適應(yīng)的變長編碼(Context-based Adaptive Variable-Length Coding,CAVLC)與上下文自適應(yīng)的二進(jìn)制算術(shù)編碼(Context-based Adaptive Binary Arithmetic Coding,CABAC)。
三、H.264 的主要規(guī)格
1、Baseline Profile(BP)
支持 I / P 幀
,只支持無交錯(Progressive)和 CAVLC;
一般用于低階或需要額外容錯的應(yīng)用,比如視頻通話、手機(jī)視頻等即時通信領(lǐng)域。
2、Extended Profile(XP)
在 Baseline 的基礎(chǔ)上增加了額外的功能,支持流之間的切換,改進(jìn)誤碼性能;
支持 I / P / B / SP / SI 幀
,只支持無交錯(Progressive)和 CAVLC;
適合于視頻流在網(wǎng)絡(luò)上的傳輸場合,比如視頻點(diǎn)播。
3、Main Profile(MP)
提供 I / P / B 幀
,支持無交錯(Progressive)和交錯(Interlaced),支持 CAVLC 和 CABAC;
用于主流消費(fèi)類電子產(chǎn)品規(guī)格如低解碼(相對而言)的 MP4、便攜的視頻播放器、PSP 和 iPod 等。
4、High Profile(HiP)
最常用的規(guī)格,在 Main 的基礎(chǔ)上增加了 8x8
內(nèi)部預(yù)測、自定義量化、無損視頻編碼和更多的 YUV 格式(如 4:4:4);
High 4:2:2 Profile(Hi422P);
High 4:4:4 Predictive Profile(Hi444PP);
High 4:2:2 Intra Profile;
High 4:4:4 Intra Profile;
用于廣播及視頻碟片存儲(藍(lán)光影片),高清電視的應(yīng)用。