直播推流的时候需要用到RTMP的视频数据格式,RTMP的视频格式和FLV很像,通过查看FLV的格式文档,可以分析FLV格式来解析RTMP格式。
RTMP中的数据就是由FLV的TAG中的数据区构成。
FLV是流媒体封装格式,我们可以将其数据看为二进制字节流。总体上看,FLV包括文件头(File Header)和文件体(File Body)两部分,其中文件体由一系列的Tag及Tag Size对组成。
文件头
头部分由一下几部分组成
Signature(3 Byte)+Version(1 Byte)+Flags(1 Bypte)+DataOffset(4 Byte)
signature 占3个字节
固定FLV三个字符作为标示。一般发现前三个字符为FLV时就认为他是flv文件。
Version 占1个字节
标示FLV的版本号。这里我们看到是1
Flags 占1个字节
内容标示。第0位和第2位,分别表示 video 与 audio 存在的情况.(1表示存在,0表示不存在)。截图看到是0x05,也就是00000101,代表既有视频,也有音频。
DataOffset 4个字节
表示FLV的header长度。这里可以看到固定是9
如下,是文件头的配置信息:
tags数据结构
对上面字段的描述:
字段 | 字节 | 描述 |
---|---|---|
类型 | 1 | 0x08: 音频 0x09: 视频 0x12: 脚本(描述信息) |
数据大小 | 3 | 数据区的大小,不包括包头。 |
时间戳 | 3 | 当前帧相对时间戳,单位是毫秒。相对于第一个TAG时戳。 |
时戳扩展 | 1 | 如果时戳大于0xFFFFFF,将会存在字节。 |
流ID | 3 | 总是0 |
数据区 | n | 音、视频包 |
在这里
09代表视频
00 00 27代表数据区的大小,不包括包头
00 00 00 时间戳
00时间戳扩展
第二行:
00 00 00 流ID 组装RTMP包的时候就是看包含17到最后的数据(视频数据)
视频数据
字段 | 占位 | 描述 |
---|---|---|
帧类型 | 4 | 1: 关键帧 2: 普通帧 ...... |
编码ID | 4 | 7: 高级视频编码 AVC ...... |
视频数据 | n | AVC则需要下面的AVCVIDEOPACKET |
AVCVIDEOPACKET
字段 | 字节 | 描述 |
---|---|---|
类型 | 1 | 0:AVC 序列头(指导播放器如何解码) 1:其他单元(其他NALU) |
合成时间 | 3 | 对于AVC,全为0 |
数据 | n | 类型不同,数据不同 |
AVC 序列头
在AVCVIDEOPACKET 中如果类型为0,则后续数据为:
类型 | 字节 | 说明 |
---|---|---|
版本 | 1 | 0x01 |
编码规格 | 3 | sps[1]+sps[2]+sps[3] (后面说明) |
几个字节表示 NALU 的长度 | 1 | 0xFF,包长为 (0xFF& 3) + 1,也就是4字节表示 |
SPS个数 | 1 | 0xE1,个数为0xE1 & 0x1F 也就是1 |
SPS长度 | 2 | 整个sps的长度 |
sps的内容 | n | 整个sps |
pps个数 | 1 | 0x01,不用计算就是1 |
pps长度 | 2 | 整个pps长度 |
pps内容 | n | 整个pps内容 |
其他
在AVCVIDEOPACKET 中如果类型为1,则后续数据为:
类型 | 字节 | 说明 |
---|---|---|
包长 | 由AVC 序列头中定义 | 后续长度 |
数据 | n | H.264数据 |
17:关键帧,高级视频编码AVC
00:AVC序列头(指导播放器如何解码)
最后3个 00 00 00 为合成时间,对于AVC,全是0
第三行:
数据:类型不同,数据不同。数据需要参考类型(0和1)
此时类型为0,则后续数据为: 如果这个类型为1的话,就是其它单元(其它NALU)
编码规格:01,使用后面的3个字节 sps[1]+sps[2]+sps[3],也就是4D 00 1F
几个字节表示NALU的长度:FF,固定为FF,也就是4字节表示
SPS个数:E1,这个是固定的。个数为0xE1&0x1F也就是1
SPS的长度:00 13 ,整个SPS的长度,占2个字节。需要将16进制的转为10进制的,13转为十进制的为 19,也就是从后面数19个字节为整个sps的内容。
SPS的内容:长度为19:
67 4D 00 1F 95 A8 14 01
6E 84 00 00 1C 20 00 05
7E 40 10
pps个数:占1个字节,倒数第二行的01
pps长度:占2个字节, 00 04 ,04转为十进制为4,从后面数4个字节为pps的内容68 EE 3C 80
最后4个字节 00 00 00 32 为前面所有与字节的长度,32转为十进制为50
多出4个字节是因为PreviousTagSize和Tag放在一起了。