RTMP视频流的帧格式分析
RTMP(Real-Time Messaging Protocol)是基于 TCP 的协议,其底层传输的数据实际上封装了 FLV(Flash Video)格式的 Tag。在 RTMP 流中,数据被切分成一个个 Chunk(块)进行发送。
为了让你深入理解,我将模拟抓取一个真实场景:一个主播正在推流,内容包含一段 H.264 视频和 AAC 音频。
以下是详细的分析:
1. RTMP Chunk Header(包头)分析
无论音频还是视频,数据包的最外层都是 RTMP Chunk Header。
- 假设数据(Hex):
03 00 00 00 00 00 04 05 00 00 00 - 详细解析:
03:Format (2 bit) + Chunk Stream ID (6 bit)。- Format=0(表示这是一个完整的 Chunk Header,包含时间戳、长度、类型等全部信息)。
- CSID=3(表示块流 ID 为 3)。
00 00 00:Timestamp (3 bytes)。时间戳为 0(通常是流的第一个包)。00 00 04:Message Length (3 bytes)。消息体长度为 4 字节(这是一个极小的包,通常用于发送握手后的配置信息)。05:Message Type ID (1 byte)。类型为 5,表示Audio Data(如果是 9 则是 Video Data)。00 00 00:Stream ID (4 bytes)。流 ID 为 0。
2. 音频包详细分析
AAC 音频在 RTMP 中有两种主要的包类型:AAC Sequence Header(配置信息)和AAC Raw Data(声音数据)。
示例场景:发送 AAC 配置信息
这是推流开始后发送的第一个音频包,解码器需要它来知道采样率、声道数等。
假设 Payload 数据(Hex):
AF 00 11 90 56 E5- (注意:不包含上面的 Chunk Header,这里是 Tag Body 的内容)
详细格式解析:
AF:Sound Format & Info (1 byte)- 高 4 位
1010(10):Sound Format= AAC。 - 高 3-2 位
11(3):Sample Rate= 44 kHz。 - 高 1 位
1(1):Sample Size= 16-bit。 - 高 0 位
1(1):Sound Type= Stereo (立体声)。 - 总结: 44100Hz, 16位, 立体声 AAC。
- 高 4 位
00:AAC Packet Type (1 byte)00=AAC Sequence Header(AudioSpecificConfig)。01= AAC Raw Data (真正的音频帧)。- 分析: 这里
00说明这是配置包,告诉播放器如何初始化解码器。
11 90 56 E5:AudioSpecificConfig Data (4 bytes)- 这是 AAC 的 ADTS(Audio Data Transport Stream)头部信息去掉同步字后的紧凑格式。
- 通常包含 Profile (如 LC)、Sampling Frequency Index、Channel Configuration 等信息。
- 播放器会将这部分数据提取出来,构建解码器上下文。
示例场景:发送真实的音频帧
- 假设 Payload 数据:
AF 01 [后面跟随一长串 AAC 压缩数据]AF: 同上,音频格式信息。01:AAC Packet Type= 1。表示后面的数据是裸的 AAC ES (Elementary Stream) 数据,不包含 ADTS 头(因为 RTMP/FLV 已经在配置包里定义了格式,这里为了节省带宽不再重复发送头部)。
3. 视频包详细分析
H.264 视频在 RTMP 中也分两种:AVC Sequence Header(SPS/PPS) 和AVC NALU(I帧/P帧/B帧)。
示例场景:发送 AVC 配置信息 (SPS/PPS)
这是推流的第一个视频包,没有画面,只有元数据。
假设 Payload 数据(Hex):
17 00 00 00 00 01 67 42 ...- (注:为了演示清晰,简化了数据长度)
详细格式解析:
17:Frame Type & Codec ID (1 byte)- 高 4 位
0001(1):Frame Type= Keyframe (IDR 帧)。- 1: Keyframe (I帧)
- 2: Inter frame (P帧/B帧)
- 3: Disposable inter frame
- …
- 低 4 位
0111(7):Codec ID= AVC。- 7 = H.264 (AVC)
- 12 = H.265 (HEVC)
- 含义: 这是一个关键帧的配置包。
- 高 4 位
00:AVCPacket Type (1 byte)00=AVC Sequence Header。01= AVC NALU unit。- 分析: 这里
00表示这是包含 SPS 和 PPS 的配置包。
00 00 00:Composition Time (3 bytes)- 仅在 Packet Type 为 1 时有意义。这里因为是 Header,通常为 0。
01 ...:DecoderConfigurationRecord Data- 这里存储的是 ISO BMFF 格式的 AVCDecoderConfigurationRecord。
- 它包含:ConfigurationVersion、AVCProfileIndication、ProfileCompatibility、AVCLevelIndication、LengthSizeMinusOne(通常为 3,表示 NALU 长度用 4 字节表示)。
- 紧接着是SPS (Sequence Parameter Set)和PPS (Picture Parameter Set)的数据。
示例场景:发送关键帧数据 (I-Frame)
假设 Payload 数据:
17 01 00 00 1D 00 00 00 01 67 42 ...- (注:实际长度字段取决于配置)
详细格式解析:
17:Frame Type= Keyframe (1),Codec ID= AVC (7)。01:AVCPacket Type= AVC NALU (1)。表示这是真正的视频画面数据。00 00 1D:Composition Time (3 bytes)。- 表示解码时间戳与显示时间戳之间的偏移量 (PTS - DTS)。假设值为 29ms(0x001D),意味着这个帧应该比解码时间晚 29ms 显示(B帧常用,但在纯 I/P 帧流中通常为 0)。
00 00 00 01:NALU Start Code (4 bytes)(虽然 FLV 通常使用 Length 字段,但在分析底层 H.264 码流时常见 Start Code,但在 RTMP Tag Body 内部,通常是 [长度][数据] 的结构)。- 修正:在 FLV 结构中,这里应该是NALU Length。如果 LengthSizeMinusOne=3,这里就是 4 字节长度。
- 假设 Length =
00 00 00 1C(28 字节)。
67 ...:NALU Data。67(十进制 103) 代表 NALU 类型为 SPS (非关键 IDR)。但这里如果是 I 帧,通常会包含 SPS/PPS(如果 IDR 周期性插入配置),或者类型65(IDR slice)。- 实际数据结构示例循环:
[4 Bytes: Length] [1 Byte: NALU Header] [N Bytes: Payload][4 Bytes: Length] [1 Byte: NALU Header] [N Bytes: Payload]
4. 总结对比表
| 字段位置 | 音频包 (AAC) | 视频包 |
|---|---|---|
| 第一个字节 | AF(Sound Format=AAC, 44k, Stereo, 16bit) | 17(Frame Type=Keyframe, Codec=AVC) |
| 第二个字节 | 00(Seq Header) 或01(Raw Data) | 00(Seq Header) 或01(NALU) |
| 后续字节 | AAC AudioSpecificConfig 或 Raw ES Data | 3字节 CompTime + DecoderRecord 或 NALU Units |
核心点记忆:
- 配置包 是必须先发送的,包含了解码必需的表头信息。
- 音频 AAC:
00类型是头,01类型是去掉 ADTS头的裸流。 - 视频 AVC:
00类型是 SPS/PPS 头,01类型是 NALU 单元。 - Composition Time:只在视频
01类型中有意义,用于音画同步中的补正。
希望这个详细的数据包分析能帮你理解 RTMP 流的内部结构!
