rtmp协议相关知识

    RTMP应用场景:
    互动式直播,视频会议,监控
    优点:1,adobe、支持很好 2,适合长时间播放 3,延迟较低 
    缺点:累积误差,原因是RTMP基于TCP不会丢包。所以当网络状态差时,服务器会将包缓存起来,导致累积的延迟,待网络状况好了,就一起发给客户端。
    解决的策略:当客户端的缓冲区很大,就断开重连。


    Real Time Messaging Protocol(实时消息传送协议)是Adobe Systems公司为Flash播放器和服务器之间音频、视频和数据传输开发的私有协议。


    RTMP协议是为了和flash之间交换信令以及媒体数据。为了提高使用效率,信令和媒体数据都是使用相同的机制。


    在RTMP协议中信令和媒体数据都称之为Message,在网络中传输这些Message,为了区分它们肯定是要加一个Message  head的,所以RTMP协议也有一个Message head,还有一个问题因为RTMP协议是基于TCP的,由于TCP的包长度是有限制的(一般来说不超过1500个字节),而RTMP的Message长度是有可能很大的,像一个视频帧的包可能会有几十甚至几千K,这个问题就必然有一个分片的问题,在RTMP协议中对应的说法就是chunk(块),每一个Message + head都是由一个和多个chunk组成的。


    RTMP Head组成:
    RTMP的head在协议中的表现形式是chunk head,前面已经说到一个Message + head可以分成一个和多个chunk,为了区分这些chunk,肯定是需要一个chunk head的,具体的实现就把Message  head的信息和chunk head的信息合并在一起以chunk head的形式表现。
   
    一个完整的chunk的组成有:
    Chunk Basic header + Chunk Msg Header + Extend TimeStamp + Chunk Data


    Chunk basic header:
    该字段包含chunk的stream ID和 type 。chunk的Type决定了消息头的编码方式。该字段的长度完全依赖于stream ID,该字段是一个可变长的字段。
    目前chunk basic head的长度一般为1个字节。这一个字节由两部分组成: fmt + cs id
    fmt占两个bit用来标识紧跟其后的chunk Msg Header的长度,cs id占六个bit。
    两位的fmt取值为 0~3,分别代表的意义如下:
    case 0:chunk Msg Header长度为11;
    case 1:chunk Msg Header长度为7;
    case 2:chunk Msg Header长度为3;
    case 3:chunk Msg Header长度为0;
    所以 只有一个字节的chunk basic header取值为 chunk basic header = (fmt << 6) | (cs id).


    Chunk Msg Header:0, 3 ,7, 11
    该字段包含了将要发送的消息的信息(或者是一部分,一个消息拆成多个chunk的情况下是一部分)该字段的长度由chunk basic header中的type决定。


    Extend Timestamp: 0 ,4 bytes
    该字段发送的时候必须是正常的时间戳设置成0xffffff时,当正常时间戳不为0xffffff时,该字段不发送。当时间戳比0xffffff小该字段不发送,当时间戳比0xffffff大时该字段必须发送,且正常时间戳设置成0xffffff。
        
    Chunk Data:
    实际数据(Payload),可以是信令,也可以是媒体数据。




    Chunk Msg Header的长度是可变的,Chunk Msg Header可变的原因是为了压缩传输的字节数,把一些相同类型的chunk的head去掉一些字节,换句话说就是四种类型的包头都可以通过一定的规则还原成11个字节,这个压缩和还原在RTMP协议中称之为复用/解复用。


    11个字节的完整包头来解释Chunk Msg Header:
    timestamp  +  message length  +  message type id  +  message stream id


    Timestamp : 3bytes
    对于type为0的chunk,绝对时间戳在这里表示,如果时间戳值大于等于0xffffff(16777215),该值必须是
0xffffff,且时间戳扩展字段必须发送,其他情况没有要求。


    message length:3bytes
Message的长度,注意这里的长度并不是跟随chunk head其后的chunk data(Payload)的长度,而是前文提到的一条信令或者一帧视频数据或音频数据的长度。前文提到过信令或者媒体数据都称之为Message,一条Message可以分为一条或者多条chunk。


    message type  id:1byte


Message的类型ID,具体的值将在后文专门来讨论。
message stream id:4bytes
message stream id的字节序是小端序,这个字段是为了解复用而设计的,RTMP文档上说的相当的模糊,


    长度是7 bytes 的chunk head,该类型不包含stream ID,该chunk的streamID和前一个chunk的stream ID是相同的,变长的消息,例如视频流格式
    timestamp delta  + message length  + message type id


    3 bytes的chunk head,该类型既不包含stream ID 也不包含消息长度,这种类型用于stream ID和前一个chunk相同,且有固定长度的信息,例如音频流格式


    0 bytes的chunk head,这种类型的chunk从前一个chunk得到值信息,当一个单个消息拆成多个chunk时,这些chunk除了第一个以外,其他的都应该使用这种类型.




    RTMP 协议封包 由一个包头和一个包体组成,包头可以是4种长度的任意一种,12,8,4,1 byte。
    12 bytes RTMP包头:时间戳,AMFSize,AMFType,StreamID信息,
    8 bytes RTMP包头:时间戳,AMFSize,AMFType
    4 bytes RTMP包头:时间戳,AMFSize
    1 bytes RTMP包头:时间戳


    包体最大长度默认为128字节,通过chunkSize可以改变包体最大长度,通常当一段AMF数据超过128字节后,超过128的部分放到了其他的RTMP封包中。


    完整的12字节RTMP包头每个字节的含义:
    Head_Type  1  包头         Format:2bit   Chunk Stream ID:6bit 总共一个字节
    TIMMER     3  时间戳       Timestamp
    AMFSize    3  数据大小     Body size
    AMFType    1  数据类型     Type ID   例如:AMF0 Command(0x14),User Control Message(0x04)
    StreamID   4  流ID         Stream 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 
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也用来发送音频或视频数据 
例如在rtmp包里面经常看到的0xC2, 就表示一字节的包头,channel=2. 


三、AMFSize(就是报文头部对应的Body size) 
AMFSize占三个字节,这个长度是AMF长度,可超过RTMP包的最大长度128字节。如果超过了128字节,那么由多个后续RTMP封包组合,每个后续RTMP封包的头只占一个字节。一般就是以0xC?开头。 


四、AMFType (其实就是报文头部对应的Type ID)
AMFSize占三个字节,这个长度是AMF长度,可超过RTMP包的最大长度128字节。 
AMFType是包的类型 
0x01 Chunk Size changes the chunk size for packets 
0x02 Unknown 
0x03 Bytes Read send every x bytes read by both sides 
0x04 Ping ping is a stream control message, has subtypes 
0x05 Server BW the servers downstream bw 
0x06 Client BW the clients upstream bw 
0x07 Unknown 
0x08 Audio Data packet containing audio 
0x09 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 
0x12 Notify an invoke which does not expect a reply 
0x13 Shared Object has subtypes 
0x14 Invoke like remoting call, used for stream actions too. 
0x16 StreamData 这是FMS3出来后新增的数据类型,这种类型数据中包含AudioData和VideoData 


    封包分析:
    RTMP封包的数据:03 00 00 00 00 01 02 14 00 00 00 00 | 02 00 07 63 6F 6E 6E 65 ...
    | 给开的前部分是包头部分,这里有12个字节,后面都是包体部分
    03 :表示12字节头,channelid = 3
    00 00 00:表示Timmer = 0
    00 01 02:表示AMFSize = 18
    14:表示 AMFType = Invoke 方法调用
    00 00 00 00: 表示 StreamID = 0


    
包体即指的是AMF数据,里面可以是命令也可以是音视频数据,由ObjType 加上 ObjValue。ObjType的大小为一个字节。ObjValue的大小不固定,和ObjType相关ObjValue大小整理如下,详细的ObjType的数据在本文的最下面列出:
    类型说明(ObjType)       数据    dataSize
    CORE_String             0x02    2字节 (2字节的数据纪录了String的实际长度)
    CORE_Object             0x03    0字节(开始嵌套0x00000009表示嵌套结束)
    NULL                    0x05    0字节 空字节无意义
    CORE_NUMBER             0x00    8字节 
    CORE_Map                0x08    4字节(开始嵌套)
    CORE_BOOLEAN            0x01    1字节




详细的ObjType如下枚举:
enum AMF
{
    /**
     * Boolean value marker constant
     */
    TYPE_BOOLEAN = 0x01,
    /**
     * String marker constant
     */
 TYPE_STRING = 0x02,
    /**
     * Object marker constant
     */
    TYPE_OBJECT = 0x03,
    /**
     * Movieclip marker constant
     */
    TYPE_MOVIECLIP = 0x04 ,
    /**
     * Null marker constant
     */
 TYPE_NULL = 0x05,
    /**
     * Undefined marker constant
     */
 TYPE_UNDEFINED = 0x06,
    /**
     * Object reference marker constant
     */
 TYPE_REFERENCE = 0x07,
    /**
     * Mixed array marker constant
     */
 TYPE_MIXED_ARRAY = 0x08,
    /**
     * End of object marker constant
     */
 TYPE_END_OF_OBJECT = 0x09,
    /**
     * Array marker constant
     */
 TYPE_ARRAY = 0x0A,
    /**
     * Date marker constant
     */
 TYPE_DATE = 0x0B,
    /**
     * Long string marker constant
     */
 TYPE_LONG_STRING = 0x0C,
    /**
     * Unsupported type marker constant
     */
 TYPE_UNSUPPORTED = 0x0D,
    /**
     * Recordset marker constant
     */
 TYPE_RECORDSET = 0x0E,
    /**
     * XML marker constant
     */
 TYPE_XML = 0x0F,
    /**
     * Class marker constant
     */
 TYPE_CLASS_OBJECT = 0x10,
    /**
     * Object marker constant (for AMF3)
     */
 TYPE_AMF3_OBJECT = 0x11,
    /**
     * true marker constant
     */
 VALUE_TRUE = 0x01,
    /**
     * false marker constant
     */
 VALUE_FALSE = 0x00
};






    RTMP协议规定,播放一个流媒体有两个前提步骤:
    第一步:建立一个网络连接(NetConnection)
    第二部:建立一个网络流(NetStream),其中网络连接代表服务器端应用程序和客户端字节基础的连通关系。网络流代表了发送多媒体数据的通道。
    服务器和客户端之间只能建立一个网络连接,但是基于该连接可以创建很多网络流。


    播放一个RTMP协议的流媒体需要经过以下几个步骤:握手,建立连接,建立流,播放。RTMP连接都是以握手作为开始的。建立连接阶段用于建立客户端与服务器之间的网络连接;
建立流阶段用于建立客户端与服务器之间的网络流;播放阶段用于传输视音频数据。


    握手(HandShake):
    一个RTMP连接以握手开始,双方分别发送大小固定的三个数据块
    a) 握手开始于客户端发送c0,c1块。服务器收到c0或c1后发送s0和s1
    b) 当客户端收齐s0和s1后,开始发送c2。当服务器收齐c0和c1后,开始发送s2
    c) 当客户端和服务器分别收到s2和c2后,握手完成


    建立网络连接(NetConnection):
    a) 客户端发送命令消息中的连接(connect)到服务器,请求与一个服务应用实例建立连接。
    b) 服务器收到连接命令消息后,发送确认窗口大小(Window Acknowledgement Size)协议消息到客户端,同时连接到连接命令中提到的应用程序。
    c) 服务器发送设置带宽协议消息到客户端
    d) 客户端处理设置带宽协议消息后,发送确认窗口大小(Window Acknowledgement Size)协议消息到服务器端。
    e) 服务器发送用户控制消息中的流开始(Stream Begin)消息到客户端。
    f) 服务器发送命令消息中的结果(_result),通知客户端连接的状态。


    建立网络流(NetStream)
    a) 客户端发送命令消息中的创建流(createStream)命令到服务器端。
    b) 服务器端接收到创建流命令后,发送命令消息中的结果(_result),通知客户端流的状态。


    
    播放(Play)
    a) 客户端发送命令消息中的播放(play)命令到服务器
    b) 接收到播放命令后,服务器发送设置块大小(ChunkSize)协议消息。
    c) 服务器发送用户控制消息中的streambegin,告知客户端流ID
    d) 播放命令成功的话,服务器发送命令消息中的响应状态NetStream.Play.Start & NetStream.Play.reset,告知客户端播放命令执行成功。
    e) 在此之后服务器发送客户端要播放的音频和视频数据。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值