分类: 系统运维
2011-06-29 17:34:52
RTMP协议封包 由一个包头和一个包体组成,包头可以是4种长度的任意一种:12, 8, 4, 1 byte(s).完整的RTMP包头应该是12bytes,包含了时间戳,AMFSize,AMFType,StreamID信息, 8字节的包头只纪录 了时间戳,AMFSize,AMFType,其他字节的包头纪录信息依次类推 。包体最大长度默认为128字节,通过chunkSize可改变包体最大长 度,通常当一段AFM数据超过128字节后,超过128的部分就放到了其他的RTMP封包中,包头为一个字节.
完整的12字节RTMP包头每个字节的含义:
用途 |
大小(Byte) |
含义 |
Head_Type |
1 |
包头 |
TiMMER |
3 |
时间戳 |
AMFSize |
3 |
数据大小 |
AMFType |
1 |
数据类型 |
StreamID |
4 |
流ID |
一、Head_Type
第一个字节Head_Type的前两个Bit决定了包头的长度.它可以用掩码0xC0进行"与"计算:
Head_Type的前两个Bit和长度对应关系:
Bits |
Header Length |
||||||||||||||||||||||||||||||||||||||||||||||||
00 |
12 bytes |
||||||||||||||||||||||||||||||||||||||||||||||||
01 |
8 bytes |
||||||||||||||||||||||||||||||||||||||||||||||||
10 |
4 bytes |
||||||||||||||||||||||||||||||||||||||||||||||||
11 |
1 byte |
||||||||||||||||||||||||||||||||||||||||||||||||
三、AMFSize 四、AMFType
|
|||||||||||||||||||||||||||||||||||||||||||||||||
red5代码分析如下:
Head_Type
我看到代码red5与以上分析有些出入.
“Head_Type的前两个Bit和长度对应关系”分析没有错.
而red5代码中计算头字节公式如下(头字节不一定是一个字节,有可能是两个字节或三个字节,需要说明的头字节计算结果最终会影响ChannelId):
1.当Head_Byte & 0x3F=0时,headerValue= ((int) headerByte & 0xff) << 8 | ((int) in.get() & 0xff)
此时读出字节头为两个字节
2.当Head_Byte & 0x3F=1时,headerValue = ((int) headerByte & 0xff) << 16
| ((int) in.get() & 0xff) << 8 | ((int) in.get() & 0xff)
此时读出字节头为三个字节
3.如果以上两个条件都不满足,则headerValue = (int) headerByte & 0xff;
channelId计算公式为:
1. 如果头为一个字节,则channelId = (headerValue & 0x3f)
2. 如果头为两个字节,则channelId = 64 + (headerValue & 0xff)
3. 如果头为三个字节,则channelId = 64 + ((headerValue >> 8) & 0xff) + ((headerValue & 0xff) << 8)
Head_Type的后面6个Bit和StreamID决定了ChannelID。 StreamID和ChannelID对应关系:StreamID=(ChannelID-4)/5+1 参考red5
ChannelID |
Use |
02 |
Ping 和ByteRead通道 |
03 |
Invoke通道 我们的connect() publish()和自字写的NetConnection.Call() 数据都是在这个通道的 |
04 |
Audio和Vidio通道 |
05 06 07 |
服务器保留,经观察FMS2用这些Channel也用来发送音频或视频数据 |
以下是用一个截包工具获取原始二进制数据。
03 00 00 00 00 01 30 14 00 00 00 00 02 00 07 63 6F 6E 6E 65 63 74 00 3F F0 00 00 00 00 00 00 03 00 03 61 70 70 02 00 08 72 6F 6F 6D 2F 30 30 31 00 08 66 6C 61 73 68 56 65 72 02 00 0E 57 49 4E 20 31 30 2C 30 2C 31 32 2C 33 36 00 06 73 77 66 55 72 6C 06 00 05 74 63 55 72 6C 02 00 1C 72 74 6D 70 3A 2F 2F 31 39 32 2E 31 36 38 2E 31 2E 31 38 2F 72 6F 6F 6D 2F 30 30 31 00 04 66 70 61 64 01 00 00 0C 63 61 70 61 62 69 6C 69 C3 74 69 65 73 00 40 2E 00 00 00 00 00 00 00 0B 61 75 64 69 6F 43 6F 64 65 63 73 00 40 A8 EE 00 00 00 00 00 00 0B 76 69 64 65 6F 43 6F 64 65 63 73 00 40 6F 80 00 00 00 00 00 00 0D 76 69 64 65 6F 46 75 6E 63 74 69 6F 6E 00 3F F0 00 00 00 00 00 00 00 07 70 61 67 65 55 72 6C 06 00 0E 6F 62 6A 65 63 74 45 6E 63 6F 64 69 6E 67 00 40 08 00 00 00 00 00 00 00 00 09 02 00 0F 30 38 31 32 31 31 C3 30 39 32 30 32 32 32 32 32 02 00 02 33 34 02 00 0D 31 39 35 2E 31 36 38 2E 31 34 2E 32 32 02 00 03 30 30 31 02 00 01 30 02 00 01 38 02 00 01 30
1. 下面我们来对鲜绿色背景头数据进行分析
从上面剖析包头说明判断可以第一个字节0x03,此包头有12个字节.
Head_Type=03
TiMMER=00 00 00
AMFSize=00 01 30 表示经过组合之后AMF的总字节长度(默认情况下每个RTMP包为128字节,由C3字节得知,以上包有3个rtmp封包)
AMFType=14 表示接下来第一个字符串为远程调用方法名称
02 00 07 63 6F 6E 6E 65 63 74 02字节表示字符串类型 00 07表示该字符串长度为7个字节 63 6F 6E 6E 65 63 74 为connect远程方法
StreamID=00 00 00
以后我还会陆续讲解rtmp协议中如何传输数组,map,List,Bean对象,以及基本数据类型