RTMP头RTMP协议封包参考Red5RTMP协议封包由一个包头和一个包体组成,包头可以是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_Type1包头TiMMER3时间戳AMFSize3数据大小AMFType1数据类型StreamID4流ID一、Head_Type第一个字节Head_Type的前两个Bit决定了包头的长度.它可以用掩码0xC0进行"与"计算:Head_Type的前两个Bit和长度对应关系:Bits Header Length0012 bytes018 bytes10 4 bytes11 1 byteHead_Type的后面6个Bit和StreamID决定了ChannelID。
StreamID和ChannelID对应关系:StreamID=(ChannelID-4)/5+1 参考red5ChannelID Use02Ping 和ByteRead通道03Invoke通道我们的connect() publish()和自字写的NetConnection.Call() 数据都是在这个通道的04Audio和Vidio通道05 06 07服务器保留,经观察FMS2用这些Channel也用来发送音频或视频数据二、TiMMERTiMMER占3个字节纪录的是时间戳,音视频流的时间戳是统一排的。
可分为绝对时间戳和相对时间戳。
fms对于同一个流,发布的时间戳接受的时间戳是有区别的publish时间戳,采用相对时间戳,时间戳值等于当前媒体包的绝对时间戳与上个媒体包(不区分音视频)的绝对时间戳之间的差距,单位毫秒。
play时间戳,相对时间戳,时间戳值等于当前媒体包的绝对时间戳与上个同类型媒体包(视频对应视频,音频对应音频)的绝对时间戳之间的差距,单位毫秒。
flv格式文件时间戳,绝对时间戳,时间戳长度3个字节。
超过0xFFFFFF后时间戳值等于TimeStamp & 0xFFFFFF。
flv格式文件影片总时间长度保存在onMetaData的duration属性里面,长度为8个字节,是一个翻转的double类型。
三、AMFSizeAMFSize占三个字节,这个长度是AMF长度,可超过RTMP包的最大长度128字节。
如果超过了128字节,那么由多个后续RTMP封包组合,每个后续RTMP封包的头只占一个字节。
一般就是以0xC?开头。
四、AMFTypeAMFSize占三个字节,这个长度是AMF长度,可超过RTMP包的最大长度128字节。
AMFType是包的类型0×01Chunk Size changes the chunk size for packets0×02Unknown0×03Bytes Read send every x bytes read by both sides0×04Ping ping is a stream control message, has subtypes0×05Server BW the servers downstream bw0×06Client BW the clients upstream bw0×07Unknown0×08Audio Data packet containing audio0×09Video Data packet containing video data0x0A-0x0E Unknown0x0F FLEX_STREAM_SEND TYPE_FLEX_STREAM_SEND0x10FLEX_SHARED_OBJECT TYPE_FLEX_SHARED_OBJECT0x11FLEX_MESSAGE TYPE_FLEX_MESSAGE0×12Notify an invoke which does not expect a reply0×13Shared Object has subtypes0×14Invoke like remoting call, used for stream actions too.0×16StreamData 这是FMS3出来后新增的数据类型,这种类型数据中包含AudioData和VideoData五、StreamIDStreamID是音视频流的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封包的数据0300 00 00 00 01 02 1400 00 00 00 0200 07 63 6F 6E 6E 65 63 74 003F F0 00 00 00 00 00 00 08 ,,,数据依次解析的含义03表示12字节头,channelid=3000000表示Timmer=0000102表示AMFSize=1814表示AMFType=Invoke 方法调用00 00 00 00 表示StreamID = 0//到此,12字节RTMP头结束下面的是AMF数据分析,具体的AMF0数据格式请参考 /fly2700/archive/2008/04/09/281432.html02表示String0007表示String长度763 6F 6E 6E 65 63 74 是String的Ascall值"connect"00表示Double3F F0 00 00 00 00 00 00 表示double的0.008表示Map数据开始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 参考red5ChannelID Use02 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 0200 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 0001 30 02 00 01 38 02 00 01 301.下面我们来对鲜绿色背景头数据进行分析从上面剖析包头说明判断可以第一个字节0x03,此包头有12个字节.Head_Type=03TiMMER=00 00 00AMFSize=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。