提前道谢!
首先,必须了解没有单一的标准H.264基本比特流格式。规范文件确实包含一个附件,特别是附件B,它描述了一种可能的格式,但它不是一个实际的要求。该标准规定了如何将视频编码到单个数据包中。这些数据包如何存储和传输由积分器决定。
这些数据包被称为网络抽象层单元。通常缩写为NALU(有时只是NAL),每个数据包都可以单独解析和处理。每个NALU的第一个字节包含NALU类型,特别是位3到7。(位0始终关闭,位1-2指示一个NALU是否被另一个NALU引用)。
定义了19种不同的NALU类型,分为VCL和非VCL两类:
单个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
有几种NALU类型,稍后了解这些类型可能会有所帮助。
启动代码工作是因为四个字节序列0x000000
、0x000001
、0x000002
和0x000003
在非RBSP NALU中是非法的。因此,在创建NALU时,要注意转义这些值,否则这些值可能与开始代码混淆。这是通过插入“仿真预防”字节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
附件B通常用于现场和流格式,如传输流、空中广播和DVD。在这些格式中,通常周期性地重复SPS和PPS,通常在每个IDR之前,从而为解码器创建一个随机接入点。这样就可以加入已在进行的流。
存储H.264流的另一种常用方法是AVCC格式。在这种格式中,每个NALU前面都有它的长度(大尾序格式)。这种方法更容易解析,但您丢失了附件B的字节对齐特性。为了使事情复杂化,长度可能使用1、2或4字节进行编码。此值存储在header对象中。这个头通常被称为“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 00 07 68 E8 43 8F 13 21 30
您将注意到SPS和PPS现在存储在带外。即与基本流数据分开。这些数据的存储和传输是文件容器的工作,并且超出了本文的范围。请注意,即使我们没有使用开始代码,仍然会插入仿真防止字节。
此外,还有一个名为nalulengthsizeminusone
的新变量。这个名称令人困惑的变量告诉我们要使用多少字节来存储每个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
这种格式的一个优点是能够在开始时配置解码器并跳入流的中间。这是一种常见的用例,其中介质在诸如硬盘驱动器之类的随机访问介质上可用,因此以诸如MP4和MKV之类的常见容器格式使用。
环境: 到目前为止我做了什么: 我获取所拥有原始流数据并对其进行解析。由于数据是通过RTP传输的,我需要处理NAL字节、SPS和PPS。 1.编写原始文件 视频帧的开始和结束->开始位和结束位 有效负载的类型->5个片段类型位 NAL单位字节 在我的例子中,需要的片段类型有: NAL字节是通过将来自字节1和2的NAL单位位放在一起来创建的。 现在,根据碎片类型,我执行以下操作: SPS/PPS:
我正在开发一个使用MediaCodec API的H.264解码器。我试图在JNI层中调用MediaCodec java API,该函数如下所示: 稍后,我将把发送到我现有的视频呈现管道,并在上呈现。 我希望我能够编写一个Java函数来解码输入流,但这些将是一个挑战- 此资源声明- …你不能对解码的视频帧做任何事情,只能将它们呈现在表面 这里,一个已被传递在表面上呈现输出并且声明。 那么,我是否能够
H.264分析器可以用来分析学习H.264码流结构。可以比较详细的列出H.264码流中NAL的信息。
我正在使用Java API实现一个解码器,用于解码实时H.264远程流。我正在使用回调()从本机层接收H.264编码数据,并在的上解码和呈现。我的实现已经完成(使用回调、解码和呈现等方式检索编码流)。下面是我的解码器类: 现在的问题是-流正在解码和呈现在表面,但视频不清楚。看起来像是框架被打破了,场景被扭曲了/脏了。移动是破碎的和方形的碎片到处(我真的很抱歉,因为我没有截图现在)。 关于我的流-它
问题内容: 我正在使用带有背景图像的透明1x1图像,以便能够使用精灵并仍为某些图标提供替代文本。 我想为图像使用数据URI来减少HTTP请求的数量,但是 产生透明图像的最小字符串是 什么? 我意识到我可以使用数据URI:s代替实际的图片,但将所有内容保存在CSS中而不是分散放置时,维护起来会更容易。 问题答案: 在使用不同的透明GIF玩耍后,有些不稳定并会导致CSS故障。例如,如果您有一个并且使用
我正在对来自IP摄像机的视频(H.264)和音频(AAC)进行一些集成工作。 我取得了一些进步,我可以存储视频 我现在正在尝试将流混合到MP4文件中,而不进行任何解码或编码,但到目前为止还没有找到答案。 我可以通过ffmpeg:ffmpeg-I录制手动完成。h264-i录音。aac-vcodec副本-acodec副本-absf aac_adtstoasc记录。mp4 如何使用C中的ffmpeg库执