深入淺出理解視頻編碼H264結(jié)構(gòu)(內(nèi)涵福利)

原文鏈接
引言:
在國(guó)內(nèi)直播"欣欣向榮"(ps: 其實(shí)大多都虧錢(qián),為的就是炒概念)的年代狞玛,相信很多小伙伴也投入了技術(shù)的浩瀚大洋當(dāng)中(ps: 其實(shí)就是搬磚)心肪,日復(fù)一日,音/視頻的神秘面紗開(kāi)始讓更多的小伙伴扯下慧瘤,而本博主固该,也只是剛窺探門(mén)道伐坏,慢慢摸索。好了每瞒,廢話不扯纯露,我們今天就來(lái)說(shuō)說(shuō)我們經(jīng)常在視頻編碼當(dāng)中用到的 H.264編碼格式 的結(jié)構(gòu)埠褪,相信 H.264 這個(gè)東西很多小伙伴都不陌生了,也有著自己的理解,但這東西頗為巨大罚随,里面算法千千萬(wàn)萬(wàn),博主也不會(huì)講太高深的東西遵班,只是讓各位小伙伴慢慢理解理解 H.264的主體機(jī)構(gòu),如果沒(méi)有興趣的小伙伴請(qǐng)繞道腹暖,如果有技術(shù)大牛翰萨,請(qǐng)指正本博主那愚鈍的腦袋亩鬼。

首先來(lái)一段大家都熟悉的官方話來(lái)介紹一下 H.264

H.264: H.264/AVC項(xiàng)目的目的是為了創(chuàng)建一個(gè)比以前的視頻壓縮標(biāo)準(zhǔn),在更低的比特率的情況下依然能夠提供良好視頻質(zhì)量的標(biāo)準(zhǔn)(如黄绩,一半或者更少于MPEG-2,H.263,或者M(jìn)PEG-4 Part2 )玷过。同時(shí)辛蚊,還要不會(huì)太大的增加設(shè)計(jì)的復(fù)雜性。
優(yōu)勢(shì):
1)網(wǎng)絡(luò)親和性诽里,即可適用于各種傳輸網(wǎng)絡(luò)
2)高的視頻壓縮比飞蛹,當(dāng)初提出的指標(biāo)是比 H.263卧檐,MPEG-4,約為它們的 2 倍捕仔,現(xiàn)在都已基 實(shí)現(xiàn);

那么很明顯盈罐,什么時(shí)候需要到壓縮呢?當(dāng)然是文件體積太大的時(shí)候啦钓葫,我們想想础浮,所謂的視頻,就是像小時(shí)候的連環(huán)畫(huà)一樣豆同,在一秒內(nèi)翻過(guò) 24 張以上的圖片影锈,就感覺(jué)圖像是連續(xù)的了,這就是視頻的原理锄禽。但是大家有沒(méi)有想過(guò)靴姿,一張圖片有多大呢佛吓?我們的屏幕分辨率按 1280 * 720 算的話,一秒鐘的視頻大概就 2.64 MB 了淤刃,大家想想吱型,我們大部分的小伙伴為了下載個(gè)小嗨片省吃儉用才開(kāi)了個(gè) 1M 的網(wǎng)線津滞,然后連個(gè)直播都看不了是什么感覺(jué)。那肯定不能這樣了咪鲜,所以我們要進(jìn)行壓縮撞鹉,而 H.264 不僅壓縮比比較高鸟雏,對(duì)網(wǎng)絡(luò)的兼容性也非常好,所以大多數(shù)人做直播也就選擇了 H.264 作為編碼格式了炊琉。

編碼流程:
那么 H.264 其編解碼流程是怎么樣的呢温自?其實(shí)可以主要分為 5 部分: 幀間和幀內(nèi)預(yù)測(cè)(Estimation)皇钞、變換(Transform)和反變換、量化(Quantization)和反量化馆里、環(huán)路濾波(Loop Filter)鸠踪、熵編碼(Entropy Coding)复斥。
看起來(lái)很高深的樣子,實(shí)際上也是很高深的樣子评汰,因?yàn)檫@里面包含著許許多多的算法和專(zhuān)業(yè)知識(shí)被去,這里我們就不做過(guò)多的講解奖唯,有興趣的同學(xué)可以上網(wǎng)翻翻,夠你看到睡覺(jué)的了坯墨。H.264詳細(xì)文檔


原理簡(jiǎn)介

H.264 原始碼流(又稱(chēng)為裸流)畅蹂,是有一個(gè)接一個(gè)的 NALU 組成的荣恐,而它的功能分為兩層:視頻編碼層(VCL, Video Coding Layer)和網(wǎng)絡(luò)提取層(NAL, Network Abstraction Layer)。
VCL 數(shù)據(jù)即編碼處理的輸出少漆,它表示被壓縮編碼后的視頻數(shù)據(jù) 序列示损。在 VCL 數(shù)據(jù)傳輸或存儲(chǔ)之前嚷硫,這些編碼的 VCL 數(shù)據(jù)始鱼,先被映射或封裝進(jìn) NAL 單元(以下簡(jiǎn)稱(chēng) NALU医清,Nal Unit) 中卖氨。每個(gè) NALU 包括一個(gè)原始字節(jié)序列負(fù)荷(RBSP, Raw Byte Sequence Payload)筒捺、一組 對(duì)應(yīng)于視頻編碼的 NALU 頭部信息。RBSP 的基本結(jié)構(gòu)是:在原始編碼數(shù)據(jù)的后面填加了結(jié)尾 比特五嫂。一個(gè) bit“1”若干比特“0”贫导,以便字節(jié)對(duì)齊蟆盹。

NAL 單元排列

上圖中的 NALU頭 + RBSP 就相當(dāng)與一個(gè) NALU (Nal Unit), 每個(gè)單元都按獨(dú)立的 NALU 傳送逾滥。 其實(shí)說(shuō)白了,H.264 中的結(jié)構(gòu)全部都是以 NALU 為主的讥巡,理解了 NALU舔哪,就理解 H.264 的結(jié)構(gòu)了捉蚤。


一幀圖片跟 NALU 的關(guān)聯(lián) :

究竟 NALU 是怎么由一幀圖片變化而來(lái)的呀,H.264究竟為什么這么神奇布持?

一幀圖片經(jīng)過(guò) H.264 編碼器之后题暖,就被編碼為一個(gè)或多個(gè)片(slice),而裝載著這些片(slice)的載體唯绍,就是 NALU 了枝誊,我們可以來(lái)看看 NALU 跟片的關(guān)系(slice)侧啼。

圖片編碼后
NALU 結(jié)構(gòu)

小伙伴們要明白痊乾,片(slice)的概念不同與幀(frame)哪审,幀(frame)是用作描述一張圖片的湿滓,一幀(frame)對(duì)應(yīng)一張圖片舌狗,而片(slice),是 H.264 中提出的新概念朝氓,是通過(guò)編碼圖片后切分通過(guò)高效的方式整合出來(lái)的概念赵哲,一張圖片至少有一個(gè)或多個(gè)片(slice)君丁。

上圖中可以看出,片(slice)都是又 NALU 裝載并進(jìn)行網(wǎng)絡(luò)傳輸?shù)南鹋樱沁@并不代表 NALU 內(nèi)就一定是切片毙死,這是充分不必要條件喻鳄,因?yàn)?NALU 還有可能裝載著其他用作描述視頻的信息。


什么是切片(slice)?

片的主要作用是用作宏塊(Macroblock)的載體(ps:下面會(huì)介紹到宏塊的概念)爪喘。片之所以被創(chuàng)造出來(lái)纠拔,主要目的是為限制誤碼的擴(kuò)散和傳輸。
如何限制誤碼的擴(kuò)散和傳輸侦鹏?
每個(gè)片(slice)都應(yīng)該是互相獨(dú)立被傳輸?shù)穆运称念A(yù)測(cè)(片(slice)內(nèi)預(yù)測(cè)和片(slice)間預(yù)測(cè))不能以其它片中的宏塊(Macroblock)為參考圖像劝萤。

那么片(slice)的具體結(jié)構(gòu)床嫌,我們用一張圖來(lái)直觀說(shuō)明吧:

我們可以理解為一 張/幀 圖片可以包含一個(gè)或多個(gè)分片(Slice),而每一個(gè)分片(Slice)包含整數(shù)個(gè)宏塊(Macroblock)鳖谈,即每片(slice)至少一個(gè) 宏塊(Macroblock)蚯姆,最多時(shí)每片包 整個(gè)圖像的宏塊洒敏。

上圖結(jié)構(gòu)中,我們不難看出郭毕,每個(gè)分片也包含著頭和數(shù)據(jù)兩部分:
1显押、分片頭中包含著分片類(lèi)型傻挂、分片中的宏塊類(lèi)型、分片幀的數(shù)量兽肤、分片屬于那個(gè)圖像以及對(duì)應(yīng)的幀的設(shè)置和參數(shù)等信息。
2电禀、分片數(shù)據(jù)中則是宏塊笤休,這里就是我們要找的存儲(chǔ)像素?cái)?shù)據(jù)的地方店雅。

什么是宏塊?

宏塊是視頻信息的主要承載者腋么,因?yàn)樗恳粋€(gè)像素的亮度和色度信息亥揖。視頻解碼最主要的工作則是提供高效的方式從碼流中獲得宏塊中的像素陣列费变。
組成部分:一個(gè)宏塊由一個(gè)16×16亮度像素和附加的一個(gè)8×8 Cb和一個(gè) 8×8 Cr 彩色像素塊組成挚歧。每個(gè)圖象中吁峻,若干宏塊被排列成片的形式用含。

我們先來(lái)看看宏塊的結(jié)構(gòu)圖:

從上圖中啄骇,可以看到,宏塊中包含了宏塊類(lèi)型痪寻、預(yù)測(cè)類(lèi)型虽惭、Coded Block Pattern、Quantization Parameter顾画、像素的亮度和色度數(shù)據(jù)集等等信息亲雪。


切片(slice)類(lèi)型跟宏塊類(lèi)型的關(guān)系

對(duì)于切片(slice)來(lái)講,分為以下幾種類(lèi)型:

0 P-slice. Consists of P-macroblocks (each macro block is predicted using one reference frame) and / or I-macroblocks.
1 B-slice. Consists of B-macroblocks (each macroblock is predicted using one or two reference frames) and / or I-macroblocks.
2 I-slice. Contains only I-macroblocks. Each macroblock is predicted from previously coded blocks of the same slice.
3 SP-slice. Consists of P and / or I-macroblocks and lets you switch between encoded streams.
4 SI-slice. It consists of a special type of SI-macroblocks and lets you switch between encoded streams.

I片:只包 I宏塊虾标,I 宏塊利用從當(dāng)前片中已解碼的像素作為參考進(jìn)行幀內(nèi)預(yù)測(cè)(不能取其它片中的已解碼像素作為參考進(jìn)行幀內(nèi)預(yù)測(cè))璧函。

P片:可包 P和I宏塊基显,P 宏塊利用前面已編碼圖象作為參考圖象進(jìn)行幀內(nèi)預(yù)測(cè),一個(gè)幀內(nèi)編碼的宏塊可進(jìn)一步作宏塊的分割:即 16×16库继、16×8宪萄、8×16 或 8×8 亮度像素塊(以及附帶的彩色像素);如果選了 8×8 的子宏塊榨惰,則可再分成各種子宏塊的分割,其尺寸為 8×8居凶、8×4藤抡、4×8 或 4×4 亮度像素塊(以及附帶的彩色像素)。

B片:可包 B和I宏塊舆床,B 宏塊則利用雙向的參考圖象(當(dāng)前和 來(lái)的已編碼圖象幀)進(jìn)行幀內(nèi)預(yù)測(cè)嫁佳。

SP片(切換P):用于不同編碼流之間的切換蒿往,包含 P 和/或 I 宏塊

SI片:擴(kuò)展檔次中必須具有的切換,它包 了一種特殊類(lèi)型的編碼宏塊腾夯,叫做 SI 宏塊,SI 也是擴(kuò)展檔次中的必備功能蝶俱。


整體結(jié)構(gòu)
通過(guò)剖析了這么多個(gè)小零件,是時(shí)候個(gè)大家一個(gè)世界地圖了罗标,
那么我們的 NALU 整體結(jié)構(gòu)可以呼之欲出了闯割,以下就引用 H.264 文檔當(dāng)中的一幅圖了


其實(shí) H.264 的碼流結(jié)構(gòu)并沒(méi)有大家想的那么復(fù)雜竿拆,編碼后視頻的每一組圖像(GOP丙笋,圖像組)都給予了傳輸中的序列(PPS)和本身這個(gè)幀的圖像參數(shù)(SPS),所以锥忿,我們的整體結(jié)構(gòu)稳吮,應(yīng)該如此:

GOP (圖像組)主要用作形容一個(gè) i 幀 到下一個(gè) i 幀之間的間隔了多少個(gè)幀灶似,增大圖片組能有效的減少編碼后的視頻體積酪惭,但是也會(huì)降低視頻質(zhì)量者甲,至于怎么取舍,得看需求了鲫懒。


主題外:(未完待續(xù))

那么窥岩,NALU 頭部中的類(lèi)型確定著什么信息呢宰缤?
我們首先來(lái)看看 NALU 中究竟有哪幾種類(lèi)型,我們來(lái)看看 H.264 中源碼對(duì) nal_unit_type_e 中的定義:

enum nal_unit_type_e
{
NAL_UNKNOWN = 0, // 未使用
NAL_SLICE = 1, // 不分區(qū)朦乏、非 IDR 圖像的片(片的頭信息和數(shù)據(jù))
NAL_SLICE_DPA = 2, // 片分區(qū) A
NAL_SLICE_DPB = 3, // 片分區(qū) B
NAL_SLICE_DPC = 4, // 片分區(qū) C
NAL_SLICE_IDR = 5, /* ref_idc != 0 / // IDR 圖像中的片
NAL_SEI = 6, /
ref_idc == 0 */ // 補(bǔ)充增強(qiáng)信息單元

參數(shù)集是 H.264 標(biāo)準(zhǔn)的一個(gè)新概念,是一種通過(guò)改進(jìn)視頻碼流結(jié)構(gòu)增強(qiáng)錯(cuò)誤恢復(fù)能力的方法吃引。
NAL_SPS = 7, // 序列參數(shù)集 (包括一個(gè)圖像序列的所有信息际歼,即兩個(gè) IDR 圖像間的所有圖像信息,如圖像尺寸鹅心、視頻格式等)
NAL_PPS = 8, // 圖像參數(shù)集 (包括一個(gè)圖像的所有分片的所有相關(guān)信息纺荧, 包括圖像類(lèi)型、序列號(hào)等输枯,解碼時(shí)某些序列號(hào)的丟失可用來(lái)檢驗(yàn)信息包的丟失與否)

  • NAL_AUD = 9, // 分界符
    NAL_FILLER = 12, // 填充(啞元數(shù)據(jù)占贫,用于填充字節(jié))
    /* ref_idc == 0 for 6,9, 10 (表明下一圖像為 IDR 圖像),11(表明該流中已沒(méi)有圖像),12 */
    };
    ps: 以上括號(hào)()中的為類(lèi)型描述

上面NALU類(lèi)型當(dāng)中,分片/切片(slice)的概念我們都已經(jīng)很清楚了瞳收,但是用 NALU 作載體的還有 SEI厢汹、SPS烫葬、PPS 等等。

今天我們不一一聚述這些類(lèi)型對(duì)整個(gè)流程的作用了垢箕,我們挑出兩個(gè)符合我們今天主題的類(lèi)型來(lái)講兑巾,PPS 和 SPS闪朱。


那么今天我們講的 H.264 的碼流結(jié)構(gòu)相信大家都有個(gè)大概輪廓的了解了,總結(jié)的一句話就是:

H.264 中锄开,句法元素共被組織成 序列萍悴、圖像、片计维、宏塊撕予、子宏塊五個(gè)層次实抡。

希望大家用心體會(huì),畢竟手工打字和作圖不易赏淌,大家能關(guān)注的關(guān)注六水,能有閑錢(qián)的打賞一個(gè)辣卒,能有贊的贊一下嘛


最后福利:
文章的最后為了方便小伙伴學(xué)習(xí)添寺,本博主用 ffmpeg 在 iOS 設(shè)備寫(xiě)了一個(gè)實(shí)例代碼懈费,主要功能是利用攝像頭實(shí)時(shí)錄制 yuv 格式文件并編碼 H.264 后,實(shí)時(shí)分析 H.264 中每個(gè)幀(frame)中的 NALU 的數(shù)據(jù)票罐,希望對(duì)小伙伴們有所幫助该押,找到入門(mén)的方法。
(本博主將所有代碼只放在個(gè)人博客末尾當(dāng)中: 代碼地址『所有代碼只用做學(xué)習(xí)只用蚕礼,并不提供商業(yè)用途,如果違反朝聋,必究冀痕±暄荩』)

心如止水宵距,奮力前行

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末消玄,一起剝皮案震驚了整個(gè)濱河市翩瓜,隨后出現(xiàn)的幾起案子兔跌,更是在濱河造成了極大的恐慌,老刑警劉巖坟桅,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件赖舟,死亡現(xiàn)場(chǎng)離奇詭異夸楣,居然都是意外死亡豫喧,警方通過(guò)查閱死者的電腦和手機(jī)紧显,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)涉兽,“玉大人招驴,你說(shuō)我怎么就攤上這事〖衔罚” “怎么了忽匈?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)矿辽。 經(jīng)常有香客問(wèn)我丹允,道長(zhǎng),這世上最難降的妖魔是什么袋倔? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任雕蔽,我火速辦了婚禮,結(jié)果婚禮上宾娜,老公的妹妹穿的比我還像新娘批狐。我一直安慰自己,他們只是感情好食零,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著吱抚,像睡著了一般秘豹。 火紅的嫁衣襯著肌膚如雪既绕。 梳的紋絲不亂的頭發(fā)上鸵膏,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天廓译,我揣著相機(jī)與錄音非区,去河邊找鬼久橙。 笑死,一個(gè)胖子當(dāng)著我的面吹牛祝拯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播康嘉,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了峭范?” 一聲冷哼從身側(cè)響起纱控,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤球昨,失蹤者是張志新(化名)和其女友劉穎嚣州,沒(méi)想到半個(gè)月后该肴,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體秦效,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡铸抑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了滥嘴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖互广,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤媳谁,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響进苍,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜杠人,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一学歧、第九天 我趴在偏房一處隱蔽的房頂上張望袁铐。 院中可真熱鬧剔桨,春花似錦、人聲如沸帝洪。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春筐钟,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留惊畏,地道東北人浪讳。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親须尚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容