本文主要介紹一種非常流行的視頻編碼:H.264韵卤。
計(jì)算一下:10秒鐘1080p(1920x1080)拴清、30fps的YUV420P原始視頻贮庞,需要占用多大的存儲(chǔ)空間验毡?
- (10 * 30) * (1920 * 1080) * 1.5 = 933120000字節(jié) ≈ 889.89MB
- 可以看得出來(lái)升熊,原始視頻的體積是非常巨大的
由于網(wǎng)絡(luò)帶寬和硬盤(pán)存儲(chǔ)空間都是非常有限的虚青,因此,需要先使用視頻編碼技術(shù)(比如H.264編碼)對(duì)原始視頻進(jìn)行壓縮边酒,然后再進(jìn)行存儲(chǔ)和分發(fā)经柴。H.264編碼的壓縮比可以達(dá)到至少是100:1。
簡(jiǎn)介
H.264墩朦,又稱為MPEG-4 Part 10坯认,Advanced Video Coding。
- 譯為:MPEG-4第10部分氓涣,高級(jí)視頻編碼
- 簡(jiǎn)稱:MPEG-4 AVC
H.264是迄今為止視頻錄制牛哺、壓縮和分發(fā)的最常用格式。截至2019年9月劳吠,已有91%的視頻開(kāi)發(fā)人員使用了該格式引润。H.264提供了明顯優(yōu)于以前任何標(biāo)準(zhǔn)的壓縮性能。H.264因其是藍(lán)光盤(pán)的其中一種編解碼標(biāo)準(zhǔn)而著名痒玩,所有藍(lán)光盤(pán)播放器都必須能解碼H.264淳附。
編碼器
H.264標(biāo)準(zhǔn)允許制造廠商自由地開(kāi)發(fā)具有競(jìng)爭(zhēng)力的創(chuàng)新產(chǎn)品,它并沒(méi)有定義一個(gè)編碼器蠢古,而是定義了編碼器應(yīng)該產(chǎn)生的輸出碼流奴曙。
x264是一款免費(fèi)的高性能的H.264開(kāi)源編碼器。x264編碼器在FFmpeg中的名稱是libx264草讶。
AVCodec *codec = avcodec_find_encoder_by_name("libx264");
解碼器
H.264標(biāo)準(zhǔn)中定義了一個(gè)解碼方法洽糟,但是制造廠商可以自由地開(kāi)發(fā)可選的具有競(jìng)爭(zhēng)力的、新的解碼器堕战,前提是他們能夠獲得與標(biāo)準(zhǔn)中采用的方法同樣的結(jié)果坤溃。
FFmpeg默認(rèn)已經(jīng)內(nèi)置了一個(gè)H.264的解碼器,名稱是h264嘱丢。
AVCodec *codec1 = avcodec_find_decoder_by_name("h264");
// 或者
AVCodec *codec2 = avcodec_find_decoder(AV_CODEC_ID_H264);
編碼過(guò)程與原理
H.264的編程過(guò)程比較復(fù)雜薪介,本文只介紹大體的框架和脈絡(luò),具體細(xì)節(jié)就不展開(kāi)了越驻。
大體可以歸納為以下幾個(gè)主要步驟:
- 劃分幀類型
- 幀內(nèi)/幀間編碼
- 變換 + 量化
- 濾波
- 熵編碼
劃分幀類型
有統(tǒng)計(jì)結(jié)果表明:在連續(xù)的幾幀圖像中汁政,一般只有10%以內(nèi)的像素有差別,亮度的差值變化不超過(guò)2%伐谈,而色度的差值變化只在1%以內(nèi)烂完。
GOP
于是可以將一串連續(xù)的相似的幀歸到一個(gè)圖像群組(Group Of Pictures,GOP)诵棵。
GOP中的幀可以分為3種類型:
-
I幀(I Picture抠蚣、I Frame、Intra Coded Picture)履澳,譯為:幀內(nèi)編碼圖像嘶窄,也叫做關(guān)鍵幀(Keyframe)
- 是視頻的第一幀怀跛,也是GOP的第一幀,一個(gè)GOP只有一個(gè)I幀
- 編碼
- 對(duì)整幀圖像數(shù)據(jù)進(jìn)行編碼
- 解碼
- 僅用當(dāng)前I幀的編碼數(shù)據(jù)就可以解碼出完整的圖像
- 是一種自帶全部信息的獨(dú)立幀柄冲,無(wú)需參考其他圖像便可獨(dú)立進(jìn)行解碼吻谋,可以簡(jiǎn)單理解為一張靜態(tài)圖像
-
P幀(P Picture、P Frame现横、Predictive Coded Picture)漓拾,譯為:預(yù)測(cè)編碼圖像
- 編碼
- 并不會(huì)對(duì)整幀圖像數(shù)據(jù)進(jìn)行編碼
- 以前面的I幀或P幀作為參考幀,只編碼當(dāng)前P幀與參考幀的差異數(shù)據(jù)
- 解碼
- 需要先解碼出前面的參考幀戒祠,再結(jié)合差異數(shù)據(jù)解碼出當(dāng)前P幀完整的圖像
- 編碼
-
B幀(B Picture骇两、B Frame、Bipredictive Coded Picture)姜盈,譯為:前后預(yù)測(cè)編碼圖像
- 編碼
- 并不會(huì)對(duì)整幀圖像數(shù)據(jù)進(jìn)行編碼
- 同時(shí)以前面低千、后面的I幀或P幀作為參考幀,只編碼當(dāng)前B幀與前后參考幀的差異數(shù)據(jù)
- 因?yàn)榭蓞⒖嫉膸兌嗔肆笏蹋灾恍枰鎯?chǔ)更少的差異數(shù)據(jù)
- 解碼
- 需要先解碼出前后的參考幀示血,再結(jié)合差異數(shù)據(jù)解碼出當(dāng)前B幀完整的圖像
- 編碼
不難看出,編碼后的數(shù)據(jù)大芯壤:I幀 > P幀 > B幀难审。
在較早的視頻編碼標(biāo)準(zhǔn)(例如MPEG-2)中,P幀只能使用一個(gè)參考幀近上,而一些現(xiàn)代視頻編碼標(biāo)準(zhǔn)(比如H.264)剔宪,允許使用多個(gè)參考幀拂铡。
GOP的長(zhǎng)度
GOP的長(zhǎng)度表示GOP的幀數(shù)壹无。GOP的長(zhǎng)度需要控制在合理范圍,以平衡視頻質(zhì)量感帅、視頻大卸范А(網(wǎng)絡(luò)帶寬)和seek效果(拖動(dòng)、快進(jìn)的響應(yīng)速度)等失球。
加大GOP長(zhǎng)度有利于減小視頻文件大小岖是,但也不宜設(shè)置過(guò)大,太大則會(huì)導(dǎo)致GOP后部幀的畫(huà)面失真实苞,影響視頻質(zhì)量
由于P豺撑、B幀的復(fù)雜度大于I幀,GOP值過(guò)大黔牵,過(guò)多的P聪轿、B幀會(huì)影響編碼效率,使編碼效率降低
如果設(shè)置過(guò)小的GOP值猾浦,視頻文件會(huì)比較大陆错,則需要提高視頻的輸出碼率灯抛,以確保畫(huà)面質(zhì)量不會(huì)降低,故會(huì)增加網(wǎng)絡(luò)帶寬
GOP長(zhǎng)度也是影響視頻seek響應(yīng)速度的關(guān)鍵因素音瓷,seek時(shí)播放器需要定位到離指定位置最近的前一個(gè)I幀对嚼,如果GOP太大意味著距離指定位置可能越遠(yuǎn)(需要解碼的參考幀就越多)、seek響應(yīng)的時(shí)間(緩沖時(shí)間)也越長(zhǎng)
GOP的類型
GOP又可以分為開(kāi)放(Open)绳慎、封閉(Closed)兩種纵竖。
- Open
- 前一個(gè)GOP的B幀可以參考下一個(gè)GOP的I幀
- Closed
- 前一個(gè)GOP的B幀不能參考下一個(gè)GOP的I幀
- GOP不能以B幀結(jié)尾
需要注意的是:
由于P幀、B幀都對(duì)前面的參考幀(P幀杏愤、I幀)有依賴性磨确,因此,一旦前面的參考幀出現(xiàn)數(shù)據(jù)錯(cuò)誤声邦,就會(huì)導(dǎo)致后面的P幀乏奥、B幀也出現(xiàn)數(shù)據(jù)錯(cuò)誤,而且這種錯(cuò)誤還會(huì)繼續(xù)向后傳播
對(duì)于普通的I幀亥曹,其后的P幀和B幀可以參考該普通I幀之前的其他I幀
在Closed GOP中邓了,有一種特殊的I幀,叫做IDR幀(Instantaneous Decoder Refresh媳瞪,譯為:即時(shí)解碼刷新)骗炉。
- 當(dāng)遇到IDR幀時(shí),會(huì)清空參考幀隊(duì)列
- 如果前一個(gè)序列出現(xiàn)重大錯(cuò)誤蛇受,在這里可以獲得重新同步的機(jī)會(huì)句葵,使錯(cuò)誤不會(huì)繼續(xù)往下傳播
- 一個(gè)IDR幀之后的所有幀,永遠(yuǎn)都不會(huì)參考該IDR幀之前的幀
- 視頻播放時(shí)兢仰,播放器一般都支持隨機(jī)seek(拖動(dòng))到指定位置乍丈,而播放器直接選擇到指定位置附近的IDR幀進(jìn)行播放最為便捷,因?yàn)榭梢悦鞔_知道該IDR幀之后的所有幀都不會(huì)參考其之前的其他I幀把将,從而避免較為復(fù)雜的反向解析
幀內(nèi)/幀間編碼
I幀采用的是幀內(nèi)(Intra Frame)編碼轻专,處理的是空間冗余。
P幀察蹲、B幀采用的是幀間(Inter Frame)編碼请垛,處理的是時(shí)間冗余。
劃分宏塊
在進(jìn)行編碼之前洽议,首先要將一張完整的幀切割成多個(gè)宏塊(Macroblock)宗收,H.264中的宏塊大小通常是16x16。
宏塊可以進(jìn)一步拆分為多個(gè)更小的變換塊(Transform blocks)亚兄、預(yù)測(cè)塊(Prediction blocks)混稽。
變換塊的尺寸有:16x16、8x8、4x4
預(yù)測(cè)塊的尺寸有:16×16荚坞、16×8挑宠、8×16、8×8颓影、8×4各淀、4×8、4×4
幀內(nèi)編碼
幀內(nèi)編碼诡挂,也稱幀內(nèi)預(yù)測(cè)碎浇。以4x4的預(yù)測(cè)塊為例,共有9種可選的預(yù)測(cè)模式璃俗。
利用幀內(nèi)預(yù)測(cè)技術(shù)奴璃,可以得到預(yù)測(cè)幀,最終只需要保留預(yù)測(cè)模式信息城豁、以及預(yù)測(cè)幀與原始幀的殘差值苟穆。
編碼器會(huì)選取最佳預(yù)測(cè)模式,使預(yù)測(cè)幀更加接近原始幀唱星,減少相互間的差異雳旅,提高編碼的壓縮效率。
幀間編碼
幀間編碼间聊,也稱幀間預(yù)測(cè)攒盈,用到了運(yùn)動(dòng)補(bǔ)償(Motion compensation)技術(shù)。
編碼器利用塊匹配算法哎榴,嘗試在先前已編碼的幀(稱為參考幀)上搜索與正在編碼的塊相似的塊型豁。如果編碼器搜索成功,則可以使用稱為運(yùn)動(dòng)矢量的向量對(duì)塊進(jìn)行編碼尚蝌,該向量指向匹配塊在參考幀處的位置迎变。
在大多數(shù)情況下,編碼器將成功執(zhí)行驼壶,但是找到的塊可能與它正在編碼的塊不完全匹配氏豌。這就是編碼器將計(jì)算它們之間差異的原因喉酌。這些殘差值稱為預(yù)測(cè)誤差热凹,需要進(jìn)行變換并將其發(fā)送給解碼器。
綜上所述泪电,如果編碼器在參考幀上成功找到匹配塊般妙,它將獲得指向匹配塊的運(yùn)動(dòng)矢量和預(yù)測(cè)誤差。使用這兩個(gè)元素相速,解碼器將能夠恢復(fù)該塊的原始像素碟渺。
如果一切順利,該算法將能夠找到一個(gè)幾乎沒(méi)有預(yù)測(cè)誤差的匹配塊突诬,因此苫拍,一旦進(jìn)行變換芜繁,運(yùn)動(dòng)矢量加上預(yù)測(cè)誤差的總大小將小于原始編碼的大小。
如果塊匹配算法未能找到合適的匹配绒极,則預(yù)測(cè)誤差將是可觀的骏令。因此,運(yùn)動(dòng)矢量的總大小加上預(yù)測(cè)誤差將大于原始編碼垄提。在這種情況下榔袋,編碼器將產(chǎn)生異常,并為該特定塊發(fā)送原始編碼铡俐。
變換與量化
接下來(lái)對(duì)殘差值進(jìn)行DCT變換(Discrete Cosine Transform凰兑,譯為離散余弦變換)。
規(guī)格
H.264的主要規(guī)格有:
- Baseline Profile(BP)
- 支持I/P幀审丘,只支持無(wú)交錯(cuò)(Progressive)和CAVLC
- 一般用于低階或需要額外容錯(cuò)的應(yīng)用吏够,比如視頻通話、手機(jī)視頻等即時(shí)通信領(lǐng)域
- Extended Profile(XP)
- 在Baseline的基礎(chǔ)上增加了額外的功能滩报,支持流之間的切換稿饰,改進(jìn)誤碼性能
- 支持I/P/B/SP/SI幀,只支持無(wú)交錯(cuò)(Progressive)和CAVLC
- 適合于視頻流在網(wǎng)絡(luò)上的傳輸場(chǎng)合露泊,比如視頻點(diǎn)播
- Main Profile(MP)
- 提供I/P/B幀喉镰,支持無(wú)交錯(cuò)(Progressive)和交錯(cuò)(Interlaced),支持CAVLC和CABAC
- 用于主流消費(fèi)類電子產(chǎn)品規(guī)格如低解碼(相對(duì)而言)的MP4惭笑、便攜的視頻播放器侣姆、PSP和iPod等
- High Profile(HiP)
- 最常用的規(guī)格
- 在Main的基礎(chǔ)上增加了8x8內(nèi)部預(yù)測(cè)、自定義量化沉噩、無(wú)損視頻編碼和更多的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
- 用于廣播及視頻碟片存儲(chǔ)(藍(lán)光影片)捺宗,高清電視的應(yīng)用