一、基于TCP之上的高层协议;
二、自定义新的包结构chunk;
三、基于TCP,又有自己的包,所以提出个概念——消息块流 chunk message stream;
怎么讲呢?就是说包肯定不能太大了,TCP包都有个最大值,所以得分开成自己的包,但还要考虑节省带宽,而又基于TCP流,是一种安全的流,所以当然还是分为包头和包体,但这个包头是可以节省的,从1个字节到12个字节不等,这又是怎么回事呢?是这样的,首先有一个基本的chunk basic header这个是必须都有的,但就这个header都还是一个1到3字节可变的头,再加上一个0到11字节的chunk message header都是由chunk basic header头的第一个字节的前2bit分成的四个类型来控制的,这四种类型就说明了这个消息块是一个新消息包的开始块?一个跟随前面块的消息块?等!从而来决定这个chunk message header中的四种内容是需要还是不需要,所以就出现0,3,7,11字节这四种情况,chunk message header中包括时间戳、消息长度、stream id、消息类型、扩展时间戳这种数据。
四、其实主要还是得知道chunk basic header的构成,它是一个2 + 6 + 8 + 8 bit的情况,2就是前面说的类型,后面的这22bit是个chunk stream id,这个好像很重要,现在还没有搞清楚,大致是6处为0的话,第一个8是有效的,而得到的chunk stream id的值为1片8的值+64,如果6处为1,则第一8第二8都是有效的,最终的chunk stream id的值就是第二8*256 + 第一8 + 64,这就说明6处0 1 都为保留值,当然现在2也是个说什么低层协议的消息( 在RTMP协议中控制信令的chunk stream ID都是2)这个暂不明白什么是控制信令,“ 2~7都是约定的,8是用来传输publish play等命令”,这个就得继续再找资料看了!
==============================================================
完整的12字节RTMP包头每个字节的含义:
一、Head_Type
第一个字节Head_Type的前两个Bit决定了包头的长度.它可以用掩码0xC0 进行"与"计算:
Head_Type的前两个Bit和长度对应关系:
Head_Type的后面6个Bit和StreamID决定了ChannelID。 StreamID和ChannelID对应关系:StreamID=(ChannelID-4)/5+1 参考red5
例如在 rtmp包里面经常看到的0xC2, 就表示一字节的包头,channel=2.
四、AMFType
AMFSize占三个字节,这个长度是AMF长度,可超过RTMP包的最大长度128字节。
AMFType是包的类型
五、StreamID
StreamID是音视频流的ID,如果AMFType!=0x08 或!=0x09那么 StreamID为0。
ChannelID 和StreamID之间的计算公式:StreamID=(ChannelID-4)/5+1 参考red5
例如当ChannelID为2、3、4 时StreamID都为1 当ChannelID为9的时候StreamID为2
六、封包分析
例如有一个RTMP封包的数据 03 00 00 00 00 01 02 14 00 00 00 00 02 00 07 63 6F 6E 6E 65 63 74 00 3F F0 00 00 00 00 00 00 08 ,,,
数据依次解析的含义
03表示12字节头,channelid=3
000000表示Timmer=0
000102 表示AMFSize=18
14表示AMFType=Invoke 方法调用
00 00 00 00 表示StreamID = 0
// 到此,12字节RTMP头结束
下面的是AMF数据分析,具体的AMF0数据格式请参考
http://www.cnweblog.com/fly2700/archive/2008/04/09/281432.html
02表示String
0007表示String长度7
63 6F 6E 6E 65 63 74 是String的Ascall值"connect"
00表示Double
3F F0 00 00 00 00 00 00 表示double的0.0
08表示Map数据开始
===================================================================
例如完成握手后,Flash向FMS发送的第一个RTMP数据,内容如下:
![](https://i-blog.csdnimg.cn/blog_migrate/9e007974b2f57e89f2a0c295f0b77f22.jpeg)
上面一段数据由2个RTMP包组成,2个RTMP包头分别用蓝色表示,第一个蓝色的是12字节的包头,后面一个蓝色的C3是一个字节的包头,绿色部分是AMF数据,红色的是AMF数据类型,整个RTMP解码过程如下
[2008-06-18 16:59:20] DecodeInvoke:
[2008-06-18 16:59:20] InvokeName:String:connect
[2008-06-18 16:59:20] InvokeID:Double:0
[2008-06-18 16:59:20] Map:MapNum:0
[2008-06-18 16:59:20] Params:{
[2008-06-18 16:59:20] Key:String:objectEncoding
[2008-06-18 16:59:20] Value:Double:0
[2008-06-18 16:59:20] Key:String:app
[2008-06-18 16:59:20] Value:String:mediaserver
[2008-06-18 16:59:20] Key:String:fpda
[2008-06-18 16:59:20] Value:Bool:0
[2008-06-18 16:59:20] Key:String:tcUrl
[2008-06-18 16:59:20] Value:String:rtmp://127.0.0.1/mediaserver
[2008-06-18 16:59:20] Key:String:audioCodecs
[2008-06-18 16:59:20] Value:Double:615
[2008-06-18 16:59:20] Key:String:videoCodecs
[2008-06-18 16:59:20] Value:Double:76
[2008-06-18 16:59:20] }End Params
[2008-06-18 16:59:20] InvokeParams:String:PUBLISHER
[2008-06-18 16:59:20] InvokeParams:String:streamRecode
二、自定义新的包结构chunk;
三、基于TCP,又有自己的包,所以提出个概念——消息块流 chunk message stream;
怎么讲呢?就是说包肯定不能太大了,TCP包都有个最大值,所以得分开成自己的包,但还要考虑节省带宽,而又基于TCP流,是一种安全的流,所以当然还是分为包头和包体,但这个包头是可以节省的,从1个字节到12个字节不等,这又是怎么回事呢?是这样的,首先有一个基本的chunk basic header这个是必须都有的,但就这个header都还是一个1到3字节可变的头,再加上一个0到11字节的chunk message header都是由chunk basic header头的第一个字节的前2bit分成的四个类型来控制的,这四种类型就说明了这个消息块是一个新消息包的开始块?一个跟随前面块的消息块?等!从而来决定这个chunk message header中的四种内容是需要还是不需要,所以就出现0,3,7,11字节这四种情况,chunk message header中包括时间戳、消息长度、stream id、消息类型、扩展时间戳这种数据。
四、其实主要还是得知道chunk basic header的构成,它是一个2 + 6 + 8 + 8 bit的情况,2就是前面说的类型,后面的这22bit是个chunk stream id,这个好像很重要,现在还没有搞清楚,大致是6处为0的话,第一个8是有效的,而得到的chunk stream id的值为1片8的值+64,如果6处为1,则第一8第二8都是有效的,最终的chunk stream id的值就是第二8*256 + 第一8 + 64,这就说明6处0 1 都为保留值,当然现在2也是个说什么低层协议的消息( 在RTMP协议中控制信令的chunk stream ID都是2)这个暂不明白什么是控制信令,“ 2~7都是约定的,8是用来传输publish play等命令”,这个就得继续再找资料看了!
==============================================================
完整的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 |
ChannelID | Use |
02 | Ping 和ByteRead通道 |
03 | Invoke通道 我们的connect() publish()和自字写的NetConnection.Call() 数据都是在这个通道的 |
04 | Audio和Vidio通道 |
05 06 07 | 服务器保留,经观察FMS2用这些Channel也用来发送音频或视频数据 |
例如在 rtmp包里面经常看到的0xC2, 就表示一字节的包头,channel=2.
四、AMFType
AMFSize占三个字节,这个长度是AMF长度,可超过RTMP包的最大长度128字节。
AMFType是包的类型
0×01 | Chunk Size | changes the chunk size for packets |
0×02 | Unknown | |
0×03 | Bytes Read | send every x bytes read by both sides |
0×04 | Ping | ping is a stream control message, has subtypes |
0×05 | Server BW | the servers downstream bw |
0×06 | Client BW | the clients upstream bw |
0×07 | Unknown | |
0×08 | Audio Data | packet containing audio |
0×09 | Video Data | packet containing video data |
0x0A-0x0E | Unknown | |
0x0F | FLEX_STREAM_SEND | TYPE_FLEX_STREAM_SEND |
0x10 | FLEX_SHARED_OBJECT | TYPE_FLEX_SHARED_OBJECT |
0x11 | FLEX_MESSAGE | TYPE_FLEX_MESSAGE |
0×12 | Notify | an invoke which does not expect a reply |
0×13 | Shared Object | has subtypes |
0×14 | Invoke | like remoting call, used for stream actions too. |
0×16 | StreamData | 这是FMS3出来后新增的数据类型,这种类型数据中包含AudioData和VideoData |
StreamID是音视频流的ID,如果AMFType!=0x08 或!=0x09那么 StreamID为0。
ChannelID 和StreamID之间的计算公式:StreamID=(ChannelID-4)/5+1 参考red5
例如当ChannelID为2、3、4 时StreamID都为1 当ChannelID为9的时候StreamID为2
六、封包分析
例如有一个RTMP封包的数据 03 00 00 00 00 01 02 14 00 00 00 00 02 00 07 63 6F 6E 6E 65 63 74 00 3F F0 00 00 00 00 00 00 08 ,,,
数据依次解析的含义
03表示12字节头,channelid=3
000000表示Timmer=0
000102 表示AMFSize=18
14表示AMFType=Invoke 方法调用
00 00 00 00 表示StreamID = 0
// 到此,12字节RTMP头结束
下面的是AMF数据分析,具体的AMF0数据格式请参考
http://www.cnweblog.com/fly2700/archive/2008/04/09/281432.html
02表示String
0007表示String长度7
63 6F 6E 6E 65 63 74 是String的Ascall值"connect"
00表示Double
3F F0 00 00 00 00 00 00 表示double的0.0
08表示Map数据开始
===================================================================
例如完成握手后,Flash向FMS发送的第一个RTMP数据,内容如下:
![](https://i-blog.csdnimg.cn/blog_migrate/9e007974b2f57e89f2a0c295f0b77f22.jpeg)
上面一段数据由2个RTMP包组成,2个RTMP包头分别用蓝色表示,第一个蓝色的是12字节的包头,后面一个蓝色的C3是一个字节的包头,绿色部分是AMF数据,红色的是AMF数据类型,整个RTMP解码过程如下
[2008-06-18 16:59:20] DecodeInvoke:
[2008-06-18 16:59:20] InvokeName:String:connect
[2008-06-18 16:59:20] InvokeID:Double:0
[2008-06-18 16:59:20] Map:MapNum:0
[2008-06-18 16:59:20] Params:{
[2008-06-18 16:59:20] Key:String:objectEncoding
[2008-06-18 16:59:20] Value:Double:0
[2008-06-18 16:59:20] Key:String:app
[2008-06-18 16:59:20] Value:String:mediaserver
[2008-06-18 16:59:20] Key:String:fpda
[2008-06-18 16:59:20] Value:Bool:0
[2008-06-18 16:59:20] Key:String:tcUrl
[2008-06-18 16:59:20] Value:String:rtmp://127.0.0.1/mediaserver
[2008-06-18 16:59:20] Key:String:audioCodecs
[2008-06-18 16:59:20] Value:Double:615
[2008-06-18 16:59:20] Key:String:videoCodecs
[2008-06-18 16:59:20] Value:Double:76
[2008-06-18 16:59:20] }End Params
[2008-06-18 16:59:20] InvokeParams:String:PUBLISHER
[2008-06-18 16:59:20] InvokeParams:String:streamRecode