午夜视频在线网站,日韩视频精品在线,中文字幕精品一区二区三区在线,在线播放精品,1024你懂我懂的旧版人,欧美日韩一级黄色片,一区二区三区在线观看视频

分享

H264編碼原理及NALU介紹...

 創(chuàng)始元靈6666 2022-10-17 發(fā)布于河北

一、簡(jiǎn)述

流媒體編解碼流程大致如圖1所示:

【流媒體編解碼流程 圖1】
在這里插入圖片描述

視頻數(shù)據(jù)編解碼層格式包含有:H264,H265,MPEG4等。

本文我們主要對(duì)H264編碼原理進(jìn)行整理,并對(duì)NALU做簡(jiǎn)要介紹。

二、H264編解碼

2.1、H264簡(jiǎn)介

參考來(lái)源:H264百度百科

H.264從1999年開(kāi)始到2003年形成草案,最后在2007年定稿有待核實(shí)。在ITU的標(biāo)準(zhǔn)里稱為H.264,在MPEG的標(biāo)準(zhǔn)里是MPEG-4的一個(gè)組成部分(MPEG-4 Part 10),又叫Advanced Video Codec,因此H.264也常常稱為MPEG-4或直接叫AVC。

比如下面使用 MediaInfo工具查看flv音視頻文件的信息,可以看到video格式為AVC,其實(shí)也就是H264格式。

【flv音視頻文件基本信息 圖2】
在這里插入圖片描述

2.2、H264編解碼原理

參考來(lái)源:H264 編解碼協(xié)議詳解,深入淺出理解視頻編碼H264結(jié)構(gòu)h264編解碼結(jié)構(gòu)框圖

1、H264概述

問(wèn)題:為什么要對(duì)音視頻文件進(jìn)行H264編解碼?


因?yàn)?,在音視頻傳輸過(guò)程中,視頻文件的傳輸是個(gè)極大的問(wèn)題;一段分辨率為1920 * 1080,每個(gè)像素點(diǎn)為RGB占用3個(gè)字節(jié),幀率是25的視頻,對(duì)于傳輸帶寬的要求是:1920 * 1080 * 3 * 25/1024/1024=148.315MB/s,換成bps則意味著視頻每秒帶寬為1186.523Mbps,這樣的速率對(duì)于網(wǎng)絡(luò)存儲(chǔ)是不可接受的。因此視頻壓縮和編碼技術(shù)應(yīng)運(yùn)而生。

對(duì)于視頻文件來(lái)說(shuō),視頻由單張圖片幀所組成,比如每秒25幀,但是圖片幀的像素塊之間存在相似性,因此視頻幀圖像可以進(jìn)行圖像壓縮;H264采用了16 * 16的分塊大小對(duì),視頻幀圖像進(jìn)行相似比較和壓縮編碼。如下圖所示:

【圖像切分 圖3】
在這里插入圖片描述
壓縮編碼可以分為內(nèi)部壓縮和外部壓縮。

1)內(nèi)部壓縮
內(nèi)部壓縮指的是一幀圖片的內(nèi)部壓縮。當(dāng)H264對(duì)圖片進(jìn)行 16 * 16 分塊后,會(huì)對(duì)每個(gè)小塊內(nèi)的圖像進(jìn)行分析,如果2個(gè)小塊圖像比較相近,那么住需要存儲(chǔ)一張即可,無(wú)需存儲(chǔ)重復(fù)圖塊。這樣可以有效壓縮圖片的存儲(chǔ)大小。

比如下面一張圖片,劃分的A、B小塊圖像分析后是基本一樣的,那么只需要存儲(chǔ)A即可,B不需要進(jìn)行存儲(chǔ)。

【內(nèi)部壓縮 圖4】
在這里插入圖片描述

2)外部壓縮
外部壓縮指的是圖片間的圖像壓縮。在每幀圖片劃分成16 * 16 小塊的圖像進(jìn)行分析基礎(chǔ)上,比圖片間的數(shù)據(jù),如果兩張圖片比較相近,對(duì)相同的圖像模塊只需存儲(chǔ)一份,對(duì)不同的部分再做存儲(chǔ)。避免了重復(fù)數(shù)據(jù)的存儲(chǔ),極大改善了圖片壓縮空間。

比如下面兩張圖片 ,除了E小塊不同之外,其他都一樣,那么存儲(chǔ)圖1數(shù)據(jù)后,圖2片只需要存儲(chǔ)與圖片1不同的數(shù)據(jù)即可。

【外部壓縮 圖5】
在這里插入圖片描述


2、H264中的 I幀、P幀和B幀
H264 使用幀內(nèi)壓縮和幀間壓縮的方式提高編碼壓縮率;H264采用了獨(dú)特的 I幀,P幀和B幀策略來(lái)實(shí)現(xiàn),連續(xù)幀之間的壓縮。

【H264 IBP幀排序 圖6】
在這里插入圖片描述
1)I 幀 (幀內(nèi)編碼幀 intra picture)
I 幀通常是每個(gè) GOP(MPEG 所使用的一種視頻壓縮技術(shù))的第一個(gè)幀,經(jīng)過(guò)適度地壓縮,做為隨機(jī)訪問(wèn)的參考點(diǎn),可以當(dāng)成圖象。I幀表示關(guān)鍵幀,解碼時(shí)只需要本幀數(shù)據(jù)就可以完成。I幀可以看成是一個(gè)圖像經(jīng)過(guò)壓縮后的產(chǎn)物。自身可以通過(guò)視頻解壓算法解壓成一張單獨(dú)的完整的圖片。

I幀特點(diǎn):

  • 是一個(gè)全幀壓縮編碼幀。它將全幀圖像信息進(jìn)行JPEG壓縮編碼及傳輸。
  • 解碼時(shí)僅用 I幀的數(shù)據(jù)就可重構(gòu)完整圖像。
  • I幀描述了圖像背景和運(yùn)動(dòng)主體的詳情。
  • I幀不需要參考其他畫面而生成。
  • I幀是P幀和B幀的參考幀(I幀質(zhì)量直接影響到同組以后各幀的質(zhì)量)。
  • I幀是幀組GOP的基礎(chǔ)幀(如果為IDR則為第一幀),在一組中只有一個(gè)IDR幀,一個(gè)或多個(gè)I幀(包括IDR幀)。
  • I幀不需要考慮運(yùn)動(dòng)矢量。
  • I幀所占數(shù)據(jù)的信息量比較大。


2)P幀 (前向預(yù)測(cè)編碼幀 predictive-frame)
通過(guò)充分將低于圖像序列中前面已編碼幀的時(shí)間冗余信息來(lái)壓縮傳輸數(shù)據(jù)量的編碼圖像,也叫預(yù)測(cè)幀。
P幀表示這一幀跟之前的一個(gè)關(guān)鍵幀(或P幀)的差別,解碼時(shí)需要用之前緩存的畫面疊加上本幀定義的差別,生成最終畫面。
需要參考其前面的一個(gè)I frame 或者P frame來(lái)生成一張完整的圖片。

P幀的預(yù)測(cè)和重構(gòu):
P幀是以 I幀為參考幀,在I幀中找出P幀“某點(diǎn)”的預(yù)測(cè)值和運(yùn)動(dòng)矢量,取預(yù)測(cè)差值和運(yùn)動(dòng)矢量一起傳送。在接收端根據(jù)運(yùn)動(dòng)矢量從I幀中找出P幀“某點(diǎn)”的預(yù)測(cè)值并與差值相加得到P幀“某點(diǎn)”樣值,從而得到完整的P幀。

P幀特點(diǎn):

  • P幀是I幀后面相隔1~2幀的編碼幀。
  • P幀采用運(yùn)動(dòng)補(bǔ)償?shù)姆椒▊魉退c前面的I幀或P幀的差值及運(yùn)動(dòng)矢量(預(yù)測(cè)誤差)。
  • 解碼時(shí)必須將 I幀的預(yù)測(cè)值與預(yù)測(cè)誤差求和后才能重構(gòu)完整的P幀圖像。
  • P幀屬于向前預(yù)測(cè)的幀間編碼。它只參考前面最靠近它的I幀或P幀。
  • P幀可以是其后面P幀的參考幀,也可以是其前后的B幀的參考幀。
  • 由于P幀是參考幀,它可能造成解碼錯(cuò)誤的擴(kuò)散。
  • 由于是差值傳送,P幀的壓縮比較高。


3)B 幀 (雙向預(yù)測(cè)幀 bi-directional interpolated prediction frame)
既考慮與源圖像序列前面已編碼幀,也顧及源圖像序列后面已編碼幀之間的時(shí)間冗余信息來(lái)壓縮傳輸數(shù)據(jù)量的編碼圖像,也叫雙向預(yù)測(cè)幀。B幀要參考其前一個(gè)I或者P幀及其后面的一個(gè)P幀來(lái)生成一張完整的圖片。

B幀是雙向差別幀,B幀記錄的是本幀與前后幀的差別。要解碼B幀,不僅要取得之前的緩存畫面,還要解碼之后的畫面,通過(guò)前后畫面與本幀的疊加取得最終畫面。

B幀的預(yù)測(cè)和重構(gòu):
B幀以前面的 I幀或P幀為參考幀,找出B幀“某點(diǎn)”的預(yù)測(cè)值和兩個(gè)運(yùn)動(dòng)矢量,并取預(yù)測(cè)差值和運(yùn)動(dòng)矢量傳送。接收端根據(jù)運(yùn)行矢量在兩個(gè)參考幀中找出預(yù)測(cè)值并與差值求和,得到B幀“某點(diǎn)”樣值,從而可得到完整的B幀。

B幀特點(diǎn):

  • B幀是由前面的I幀或P幀和后面的P幀來(lái)進(jìn)行預(yù)測(cè)的。
  • B幀傳送的是它與前面的I幀或P幀之間的預(yù)測(cè)誤差及運(yùn)動(dòng)矢量。
  • B幀是雙向預(yù)測(cè)編碼幀。
  • B幀壓縮比最高,因?yàn)樗环从硡⒖紟g運(yùn)動(dòng)主體的變化情況,預(yù)測(cè)比較準(zhǔn)確。
  • B幀不是參考幀,不會(huì)造成解碼錯(cuò)誤導(dǎo)致的擴(kuò)散。

壓縮率比較:B幀 > P 幀 > I 幀



3、H264編碼結(jié)構(gòu)解析
H264除了實(shí)現(xiàn)對(duì)視頻的壓縮處理外,為了方便網(wǎng)絡(luò)傳輸,還提供了對(duì)應(yīng)的視頻編碼和分片策略。類似網(wǎng)絡(luò)數(shù)據(jù)幀封裝成IP幀,在H264中將其稱為組(GOP,group of picture)、片(slice)、宏塊(Macroblock),它們一起組成了H264的碼流分層結(jié)構(gòu)。H264將其組織成為序列(GOP)、圖片(pictrue)、片(Slice)、宏塊(Macroblock)、子塊(subblock)五個(gè)層次。

【H264結(jié)構(gòu)組織 圖7】
在這里插入圖片描述

H264將視頻分為連續(xù)的幀進(jìn)行傳輸,在連續(xù)的幀之間使用 I幀、P幀和B幀。同時(shí)對(duì)于幀內(nèi)而言,將圖像分塊為片、宏塊和字塊進(jìn)行分片傳輸;通過(guò)這個(gè)過(guò)程實(shí)現(xiàn)對(duì)視頻文件的壓縮包裝。

IDR(Instantaneous Decoding Refresh,即時(shí)解碼刷新)
一個(gè)序列的第一個(gè)圖像叫做IDR圖像(立即刷新圖像),IDR圖像都是 I 幀圖像。(I幀圖像不一定是IDR圖像)
I 幀和IDR幀都使用幀內(nèi)預(yù)測(cè)。I 幀不用參考任何幀,但是之后的P幀和B幀是有可能參考這個(gè)I幀之前的幀。但 IDR不允許這樣做。

比如原始圖像幀序?yàn)椋?IDR1 B2 B3 P4 B5 B6 P7 B8 B9 I10
解碼順序:

  • IDR1 P4 B2 B3 P7 B5 B6 I10 B8 B9 P13 B11 B12 P16 B14 B15 這里的B8可以跨過(guò)I10去參考P7
  • IDR1 P4 B2 B3 P7 B5 B6 IDR8 P11 B9 B10 P14 B11 B12 這里的B9就只能參照IDR8和P11,不可以參考IDR8前面的幀

IDR幀的核心作用是為了解碼的重同步,當(dāng)解碼器解碼到 IDR 圖像時(shí),立即將參考幀列清空,將已解碼的數(shù)據(jù)全部輸出或拋棄 ,重新查找參數(shù)集,開(kāi)始一個(gè)新的序列。這樣做的好處是,如果前一個(gè)序列出現(xiàn)重大失誤,在這里可以獲得重新同步的機(jī)會(huì)。IDR圖下之后的圖像永遠(yuǎn)不會(huì)使用 IDR幀之前的圖像的數(shù)據(jù)來(lái)解碼。

下圖為一個(gè) H264 碼流的示例(從碼流幀分析可以看出來(lái)B幀不能被當(dāng)作參考幀)

【H264 碼流的示例 圖8】
在這里插入圖片描述
GOP (圖像組)主要用作形容一個(gè)IDR幀 到下一個(gè)IDR幀之間的間隔了多少個(gè)幀。

比如說(shuō)GOP為120,如果是720 p60的話,就是2s一次 I幀。

在碼率不變的前提下,GOP值越大,P、B幀的數(shù)量越多,平均每個(gè)I、P、B幀占用的字節(jié)數(shù)越多,也更容易獲取較好的圖像質(zhì)量。

Reference(參考周期)指兩個(gè)P幀之間的距離。一個(gè)I幀所占用的字節(jié)數(shù)大于一個(gè)P幀,一個(gè)P幀所占用的字節(jié)數(shù)大于一個(gè)B幀。Reference越大,B幀的數(shù)量越多,同理也更容易獲得較好的圖像質(zhì)量。

不過(guò)通過(guò)提高GOP值來(lái)提高圖像質(zhì)量是有限度的,因?yàn)椋?/p>

  • 在遇到場(chǎng)景切換時(shí),H264編碼器會(huì)自動(dòng)強(qiáng)制插入一個(gè) I幀,此時(shí)實(shí)際的GOP值被縮短了。
  • 在一個(gè)GOP中,P、B幀是由 I幀預(yù)測(cè)得到,當(dāng) I幀的圖像質(zhì)量比較差時(shí),會(huì)影響到一個(gè)GOP中后續(xù)P、B幀的圖像質(zhì)量,直到下一個(gè)GOP開(kāi)始才得以回復(fù),因此GOP值不宜設(shè)置過(guò)大。
  • 由于P、B幀的復(fù)雜度大于I幀,所以過(guò)多的P、B幀會(huì)影響編碼效率,使編碼效率降低。
  • 過(guò)長(zhǎng)的GOP還會(huì)影響Seek操作的響應(yīng)速度,由于P、B幀是由前面的I或P幀預(yù)測(cè)得到的,所以Seek操作需要直接定位,解碼某一個(gè)P或B幀時(shí),需要先解碼得到本GOP內(nèi)的I幀及之前的N個(gè)預(yù)測(cè)幀才可以,GOP值越大,需要解碼的預(yù)測(cè)幀就越多,seek響應(yīng)的時(shí)間也越長(zhǎng)。

做直播時(shí),一般不用B幀,因?yàn)锽幀需要占用較大的緩存,并且容易出現(xiàn)延遲。因?yàn)锽幀要參考其前一個(gè)I或者P幀及其后面的一個(gè)P幀來(lái)生成一張完整的圖片,因此在編碼的時(shí)候B幀要等到P幀才能發(fā)送出去。

比如:收到的I、B、P幀的序列為(后面數(shù)值表示收到時(shí)間,單位 ms):I0 B40 B80 B120 P160,P幀是160ms的時(shí)候才收到, 這樣B40幀從收到到發(fā)出就會(huì)延遲 160-40=120ms。

三、NALU介紹


【NALU示意 圖8】
在這里插入圖片描述

  • SPS:序列參數(shù)集,SPS中保存了一組編碼視頻序列(Coded video sequence)的全局參數(shù)。
  • PPS:圖像參數(shù)集,對(duì)應(yīng)的是一個(gè)序列中某一幅圖像或者某一幅圖像的參數(shù)。
  • I幀:幀內(nèi)編碼幀,可獨(dú)立解碼生成完整的圖片。
  • P幀: 前向預(yù)測(cè)編碼幀,需要參考其前面的一個(gè)I 或者B 來(lái)生成一張完整的圖片。
  • B幀: 雙向預(yù)測(cè)內(nèi)插編碼幀,則要參考其前面?zhèn)€I或者P幀及其后面的一個(gè)P幀來(lái)生成一張完整的圖片。

注意:
1)從上圖我們可以知道,一張圖片可以有多個(gè)NALU。
2)對(duì)解碼器來(lái)說(shuō),需要先收到SPS和PPS進(jìn)行初始化,否則解碼器無(wú)法解出正常的幀數(shù)據(jù)。
3)發(fā)I幀之前,至少要發(fā)送一次SPS和PPS,因此如果在實(shí)際應(yīng)用中遇到H264無(wú)法解碼的時(shí)候,檢查SPS和PPS是否有接收到并正常初始化。


NALU結(jié)構(gòu)
H264原始碼流(裸流)是由一個(gè)接一個(gè)NALU組成,功能分為兩層:VCL(視頻編碼層)和NAL(網(wǎng)絡(luò)提取層):

  • VCL:包括核心壓縮引擎和塊,宏塊和片的語(yǔ)法級(jí)別定義,設(shè)計(jì)目標(biāo)是盡可能地獨(dú)立于網(wǎng)絡(luò)進(jìn)行高效的編碼。
  • NAL:負(fù)責(zé)將VCL產(chǎn)生的比特字符串適配到各種各樣的網(wǎng)絡(luò)和多元環(huán)境,覆蓋所有片級(jí)以上的語(yǔ)法級(jí)別。

在VCL進(jìn)行數(shù)據(jù)傳輸或存儲(chǔ)之前,這些編碼的VCL數(shù)據(jù),被映射或封裝進(jìn)NAL單元。
NALU=一組對(duì)應(yīng)視頻編碼的NALU頭部信息+一個(gè)原始字節(jié)序列負(fù)荷(RBSP,RawByte Sequence Payload)


【NALU結(jié)構(gòu)單元的主體結(jié)構(gòu) 圖9】
在這里插入圖片描述
一個(gè)原始的H264 NALU單元通常由 [StartCode] [NALU Header] [NALU Payload] 三部分組成,其中Start Code用于表示這是一個(gè)NALU單元的開(kāi)始,必須是“00 00 00 01” 或 “00 00 01”,除此之外基本相當(dāng)于一個(gè)NAL header+RBSP。

對(duì)于FFmpeg解復(fù)用,MP4,flv等文件讀取出來(lái)的packet不帶Start code,TS文件讀取出來(lái)的packet帶StartCode,因此在對(duì)MP4、flv文件解碼封裝的的時(shí)候,需要添加上Startcode,否則會(huì)出現(xiàn)生成文件損壞導(dǎo)致無(wú)法播放問(wèn)題。


NALU解析
每個(gè)NAL單元是一個(gè)一定語(yǔ)法元素的可變長(zhǎng)字節(jié)字符串,包括包含一個(gè)字節(jié)的頭信息(用來(lái)表示數(shù)據(jù)類型),以及若干整數(shù)字節(jié)的負(fù)荷數(shù)據(jù)。

NALU頭信息(占一個(gè)字節(jié)大?。?br> 【NALU頭信息 圖10】
在這里插入圖片描述
字節(jié)位參數(shù)說(shuō)明:

  • T:負(fù)荷數(shù)據(jù)類型,占 5bit。
    nal_unit_type:這個(gè)NALU單元的類型,1~12由H.264使用,24~31由H.264以外的應(yīng)用使用。

  • R:指示位,占2bit。
    nal_ref_idc.:取00~11,似乎指示這個(gè)NALU的重要性,如00的NALU解碼器可以丟棄它而不影響圖像的回放,0~3,取值越大,表示當(dāng)前NAL越重要,需要優(yōu)先受到保護(hù)。如果當(dāng)前NAL是屬于參考幀的片,或是序列參數(shù)集,或是圖像參數(shù)集這些重要的單位時(shí),本句法元素必需大于0。

  • F:禁止位,占1bit。
    forbidden_zero_bit: 在 H.264 規(guī)范中規(guī)定了這?位必須為 0。

H.264標(biāo)準(zhǔn)指出,當(dāng)數(shù)據(jù)流是儲(chǔ)存在介質(zhì)上時(shí),在每個(gè)NALU 前添加起始碼:0x000001 或 0x00000001,用來(lái)指示一個(gè)NALU 的起始和終止位置:

  • 在碼流中檢測(cè)起始碼,作為一個(gè)NALU的起始標(biāo)識(shí),當(dāng)檢測(cè)到下一個(gè)起始碼時(shí),當(dāng)前NALU結(jié)束。
  • 3字節(jié)的0x000001只有一種場(chǎng)合下使用,就是一個(gè)完整的幀被編為多個(gè)slice(片)的時(shí)候,包含這些slice的NALU 使用3字節(jié)起始碼。其余場(chǎng)合都是4字節(jié)0x00000001的。

例子:
0x00 00 00 01 67
0x00 00 00 01 68
0x00 00 00 01 65

0x67:二進(jìn)制 0110 0111 ,nal_unit_type:0 0111=7(十進(jìn)制)

【nal_unit_type數(shù)值對(duì)應(yīng)表1】
在這里插入圖片描述在這里插入圖片描述

四、H264 annexb模式

H264有兩種封裝模式:annexb模式和mp4模式。

  • annexb模式,屬于傳統(tǒng)模式,有startcode;SPS和PPS是在ES中。
  • mp4模式:mp4 mkv都是mp4模式,沒(méi)有startcode,SPS和PPS以及其它信息被封裝在container中,每一個(gè)frame前面4個(gè)字節(jié)是這個(gè)frame的長(zhǎng)度。

很多解碼器只支持annexb這種模式,因此需要將mp4做轉(zhuǎn)換:在ffmpeg中用h264_mp4toannexb_filter可以做轉(zhuǎn)換。
轉(zhuǎn)換源碼:

const AVBitStreamFilter *bsfilter = av_bsf_get_by_name("h264_mp4toannexb");
AVBSFContext *bsf_ctx = NULL;
// 2 初始化過(guò)濾器上下文
av_bsf_alloc(bsfilter, &bsf_ctx); //AVBSFContext;
// 3 添加解碼器屬性
avcodec_parameters_copy(bsf_ctx->par_in, ifmt_ctx->streams[videoindex]->codecpar);
av_bsf_init(bsf_ctx);

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多