談到視頻的編解碼,我們會自然地想到H.264、HEVC/H.265這些權(quán)威的視頻編解碼標(biāo)準(zhǔn);談到標(biāo)準(zhǔn),有人覺得這個是有專門機(jī)構(gòu)去研究的,我們關(guān)心應(yīng)用就好;即使有興趣讀了標(biāo)準(zhǔn)和相關(guān)技術(shù),面對更多的是各種數(shù)學(xué)公式和術(shù)語,如協(xié)方差、傅立葉變換、高頻、濾波等等,需要花更多時間去理解。通常更為實際的做法是,我們只要調(diào)研如何應(yīng)用這些標(biāo)準(zhǔn),如何做好軟硬件編碼方案的選型,如何優(yōu)化技術(shù)參數(shù)以及如何調(diào)用API,也就基本能夠應(yīng)對日常的視頻業(yè)務(wù)了。因此,談到視頻的編解碼,往往帶有一絲神秘色彩。
本文的目標(biāo)是以非專業(yè)的視角來看待視頻編解碼原理,試圖將所謂高大上的專業(yè)術(shù)語或名詞轉(zhuǎn)換為普通IT業(yè)者略懂的話語,從而使更多人了解視頻編解碼到底是怎么回事。
為什么要編碼?
原因很簡單,不經(jīng)過編碼的源視頻數(shù)據(jù)量太大了。例如輸出一路1920×1080分辨率、24位色、每秒30幀的高清視頻,就這么一秒鐘的視頻,它的碼率達(dá)就到了1.5Gbps.因此需要編碼,盡最大可能將其壓縮至最低。下圖展示了編解碼標(biāo)準(zhǔn)的演進(jìn)歷程,經(jīng)過H.264編碼后,視頻碼率被壓縮到10Mbps,是源視頻數(shù)據(jù)量的1/150。
那么,什么時候我們不再關(guān)心編碼了?理想的狀態(tài)就是我們不再對存儲空間和網(wǎng)絡(luò)帶寬的限制有顧慮的時候,就不需要考慮編碼了,照單全收即可。
思考:N年以后,在 G網(wǎng)絡(luò)普及之后,視頻的編解碼技術(shù)和CDN的作用會不會越來越被淡化?
什么是編碼?
狹義但不全面的解釋:編碼最主要的工作就是壓縮。但壓縮是分步驟的,不是簡單地把圖像中重復(fù)的0 聚在一起這么簡單。依據(jù)方法論,可壓縮的內(nèi)容有以下幾種:
單幅圖像壓縮
一幅圖像,分成若干小塊,每塊8×8像素大小,如果這個小塊的每個像素的顏色都是白色,是不是就可以用一個點的值來代替這所有64個點的值? 這在編碼中的標(biāo)準(zhǔn)術(shù)語叫空間冗余,相應(yīng)的方法叫幀內(nèi)壓縮。
多幅圖像間壓縮
視頻中一個連續(xù)的動作,比如畫面里的女主角在紅墻背景下閉上了眼睛,這一動作的背后,是由一系列的多幅圖片組成,而每幅圖片的內(nèi)容基本上都是一樣的,唯一變化的部分就是女主角的眼睛所在圖像區(qū)域,眼睛緩慢由開到閉,這塊區(qū)域的像素值發(fā)生了變化。對于絕大多數(shù)的背景區(qū)域,它是沒有變化的,那么除了含有閉眼動作的這塊區(qū)域,是否可以只用一幅圖像來代替這么多個連續(xù)的圖像呢?這在編碼中的術(shù)語叫時間冗余,強(qiáng)調(diào)的是在一定時間段內(nèi)如何對連續(xù)多幅圖像的冗余部分進(jìn)行壓縮,術(shù)語叫幀間壓縮。
編碼的壓縮
圖像的空間冗余和時間冗余都被壓縮了,壓縮成一串字符串,對這段字符串的展現(xiàn)有沒有進(jìn)一步壓縮的可能性呢?是所謂的編碼冗余。
所有的視頻編碼技術(shù)和標(biāo)準(zhǔn)都是努力對上述三種冗余數(shù)據(jù)進(jìn)行壓縮,絞盡腦汁采用不同的算法和策略,產(chǎn)生了不同的結(jié)果,也就產(chǎn)生了不同的視頻編碼標(biāo)準(zhǔn)。
編碼的核心技術(shù)步驟主要分為預(yù)測、變換、量化、熵編碼,這幾步之后還有個可選步驟是濾波。是不是有點懵,現(xiàn)在解釋一下。
預(yù)測
一個視頻根據(jù)時間采樣被拆成N個圖像,為了壓縮和計算方便,每個圖像被分成多個小塊,比如每個小塊由8×8個像素構(gòu)成。如果不做壓縮,就需要把每個圖像的每個像素值都存儲起來,一共存儲N幅圖像連接起來,從而構(gòu)成一個完整的原始視頻。像素值的類型分為圖像的亮度值和色彩值。為了簡化理解 ,本文通篇以亮度值舉例進(jìn)行講解。
壓縮的第一步是預(yù)測。對于一幅圖像的每個塊,根據(jù)某幾個相鄰的像素值,在指定的方向上對下一個像素點的值用一個公式做預(yù)測,從而得到該點的預(yù)測的像素值,來構(gòu)造完整的圖像。
再比如:有連續(xù)兩幅運動圖像 ,對一幅圖像不做改變,保存本來的像素值,然后以此圖像的值為基礎(chǔ),對另一幅圖像使用公式計算來做運動預(yù)測,即把第一幅圖像的某個像素的值,經(jīng)過公式計算后,預(yù)測出第二個圖像指定位置的像素值,以此類推,得到一幅完整的預(yù)測出來的圖像。
問題來了,這世上哪有那么牛的算法能計算預(yù)測得這么完美?是的,沒有。那預(yù)測還有什么用?答案是為了獲取他們的差。差值有什么用?因為差值的絕對值都很小。還是不明白?我們看下圖的三個像素值矩陣:
是不是感覺到了差值矩陣的數(shù)據(jù)存儲的絕對值比較???數(shù)值小,理論術(shù)語上是為了使包含的信息能量變低;是為了到編碼階段,使編碼壓縮的數(shù)據(jù)量更小,從而壓縮效率更高。這就是預(yù)測的作用。
我們有了原圖,又有了特定的預(yù)測公式算法,就不需要再去存儲第二幅至相關(guān)第N幅的像素原值,只需要存儲它們的差值就行了。如果要解碼,把數(shù)據(jù)拿來,利用公式還原后再加上差值,就可以把那些被預(yù)測的圖像的真面目恢復(fù)了。
在一幅圖內(nèi)做預(yù)測,就叫幀內(nèi)預(yù)測;對一系列組圖如一段扣籃動作的視頻做運動軌跡預(yù)測,屬于幀間預(yù)測。
拿來做基準(zhǔn)參考的幀,叫I幀,是關(guān)鍵幀,它的信息量最大,只能做幀內(nèi)壓縮,通常壓縮率很低;而那些后續(xù)通過參考I幀的信息做預(yù)測獲取差值的圖像,存儲的根本不是原像素值,而是些原始圖像的殘差,叫預(yù)測幀。預(yù)測幀有時候會混合使用幀內(nèi)預(yù)測和幀間預(yù)測,取決于該區(qū)塊對那種算法更適應(yīng)。
根據(jù)前一幅圖像來預(yù)測得到本幀圖像叫P幀;結(jié)合前面的圖像和后面的圖像進(jìn)行雙向預(yù)測計算得到的本幀圖像叫B幀。基于一幅關(guān)鍵I幀圖像加上一系列相應(yīng)的預(yù)測圖像如B幀、P幀構(gòu)成的一組圖像叫GOP。
現(xiàn)在該明白別人常說的I幀、B幀、P幀是什么意思了吧?I幀是圖像信息的關(guān)鍵;B幀或P幀才是主要被壓縮的地方。
思考:為了降低視頻的網(wǎng)絡(luò)傳輸延遲,在CDN上的HLS視頻數(shù)據(jù)分片是不是越細(xì)越好?
答案:不是。切片時要為每一個分片都提供至少一個I幀和一系列P幀、B幀。分得太細(xì),I幀數(shù)量反而會變多。I幀太多,就意味著壓縮率變低,網(wǎng)絡(luò)傳輸量不降反升。
變換
事情還遠(yuǎn)沒結(jié)束。雖然通過預(yù)測公式降低了眾多像素存儲的編碼信息量,但這還不是壓縮。于是引入了各種變換,如離散余弦變換DCT、小波變換等等。學(xué)術(shù)上,其目的是將圖像進(jìn)行從空域到頻域的變化,通過這些所謂的變換濾掉高頻信息,因為人眼對高頻信息不敏感,濾掉一些也無所謂。經(jīng)典的DCT公式長這樣:
是不是又懵了?好吧,翻譯一下 ,看下面這個圖。變換公式就如同是水果分揀機(jī)器,根據(jù)某種特點如按體積大小對水果進(jìn)行歸類,把個頭大的放一堆,個頭小的放一堆。經(jīng)過變換,實現(xiàn)了物以類聚,后續(xù)如果再有需求就可以很容易地進(jìn)行封箱打包的操作了。
對圖像的變換改變了原來像素信息的空間順序,取而代之的是依據(jù)頻率和幅度的存儲方式。但此時的變換,只是改變了隊形,沒有任何實際的壓縮動作。
拿一個8×8的圖像塊舉例,原始圖像塊的像素值如下:
經(jīng)DCT變換的結(jié)果如下圖。
能看出點什么特征嗎?如果還不能,提醒一下:矩陣左上角的數(shù)值較大,而右下角的數(shù)值較小,且趨近于零值。這就是傳說中的頻率劃分。經(jīng)過DCT變化,低頻的、幅值高的、重要的信息都被歸置在左上部;而人類不敏感的、高頻的、卻又低振幅的數(shù)據(jù)都放在了右下側(cè)。
這又有什么好處呢?在接下來的量化步驟,就可以對右下側(cè)的數(shù)據(jù)開刀了。因此可以簡單理解,不管是什么A變換還是B變換,不要被它的公式和名稱嚇倒,它只是為了改變隊形,為后續(xù)的編碼和壓縮做準(zhǔn)備。
量化
到現(xiàn)在為止,仍然沒有進(jìn)行實質(zhì)性的壓縮。萬事俱備,只欠量化。它是壓縮前的最后一道工序。量化就好比對剛才站好隊的隊員的身高進(jìn)行分級打分,通過一個基準(zhǔn)步長來計算出每個值的相對數(shù)值。又懵了吧? 如下圖:量化前左上角的值為236,步長為8,則量化后它值為236/8 = 30;量化前第二行首元素的值為-22,則量化后為-22/ 8 = -3。
這樣一來,經(jīng)過量化分級,數(shù)據(jù)開始變得簡潔明了,但精度也有損失了,損失的大小由量化的步長決定。圖像的失真就是由量化引起的。
回顧,經(jīng)過上面的DCT變換后以后,數(shù)據(jù)隊形已準(zhǔn)備好;再經(jīng)過量化,把很多高頻的右下角的數(shù)值變?yōu)?。對數(shù)值進(jìn)行Z字形掃描,就變成一串?dāng)?shù)字了 。
針對上面的變換后的值的量化結(jié)果為:
30, 0, -3, -1, -2, -2, -1, -1, 1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0…
為什么要進(jìn)行Z字形掃描,因為可以更方便地把0 都聚在一起;為什么0 都會排在右下角?因為經(jīng)過了DCT變換改變了隊形。 為什么把0聚在一起?為了編碼壓縮?。?/p>
熵編碼
壓縮的第一道工序叫行程編碼。什么是行程編碼?忘掉這個名詞,就是把連續(xù)重復(fù)的數(shù)據(jù)的用重復(fù)的次數(shù)值來表示??蠢?,一個原始串:
aaaaaaabbbbccccdddeeddaa
對這個原始串進(jìn)行行程編碼后,把重復(fù)的字母用一個重復(fù)的數(shù)字來代替,變成了這樣:
7a4b4c3d2e2d2a
這就是行程編碼的思想。行程編碼思想雖然簡單但用處很大,在PNG,GZIP等各種壓縮算法里都有它的影子。
這還不算完,只是壓縮的一小步,第二步就是要對行程編碼后的數(shù)據(jù)進(jìn)行變長編碼,如Huffman編碼,這才是壓縮的重頭戲。Huffman編碼主要思路是將出現(xiàn)頻率最高的字符串用最短的碼來替換,從整體上減少了原始數(shù)據(jù)的長度。網(wǎng)上的討論極多,這里不再詳述,感興趣的也可見我的文章《圖解DEFLATE編解碼》。
編解碼總結(jié)
再梳理一下視頻編碼的核心步驟:
? 先做幀內(nèi)預(yù)測和幀間預(yù)測,根據(jù)關(guān)鍵幀來獲取每幅圖像的差值,從而減少存儲的編碼信息量;
? 對其進(jìn)行變換,完成隊形調(diào)整;
? 對數(shù)據(jù)進(jìn)行有損量化,將不重要的數(shù)據(jù)歸零;
? 對量化數(shù)據(jù)進(jìn)行特定方向的掃描,將二維數(shù)據(jù)轉(zhuǎn)為一維數(shù)據(jù);
? 最后進(jìn)行壓縮,即先進(jìn)行行程編碼,再使用壓縮編碼。
解碼的步驟只是反其道而行之。
絕大部分的視頻編解碼標(biāo)準(zhǔn)都無一例外地包含這些目標(biāo)。當(dāng)然有些標(biāo)準(zhǔn)還考慮了環(huán)路濾波,但它不是必選項,這里不做解釋。
編解碼的標(biāo)準(zhǔn)
各大標(biāo)準(zhǔn)之間有什么區(qū)別?有了上面的基礎(chǔ)理解后,就比較好解釋了。不同的標(biāo)準(zhǔn),有的只用了變換,有的用了預(yù)測加變換的混合編碼;或者幀內(nèi)預(yù)測算法不一樣,預(yù)測方向不一樣,有的支持4個方向,有的支持8個方向;或者變換的算法不一樣,如有的是DCT變換,有的是小波變換;或者熵編碼算法也不一樣,有的是Huffman編碼,有的是算術(shù)編碼;等等等等……
具體一點如H.263及之前的編碼標(biāo)準(zhǔn),會對幀內(nèi)編碼塊直接進(jìn)行變換,到了H.264,它提供了基于9種方向的幀內(nèi)預(yù)測;再如到了HEVC / H.265, 采用了基于四叉樹的分塊方式;對于幀間預(yù)測提供了8種預(yù)測單元的劃分類型,除了支持離散余弦變換DCT,還首次使用了離散正弦變換DST,更有效地實現(xiàn)了對殘差矩陣的變換。
越是最近新出的編碼標(biāo)準(zhǔn),算法越先進(jìn),也越復(fù)雜。
最后
以上就是視頻編解碼的基本原理,希望讀了以后能大體明白視頻編解碼原理的基本思路。但如果真想對視頻編解碼的標(biāo)準(zhǔn)和算法細(xì)節(jié)做深入了解,那就真得要下苦功夫了。文中每個主題,都可以寫出幾本書來。請有理想有毅力的同學(xué)繼續(xù)前行,祝一切順利!
編輯:hfy
-
視頻編解碼
+關(guān)注
關(guān)注
2文章
54瀏覽量
11906
發(fā)布評論請先 登錄
新一代視頻編解碼標(biāo)準(zhǔn)H.266走向主流 頭部視頻平臺滲透率超70%

評論