日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

h264

發布時間:2025/3/14 编程问答 65 豆豆
生活随笔 收集整理的這篇文章主要介紹了 h264 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

H264--編碼原理以及I幀B幀P幀--1

?

前言

-----------------------

H264是新一代的編碼標準,以高壓縮高質量和支持多種網絡的流媒體傳輸著稱,在編碼方面,我理解的他的理論依據是:參照一段時間內圖像的統計結果表明,在相鄰幾幅圖像畫面中,一般有差別的像素只有10%以內的點,亮度差值變化不超過2%,而色度差值的變化只有1%以內。所以對于一段變化不大圖像畫面,我們可以先編碼出一個完整的圖像幀A,隨后的B幀就不編碼全部圖像,只寫入與A幀的差別,這樣B幀的大小就只有完整幀的1/10或更小!B幀之后的C幀如果變化不大,我們可以繼續以參考B的方式編碼C幀,這樣循環下去。這段圖像我們稱為一個序列(序列就是有相同特點的一段數據),當某個圖像與之前的圖像變化很大,無法參考前面的幀來生成,那我們就結束上一個序列,開始下一段序列,也就是對這個圖像生成一個完整幀A1,隨后的圖像就參考A1生成,只寫入與A1的差別內容。

在H264協議里定義了三種幀,完整編碼的幀叫I幀,參考之前的I幀生成的只包含差異部分編碼的幀叫P幀,還有一種參考前后的幀編碼的幀叫B幀。

H264采用的核心算法是幀內壓縮和幀間壓縮,幀內壓縮是生成I幀的算法,幀間壓縮是生成B幀和P幀的算法。

?

----------------------

序列的說明

----------------------

在H264中圖像以序列為單位進行組織,一個序列是一段圖像編碼后的數據流,以I幀開始,到下一個I幀結束。

一個序列的第一個圖像叫做 IDR 圖像(立即刷新圖像),IDR 圖像都是 I 幀圖像。H.264 引入 IDR 圖像是為了解碼的重同步,當解碼器解碼到 IDR 圖像時,立即將參考幀隊列清空,將已解碼的數據全部輸出或拋棄,重新查找參數集,開始一個新的序列。這樣,如果前一個序列出現重大錯誤,在這里可以獲得重新同步的機會。IDR圖像之后的圖像永遠不會使用IDR之前的圖像的數據來解碼。

一個序列就是一段內容差異不太大的圖像編碼后生成的一串數據流。當運動變化比較少時,一個序列可以很長,因為運動變化少就代表圖像畫面的內容變動很小,所以就可以編一個I幀,然后一直P幀、B幀了。當運動變化多時,可能一個序列就比較短了,比如就包含一個I幀和3、4個P幀。

-----------------------

三種幀的說明

-----------------------

I幀:幀內編碼幀 ,I幀表示關鍵幀,你可以理解為這一幀畫面的完整保留;解碼時只需要本幀數據就可以完成(因為包含完整畫面)


I幀特點:?
1.它是一個全幀壓縮編碼幀。它將全幀圖像信息進行JPEG壓縮編碼及傳輸;?
2.解碼時僅用I幀的數據就可重構完整圖像;?
3.I幀描述了圖像背景和運動主體的詳情;?
4.I幀不需要參考其他畫面而生成;?
5.I幀是P幀和B幀的參考幀(其質量直接影響到同組中以后各幀的質量);?
6.I幀是幀組GOP的基礎幀(第一幀),在一組中只有一個I幀;?
7.I幀不需要考慮運動矢量;?
8.I幀所占數據的信息量比較大。?


P幀:前向預測編碼幀。P幀表示的是這一幀跟之前的一個關鍵幀(或P幀)的差別,解碼時需要用之前緩存的畫面疊加上本幀定義的差別,生成最終畫面。(也就是差別幀,P幀沒有完整畫面數據,只有與前一幀的畫面差別的數據)


P幀的預測與重構:P幀是以I幀為參考幀,在I幀中找出P幀“某點”的預測值和運動矢量,取預測差值和運動矢量一起傳送。在接收端根據運動矢量從I幀中找出P幀“某點”的預測值并與差值相加以得到P幀“某點”樣值,從而可得到完整的P幀。
P幀特點:?
1.P幀是I幀后面相隔1~2幀的編碼幀;?
2.P幀采用運動補償的方法傳送它與前面的I或P幀的差值及運動矢量(預測誤差);?
3.解碼時必須將I幀中的預測值與預測誤差求和后才能重構完整的P幀圖像;?
4.P幀屬于前向預測的幀間編碼。它只參考前面最靠近它的I幀或P幀;?
5.P幀可以是其后面P幀的參考幀,也可以是其前后的B幀的參考幀;?
6.由于P幀是參考幀,它可能造成解碼錯誤的擴散;?
7.由于是差值傳送,P幀的壓縮比較高。?

B幀:雙向預測內插編碼幀。B幀是雙向差別幀,也就是B幀記錄的是本幀與前后幀的差別(具體比較復雜,有4種情況,但我這樣說簡單些),換言之,要解碼B幀,不僅要取得之前的緩存畫面,還要解碼之后的畫面,通過前后畫面的與本幀數據的疊加取得最終的畫面。B幀壓縮率高,但是解碼時CPU會比較累。

B幀的預測與重構?
B幀以前面的I或P幀和后面的P幀為參考幀,“找出”B幀“某點”的預測值和兩個運動矢量,并取預測差值和運動矢量傳送。接收端根據運動矢量在兩個參考幀中“找出(算出)”預測值并與差值求和,得到B幀“某點”樣值,從而可得到完整的B幀。
B幀特點?
1.B幀是由前面的I或P幀和后面的P幀來進行預測的;?
2.B幀傳送的是它與前面的I或P幀和后面的P幀之間的預測誤差及運動矢量;?
3.B幀是雙向預測編碼幀;?
4.B幀壓縮比最高,因為它只反映丙參考幀間運動主體的變化情況,預測比較準確;?
5.B幀不是參考幀,不會造成解碼錯誤的擴散。?

注:I、B、P各幀是根據壓縮算法的需要,是人為定義的,它們都是實實在在的物理幀。一般來說,I幀的壓縮率是7(跟JPG差不多),P幀是20,B幀可以達到50。可見使用B幀能節省大量空間,節省出來的空間可以用來保存多一些I幀,這樣在相同碼率下,可以提供更好的畫質。

--------------------------------

壓縮算法的說明

--------------------------------

h264的壓縮方法:

1.分組:把幾幀圖像分為一組(GOP,也就是一個序列),為防止運動變化,幀數不宜取多。?
2.定義幀:將每組內各幀圖像定義為三種類型,即I幀、B幀和P幀;?
3.預測幀:以I幀做為基礎幀,以I幀預測P幀,再由I幀和P幀預測B幀;?
4.數據傳輸:最后將I幀數據與預測的差值信息進行存儲和傳輸。

?

幀內(Intraframe)壓縮也稱為空間壓縮(Spatial compression)。當壓縮一幀圖像時,僅考慮本幀的數據而不考慮相鄰幀之間的冗余信息,這實際上與靜態圖像壓縮類似。幀內一般采用有損壓縮算法,由于幀內壓縮是編碼一個完整的圖像,所以可以獨立的解碼、顯示。幀內壓縮一般達不到很高的壓縮,跟編碼jpeg差不多。
  

幀間(Interframe)壓縮的原理是:相鄰幾幀的數據有很大的相關性,或者說前后兩幀信息變化很小的特點。也即連續的視頻其相鄰幀之間具有冗余信息,根據這一特性,壓縮相鄰幀之間的冗余量就可以進一步提高壓縮量,減小壓縮比。幀間壓縮也稱為時間壓縮(Temporal compression),它通過比較時間軸上不同幀之間的數據進行壓縮。幀間壓縮一般是無損的。幀差值(Frame differencing)算法是一種典型的時間壓縮法,它通過比較本幀與相鄰幀之間的差異,僅記錄本幀與其相鄰幀的差值,這樣可以大大減少數據量。

順便說下有損(Lossy )壓縮和無損(Lossy less)壓縮。無損壓縮也即壓縮前和解壓縮后的數據完全一致。多數的無損壓縮都采用RLE行程編碼算法。有損壓縮意味著解壓縮后的數據與壓縮前的數據不一致。在壓縮的過程中要丟失一些人眼和人耳所不敏感的圖像或音頻信息,而且丟失的信息不可恢復。幾乎所有高壓縮的算法都采用有損壓縮,這樣才能達到低數據率的目標。丟失的數據率與壓縮比有關,壓縮比越小,丟失的數據越多,解壓縮后的效果一般越差。此外,某些有損壓縮算法采用多次重復壓縮的方式,這樣還會引起額外的數據丟失。

?

前言

-------------

H264結構中,一個視頻圖像編碼后的數據叫做一幀,一幀由一個片(slice)或多個片組成,一個片由一個或多個宏塊(MB)組成,一個宏塊由16x16的yuv數據組成。宏塊作為H264編碼的基本單位。

-------------------------

名詞解釋 ------------------------- 場和幀 :?視頻的一場或一幀可用來產生一個編碼圖像。在電視中,為減少大面積閃爍現象,把一幀分成兩個隔行的場。 宏塊?:一個編碼圖像通常劃分成若干宏塊組成,一個宏塊由一個16×16亮度像素和附加的一個8×8 Cb和一個8×8 Cr彩色像素塊組成。 :每個圖象中,若干宏塊被排列成片的形式。片分為I片、B片、P片和其他一些片。 -- I片只包含I宏塊,P片可包含P和I宏塊,而B片可包含B和I宏塊。 -- I宏塊利用從當前片中已解碼的像素作為參考進行幀內預測。 -- P宏塊利用前面已編碼圖象作為參考圖象進行幀內預測。 -- B宏塊則利用雙向的參考圖象(前一幀和后一幀)進行幀內預測。 ?片的目的是為了限制誤碼的擴散和傳輸,使編碼片相互間是獨立的。某片的預測不能以其它片中的宏塊為參考圖像,這樣某一片中的預測誤差才不會傳播到其它片中去。

-----------------------------------------------

H264/AVC 的分層結構

-----------------------------------------------

H.264的主要目標是:

1.高的視頻壓縮比;

2.良好的網絡親和性;

為了完成這些目標H264的解決方案是:

1.VCL video coding layer?視頻編碼層;

2.NAL network abstraction layer?網絡提取層;

?

其中,VCL層是對核心算法引擎,塊,宏塊及片的語法級別的定義,他最終輸出編碼完的數據 SODB;

NAL層定義片級以上的語法級別(如序列參數集和圖像參數集,針對網絡傳輸),同時支持以下功能:獨立片解碼,起始碼唯一保證,SEI以及流格式編碼數據傳送,NAL層將SODB打包成RBSP然后加上NAL頭,組成一個NALU(NAL單元);

---------------------------------------------

H264網絡傳輸的結構

---------------------------------------------

H264在網絡傳輸的是NALU,NALU的結構是:NAL頭+RBSP,實際傳輸中的數據流如圖所示:


?

?

?

從前面的分析我們知道,VCL層出來的是編碼完的視頻幀數據,這些幀可能是I、B、P幀,而且這些幀可能屬于不同的序列,再者同一個序列還有相對應的一套序列參數集和圖片參數集等等,所以要完成視頻的解碼,不僅需要傳輸VCL層編碼出來的視頻幀數據,還需要傳輸序列參數集、圖像參數集等數據。

NALU頭用來標識后面的RBSP是什么類型的數據,他是否會被其他幀參考以及網絡傳輸是否有錯誤。

RBSP用來存放下表中的一種:

?

RBSP類型所寫描述
參數集PS序列的全局信息,如圖像尺寸,視頻格式等
增強信息SEI視頻序列解碼的增強信息
圖像界定符PD視頻圖像的邊界
編碼片SLICE編碼片的頭信息和數據
數據分割?DP片層的數據,用于錯誤恢復解碼
序列結束符?表明一個序列的結束,下一個圖像為IDR圖像
流結束符?表明該流中已沒有圖像
填充數據?亞元數據,用于填充字節

?

其中,

參數集:包括序列參數集 SPS?和圖像參數集 PPS
SPS
?包含的是針對一連續編碼視頻序列的參數,如標識符 seq_parameter_set_id、幀數及 POC 的約束、參考幀數目、解碼圖像尺寸和幀場編碼模式選擇標識等等。
PPS對應的是一個序列中某一幅圖像或者某幾幅圖像,其參數如標識符 pic_parameter_set_id、可選的 seq_parameter_set_id、熵編碼模式選擇標識、片組數目、初始量化參數和去方塊濾波系數調整標識等等。


數據分割:組成片的編碼數據存放在 3 個獨立的 DP(數據分割,A、B、C)中,各自包含一個編碼片的子集。分割A包含片頭和片中每個宏塊頭數據。分割B包含幀內和 SI 片宏塊的編碼殘差數據。分割 C包含幀間宏塊的編碼殘差數據。每個分割可放在獨立的 NAL 單元并獨立傳輸。


-----------------------------------------

NALU頭結構

----------------------------------------
NALU頭結構:nal_unit_type(5bit)+nal_reference_bit(2bit)+forbidden_bit(1bit)

1.nal_unit_type:NALU類型取值如下表所示。

?

nal_unit_type

NAL類型

C

0

未使用

?

1

非IDR圖像中不采用數據劃分的片段

2,3,4

2

非IDR圖像中A類數據劃分片段

2

3

非IDR圖像中B類數據劃分片段

3

4

非IDR圖像中C類數據劃分片段

4

5

IDR圖像的片

2,3

6

補充增強信息單元(SEI)

5

7

序列參數集

0

8

圖像參數集

1

9

分界符

6

10

序列結束

7

11

碼流結束

8

12

填充

9

13..23

保留

?

24..31

不保留

?

?

?



2.nal_reference_bit:nal重要性指示,標志該NAL單元的重要性,值越大,越重要,解碼器在解碼處理不過來的時候,可以丟掉重要性為0的NALU。不同類型的NALU的重要性指示如下表所示。

?

nal_unit_type

NAL類型

nal_reference_bit

0

未使用

0

1

非IDR的片

此片屬于參考幀,則不等于0,

不屬于參考幀,則等與0

2

片數據A分區

同上

3

片數據B分區

同上

4

片數據C分區

同上

5

IDR圖像的片

5

6

補充增強信息單元(SEI)

0

7

序列參數集

非0

8

圖像參數集

非0

9

分界符

0

10

序列結束

0

11

碼流結束

0

12

填充

0

13..23

保留

0

24..31

不保留

0

?

所謂參考幀,就是在其他幀解碼時需要參照的幀。比如一個I幀可能被一個或多個B幀參考,一個B幀可能被某個P幀參考。

從這個表我們也可以看出來,DIR的I幀是非常重要的,他一丟,那么這個序列的所有幀都沒辦法解碼了;然后序列參數集和圖像參數集也很重要,沒有序列參數集,這個序列的幀就沒法解;沒有圖像參數集,那用到這個圖像參數集的幀都沒法解。

3.forbidden_bit:禁止位,初始為0,當網絡發現NAL單元有比特錯誤時可設置該比特為1,以便接收方糾錯或丟掉該單元。

?


-------------------------------------
NAL的開始和結束

-------------------------------

編碼器將每個NAL各自獨立、完整地放入一個分組,因為分組都有頭部,解碼器可以方便地檢測出NAL的分界,并依次取出NAL進行解碼。每個NAL前有一個起始碼 0x00 00 01(或者0x00 00 00 01),解碼器檢測每個起始碼,作為一個NAL的起始標識,當檢測到下一個起始碼時,當前NAL結束。同時H.264規定,當檢測到0x000000時,也可以表征當前NAL的結束。那么NAL中數據出現0x000001或0x000000時怎么辦?H.264引入了防止競爭機制,如果編碼器檢測到NAL數據存在0x000001或0x000000時,編碼器會在最后個字節前插入一個新的字節0x03,這樣:
0x000000->0x00000300
0x000001->0x00000301
0x000002->0x00000302
0x000003->0x00000303
解碼器檢測到0x000003時,把03拋棄,恢復原始數據。解碼器在解碼時,首先逐個字節讀取NAL的數據,統計NAL的長度,然后再開始解碼。

?

--------------------------------------

NALU的順序要求

--------------------------------------

H.264/AVC標準對送到解碼器的NAL單元順序是有嚴格要求的,如果NAL單元的順序是混亂的,必須將其重新依照規范組織后送入解碼器,否則解碼器不能夠正確解碼。
1.序列參數集NAL單元 必須在傳送所有以此參數集為參考的其他NAL單元之前傳送,不過允許這些NAL單元中間出現重復的序列參數集NAL單元。

所謂重復的詳細解釋為:序列參數集NAL單元都有其專門的標識,如果兩個序列參數集NAL單元的標識相同,就可以認為后一個只不過是前一個的拷貝,而非新的序列參數集。
2.圖像參數集NAL單元 必須在所有以此參數集為參考的其他NAL單元之前傳送,不過允許這些NAL單元中間出現重復的圖像參數集NAL單元,這一點與上述的序列參數集NAL單元是相同的。
3.不同基本編碼圖像中的片段(slice)單元和數據劃分片段(data partition)單元在順序上不可以相互交叉,即不允許屬于某一基本編碼圖像的一系列片段(slice)單元和數據劃分片段(data partition)單元中忽然出現另一個基本編碼圖像的片段(slice)單元片段和數據劃分片段(data partition)單元。
4.參考圖像的影響:如果一幅圖像以另一幅圖像為參考,則屬于前者的所有片段(slice)單元和數據劃分片段(data partition)單元必須在屬于后者的片段和數據劃分片段之后,無論是基本編碼圖像還是冗余編碼圖像都必須遵守這個規則。
5.基本編碼圖像的所有片段(slice)單元和數據劃分片段(data partition)單元必須在屬于相應冗余編碼圖像的片段(slice)單元和數據劃分片段(data partition)單元之前。
6.如果數據流中出現了連續的無參考基本編碼圖像,則圖像序號小的在前面。
7.如果arbitrary_slice_order_allowed_flag置為1,一個基本編碼圖像中的片段(slice)單元和數據劃分片段(data partition)單元的順序是任意的,如果arbitrary_slice_order_allowed_flag置為零,則要按照片段中第一個宏塊的位置來確定片段的順序,若使用數據劃分,則A類數據劃分片段在B類數據劃分片段之前,B類數據劃分片段在C類數據劃分片段之前,而且對應不同片段的數據劃分片段不能相互交叉,也不能與沒有數據劃分的片段相互交叉。
8.如果存在SEI(補充增強信息)單元的話,它必須在它所對應的基本編碼圖像的片段(slice)單元和數據劃分片段(data partition)單元之前,并同時必須緊接在上一個基本編碼圖像的所有片段(slice)單元和數據劃分片段(data partition)單元后邊。假如SEI屬于多個基本編碼圖像,其順序僅以第一個基本編碼圖像為參照。
9.如果存在圖像分割符的話,它必須在所有SEI 單元、基本編碼圖像的所有片段slice)單元和數據劃分片段(data partition)單元之前,并且緊接著上一個基本編碼圖像那些NAL單元。
10.如果存在序列結束符,且序列結束符后還有圖像,則該圖像必須是IDR(即時解碼器刷新)圖像。序列結束符的位置應當在屬于這個IDR圖像的分割符、SEI 單元等數據之前,且緊接著前面那些圖像的NAL單元。如果序列結束符后沒有圖像了,那么它的就在比特流中所有圖像數據之后。
11.流結束符在比特流中的最后。

?

------------------------------
H.264的NAL層處理

------------------------------


H264以NALU(NAL unit)為單位來支持編碼數據在基于分組交換技術網絡中傳輸。

NALU定義了可用于基于分組和基于比特流系統的基本格式,同時給出頭信息,從而提供了視頻編碼和外部世界的接口。



H264編碼過程中的三種不同的數據形式:

SODB 數據比特串-->最原始的編碼數據,即VCL數據;

RBSP 原始字節序列載荷-->在SODB的后面填加了結尾比特(RBSP trailing bits 一個bit“1”)若干比特“0”,以便字節對齊;

EBSP 擴展字節序列載荷-->在RBSP基礎上填加了仿校驗字節(0X03)它的原因是: 在NALU加到Annexb上時,需要添加每組NALU之前的開始碼StartCodePrefix,如果該NALU對應的slice為一幀的開始則用4位字節表示,ox00000001,否則用3位字節表示ox000001(是一幀的一部分)。另外,為了使NALU主體中不包括與開始碼相沖突的,在編碼時,每遇到兩個字節連續為0,就插入一個字節的0x03。解碼時將0x03去掉。也稱為脫殼操作。

編碼處理過程:

1.??將VCL層輸出的SODB封裝成nal_unit,?NALU是一個通用封裝格式,可以適用于有序字節流方式和IP包交換方式。

2.??針對不同的傳送網絡(電路交換|包交換),將nal_unit封裝成針對不同網絡的封裝格式(比如把nalu封裝成rtp包)。



---------------------------------------------------

處理過程一,VCL數據封裝成NALU

---------------------------------------------------


VCL層輸出的比特流SODB(String Of Data Bits),到nal_unit之間,經過了以下三步處理:

1.SODB字節對齊處理后封裝成RBSP(Raw Byte Sequence Payload)。

2.為防止RBSP的字節流與有序字節流傳送方式下的SCP(start_code_prefix_one_3bytes,0x000001)出現字節競爭情形,循環檢測RBSP前三個字節,在出現字節競爭時在第三字節前加入emulation_prevention_three_byte(0x03),具體方法:?

nal_unit( NumBytesInNALunit ) {

forbidden_zero_bit

nal_ref_idc

nal_unit_type

NumBytesInRBSP = 0

for( i = 1; i < NumBytesInNALunit; i++ ) {

if( i + 2 < NumBytesInNALunit && next_bits( 24 ) = = 0x000003 ) {

rbsp_byte[ NumBytesInRBSP++ ]

rbsp_byte[ NumBytesInRBSP++ ]

i += 2

emulation_prevention_three_byte /* equal to 0x03 */

} else

rbsp_byte[ NumBytesInRBSP++ ]

}

}

3.?防字節競爭處理后的RBSP再加一個字節的header(forbidden_zero_bit+ nal_ref_idc+ nal_unit_type),封裝成nal_unit.?

------------------------------------------------

處理過程二,NALU的RTP打包

------------------------------------------------

一、NALU打包成RTP的方式有三種:

1. 單一 NAL 單元模式
???? 即一個 RTP 包僅由一個完整的 NALU 組成. 這種情況下 RTP NAL 頭類型字段和原始的 H.264的
NALU 頭類型字段是一樣的.

2. 組合封包模式
??? 即可能是由多個 NAL 單元組成一個 RTP 包. 分別有4種組合方式: STAP-A, STAP-B, MTAP16, MTAP24.
那么這里的類型值分別是 24, 25, 26 以及 27.

3. 分片封包模式
??? 用于把一個 NALU 單元封裝成多個 RTP 包. 存在兩種類型 FU-A 和 FU-B. 類型值分別是 28 和 29.

?

還記得前面nal_unit_type的定義吧,0~23是給H264用的,24~31未使用,在rtp打包時,如果一個NALU放在一個RTP包里,可 以使用NALU的nal_unit_type,但是當需要把多個NALU打包成一個RTP包,或者需要把一個NALU打包成多個RTP包時,就定義新的 type來標識。

??????Type?? Packet????? Type name???????????????????????
????? ---------------------------------------------------------
????? 0????? undefined??????????????????????????????????? -
????? 1-23?? NAL unit??? Single NAL unit packet per H.264??
????? 24???? STAP-A???? Single-time aggregation packet????
????? 25???? STAP-B???? Single-time aggregation packet????
????? 26???? MTAP16??? Multi-time aggregation packet?????
????? 27???? MTAP24??? Multi-time aggregation packet?????
????? 28???? FU-A????? Fragmentation unit????????????????
????? 29???? FU-B????? Fragmentation unit?????????????????
????? 30-31? undefined???????????????????????????????????

?

二、三種打包方式的具體格式

1 .單一 NAL 單元模式

對于 NALU 的長度小于 MTU 大小的包, 一般采用單一 NAL 單元模式.
對于一個原始的 H.264 NALU 單元常由 [Start Code] [NALU Header] [NALU Payload] 三部分組成, 其中 Start Code 用于標示這是一個

NALU 單元的開始, 必須是 "00 00 00 01" 或 "00 00 01", NALU 頭僅一個字節, 其后都是 NALU 單元內容.
打包時去除 "00 00 01" 或 "00 00 00 01" 的開始碼, 把其他數據封包的 RTP 包即可.

?????? 0?????????????????? 1?????????????????? 2?????????????????? 3
?????? 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
????? +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
????? |F|NRI| type?? |?????????????????????????????????????????????? |
????? +-+-+-+-+-+-+-+-+?????????????????????????????????????????????? |
????? |?????????????????????????????????????????????????????????????? |
????? |?????????????? Bytes 2..n of a Single NAL unit???????????????? |
????? |?????????????????????????????????????????????????????????????? |
????? |?????????????????????????????? +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
????? |?????????????????????????????? :...OPTIONAL RTP padding??????? |
????? +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


如有一個 H.264 的 NALU 是這樣的:

[00 00 00 01 67 42 A0 1E 23 56 0E 2F ... ]

這是一個序列參數集 NAL 單元. [00 00 00 01] 是四個字節的開始碼, 67 是 NALU 頭, 42 開始的數據是 NALU 內容.

封裝成 RTP 包將如下:

[ RTP Header ] [ 67 42 A0 1E 23 56 0E 2F ]

即只要去掉 4 個字節的開始碼就可以了.


2 組合封包模式

其次, 當 NALU 的長度特別小時, 可以把幾個 NALU 單元封在一個 RTP 包中.


?????? 0?????????????????? 1?????????????????? 2?????????????????? 3
?????? 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
????? +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
????? |????????????????????????? RTP Header?????????????????????????? |
????? +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
????? |STAP-A NAL HDR |???????? NALU 1 Size?????????? | NALU 1 HDR??? |
????? +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
????? |???????????????????????? NALU 1 Data?????????????????????????? |
????? :?????????????????????????????????????????????????????????????? :
????? +?????????????? +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
????? |?????????????? | NALU 2 Size?????????????????? | NALU 2 HDR??? |
????? +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
????? |???????????????????????? NALU 2 Data?????????????????????????? |
????? :?????????????????????????????????????????????????????????????? :
????? |?????????????????????????????? +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
????? |?????????????????????????????? :...OPTIONAL RTP padding??????? |
????? +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+


3 Fragmentation Units (FUs).

而當 NALU 的長度超過 MTU 時, 就必須對 NALU 單元進行分片封包. 也稱為 Fragmentation Units (FUs).

?????? 0?????????????????? 1?????????????????? 2?????????????????? 3
?????? 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
????? +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
????? | FU indicator |?? FU header?? |?????????????????????????????? |
????? +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+?????????????????????????????? |
????? |?????????????????????????????????????????????????????????????? |
????? |???????????????????????? FU payload??????????????????????????? |
????? |?????????????????????????????????????????????????????????????? |
????? |?????????????????????????????? +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
????? |?????????????????????????????? :...OPTIONAL RTP padding??????? |
????? +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

????? Figure 14. RTP payload format for FU-A

?? FU indicator有以下格式:
????? +---------------+
????? |0|1|2|3|4|5|6|7|
????? +-+-+-+-+-+-+-+-+
????? |F|NRI|? Type?? |
????? +---------------+
?? FU指示字節的類型域 Type=28表示FU-A。。NRI域的值必須根據分片NAL單元的NRI域的值設置。
?
?? FU header的格式如下:
????? +---------------+
????? |0|1|2|3|4|5|6|7|
????? +-+-+-+-+-+-+-+-+
????? |S|E|R|? Type?? |
????? +---------------+
?? S: 1 bit
?? 當設置成1,開始位指示分片NAL單元的開始。當跟隨的FU荷載不是分片NAL單元荷載的開始,開始位設為0。
?? E: 1 bit
?? 當設置成1, 結束位指示分片NAL單元的結束,即, 荷載的最后字節也是分片NAL單元的最后一個字節。當跟隨的FU荷載不是分片NAL單元的最后分片,結束位設置為0。
?? R: 1 bit
?? 保留位必須設置為0,接收者必須忽略該位。
?? Type: 5 bits

三、拆包和解包

拆包:當編碼器在編碼時需要將原有一個NAL按照FU-A進行分片,原有的NAL的單元頭與分片后的FU-A的單元頭有如下關系:
原始的NAL頭的前三位為FU indicator的前三位,原始的NAL頭的后五位為FU header的后五位,FU indicator與FU header的剩余位數根據實際情況決定。
?
解包:當接收端收到FU-A的分片數據,需要將所有的分片包組合還原成原始的NAl包時,FU-A的單元頭與還原后的NAL的關系如下:
還原后的NAL頭的八位是由FU indicator的前三位加FU header的后五位組成,即:
nal_unit_type = (fu_indicator & 0xe0) | (fu_header & 0x1f)

四、代碼實現

從RTP包里面得到H264視頻數據的方法:

?

?
?//?功能:解碼RTP?H.264視頻
?//?參數:1.RTP包緩沖地址?2.RTP包數據大小?3.H264輸出地址?4.輸出數據大小
?//?返回:true:表示一幀結束??false:FU-A分片未結束或幀未結束?
?#define??RTP_HEADLEN?12?
?bool??UnpackRTPH264(?void???*??bufIn,??int??len,???void?**??pBufOut,???int???*??pOutLen)
??{
?????*?pOutLen??=???0?;
?????if??(len??<??RTP_HEADLEN)
??????{
?????????return???false?;
????}?
?
????unsigned??char?*??src??=??(unsigned??char?*?)bufIn??+??RTP_HEADLEN;
????unsigned??char??head1??=???*?src;?//?獲取第一個字節?
?????unsigned??char??head2??=???*?(src?+?1?);?//?獲取第二個字節?
?????unsigned??char??nal??=??head1??&???0x1f?;?//?獲取FU?indicator的類型域,?
?????unsigned??char??flag??=??head2??&???0xe0?;?//?獲取FU?header的前三位,判斷當前是分包的開始、中間或結束?
?????unsigned??char??nal_fua??=??(head1??&???0xe0?)??|??(head2??&???0x1f?);?//?FU_A?nal?
??????bool??bFinishFrame??=???false?;
?????if??(nal?==?0x1c?)?//?判斷NAL的類型為0x1c=28,說明是FU-A分片?
????????{?//?fu-a?
??????????if??(flag?==?0x80?)?//?開始?
????????????{
?????????????*?pBufOut??=??src?-?3?;
?????????????*?((?int?*?)(?*?pBufOut))??=???0x01000000??;?//?zyf:大模式會有問題?
??????????????*?((?char?*?)(?*?pBufOut)?+?4?)??=??nal_fua;
?????????????*??pOutLen??=??len??-??RTP_HEADLEN??+???3?;
????????}?
?????????else???if?(flag?==?0x40?)?//?結束?
????????????{
?????????????*?pBufOut??=??src?+?2?;
?????????????*??pOutLen??=??len??-??RTP_HEADLEN??-???2?;
????????}?
?????????else?//?中間?
????????????{
?????????????*?pBufOut??=??src?+?2?;
?????????????*??pOutLen??=??len??-??RTP_HEADLEN??-???2?;
????????}?
????}?
?????else?//?單包數據?
????????{
?????????*?pBufOut??=??src?-?4?;
?????????*?((?int?*?)(?*?pBufOut))??=???0x01000000?;?//?zyf:大模式會有問題?
??????????*??pOutLen??=??len??-??RTP_HEADLEN??+???4?;
????}?
?
????unsigned??char?*??bufTmp??=??(unsigned??char?*?)bufIn;
?????if??(bufTmp[?1?]??&???0x80?)
??????{
????????bFinishFrame??=???true?;?//?rtp?mark?
?????}?
?????else?
???????{
????????bFinishFrame??=???false?;
????}?
?????return??bFinishFrame;
}???


從RTP包里面得到AAC音頻數據的方法:


//功能:解RTP?AAC音頻包,聲道和采樣頻率必須知道。
//參數:1.RTP包緩沖地址?2.RTP包數據大小?3.H264輸出地址?4.輸出數據大小
//返回:true:表示一幀結束??false:幀未結束?一般AAC音頻包比較小,沒有分片。
bool?UnpackRTPAAC(void?*?bufIn,?int?recvLen,?void**?pBufOut,??int*?pOutLen)
{
????unsigned?char*??bufRecv?=?(unsigned?char*)bufIn;
????//char?strFileName[20];
????
????unsigned?char?ADTS[]?=?{0xFF,?0xF1,?0x00,?0x00,?0x00,?0x00,?0xFC};?
????int?audioSamprate?=?32000;//音頻采樣率
????int?audioChannel?=?2;//音頻聲道?1或2
????int?audioBit?=?16;//16位?固定
????switch(audioSamprate)
????{
????case??16000:
????????ADTS[2]?=?0x60;
????????break;
????case??32000:
????????ADTS[2]?=?0x54;
????????break;
????case??44100:
????????ADTS[2]?=?0x50;
????????break;
????case??48000:
????????ADTS[2]?=?0x4C;
????????break;
????case??96000:
????????ADTS[2]?=?0x40;
????????break;
????default:
????????break;
????}
????ADTS[3]?=?(audioChannel==2)?0x80:0x40;

????int?len?=?recvLen?-?16?+?7;
????len?<<=?5;//8bit?*?2?-?11?=?5(headerSize?11bit)
????len?|=?0x1F;//5?bit????1????????????
????ADTS[4]?=?len>>8;
????ADTS[5]?=?len?&?0xFF;
????*pBufOut?=?(char*)bufIn+16-7;
????memcpy(*pBufOut,?ADTS,?sizeof(ADTS));
????*pOutLen?=?recvLen?-?16?+?7;

????unsigned?char*?bufTmp?=?(unsigned?char*)bufIn;
????bool?bFinishFrame?=?false;
????if?(bufTmp[1]?&?0x80)
????{
????????//DebugTrace::D("Marker");
????????bFinishFrame?=?true;
????}
????else
????{
????????bFinishFrame?=?false;
????}
????return?true;
}

編碼器輸出格式

----------------------------------

總的來說H264的碼流的打包方式有兩種,一種為annex-b byte stream format的格式,這個是絕大部分編碼器的默認輸出格式,就是每個幀的開頭的3~4個字節是H264的start_code,0x00000001或者0x000001。
另一種是原始的NAL打包格式,就是開始的若干字節(1,2,4字節)是NAL的長度,而不是start_code,此時必須借助某個全局的數據來獲得編碼器的profile,level,PPS,SPS等信息才可以解碼。

?

@之前還疑惑過PPS 和SPS是哪里來的,答案是編碼器給出的。

?

------------------------------

編碼數據流分析

------------------------------

首先明確一下,NAL數據流的組成:開始碼+NAL頭(forbidden_bit+nal_ref+nal_type)+RBSP

下面對一段H264編碼數據流進行分析。

?

00 00 00 01 67 42 00 1E 99 A0 B1 31 00 00 00 01

H264的數據流分為兩種,一種是NAL UNIT stream(RTP),一種是 bits stream,

兩者可以互相轉換。我們分析的這個是 bit stream,根據AnnexB

00 00 00 01 67 42 00 1E 99 A0 B1 31 是 一個NAL,在兩個00 00 00 01之間

0110 0111 0100 0010 0000 0000 0001 1110 1001 1001 1010 0000 1011 0001 0011 0001

forbidden_zero_bit(1)= 0//網絡傳輸正確

nal_ref_idc(2)= 11//參考值為3

nal_unit_type(5) = 0 0111:seq_parameter_set_rbsp( )//7,序列參數集

說明這個NALU的RBSP里裝的是SPS數據 ,所以 processSPS

profile_idc(8):42:0100 0010

constraint_set0_flag(1):0

constraint_set1_flag(1):0

constraint_set2_flag(1):0

constraint_set3_flag(1):0

reserved_zero_4bits(4):0

level_idc(8):1E

seq_parameter_set_id(UE(V)):

ue(v): unsigned integer Exp-Golomb-coded syntax element with the left bit first. The parsing process for this descriptor is specified in subclause9.1

uvlC: 1001:根據Table9.1 , value= 0,只占1bit.

根據profile_idc忽略掉一部分。

log2_max_frame_num_minus4(ue(v): 001 1001,len = 5,value= 5

pic_order_cnt_type(ue(v)):01 1010,len = 3,value = 2

根據pic_order_cnt_type忽略幾個參數

num_ref_frames(ue):010,len = 3,value = 1

0000?1011 0001 0011 0001

gaps_in_frame_num_value_allowed_flag(1) = 0

pic_width_in_mbs_minus1(ue):000 1011 ,len = 7,value = 10;

pic_height_in_map_units_minus1(ue):0001 001,len = 7,value = 8

frame_mbs_only_flag(1) = 1

忽略1

direct_8x8_inference_flag(1):0

忽略

vui_parameters_present_flag(1):0

忽略

NALU結束

?

68 CE 38 80 00 00 00 01

0110 1000

forbidden_zero_bit(1)= 0

nal_ref_idc(2)= 11

nal_unit_type(5) =01000:pic_parameter_set_rbsp( ),7.3.2.2//8圖像參數集

1100

pic_parameter_set_id (ue)=0

seq_parameter_set_id(ue)=0

entropy_coding_mode_flag(1) :0, 重要的flag,0表示編碼Exp-Golomb coded and CAVLC,1表示CABAC

pic_order_present_flag(1):0

1110

num_slice_groups_minus1(ue):0

忽略

num_ref_idx_l0_active_minus1(ue):0

num_ref_idx_l1_active_minus1(ue):0

weighted_pred_flag(1);0

0011 1000 1000 0000

weighted_bipred_idc(2):00

pic_init_qp_minus26 /* relative to 26 */(se):0

pic_init_qs_minus26?/* relative to 26 */(se):0

chroma_qp_index_offset(se):0

deblocking_filter_control_present_flag(1);0

constrained_intra_pred_flag(1):0

redundant_pic_cnt_present_flag(1):0

忽略

NALU結束

?

65 88 80 21 71 27 1B 88…….3888*16 byte

65:0110 0101

forbidden_zero_bit(1)= 0

nal_ref_idc(2)= 11

nal_unit_type(5) =0 0101:slice_layer_without_partitioning_rbsp( )//IDR幀

Slice

Slice_Header:

first_mb_in_slice(ue):0

slice_type(ue):000 1000 = 7

pic_parameter_set_id(ue) = 0

80 21:000 0000 0010 0001

frame_num(u(v): frame_num?is used as an identifier for pictures and shall be represented by log2_max_frame_num_minus4 + 4 bits,9 bits = 0

忽略

if( nal_unit_type = = 5 ) //IDR frame

idr_pic_id(u(e)):0

忽略N多

ref_pic_list_reordering( ) 見7。3。3。1忽略,Islice,SI slice,B slice

nal_ref_idc =11 所以dec_ref_pic_marking( )

nal_unit_type = 5,所以

no_output_of_prior_pics_flag(1):0

long_term_reference_flag(1):0

忽略

。。71 27

001 0111 0001 0010 0111

slice_qp_delta(se(v):001 01,4:-2

忽略

?

slice_data( ):7.3.4

對I-Slice:忽略N多

進入if( moreDataFlag ) { if( MbaffFrameFlag && ( CurrMbAddr % 2 = = 0 | | ( CurrMbAddr % 2 = = 1 && prevMbSkipped ) ) )mb_field_decoding_flag

macroblock_layer( )}

mb_field_decoding_flag忽略

macroblock_layer( )

mb_type(ue(v):0

mb_pred( mb_type )

prev_intra4x4_pred_mode_flag[?luma4x4BlkIdx?](1bit,對babac是ae(v)):1

1 27:0001 0010 0111

prev_intra4x4_pred_mode_flag[?1?] : 0001,0,001

0010 0111

prev_intra4x4_pred_mode_flag[?2?] : 0010,0,010

prev_intra4x4_pred_mode_flag[?3] : 0111,0,111

……16個

1b 88 00 3e cf.

intra_chroma_pred_mode(ue(v)) :最后的一個1bit:0

?

接下來是macroblock_layer的coded_block_pattern和run level,既系數

c0 06 ad a0 18

1100 0000 0000 0110 1010 0000 0001 1000

coded_block_pattern(me(v):0,根據T= 47,0x2f

mb_qp_delta(se(v):):0 len =1

residual( )見7.3.5.3

residual_block( LumaLevel[ i8x8 * 4 + i4x4 ], 16 )

coeff_token(ce(v): 00 0000 0000 0110 1

nc = 0(left block and top block 相關的):

len: { // 0702

{ 1, 6, 8, 9,10,11,13,13,13,14,14,15,15,16,16,16,16},

{ 0, 2, 6, 8, 9,10,11,13,13,14,14,15,15,15,16,16,16},

{ 0, 0, 3, 7, 8, 9,10,11,13,13,14,14,15,15,16,16,16},

{ 0, 0, 0, 5, 6, 7, 8, 9,10,11,13,14,14,15,15,16,16},

},

{

{ 2, 6, 6, 7, 8, 8, 9,11,11,12,12,12,13,13,13,14,14},

{ 0, 2, 5, 6, 6, 7, 8, 9,11,11,12,12,13,13,14,14,14},

{ 0, 0, 3, 6, 6, 7, 8, 9,11,11,12,12,13,13,13,14,14},

{ 0, 0, 0, 4, 4, 5, 6, 6, 7, 9,11,11,12,13,13,13,14},

},

{

{ 4, 6, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 9,10,10,10,10},

{ 0, 4, 5, 5, 5, 5, 6, 6, 7, 8, 8, 9, 9, 9,10,10,10},

{ 0, 0, 4, 5, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,10,10,10},

{ 0, 0, 0, 4, 4, 4, 4, 4, 5, 6, 7, 8, 8, 9,10,10,10},

},

code:

{ 1, 5, 7, 7, 7, 7,15,11, 8,15,11,15,11,15,11, 7,4},

{ 0, 1, 4, 6, 6, 6, 6,14,10,14,10,14,10, 1,14,10,6},

{ 0, 0, 1, 5, 5, 5, 5, 5,13, 9,13, 9,13, 9,13, 9,5},

{ 0, 0, 0, 3, 3, 4, 4, 4, 4, 4,12,12, 8,12, 8,12,8},

},

{

{ 3,11, 7, 7, 7, 4, 7,15,11,15,11, 8,15,11, 7, 9,7},

{ 0, 2, 7,10, 6, 6, 6, 6,14,10,14,10,14,10,11, 8,6},

{ 0, 0, 3, 9, 5, 5, 5, 5,13, 9,13, 9,13, 9, 6,10,5},

{ 0, 0, 0, 5, 4, 6, 8, 4, 4, 4,12, 8,12,12, 8, 1,4},

},

{

{15,15,11, 8,15,11, 9, 8,15,11,15,11, 8,13, 9, 5,1},

{ 0,14,15,12,10, 8,14,10,14,14,10,14,10, 7,12, 8,4},

{ 0, 0,13,14,11, 9,13, 9,13,10,13, 9,13, 9,11, 7,3},

{ 0, 0, 0,12,11,10, 9, 8,13,12,12,12, 8,12,10, 6,2},

},

根據表查的:

code = 13,len = 15,i= 12,j=2

所以numcoeff = 12,numtrailingones = 2

010 0000 0001 1000: totalzeros:根據numcoeff

int lentab[TOTRUN_NUM][16] =

{

?

{ 1,3,3,4,4,5,5,6,6,7,7,8,8,9,9,9},

{ 3,3,3,3,3,4,4,4,4,5,5,6,6,6,6},

{ 4,3,3,3,4,4,3,3,4,5,5,6,5,6},

{ 5,3,4,4,3,3,3,4,3,4,5,5,5},

{ 4,4,4,3,3,3,3,3,4,5,4,5},

{ 6,5,3,3,3,3,3,3,4,3,6},

{ 6,5,3,3,3,2,3,4,3,6},

{ 6,4,5,3,2,2,3,3,6},

{ 6,6,4,2,2,3,2,5},

{ 5,5,3,2,2,2,4},

{ 4,4,3,3,1,3},

{ 4,4,2,1,3},?numcoeff開始

{ 3,3,1,2},

{ 2,2,1},

{ 1,1},

};

?

int codtab[TOTRUN_NUM][16] =

{

{1,3,2,3,2,3,2,3,2,3,2,3,2,3,2,1},

{7,6,5,4,3,5,4,3,2,3,2,3,2,1,0},

{5,7,6,5,4,3,4,3,2,3,2,1,1,0},

{3,7,5,4,6,5,4,3,3,2,2,1,0},

{5,4,3,7,6,5,4,3,2,1,1,0},

{1,1,7,6,5,4,3,2,1,1,0},

{1,1,5,4,3,3,2,1,1,0},

{1,1,1,3,3,2,2,1,0},

{1,0,1,3,2,1,1,1,},

{1,0,1,3,2,1,1,},

{0,1,1,2,1,3},

{0,1,1,1,1},?numcoeff開始

{0,1,1,1},

{0,1,1},

{0,1},

};

Code = 1,len = 2,i=2,j = 0,?totzeros = 2

Read run:?0 0000 0001 1000根據totzeros = 2

int lentab[TOTRUN_NUM][16] =

{

{1,1},

{1,2,2},

{2,2,2,2},

{2,2,2,3,3},

{2,2,3,3,3,3},

{2,3,3,3,3,3,3},

{3,3,3,3,3,3,3,4,5,6,7,8,9,10,11},

};

?

int codtab[TOTRUN_NUM][16] =

{

{1,0},

{1,1,0},

{3,2,1,0},

{3,2,1,1,0},

{3,2,3,2,1,0},

{3,0,1,3,2,5,4},

{7,6,5,4,3,2,1,1,1,1,1,1,1,1,1},

Code = 1,len =1,I = 0,j = 0

?

0.1.1 Slice data syntax

?

slice_data( ) {

C

Descriptor

if( entropy_coding_mode_flag )

??

while( !byte_aligned( ) )

??

cabac_alignment_one_bit

2

f(1)

CurrMbAddr = first_mb_in_slice * ( 1 + MbaffFrameFlag )

??

moreDataFlag = 1

??

prevMbSkipped = 0

??

do {

??

if( slice_type != I && slice_type != SI )

??

if( !entropy_coding_mode_flag ) {

??

mb_skip_run

2

ue(v)

prevMbSkipped = ( mb_skip_run > 0 )

??

for( i=0; i<mb_skip_run; i++ )

??

CurrMbAddr = NextMbAddress( CurrMbAddr )

??

moreDataFlag = more_rbsp_data( )

??

} else {

??

mb_skip_flag

2

ae(v)

moreDataFlag = !mb_skip_flag

??

}

??

if( moreDataFlag ) {

??

if( MbaffFrameFlag && ( CurrMbAddr % 2 = = 0 | |

( CurrMbAddr % 2 = = 1 && prevMbSkipped ) ) )

??

mb_field_decoding_flag

2

u(1) | ae(v)

macroblock_layer( )

2 | 3 | 4

?

}

??

if( !entropy_coding_mode_flag )

??

moreDataFlag = more_rbsp_data( )

??

else {

??

if( slice_type != I && slice_type != SI )

??

prevMbSkipped = mb_skip_flag

??

if( MbaffFrameFlag && CurrMbAddr % 2 = = 0 )

??

moreDataFlag = 1

??

else {

??

end_of_slice_flag

2

ae(v)

moreDataFlag = !end_of_slice_flag

??

}

??

}

??

CurrMbAddr = NextMbAddress( CurrMbAddr )

??

} while( moreDataFlag )

??

}

??

?

?

?

?

se(v) : CABAC正式介紹。根據Table 9 5 – coeff_token mapping to TotalCoeff( coeff_token ) and TrailingOnes( coeff_token )。

chroma_format_idc 無

?

?

?

Table9?1 – Bit strings with “prefix” and “suffix” bits and assignment to codeNum ranges (informative)

Bit string form

Range of codeNum

1

0

0 1 x0

1-2

0 0 1 x1?x0

3-6

0 0 0 1 x2?x1?x0

7-14

0 0 0 0 1 x3?x2?x1?x0

15-30

0 0 0 0 0 1 x4?x3?x2?x1?x0

31-62

?

0.1.1.1 Slice layer without partitioning RBSP syntax

?

slice_layer_without_partitioning_rbsp( ) {

C

Descriptor

slice_header( )

2

?

slice_data( ) /* all categories of slice_data( ) syntax */

2 | 3 | 4

?

rbsp_slice_trailing_bits( )

2

?

}

??

?

?

?

?

0.1.1.2 Sequence parameter set RBSP syntax

?

seq_parameter_set_rbsp( ) {

C

Descriptor

profile_idc

0

u(8)

constraint_set0_flag

0

u(1)

constraint_set1_flag

0

u(1)

constraint_set2_flag

0

u(1)

constraint_set3_flag

0

u(1)

reserved_zero_4bits?/* equal to 0 */

0

u(4)

level_idc

0

u(8)

seq_parameter_set_id

0

ue(v)

if( profile_idc = = 100 | | profile_idc = = 110 | |
profile_idc = = 122 | | profile_idc = = 144 ) {

??

chroma_format_idc

0

ue(v)

if( chroma_format_idc = = 3 )

??

residual_colour_transform_flag

0

u(1)

bit_depth_luma_minus8

0

ue(v)

bit_depth_chroma_minus8

0

ue(v)

qpprime_y_zero_transform_bypass_flag

0

u(1)

seq_scaling_matrix_present_flag

0

u(1)

if( seq_scaling_matrix_present_flag )

??

for( i = 0; i < 8; i++ ) {

??

seq_scaling_list_present_flag[?i]

0

u(1)

if( seq_scaling_list_present_flag[ i ] )

??

if( i < 6 )

??

scaling_list( ScalingList4x4[ i ], 16,
UseDefaultScalingMatrix4x4Flag[ i ])

0

?

else

??

scaling_list( ScalingList8x8[ i – 6 ], 64,
UseDefaultScalingMatrix8x8Flag[ i – 6 ] )

0

?

}

??

}

??

log2_max_frame_num_minus4

0

ue(v)

pic_order_cnt_type

0

ue(v)

if( pic_order_cnt_type = = 0 )

??

log2_max_pic_order_cnt_lsb_minus4

0

ue(v)

else if( pic_order_cnt_type = = 1 ) {

??

delta_pic_order_always_zero_flag

0

u(1)

offset_for_non_ref_pic

0

se(v)

offset_for_top_to_bottom_field

0

se(v)

num_ref_frames_in_pic_order_cnt_cycle

0

ue(v)

for( i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++ )

??

offset_for_ref_frame[?i?]

0

se(v)

}

??

num_ref_frames

0

ue(v)

gaps_in_frame_num_value_allowed_flag

0

u(1)

pic_width_in_mbs_minus1

0

ue(v)

pic_height_in_map_units_minus1

0

ue(v)

frame_mbs_only_flag

0

u(1)

if( !frame_mbs_only_flag )

??

mb_adaptive_frame_field_flag

0

u(1)

direct_8x8_inference_flag

0

u(1)

frame_cropping_flag

0

u(1)

if( frame_cropping_flag ) {

??

frame_crop_left_offset

0

ue(v)

frame_crop_right_offset

0

ue(v)

frame_crop_top_offset

0

ue(v)

frame_crop_bottom_offset

0

ue(v)

}

??

vui_parameters_present_flag

0

u(1)

if( vui_parameters_present_flag )

??

vui_parameters( )

0

?

rbsp_trailing_bits( )

0

?

}

??

?

?

Table7?1 – NAL unit type codes

nal_unit_type

Content of NAL unit and RBSP syntax structure

C

0

Unspecified

?

1

Coded slice of a non-IDR picture
slice_layer_without_partitioning_rbsp( )

2, 3, 4

2

Coded slice data partition A?
slice_data_partition_a_layer_rbsp( )

2

3

Coded slice data partition B?
slice_data_partition_b_layer_rbsp( )

3

4

Coded slice data partition C?
slice_data_partition_c_layer_rbsp( )

4

5

Coded slice of an IDR picture
slice_layer_without_partitioning_rbsp( )

2, 3

6

Supplemental enhancement information (SEI)
sei_rbsp( )

5

7

Sequence parameter set
seq_parameter_set_rbsp( )

0

8

Picture parameter set
pic_parameter_set_rbsp( )

1

9

Access unit delimiter
access_unit_delimiter_rbsp( )

6

10

End of sequence
end_of_seq_rbsp( )

7

11

End of stream
end_of_stream_rbsp( )

8

12

Filler data
filler_data_rbsp( )

9

13

Sequence parameter set extension
seq_parameter_set_extension_rbsp( )

10

14..18

Reserved

?

19

Coded slice of an auxiliary coded picture without partitioning
slice_layer_without_partitioning_rbsp( )

2, 3, 4

20..23

Reserved

?

24..31

Unspecified

?

?

?

?

?

byte_stream_nal_unit( NumBytesInNALunit ) {

C

Descriptor

while( next_bits( 24 ) != 0x000001 &&
next_bits( 32 ) != 0x00000001 )

??

leading_zero_8bits?/* equal to 0x00 */

?

f(8)

if( next_bits( 24 ) != 0x000001 )

??

zero_byte?/* equal to 0x00 */

?

f(8)

start_code_prefix_one_3bytes?/* equal to 0x000001 */

?

f(24)

nal_unit( NumBytesInNALunit)

??

while( more_data_in_byte_stream( ) &&
next_bits( 24 ) != 0x000001 &&
next_bits( 32 ) != 0x00000001 )

??

trailing_zero_8bits?/* equal to 0x00 */

?

f(8)

}

??

?

?

?

?

0.1.1.3 Picture parameter set RBSP syntax

?

pic_parameter_set_rbsp( ) {

C

Descriptor

pic_parameter_set_id

1

ue(v)

seq_parameter_set_id

1

ue(v)

entropy_coding_mode_flag

1

u(1)

pic_order_present_flag

1

u(1)

num_slice_groups_minus1

1

ue(v)

if( num_slice_groups_minus1 > 0 ) {

??

slice_group_map_type

1

ue(v)

if( slice_group_map_type = = 0 )

??

for( iGroup = 0; iGroup <= num_slice_groups_minus1; iGroup++ )

??

run_length_minus1[?iGroup?]

1

ue(v)

else if( slice_group_map_type = = 2 )

??

for( iGroup = 0; iGroup < num_slice_groups_minus1; iGroup++ ) {

??

top_left[?iGroup?]

1

ue(v)

bottom_right[?iGroup?]

1

ue(v)

}

??

else if( slice_group_map_type = = 3 | |?
slice_group_map_type = = 4 | |?
slice_group_map_type = = 5 ) {

??

slice_group_change_direction_flag

1

u(1)

slice_group_change_rate_minus1

1

ue(v)

} else if( slice_group_map_type = = 6 ) {

??

pic_size_in_map_units_minus1

1

ue(v)

for( i = 0; i <= pic_size_in_map_units_minus1; i++ )

??

slice_group_id[?i?]

1

u(v)

}

??

}

??

num_ref_idx_l0_active_minus1

1

ue(v)

num_ref_idx_l1_active_minus1

1

ue(v)

weighted_pred_flag

1

u(1)

weighted_bipred_idc

1

u(2)

pic_init_qp_minus26 /* relative to 26 */

1

se(v)

pic_init_qs_minus26?/* relative to 26 */

1

se(v)

chroma_qp_index_offset

1

se(v)

deblocking_filter_control_present_flag

1

u(1)

constrained_intra_pred_flag

1

u(1)

redundant_pic_cnt_present_flag

1

u(1)

if( more_rbsp_data( ) ) {

??

transform_8x8_mode_flag

1

u(1)

pic_scaling_matrix_present_flag

1

u(1)

if( pic_scaling_matrix_present_flag )

??

for( i = 0; i < 6 + 2* transform_8x8_mode_flag; i++ ) {

??

pic_scaling_list_present_flag[?i]

1

u(1)

if( pic_scaling_list_present_flag[ i ] )

??

if( i < 6 )

??

scaling_list( ScalingList4x4[ i ], 16,
UseDefaultScalingMatrix4x4Flag[ i ] )

1

?

else

??

scaling_list( ScalingList8x8[ i – 6 ], 64,
UseDefaultScalingMatrix8x8Flag[ i – 6 ] )

1

?

}

??

second_chroma_qp_index_offset

1

se(v)

}

??

rbsp_trailing_bits( )

1

?

}

??

?

0.1.2 Slice header syntax

?

slice_header( ) {

C

Descriptor

first_mb_in_slice

2

ue(v)

slice_type

2

ue(v)

pic_parameter_set_id

2

ue(v)

frame_num

2

u(v)

if( !frame_mbs_only_flag ) {

??

field_pic_flag

2

u(1)

if( field_pic_flag )

??

bottom_field_flag

2

u(1)

}

??

if( nal_unit_type = = 5 )

??

idr_pic_id

2

ue(v)

if( pic_order_cnt_type = = 0 ) {

??

pic_order_cnt_lsb

2

u(v)

if( pic_order_present_flag && !field_pic_flag )

??

delta_pic_order_cnt_bottom

2

se(v)

}

??

if( pic_order_cnt_type = = 1 && !delta_pic_order_always_zero_flag ) {

??

delta_pic_order_cnt[?0?]

2

se(v)

if( pic_order_present_flag && !field_pic_flag )

??

delta_pic_order_cnt[?1?]

2

se(v)

}

??

if( redundant_pic_cnt_present_flag )

??

redundant_pic_cnt

2

ue(v)

if( slice_type = = B )

??

direct_spatial_mv_pred_flag

2

u(1)

if( slice_type = = P | | slice_type = = SP | | slice_type = = B ) {

??

num_ref_idx_active_override_flag

2

u(1)

if( num_ref_idx_active_override_flag ) {

??

num_ref_idx_l0_active_minus1

2

ue(v)

if( slice_type = = B )

??

num_ref_idx_l1_active_minus1

2

ue(v)

}

??

}

??

ref_pic_list_reordering( )

2

?

if( ( weighted_pred_flag && ( slice_type = = P | | slice_type = = SP ) ) | |
( weighted_bipred_idc = = 1 && slice_type = = B ) )

??

pred_weight_table( )

2

?

if( nal_ref_idc != 0 )

??

dec_ref_pic_marking( )

2

?

if( entropy_coding_mode_flag && slice_type != I && slice_type != SI )

??

cabac_init_idc

2

ue(v)

slice_qp_delta

2

se(v)

if( slice_type = = SP | | slice_type = = SI ) {

??

if( slice_type = = SP )

??

sp_for_switch_flag

2

u(1)

slice_qs_delta

2

se(v)

}

??

if( deblocking_filter_control_present_flag ) {

??

disable_deblocking_filter_idc

2

ue(v)

if( disable_deblocking_filter_idc != 1 ) {

??

slice_alpha_c0_offset_div2

2

se(v)

slice_beta_offset_div2

2

se(v)

}

??

}

??

if( num_slice_groups_minus1 > 0 &&
slice_group_map_type >= 3 && slice_group_map_type <= 5)

??

slice_group_change_cycle

2

u(v)

}

??

?

0.1.3 Slice data syntax

?

slice_data( ) {

C

Descriptor

if( entropy_coding_mode_flag )

??

while( !byte_aligned( ) )

??

cabac_alignment_one_bit

2

f(1)

CurrMbAddr = first_mb_in_slice * ( 1 + MbaffFrameFlag )

??

moreDataFlag = 1

??

prevMbSkipped = 0

??

do {

??

if( slice_type != I && slice_type != SI )

??

if( !entropy_coding_mode_flag ) {

??

mb_skip_run

2

ue(v)

prevMbSkipped = ( mb_skip_run > 0 )

??

for( i=0; i<mb_skip_run; i++ )

??

CurrMbAddr = NextMbAddress( CurrMbAddr )

??

moreDataFlag = more_rbsp_data( )

??

} else {

??

mb_skip_flag

2

ae(v)

moreDataFlag = !mb_skip_flag

??

}

??

if( moreDataFlag ) {

??

if( MbaffFrameFlag && ( CurrMbAddr % 2 = = 0 | |

( CurrMbAddr % 2 = = 1 && prevMbSkipped ) ) )

??

mb_field_decoding_flag

2

u(1) | ae(v)

macroblock_layer( )

2 | 3 | 4

?

}

??

if( !entropy_coding_mode_flag )

??

moreDataFlag = more_rbsp_data( )

??

else {

??

if( slice_type != I && slice_type != SI )

??

prevMbSkipped = mb_skip_flag

??

if( MbaffFrameFlag && CurrMbAddr % 2 = = 0 )

??

moreDataFlag = 1

??

else {

??

end_of_slice_flag

2

ae(v)

moreDataFlag = !end_of_slice_flag

??

}

??

}

??

CurrMbAddr = NextMbAddress( CurrMbAddr )

??

} while( moreDataFlag )

??

}

??

The variable MbaffFrameFlag is derived as follows.

MbaffFrameFlag = ( mb_adaptive_frame_field_flag && !field_pic_flag ) (7-22)

?

0.1.4 Macroblock layer syntax

?

macroblock_layer( ) {

C

Descriptor

mb_type

2

ue(v) | ae(v)

if( mb_type = = I_PCM ) {

??

while( !byte_aligned( ) )

??

pcm_alignment_zero_bit

2

f(1)

for( i = 0; i < 256; i++ )

??

pcm_sample_luma[?i?]

2

u(v)

for( i = 0; i < 2 * MbWidthC * MbHeightC; i++ )

??

pcm_sample_chroma[?i?]

2

u(v)

} else {

??

noSubMbPartSizeLessThan8x8Flag = 1

??

if( mb_type != I_NxN &&

MbPartPredMode( mb_type, 0 ) != Intra_16x16 &&

NumMbPart( mb_type ) = = 4 ) {

??

sub_mb_pred( mb_type )

2

?

for( mbPartIdx = 0; mbPartIdx < 4; mbPartIdx++ )

??

if( sub_mb_type[ mbPartIdx ] != B_Direct_8x8 ) {

??

if( NumSubMbPart( sub_mb_type[ mbPartIdx ] ) > 1 )

??

noSubMbPartSizeLessThan8x8Flag = 0

??

} else if( !direct_8x8_inference_flag )

??

noSubMbPartSizeLessThan8x8Flag = 0

??

} else {

??

if( transform_8x8_mode_flag && mb_type = = I_NxN )

??

transform_size_8x8_flag

2

u(1) | ae(v)

mb_pred( mb_type )

2

?

}

??

if( MbPartPredMode( mb_type, 0 ) != Intra_16x16 ) {

??

coded_block_pattern

2

me(v) | ae(v)

if( CodedBlockPatternLuma > 0 &&

transform_8x8_mode_flag && mb_type != I_NxN &&

noSubMbPartSizeLessThan8x8Flag &&

( mb_type != B_Direct_16x16 | | direct_8x8_inference_flag ) )

??

transform_size_8x8_flag

2

u(1) | ae(v)

}

??

if( CodedBlockPatternLuma > 0 | | CodedBlockPatternChroma > 0 | |
MbPartPredMode( mb_type, 0 ) = = Intra_16x16 ) {

??

mb_qp_delta

2

se(v) | ae(v)

residual( )

3 | 4

?

}

??

}

??

}

??

?

0.1.4.1 Macroblock prediction syntax

?

mb_pred( mb_type ) {

C

Descriptor

if( MbPartPredMode( mb_type, 0 ) = = Intra_4x4 | |?
MbPartPredMode( mb_type, 0 ) = = Intra_8x8 | |?
MbPartPredMode( mb_type, 0 ) = = Intra_16x16 ) {

??

if( MbPartPredMode( mb_type, 0 ) = = Intra_4x4 )

??

for( luma4x4BlkIdx=0; luma4x4BlkIdx<16; luma4x4BlkIdx++ ) {

??

prev_intra4x4_pred_mode_flag[?luma4x4BlkIdx?]

2

u(1) | ae(v)

if( !prev_intra4x4_pred_mode_flag[?luma4x4BlkIdx?]?)

??

rem_intra4x4_pred_mode[?luma4x4BlkIdx?]

2

u(3) | ae(v)

}

??

if( MbPartPredMode( mb_type, 0 ) = = Intra_8x8 )

??

for( luma8x8BlkIdx=0; luma8x8BlkIdx<4; luma8x8BlkIdx++ ) {

??

prev_intra8x8_pred_mode_flag[?luma8x8BlkIdx?]

2

u(1) | ae(v)

if( !prev_intra8x8_pred_mode_flag[ luma8x8BlkIdx ] )

??

rem_intra8x8_pred_mode[?luma8x8BlkIdx?]

2

u(3) | ae(v)

}

??

if( chroma_format_idc != 0 )

??

intra_chroma_pred_mode

2

ue(v) | ae(v)

} else if( MbPartPredMode( mb_type, 0 ) != Direct ) {

??

for( mbPartIdx = 0; mbPartIdx < NumMbPart( mb_type ); mbPartIdx++)

??

if( ( num_ref_idx_l0_active_minus1 > 0 | |
mb_field_decoding_flag ) &&?
MbPartPredMode( mb_type, mbPartIdx ) != Pred_L1 )

??

ref_idx_l0[?mbPartIdx?]

2

te(v) | ae(v)

for( mbPartIdx = 0; mbPartIdx < NumMbPart( mb_type ); mbPartIdx++)

??

if( ( num_ref_idx_l1_active_minus1 > 0 | |
mb_field_decoding_flag ) &&?
MbPartPredMode( mb_type, mbPartIdx ) != Pred_L0 )

??

ref_idx_l1[?mbPartIdx?]

2

te(v) | ae(v)

for( mbPartIdx = 0; mbPartIdx < NumMbPart( mb_type ); mbPartIdx++)

??

if( MbPartPredMode ( mb_type, mbPartIdx ) != Pred_L1 )

??

for( compIdx = 0; compIdx < 2; compIdx++ )

??

mvd_l0[?mbPartIdx?][?0?][?compIdx]

2

se(v) | ae(v)

for( mbPartIdx = 0; mbPartIdx < NumMbPart( mb_type ); mbPartIdx++)

??

if( MbPartPredMode( mb_type, mbPartIdx ) != Pred_L0 )

??

for( compIdx = 0; compIdx < 2; compIdx++ )

??

mvd_l1[?mbPartIdx?][?0?][?compIdx]

2

se(v) | ae(v)

}

??

}

??

?

0.1.4.2 Residual data syntax

?

residual( ) {

C

Descriptor

if( !entropy_coding_mode_flag )

??

residual_block = residual_block_cavlc

??

else

??

residual_block = residual_block_cabac

??

if( MbPartPredMode( mb_type, 0 ) = = Intra_16x16 )

??

residual_block( Intra16x16DCLevel, 16 )

3

?

for( i8x8 = 0; i8x8 < 4; i8x8++ ) /* each luma 8x8 block */

??

if( !transform_size_8x8_flag | | !entropy_coding_mode_flag )

??

for( i4x4 = 0; i4x4 < 4; i4x4++ ) { /* each 4x4 sub-block of block */

??

if( CodedBlockPatternLuma & ( 1 << i8x8 ) )

??

if( MbPartPredMode( mb_type, 0 ) = = Intra_16x16 )

??

residual_block( Intra16x16ACLevel[ i8x8 * 4 + i4x4 ], 15 )

3

?

else

??

residual_block( LumaLevel[ i8x8 * 4 + i4x4 ], 16 )

3 | 4

?

else if( MbPartPredMode( mb_type, 0 ) = = Intra_16x16 )

??

for( i = 0; i < 15; i++ )

??

Intra16x16ACLevel[ i8x8 * 4 + i4x4 ][ i ] = 0

??

else

??

for( i = 0; i < 16; i++ )

??

LumaLevel[ i8x8 * 4 + i4x4 ][ i ] = 0

??

if( !entropy_coding_mode_flag && transform_size_8x8_flag )

??

for( i = 0; i < 16; i++ )

??

LumaLevel8x8[ i8x8 ][ 4 * i + i4x4 ] =
LumaLevel[ i8x8 * 4 + i4x4 ][ i ]

??

}

??

else if( CodedBlockPatternLuma & ( 1 << i8x8 ) )

??

residual_block( LumaLevel8x8[ i8x8 ], 64 )

3 | 4

?

else

??

for( i = 0; i < 64; i++ )

??

LumaLevel8x8[ i8x8 ][ i ] = 0

??

if( chroma_format_idc != 0 ) {

??

NumC8x8 = 4 / ( SubWidthC * SubHeightC )

??

for( iCbCr = 0; iCbCr < 2; iCbCr++ )

??

if( CodedBlockPatternChroma & 3 ) /* chroma DC residual present */

??

residual_block( ChromaDCLevel[ iCbCr ], 4 * NumC8x8 )

3 | 4

?

else

??

for( i = 0; i < 4 * NumC8x8; i++ )

??

ChromaDCLevel[ iCbCr ][ i ] = 0

??

for( iCbCr = 0; iCbCr < 2; iCbCr++ )

??

for( i8x8 = 0; i8x8 < NumC8x8; i8x8++ )

??

for( i4x4 = 0; i4x4 < 4; i4x4++ )

??

if( CodedBlockPatternChroma & 2 )
/* chroma AC residual present */

??

residual_block( ChromaACLevel[ iCbCr ][ i8x8*4+i4x4 ], 15)

3 | 4

?

else

??

for( i = 0; i < 15; i++ )

??

ChromaACLevel[ iCbCr ][ i8x8*4+i4x4 ][ i ] = 0

??

}

??

?

?

residual_block_cavlc( coeffLevel, maxNumCoeff ) {

C

Descriptor

for( i = 0; i < maxNumCoeff; i++ )

??

coeffLevel[ i ] = 0

??

coeff_token

3 | 4

ce(v)

if( TotalCoeff( coeff_token ) > 0 ) {

??

if( TotalCoeff( coeff_token ) > 10 && TrailingOnes( coeff_token ) < 3 )

??

suffixLength = 1

??

else

??

suffixLength = 0

??

for( i = 0; i < TotalCoeff( coeff_token ); i++ )

??

if( i < TrailingOnes( coeff_token ) ) {

??

trailing_ones_sign_flag

3 | 4

u(1)

level[ i ] = 1 – 2 * trailing_ones_sign_flag

??

} else {

??

level_prefix

3 | 4

ce(v)

levelCode = ( Min( 15, level_prefix ) << suffixLength )

??

if( suffixLength > 0 | | level_prefix >= 14 ) {

??

level_suffix

3 | 4

u(v)

levelCode += level_suffix

??

}

??

if( level_prefix > = 15 && suffixLength = = 0 )

??

levelCode += 15

??

if( level_prefix > = 16 )

??

levelCode += ( 1 << ( level_prefix – 3 ) ) – 4096

??

if( i = = TrailingOnes( coeff_token ) &&?
TrailingOnes( coeff_token ) < 3 )

??

levelCode += 2

??

if( levelCode % 2 = = 0 )

??

level[ i ] = ( levelCode + 2 ) >> 1

??

else

??

level[ i ] = ( –levelCode – 1 ) >> 1

??

if( suffixLength = = 0 )

??

suffixLength = 1

??

if( Abs( level[ i ] ) > ( 3 << ( suffixLength – 1 ) ) &&?
suffixLength < 6 )

??

suffixLength++

??

}

??

if( TotalCoeff( coeff_token ) < maxNumCoeff ) {

??

total_zeros

3 | 4

ce(v)

zerosLeft = total_zeros

??

} else

??

zerosLeft = 0

??

for( i = 0; i < TotalCoeff( coeff_token ) – 1; i++ ) {

??

if( zerosLeft > 0 ) {

??

run_before

3 | 4

ce(v)

run[ i ] = run_before

??

} else

??

run[ i ] = 0

??

zerosLeft = zerosLeft – run[ i ]

??

}

??

run[ TotalCoeff( coeff_token ) – 1 ] = zerosLeft

??

coeffNum = ?1

??

for( i = TotalCoeff( coeff_token ) – 1; i >= 0; i-- ) {

??

coeffNum += run[ i ] + 1

??

coeffLevel[ coeffNum ] = level[ i ]

??

}

??

}

??

}

解碼器在解碼時,首先逐個字節讀取NAL的數據,統計NAL的長度,然后再開始解碼。

nal_unit( NumBytesInNALunit ) {/* NumBytesInNALunit為統計出來的數據長度 */
forbidden_zero_bit?// forbidden_zero_bit 等于 0表示網絡傳輸沒有出錯
nal_ref_idc?// 指示當前 NAL 的優先級。取值范圍為 0-3, 值越高,表示當前 NAL 越重要,需要優先受到保護。H.264 規定如果當前 NAL 是屬于參考幀的片,或是序列參數集,或是圖像參數集這些重要的數據單位時,本句法元素必須大于 0。
nal_unit_type?// NAL類型 指明當前 NAL unit 的類型
NumBytesInRBSP?=?0?
/* rbsp_byte[i] RBSP 的第 i 個字節。 RBSP 指原始字節載荷,它是 NAL 單元的數據部分的封裝格式,封裝的數據來自 SODB(原始數據比特流)。SODB 是編碼后的原始數據,SODB 經封裝為 RBSP 后放入 NAL 的數據部分。下面介紹一個 RBSP 的生成順序。
從 SODB 到 RBSP 的生成過程:?
- 如果 SODB 內容是空的,生成的 RBSP 也是空的?
- 否則,RBSP 由如下的方式生成:?
1) RBSP 的第一個字節直接取自 SODB 的第 1 到 8 個比特,(RBSP 字節內的比特按照從左到右對應為從高到低的順序排列,most significant),以此類推,RBSP 其余的每個字節都直接取自 SODB的相應比特。RBSP 的最后一個字節包含 SODB 的最后幾個比特,及如下的 rbsp_trailing_bits()
2) rbsp_trailing_bits()的第一個比特是 1,接下來填充 0,直到字節對齊。(填充 0 的目的也是為了字節對齊)?
3) 最后添加若干個 cabac_zero_word(其值等于 0x0000)?
*/?
for( i?=?1; i?<</span> NumBytesInNALunit; i++?) {
if( i?+?2?<</span> NumBytesInNALunit&&?next_bits(24?)=?=?0x000003?) {?
/* 0x000003偽起始碼,需要刪除0x03這個字節 */?
rbsp_byte[ NumBytesInRBSP++?]?
rbsp_byte[ NumBytesInRBSP++?]?
i?+=?2?/* 取出前兩個0x00后,跳過0x03 */?
//emulation_prevention_three_byte NAL 內部為防止與起始碼競爭而引入的填充字節 ,值為 0x03。
emulation_prevention_three_byte?
}?else?
rbsp_byte[ NumBytesInRBSP++?]?/* 繼續讀取后面的字節 */


}?
}

?

序列參數集(SPS)

句法

C

Desc

seq_parameter_set_rbsp(){

??

profile_idc/*指明所用的Profile */

0

u(8)

constraint_set0_flag

0

u(1)

constraint_set1_flag

0

u(1)

constraint_set1_flag

0

u(1)

reserved_zero_5bits?/* equal to 0 */

0

u(5)

level_idc?/*?指明所用的Level */

0

u(8)

seq_parameter_set_id?/*指明本序列參數集的id號,0-31,被圖像集引用,編碼需要產生新的序列集時,使用新的id,而不是改變原來參數集的內容?*/

0

ue(v)

log2_max_frame_num_minus4/*為讀取元素frame_num服務,frame_num標識圖像的解碼順序,frame_num的解碼函數是ue(v),其中v=log2_max_frame_num_minus4+4,該元素同時指明frame_num的最大值MaxFrameNum=2( log2_max_frame_num_minus4+4)*/

0

ue(v)

pic_order_cnt_type?/*?指明poc的編碼方法,poc標識圖像的播放順序,poc可以由frame_num計算,也可以顯示傳送。poc共三種計算方式?*/

0

ue(v)

if(pic_order_cnt_type==0)

??

log2_max_pic_order_cnt_lsb_minus4?/*?指明變量MaxPicOrderCntLsb的值,MaxPicOrderCntLsb=2(log2_max_pic_order_cnt_lsb_minus4+4) */

0

ue(v)

else if(pic_order_cnt_type==1){

??

delta_pic_order_always_zero_flag?/*?等于1時,元素delta_pic_order_cnt[0]和delta_pic_order_cnt[1]不在片頭中出現,并且它們的默認值是0,等于0時,上述兩元素出現的片頭中?*/

0

u(1)

offset_for_non_ref_pic?/*?用來計算非參考幀或場的poc,[-231,231-1] */

0

se(v)

offset_for_top_to_bottom_field/*計算幀的底場的poc */

0

se(v)

num_ref_frames_inpic_order_cnt_cycle?/*?用來解碼poc,[0.255] */

0

ue(v)

for(i=0;i<num_ref_frames_inpic_order_cnt_cycle;i++)

??

offset_for_ref_frame[i]/*用來解碼poc,對于循環中的每個元素指定一個偏移?*/

0

se(v)

}

??

num_ref_frames?/*?參考幀隊列可達到的最大長度,[0,16] */

0

ue(v)

gaps_in_frame_num_value_allowed_flag /* 為1,允許slice header中的frame_num不連續 */

0

u(1)

pic_width_inmbs_minus1?/*本元素加1,指明以宏塊為單位的圖像寬度PicWidthInMbs=pic_width_in_mbs_minus1+1 */

0

ue(v)

pic_height_in_map_units_minus1?/*?本元素加1,指明以宏塊為單位的圖像高寬度PicHeightInMapUnitsMbs=pic_height_in_map_units_minus1+1 */

0

ue(v)

frame_mbs_only_flag?/*?等于0表示本序列中所有圖像均為幀編碼;等于1,表示可能是幀,也可能場或幀場自適應,具體編碼方式由其它元素決定。結合前一元素:FrameHeightInMbs=(2-frame_mbs_only_flag)*PicHeightInMapUnits */

0

ue(v)

if(frame_mbs_only_flag)

??

mb_adaptiv_frame_field_flag?/*?指明本序列是否是幀場自適應模式:

frame_mbs_only_flag=1,全部是幀

frame_mbs_only_flag=0,?mb_adaptiv_frame_field_flag=0,幀場共存

frame_mbs_only_flag=0,?mb_adaptiv_frame_field_flag=1,幀場自適應和場共存*/

0

u(1)

direct_8x8_inference_flag?/*?用于指明B片的直接和skip模式下的運動矢量的計算方式?*/

0

u(1)

frame_cropping_flag?/*解碼器是否要將圖像裁剪后輸出,如果是,后面為裁剪的左右上下的寬度?*/

0

u(1)

if(frame_cropping_flag){

??

frame_crop_left_offset

0

ue(1)

frame_crop_right_offset

0

ue(1)

frame_crop_top_offset

0

ue(1)

frame_crop_bottom_offset

0

ue(1)

}

??

vui_parameters_present_flag?/*?指明vui子結構是否出現在碼流中,vui子結構在附錄中指明,用于表征視頻格式的信息?*/

0

u(1)

if(vui_parameters_present_flag)

??

vui_parameters()

0

?

rbsp_trailing_bits()

0

?

}

??

轉載于:https://www.cnblogs.com/virusolf/p/4942998.html

總結

以上是生活随笔為你收集整理的h264的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。