首先要理解的是沒有標准的H.264基本流格式。文檔中的確包含了一個Annex,特別是描述了一種可能的格式Annex B格式,但是這個並不是一個必須要求的格式。標准文檔中指定了視頻怎樣編碼成獨立的包,但是這些包是怎樣存儲和傳輸的卻是開放的。
一. Annex B
1. 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類型,如表 7-1 所示。VCL NAL 單元是指那些 nal_unit_type 值等於 1 到 5(包括 1 和 5)的 NAL 單元。所有其他的 NAL 單元都稱作非 VCL NAL 單元。:
2. 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字節類型的開始碼以減少數據量。
3. Emulation Prevention Bytes, 防競爭字節
開始碼能起作用是因為3字節的序列0x000000,0x000001,0x000002和0x000003(應該是所有的0x0000**)在non-VCL(原文是non-RBSP,譯者修改)NALU包中是非法的,所以在構建ANLU包時,必須確保排除這些數值序列,這是由向每個這種類型的序列插入防競爭字節0x03實現的,那么插入防競爭字節后,0x000001變成了0x00000301。
當解碼的時候,查找和去除防競爭字節非常重要。因為防競爭字節可能出現在NALU包的任意位置,在文檔中通常更方便的做法是假定它們已經被去除了,Raw Byte Sequence Payload原始字節序列負載 (RBSP)表示沒有防競爭字節的數據序列(包)。
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格式來存儲。