Rtmp协议简单分析(一)——协议数据

        首先说下rtmp协议包的格式。握手之后,rtmp传输一个数据默认的长度是128bytes,这128bytes不包括包头的长度,只是数据的长度,文档上面没有说明,很憋了我一段时间,数据超过这个长度之后就要分块,超过128bytes的数据放到下一个块中,以此类推。块大小是可配置的,最大块是65535字节,最小块是128字节。块越大CPU使用率越低,但是也导致大的写入,在低带宽下产生其他内容的延迟。
        Rtmp协议是包头加包体(数据)组成,包头可以是4种长度的任意一种:12、8、4、1等byte(s)。包头包含了Head_Type、时间戳、amf size、amf type、streamID。完整的RTMP包头有12字节,由下面5个部分组成:
用途 大小(Byte) 含义
Head_Type 1 包头
TIMER 3 时间戳
AMFSize 3 数据大小
AMFType 1 数据类型
StreamID 4 流ID

        Head_Type占用RTMP包的第一个字节,这个字节里面记录了包的类型和包的ChannelID。Head_Type字节的前两个Bits决定了包头的长度。

Bits Header Length
00 12 bytes
01 8 bytes
10 4 bytes
11 1 byte

        一个视频流的第一个包必须是12bytes,也就是00,要告诉对方这个流的信息。Head_Type的后面6个Bits记录着ChannelID,其为一下内容:

02 Ping 和ByteRead通道
03 Invoke通道 我们的connect() publish()和自字写的NetConnection.Call() 数据都是在这个通道的
04 Audio和Vidio通道
05 06 07 服务器保留,经观察FMS2用这些Channel也用来发送音频或视频数据

      比如传一个视频流,第一个块的head type就是00 00 00 04(0x04)。实测fms用4或者5在传影视频。官方文档上面说head_type可能会不止一个byte,但实际情况用一个byte也够了。
        TiMMER - 时间戳
音视频的播放同步是由时间戳来控制的,单位是毫秒。如果时间戳大于或等于16777215(16进制0x00ffffff),该值必须为16777215,并且扩展时间戳必须出现,4bytes的扩展时间戳出现在包头之后包体之前。这个时间戳一般去flv文件里面每个tag里面的时间戳。
        AMFSize - 数据大小
AMFSize占三个字节,这个长度是AMF长度,其实就是本次数据的长度。
        AMFType - 数据类型
AMFType是RTMP包里面的数据的类型,占用1个字节。例如音频包的类型为8,视频包的类型为9。下面列出的是常用的数据类型:

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
占用RTMP包头的最后4个字节,是一个big-endian的int型数据,每个消息所关联的ID,用于区分其所在的消息流。
前面说包头有几种长度,第一个长度是12bytes,包含了全部的头信息,第一个数据流也就是流的开始必须是这个长度。
第二种8bytes的包,没有了streamID,发这种包,对方就默认此streamID和上次相同,一个视频数据在第一个流之后都可以使这种格式,比如一个1M的视频,第一次发128bytes用12bytes的包,之后每次发的数据都应该用8bytes的包。当然如果每次都用12bytes也没有问题。
第三种为4bytes,只有head_type和时间戳,缺少的对方认为与之前的一样,实际应用中很难出现。
第四中就只有head_type一个byte。如果一次数据超过了长度(默认是128bytes),就要分块,第一个块是12bytes或者8bytes的,之后的块就是1byte。因为分的N块,每一块的信息都是一样的,所以只需要告诉对方此次包的长度就行了。
        例子:
例如有一个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
00 00 00    表示时间戳 Timer=0
00 01 02    表示AMFSize=18
14    表示AMFType=Invoke 方法调用
00 00 00 00 表示StreamID = 0                   //到此,12字节RTMP头结束下面的是AMF数据分析 
02    表示String
00 07    表示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数据开始


官方文档上面的例子:
展示一个简单的音频消息流。这个例子显示了信息的冗余。
  Message Stream ID Message Type ID Time Length
Msg # 1   12345   8  1000 32
Msg # 2   12345   8  1020 32
Msg # 3   12345   8  1040 32
Msg # 4   12345   8  1060 32

下表显示了这个流产生的块。从消息3开始,数据传输开始优化。在消息3之后,每个消息只有一个字节的开销。

  Chunk Stream ID Chunk Type Header Data No.of Bytes After Header Total No.ofBytes in the Chunk
Chunk#1 3 0 delta: 1000length: 32type: 8stream ID:1234(11bytes) 32 44
Chunk#2 3 2 20 (3 bytes) 32 36
Chunk#3 3 3 none(0 bytes) 32 33
Chunk#4 3 3 none(0 bytes) 32 33

演示一个消息由于太长,而被分割成128字节的块。

  Message Stream ID Message TYpe ID Time Length
Msg # 1 12346 9 (video) 1000 307

下面是产生的块。

  Chunk Stream ID Chunk Type Header Data No. of Bytes after Header Total No. of bytes in  the chunk
Chunk#1 4 0 delta: 1000length: 307type: 9streamID: 12346(11 bytes) 128 140 
Chunk#2 4 3 none (0 bytes) 128   129
Chunk#3 4 3 none (0 bytes) 51 52

数据传输的限定大小默认是128bytes,可以通过控制消息来改变,RTMP的约定是当Chunk流ID为2,消息流ID为0的时候,被认为是控制消息。


参考资料:
1、rtmp协议简单解析以及用其发送h264的flv文件


你可能感兴趣的:(rtmp)