原文地址:http://www.szatmary.org/blog/25
这篇文章,我会讲一下AVC编码的基本码流和码流在不同容器中的不同变化。如果前一句话你不理解,后面的就没必要看了。
附录B
首先需要明白的是,h.264基本码流的格式并非唯一的。标准包含了一个附录B,描述了一种可行的格式,但那不是要求。标准指出了视频要怎样编码成独立的packet,但packet怎么存储和传输是开放的。
h.264打包成的packet称为网络抽象层单元(简称NALU)。每个packet可以被独立的解析或处理(注:这点很重要),每个NALU的第一个字节是NALU的类型信息,具体来说是第3到第7bit(bit0总是0,bit1-2表明这个NALU是不是被其他NALU引用)。一种有18个不同类型的NALU,它们分成2类:VCL(视频编码层)和非VCL。VCL的packet包含视频信息,而非VCL的packet包含的metadata有些是解码必须的,有些不是。NALU或者VCL的NALU和帧(frame)不是一回事。一帧视频可以被分成多个NALU(slice),就像你可以切一块披萨。多个slice随后组成访问单元(Access Units),构成一帧视频。分割当然会造成一点质量损失,所以不是经常使用,下面是一个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..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类型对后面的内容比较重要,这里介绍一下:
- 序列参数集(SPS),这是个非VCL的NALU,它包含解码器的配置信息,比如档次,级别,分辨率,帧率等
- 图像参数集(PPS),跟SPS相似,包含了熵编码类型,片组信息,运动预测和去块效应滤波器的信息
- 即时解码刷新(IDR),这是VCL的NALU,它是个自包含的图像分片,它可以完全独立解码,不需要参考任何其他NALU(除了SPS PPS的NALU外)
- 访问单元分界(AUD),这是可选的NALU,可以被用来分隔基本码流中的frame,它不是必须的,但是它在定位帧起始时很有用,因为这就不需要解析每个NALU了。
0x000001
或者 0x00000001,后者在串行传输中很有用,因为串行连接的信道中,四字节对齐是很常见的,通过检测31个0bit和一个1bit,可以找到它。如果随后的一个bit是0(因为每个NALU的第一个位都是0),就可以知道它是NALU的起点。
四个字节的版本通常用在快速定位SPS PPS AUD和IDR类型的NALU,三个字节的版本用在其余的NALU类型上来节省空间。起始码能工作的原因是因为在NALU中不允许出现0x000000
, 0x000001
和 0x000002,所以在创建NALU的时候要避免出现这几种情况。通过插入emulation prevention bytes(0x03)来防止出现上述情况,比如0x000001变成0x00000301,在解码的时候一定要去掉这些插入的字节,没有插入0x03的负载称为原始字节序列负载(RBSP)。
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
这是一个完整的访问单元,包含三个NALU,起始码已经用红色标出来了。第一个起始码后面跟的是SPS,在这个NALU中有两个蓝色标出的
Emulation Prevention bytes,如果没有Emulation Prevention bytes,你可以看到0x000000可以在任何地方出现,可能造成假的起始码出现。接着,第二个起始码跟着的是PPS,最后一个起始码跟着的是一个IDR片。这就构成了一个完整的H.264码流,如果你把这个码流放到一个hex编辑器然后改成.264后缀,那你就可以把它转成一个图像了。
AVCC
另一种常用的存储264码流的格式是AVCC,这种格式中,每个NALU之前有长度信息。这个方式比较容易解析。长度可以用一个字节,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 | |
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
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
这个格式的好处是只要开始的时候配置了decoder,就可以跳到后面的任意位置,当媒体是可以随机访问的时候,比如存在硬盘上,则通常用这种格式,比如MP4和MKV容器中就用的这种格式。