H264 Annex B 與 AVCC的區別

   本文鏈接:https://blog.csdn.net/Romantic_Energy/article/details/50508332

   首先要理解的是沒有標準的H.264基本流格式。文檔中的確包含了一個Annex,特別是描述了一種可能的格式Annex B格式,但是這個並不是一個必須要求的格式。標準文檔中指定了視頻怎樣編碼成獨立的包,但是這些包是怎樣存儲和傳輸的卻是開放的。


一. Annex B
A.Network Abstraction Layer Units
    視頻編碼成的包叫做Network Abstraction Layer Units, 也簡稱爲NALU、NAL,每個NALU包都可以被單獨的解析和處理,每個NALU包的第一個字節包含了NALU類型,bit3-bit7包含的內容尤其重要(bit 0一定是off的,bit1-2指定了這個NALU是否被其他NALU引用)。
    NALU格式分爲2類,VCL和non-VCL,總共有19種不同的NALU格式。
       

VCL, Video Coding Layer packets contain the actual visual information.  即視頻編碼後的數據
        Non-VCL, contain metadata that may or may not be required to decode the video.  非視頻數據,配置信息

    一個單獨的NALU包、或者甚至一個VCL NALU包都不意味着是一個獨立的幀,一幀數據可以被分割成幾個NALU,一個或多個NALU組成了一個Access Units(AU),AU包含了一個完整的幀。把幀分割成幾個獨立的NALU需要耗費許多CPU資源,所以分割幀數據並不經常使用。
    以下是所有定義了的NALU類型:    
0      Unspecified                                                    non-VCL
1      Coded slice of a non-IDR picture                               VCL
2      Coded slice data partition A                                   VCL
3      Coded slice data partition B                                   VCL
4      Coded slice data partition C                                   VCL
5      Coded slice of an IDR picture                                  VCL
6      Supplemental enhancement information (SEI)                     non-VCL
7      Sequence parameter set                                         non-VCL
8      Picture parameter set                                          non-VCL
9      Access unit delimiter                                          non-VCL
10     End of sequence                                                non-VCL
11     End of stream                                                  non-VCL
12     Filler data                                                    non-VCL
13     Sequence parameter set extension                               non-VCL
14     Prefix NAL unit                                                non-VCL
15     Subset sequence parameter set                                  non-VCL
16     Depth parameter set                                            non-VCL
17..18 Reserved                                                       non-VCL
19     Coded slice of an auxiliary coded picture without partitioning non-VCL
20     Coded slice extension                                          non-VCL
21     Coded slice extension for depth view components                non-VCL
22..23 Reserved                                                       non-VCL
24..31 Unspecified                                                    non-VCL

    有幾種NALU格式的包包含了非常有用的信息。
    
    Sequence Parameter Set (SPS). This non-VCL NALU contains information required to configure the decoder such as profile, level, resolution, frame rate.
    Picture Parameter Set (PPS). Similar to the SPS, this non-VCL contains information on entropy coding mode, slice groups, motion prediction and deblocking filters.
    Instantaneous Decoder Refresh (IDR). This VCL NALU is a self contained image slice. That is, an IDR can be decoded and displayed without referencing any other NALU save SPS and PPS.
    Access Unit Delimiter (AUD). An AUD is an optional NALU that can be use to delimit frames in an elementary stream. It is not required (unless otherwise stated by the container/protocol, like TS), and is often not included in order to save space, but it can be useful to finds the start of a frame without having to fully parse each NALU.

B. NALU Start Codes, NALU包開始碼
    一個NALU包中的數據並不包含它的大小(長度)信息,因此不能簡單的連接NALU包來建立一個流,因爲你不知道一個包從哪裏結束,另一個包從哪裏開始。
    Annex B格式用開始碼來解決這個問題,即給每個NALU加上前綴碼:2個或者3個0x00,後面再加一個0x01, 如:0x000001或者0x00000001。
    4字節類型的開始碼在在連續的數據傳輸中非常有用,因爲用字節來對齊、分割流數據,比如:用連續的31個bit0後接一個bit1來分割流數據,是很容易的。
如果接下來的bit是0(因爲每個NALU都以bit0開始),那麼這就是一個NALU包數據的起始位置了。4字節類型的開始碼通常只用於標識流中的隨機訪問點,
如SPS PPS AUD和IDR,然後其他地方都用3字節類型的開始碼以減少數據量。


C. Emulation Prevention Bytes, 防競爭字節
    開始碼能起作用是因爲3字節的序列0x000000,0x000001,0x000002和0x000003(應該是所有的0x0000**)在non-VCL(原文是non-RBSP,譯者修改)NALU包中是非法的,所以在構建ANLU包時,必須確保排除這些數值序列,這是由向每個這種類型的序列插入防競爭字節0x03實現的,那麼插入防競爭字節後,0x000001變成了0x00000301。
    當解碼的時候,查找和去除防競爭字節非常重要。因爲防競爭字節可能出現在NALU包的任意位置,在文檔中通常更方便的做法是假定它們已經被去除了,Raw Byte Sequence Payload原始字節序列負載 (RBSP)表示沒有防競爭字節的數據序列(包)。


D. Example
    以下是一個完整的例子:

<pre><code>0x0000 | 00 00 00 01 67 64 00 0A AC 72 84 44 26 84 00 00
0x0010 | 03 00 04 00 00 03 00 CA 3C 48 96 11 80 00 00 00
0x0020 | 01 68 E8 43 8F 13 21 30 00 00 01 65 88 81 00 05
0x0030 | 4E 7F 87 DF 61 A5 8B 95 EE A4 E9 38 B7 6A 30 6A
0x0040 | 71 B9 55 60 0B 76 2E B5 0E E4 80 59 27 B8 67 A9
0x0050 | 63 37 5E 82 20 55 FB E4 6A E9 37 35 72 E2 22 91
0x0060 | 9E 4D FF 60 86 CE 7E 42 B7 95 CE 2A E1 26 BE 87
0x0070 | 73 84 26 BA 16 36 F4 E6 9F 17 DA D8 64 75 54 B1
0x0080 | F3 45 0C 0B 3C 74 B3 9D BC EB 53 73 87 C3 0E 62
0x0090 | 47 48 62 CA 59 EB 86 3F 3A FA 86 B5 BF A8 6D 06
0x00A0 | 16 50 82 C4 CE 62 9E 4E E6 4C C7 30 3E DE A1 0B
0x00B0 | D8 83 0B B6 B8 28 BC A9 EB 77 43 FC 7A 17 94 85
0x00C0 | 21 CA 37 6B 30 95 B5 46 77 30 60 B7 12 D6 8C C5
0x00D0 | 54 85 29 D8 69 A9 6F 12 4E 71 DF E3 E2 B1 6B 6B
0x00E0 | BF 9F FB 2E 57 30 A9 69 76 C4 46 A2 DF FA 91 D9
0x00F0 | 50 74 55 1D 49 04 5A 1C D6 86 68 7C B6 61 48 6C
0x0100 | 96 E6 12 4C 27 AD BA C7 51 99 8E D0 F0 ED 8E F6
0x0110 | 65 79 79 A6 12 A1 95 DB C8 AE E3 B6 35 E6 8D BC
0x0120 | 48 A3 7F AF 4A 28 8A 53 E2 7E 68 08 9F 67 77 98
0x0130 | 52 DB 50 84 D6 5E 25 E1 4A 99 58 34 C7 11 D6 43
0x0140 | FF C4 FD 9A 44 16 D1 B2 FB 02 DB A1 89 69 34 C2
0x0150 | 32 55 98 F9 9B B2 31 3F 49 59 0C 06 8C DB A5 B2
0x0160 | 9D 7E 12 2F D0 87 94 44 E4 0A 76 EF 99 2D 91 18
0x0170 | 39 50 3B 29 3B F5 2C 97 73 48 91 83 B0 A6 F3 4B
0x0180 | 70 2F 1C 8F 3B 78 23 C6 AA 86 46 43 1D D7 2A 23
0x0190 | 5E 2C D9 48 0A F5 F5 2C D1 FB 3F F0 4B 78 37 E9
0x01A0 | 45 DD 72 CF 80 35 C3 95 07 F3 D9 06 E5 4A 58 76
0x01B0 | 03 6C 81 20 62 45 65 44 73 BC FE C1 9F 31 E5 DB
0x01C0 | 89 5C 6B 79 D8 68 90 D7 26 A8 A1 88 86 81 DC 9A
0x01D0 | 4F 40 A5 23 C7 DE BE 6F 76 AB 79 16 51 21 67 83
0x01E0 | 2E F3 D6 27 1A 42 C2 94 D1 5D 6C DB 4A 7A E2 CB
0x01F0 | 0B B0 68 0B BE 19 59 00 50 FC C0 BD 9D F5 F5 F8
0x0200 | A8 17 19 D6 B3 E9 74 BA 50 E5 2C 45 7B F9 93 EA
0x0210 | 5A F9 A9 30 B1 6F 5B 36 24 1E 8D 55 57 F4 CC 67
0x0220 | B2 65 6A A9 36 26 D0 06 B8 E2 E3 73 8B D1 C0 1C
0x0230 | 52 15 CA B5 AC 60 3E 36 42 F1 2C BD 99 77 AB A8
0x0240 | A9 A4 8E 9C 8B 84 DE 73 F0 91 29 97 AE DB AF D6
0x0250 | F8 5E 9B 86 B3 B3 03 B3 AC 75 6F A6 11 69 2F 3D
0x0260 | 3A CE FA 53 86 60 95 6C BB C5 4E F3</code>
     

    這是一個完整的訪問單元(AU),包括3個NALU包,如你所見,數據序列以開始碼開始,後面接了一個SPS(SPS 以0x67開始),在SPS中,你可以看到有2個防競爭字節。沒有這些字節那麼非法的數據序列就會出現在這些位置。然後可以看到一個開始碼後面接着一個PPS(PPS 以0x68開始),然後是一個最後的開始碼,後面跟着一個IDR包。這是一個完整的H.264流,如果你把這些數據以16進制的方式保存到一個以.264爲後綴名的文件中,可以把這些數據轉換成以下圖片:


Annex B格式通常用於實時的流格式,比如說傳輸流,通過無線傳輸的廣播、DVD等。在這些格式中通常會週期性的重複SPS和PPS包,經常是在每一個關鍵幀之前,
因此據此建立解碼器可以一個隨機訪問的點,這樣就可以加入一個正在進行的流,及播放一個已經在傳輸的流。


二. AVCC
    另一個存儲H.264流的方式是AVCC格式,在這種格式中,每一個NALU包都加上了一個指定其長度(NALU包大小)的前綴(in big endian format大端格式),這種格式的包非常容易解析,但是這種格式去掉了Annex B格式中的字節對齊特性,而且前綴可以是1、2或4字節,這讓AVCC格式變得更復雜了,指定前綴字節數(1、2或4字節)的值保存在一個頭部對象中(流開始的部分),這個頭通常稱爲'extradata'或者'sequence header',它的基本格式如下:

bits    
8   version ( always 0x01 )
8   avc profile ( sps[0][1] )
8   avc compatibility ( sps[0][2] )
8   avc level ( sps[0][3] )
6   reserved ( all bits on )
2   NALULengthSizeMinusOne    // 這個值是(前綴長度-1),值如果是3,那前綴就是4,因爲4-1=3
3   reserved ( all bits on )
5   number of SPS NALUs (usually 1)
repeated once per SPS:
  16     SPS size
  variable   SPS NALU data
8   number of PPS NALUs (usually 1)
repeated once per PPS
  16    PPS size
  variable PPS NALU data

    使用上面的例子,那麼AVCC extradata看起來像是這樣的:
0x0000 | 01 64 00 0A FF E1 00 19 67 64 00 0A AC 72 84 44
0x0010 | 26 84 00 00 03 00 04 00 00 03 00 CA 3C 48 96 11
0x0020 | 80 01 07 68 E8 43 8F 13 21 30
    你會發現SPS和PPS被存儲在了非NALU包中(out of band帶外),即獨立於基本流數據。這些數據的存儲和傳輸是文件容器的任務,超出了本文的範疇。
注意:雖然AVCC格式不使用起始碼,防競爭字節還是有的。

    另外,extradata中有一個命名比較容易讓人困惑的變量NALULengthSizeMinusOne,這個變量告訴我們用幾個字節來存儲NALU的長度(前綴:1、2或4),如果NALULengthSizeMinusOne是0,那麼每個NALU使用一個字節的前綴來指定長度,那麼每個NALU包的最大長度是255字節,這個明顯太小了,這種方式對於存儲一個完整的關鍵幀來說太小了。使用2個字節的前綴來指定長度,那麼每個NALU包的最大長度是64K字節,這個對於我們的例子來說是足夠了,但是限制還是比較大;3字節是比較完美的,但是因爲一些原因沒有被廣泛支持;因此,4字節長度的前綴是目前使用最多的方式,也是這裏我們使用的方式:

0x0000 | 00 00 02 41 65 88 81 00 05 4E 7F 87 DF 61 A5 8B
0x0010 | 95 EE A4 E9 38 B7 6A 30 6A 71 B9 55 60 0B 76 2E
0x0020 | B5 0E E4 80 59 27 B8 67 A9 63 37 5E 82 20 55 FB
0x0030 | E4 6A E9 37 35 72 E2 22 91 9E 4D FF 60 86 CE 7E
0x0040 | 42 B7 95 CE 2A E1 26 BE 87 73 84 26 BA 16 36 F4
0x0050 | E6 9F 17 DA D8 64 75 54 B1 F3 45 0C 0B 3C 74 B3
0x0060 | 9D BC EB 53 73 87 C3 0E 62 47 48 62 CA 59 EB 86
0x0070 | 3F 3A FA 86 B5 BF A8 6D 06 16 50 82 C4 CE 62 9E
0x0080 | 4E E6 4C C7 30 3E DE A1 0B D8 83 0B B6 B8 28 BC
0x0090 | A9 EB 77 43 FC 7A 17 94 85 21 CA 37 6B 30 95 B5
0x00A0 | 46 77 30 60 B7 12 D6 8C C5 54 85 29 D8 69 A9 6F
0x00B0 | 12 4E 71 DF E3 E2 B1 6B 6B BF 9F FB 2E 57 30 A9
0x00C0 | 69 76 C4 46 A2 DF FA 91 D9 50 74 55 1D 49 04 5A
0x00D0 | 1C D6 86 68 7C B6 61 48 6C 96 E6 12 4C 27 AD BA
0x00E0 | C7 51 99 8E D0 F0 ED 8E F6 65 79 79 A6 12 A1 95
0x00F0 | DB C8 AE E3 B6 35 E6 8D BC 48 A3 7F AF 4A 28 8A
0x0100 | 53 E2 7E 68 08 9F 67 77 98 52 DB 50 84 D6 5E 25
0x0110 | E1 4A 99 58 34 C7 11 D6 43 FF C4 FD 9A 44 16 D1
0x0120 | B2 FB 02 DB A1 89 69 34 C2 32 55 98 F9 9B B2 31
0x0130 | 3F 49 59 0C 06 8C DB A5 B2 9D 7E 12 2F D0 87 94
0x0140 | 44 E4 0A 76 EF 99 2D 91 18 39 50 3B 29 3B F5 2C
0x0150 | 97 73 48 91 83 B0 A6 F3 4B 70 2F 1C 8F 3B 78 23
0x0160 | C6 AA 86 46 43 1D D7 2A 23 5E 2C D9 48 0A F5 F5
0x0170 | 2C D1 FB 3F F0 4B 78 37 E9 45 DD 72 CF 80 35 C3
0x0180 | 95 07 F3 D9 06 E5 4A 58 76 03 6C 81 20 62 45 65
0x0190 | 44 73 BC FE C1 9F 31 E5 DB 89 5C 6B 79 D8 68 90
0x01A0 | D7 26 A8 A1 88 86 81 DC 9A 4F 40 A5 23 C7 DE BE
0x01B0 | 6F 76 AB 79 16 51 21 67 83 2E F3 D6 27 1A 42 C2
0x01C0 | 94 D1 5D 6C DB 4A 7A E2 CB 0B B0 68 0B BE 19 59
0x01D0 | 00 50 FC C0 BD 9D F5 F5 F8 A8 17 19 D6 B3 E9 74
0x01E0 | BA 50 E5 2C 45 7B F9 93 EA 5A F9 A9 30 B1 6F 5B
0x01F0 | 36 24 1E 8D 55 57 F4 CC 67 B2 65 6A A9 36 26 D0
0x0200 | 06 B8 E2 E3 73 8B D1 C0 1C 52 15 CA B5 AC 60 3E
0x0210 | 36 42 F1 2C BD 99 77 AB A8 A9 A4 8E 9C 8B 84 DE
0x0220 | 73 F0 91 29 97 AE DB AF D6 F8 5E 9B 86 B3 B3 03
0x0230 | B3 AC 75 6F A6 11 69 2F 3D 3A CE FA 53 86 60 95
0x0240 | 6C BB C5 4E F3

    AVCC格式的一個優點是在開始配置解碼器的時候可以跳到流的中間播放,這種格式通常用於可以被隨機訪問的多媒體數據,如存儲在硬盤的文件。
也因爲這個特性,MP4、MKV通常用AVCC格式來存儲。
————————————————
版權聲明:本文爲CSDN博主「Chucky_Hu」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/Romantic_Energy/article/details/50508332

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章