H.264stream的序列/图像参数集的可能位置
我正在研究一个H.264解码器,我想知道在哪里可以findSPS和PPS。 我的参考文献告诉我这些是在H.264-Stream中编码的NAL单元,但是当我用IsoViewer看一个例子 – MP4文件时,它说SPS和PPS在avcC Box中。
这个工作到底如何? 它如何查找.mkv文件或其他H.264容器?
提前致谢!
首先,了解没有单一的标准H.264基本比特stream格式是很重要的。 规范文件确实包含一个附件,特别是附录B,描述了一种可能的格式,但这不是一个实际的要求。 该标准规定了video如何编码成单独的数据包。 如何将这些数据包存储和传输给集成商。
1.附件B
networking抽象层单元
数据包被称为networking抽象层单元。 通常缩写NALU(或有时只是NAL)每个数据包可以单独分析和处理。 每个NALU的第一个字节包含NALUtypes,尤其是第3到第7位(第0位总是closures,第1-2位表示NALU是否被另一个NALU引用)。
定义了19种不同的NALUtypes,分为VCL和non-VCL两类:
- VCL或video编码层分组包含实际的视觉信息。
- 非VCL包含解码video可能需要或不需要的元数据。
一个NALU,甚至一个VCL NALU都不是一个框架。 一个帧可以被“切片”成几个NALU。 就像你可以切一块披萨一样。 然后将一个或多个切片虚拟地分组为包含一个帧的访问单元(AU)。 切片确实有一点质量成本,所以不经常使用。
以下是所有定义的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
有一些NALUtypes的知识可能会有所帮助。
- 序列参数集(SPS)。 这个非VCL NALU包含configuration解码器所需的信息,如configuration文件,等级,分辨率,帧速率。
- 图片参数集(PPS)。 类似于SPS,这个非VCL包含关于熵编码模式,切片组,运动预测和去块滤波器的信息。
- 即时解码器刷新(IDR)。 这个VCL NALU是一个独立的图像切片。 也就是说,IDR可以被解码和显示,而不用参考任何其他的NALU保存SPS和PPS。
- 访问单位分隔符(AUD)。 AUD是一个可选的NALU,可用于分隔基本stream中的帧。 它不是必需的(除非容器/协议另有说明,如TS),并且为了节省空间通常不被包括,但是find帧的开始而不必完全parsing每个NALU可能是有用的。
NALU开始代码
NALU不包含它的大小。 因此,简单地连接NALU来创buildstream将不起作用,因为您不知道哪里停止,哪下一个开始。
附录B规范通过在每个NALU之前要求“开始代码”来解决这个问题。 起始码是2或3个0x00
字节,后跟一个0x01
字节。 例如0x000001
或0x00000001
。
4字节的变化对于通过串行连接传输是有用的,因为通过寻找31个零比特跟随1个字节来对字节进行字节alignment是微不足道的。 如果下一位是0(因为每个NALU都以0位开始),那么这是NALU的开始。 4字节的变化通常仅用于发送stream中的随机访问点,例如SPS PPS AUD和IDR,其中3字节变化用于其他地方以节省空间。
仿真预防字节
启动代码工作,因为四个字节序列0x000000
和0x000003
在非RBSP NALU内是非法的。 所以在创buildNALU时,要注意避免这些值,否则可能会与起始代码混淆。 这是通过插入一个'Emulation Prevention'字节0x03
,所以0x000001
变成了0x00000301
。
解码时,查找和忽略仿真防止字节是很重要的。 由于模拟预防字节几乎可以在NALU中的任何地方发生,因此在文档中假定它们已经被删除通常更方便。 没有仿真阻止字节的表示称为原始字节序列有效载荷(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
这是一个包含3个NALU的完整AU。 正如你所看到的,我们从开始代码开始,然后是SPS(SPS以67开头)。 在SPS中,您将看到两个仿真预防字节。 没有这些字节,这些位置就会出现非法序列0x000000
。 接下来,您将看到一个开始代码,后面跟着一个PPS(PPS以68开始)和一个最后的开始代码,然后是一个IDR片段。 这是一个完整的H.264stream。 如果您将这些值input到hex编辑器中并以.264
扩展名保存该文件,则可以将其转换为此图像:
附件B通常用于现场和stream媒体格式,如传输stream,无线广播和DVD。 在这些格式中,通常周期性地重复SPS和PPS,通常在每个IDR之前,从而为解码器创build随机接入点。 这使得能够join已经在进行中的stream。
2. AVCC
存储H.264stream的另一种常见方法是AVCC格式。 在这种格式下,每个NALU都以其长度(以大端格式)排列。 这个方法更容易parsing,但是你失去了附件B的字节alignmentfunction。只是使事情变得复杂,长度可以用1,2或者4字节编码。 该值存储在标题对象中。 这个头文件通常被称为“extradata”或“序列头文件”。 其基本格式如下:
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 00 07 68 E8 43 8F 13 21 30
您会注意到SPS和PPS现在被存储在带外。 也就是说,与基本stream数据分开。 这个数据的存储和传输是文件容器的工作,超出了本文的范围。 请注意,即使我们没有使用起始代码,仍然会插入仿真阻止字节。
此外,还有一个名为NALULengthSizeMinusOne
的新variables。 这个容易混淆的variables告诉我们要用多less个字节来存储每个NALU的长度。 所以,如果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
这种格式的一个优点是能够在开始时configuration解码器并跳到stream的中间。 这是一种常见的使用情况,媒体可以在诸如硬盘的随机存取介质上使用,因此可用于普通的容器格式,如MP4和MKV。
- 在Reporting Services中为单个parameter passing多个值
- 检测parameter passing是一个数组? Javascript
- Android:我如何传递参数到AsyncTask的onExExecute()?
- 我怎样才能将一个parameter passing给setTimeout()callback?
- 将函数的所有parameter passing给另一个函数
- 使用request.setAttribute()传递的值不能通过request.getParameter()
- Git别名与位置参数
- 为什么当模板参数被用作另一个模板的模板参数时,不能推导出模板参数?
- 将字典传递给python中的函数作为关键字参数