RTMP 协议简析

RTMP 协议简析

参考:http://hi.baidu.com/janins/

参考:http://www.cnblogs.com/MonkChen/archive/2011/08/17/2141709.html



C0、C1、C2、S0、S1、S2的发送时间及格式,详细参考RTMP协议。

RTMP的握手在协议中叫Handshake,其过程如下:
1)    首先客户端在建立链接的时候向服务器端发送两个固定长度的数据块(C0,C1)。
2)    然后客户端必须接收到S1之后,才能发送C2。
3)    客户端接收到服务器的S2之后,才能发送其他数据。
4)    服务端必须在接收到C0之后,才能发送(S0,S1),也可以在另外再等待同时接收到C1之后再发。

5)    服务端必须在接收到C1之后,才能发送S2。

6)    服务端必须在接收到C2之后,才能发送其他数据。
其中数据格式要求如下:
C0和S0的格式是一样的,由8位表示的数字3组成(RTMP1.0的定义)。
C1和S1由1536字节组成,只有对前面的8字节有特殊要求,后面的数据都由随机位组成。
C2和S2也有1536字节组成,并且对前面的8字节有特殊要求,后面的数据都由随机位组成。

 Time2 (4 bytes):  This field MUST contain the timestamp at which the previous packet(s1 or c1) sent by the peer was read.


握手之后,客户端与服务器便通过chunk交互信息,


RTMP的协议栈整体上可以分为三层:传输层(即所谓的Chunk);消息层(即所谓的Message);应用层(即所谓的Message Command)

Chunk的目的就是在RTMP传输层将消息截成可传输的数据包,所以一个Chunk应该能够体现属于哪个逻辑流(传输层面的通道,与后面我们谈到的Message Stream ID表示的通道是两个概念,可以用于负载均衡等)、重新组装时的顺序和具体的数据信息。


每个Chunk由数据头和数据组成,其中数据头由Basic Header、Chunk Msg Header和Extended Time Stamp组成,这里相对复杂的是Chunk的头是可变长度的,其可变的初衷是为了进行数据压缩,其实大家觉得压缩10几个字节好像没有什么,但对一个比较大的流的话,这种压缩还是很有效的。
Chunk的头压缩是一种约定性的空间利用压缩,其本质是一个微型的头+可变数据块的机制,解决了固定数据块带来的空间浪费。
BASIC HEADER
首先一个Chunk的前两位主要用来表示后面数据的具体结构。接下来的6位如果等于1表示后面的16位是Chunk流ID的数据(范围2^6+2^8到2^6+2^8*2^8-1,即320到65599),如果等于0表示后面的8位是Chunk流ID的数据(范围2^6到2^8+2^6-1,即64到319),如果大于1,说明Chunk流ID就是(范围2到2^6-1,即2到63)此六位的值。
上面的计算约定伪代码如下:
如果 (第一个字节[2-7]==0){
      Chunk流ID = 26+ 第二个字节的值;
} 否则 如果 (第一个字节[2-7]==1){
      Chunk流ID = 26 + 第二个字节的值+ 第三个字节的值*216;
} 否则 {
      Chunk流ID = 第一个字节[2-7]的值;
}
通过上面我们基本知道理论上RTMP可以支持2到65599范围内的流ID,即支持65597个流。说实话实际应用中不会同时超过10个吧。
从上面我们直到一个Chunk的Basic Header可能会占用1到3个字节,这些完全取决于首个字节后六位的值。
CHUNK MESSAGE HEADER
接下来的数据在RTMP协议中被称作Chunk Message Header,其具体的数据格式由前面提到的Chunk首个字节的前两位来决定,即把后面的数据通过此两位分成四种类型,每种类型可以适当省略一些没有必要携带的重复信息,从而达到数据压缩的目的。
类型0(即前两位的值为0):
其Chunk Message Header长度为11个字节,如下图:


一个Chunk流的第一个Chunk必须采用该类型,换句话来说,如果有一个这样的Chunk到客户端,客户端都应该重置流,无论其传回来的时间戳在相同ID的Chunk流中的位置。例如我们在视频播放中的Seek。
类型1:
其Chunk Message Header的长度为7个字节,如下图:


该类型其实就是省略掉了message stream id。其省略掉的前提就是前面继承前面的类型0的信息。此类型不要求服务器端和客户端必须这么做,但这句话的意思并不是说客户端和服务器端置之不理也不会影响正常通信,而是说如果你嫌麻烦可以把该消息用类型0的方式来不压缩传递,其出了影响压缩之外还是可以正常工作的。
类型2:
其Chunk Message Header长度为3个字节,如下图:


该类型的原理和类型1是一样的,有其自己的约定。该类型在具体的协议通信中很难出现,其出现的可能就是要服务器端和客户端有个协商,例如我们播放视频的时候,由于持续的流可能会很长,这时候一个Chunk的大小很可能把一个视频帧分成两部分,并且这个分解随着时间的推移越来越没有规则,这时候对服务器端还是客户端都造成消息切割和组装的负担,如果这时能够引入客户端和服务器端的协商机制,让一个Chunk就承载一个完整的消息并且消息大小都一样那多好啊。如果能达到这种一致,类型2就可以使用。
类型3:
Chunk Message Header不占用任何字节。这种消息更容易理解,例如当一个消息被分解成多个Chunk的时候,第一个遇到消息的Chunk处理之后,就等待后面的Chunk的消息补上了,直到后面的消息有新的消息ID产生为止。
EXTENDED TIME STAMP
扩展时间戳就比较好理解的,就是当Chunk Message Header的时间戳大于等于0xffffff的时候Chunk Message Header后面的四个字节就代表扩展时间。
CHUNK协议控制消息
我前面好像提到过Chunk的切分大小可以由客户端和服务器端协商着来,那如何协商就是通过控制消息来完成的。Chunk的控制消息有两个,一个是设置Chunk的大小,一个是终止持续发送Chunk。那么我们如何判断一个Chunk中传载的消息是控制消息呢?RTMP的约定是当Chunk流ID为2,消息流ID为0的时候,被认为是控制消息。当然控制消息应该一个Chunk一个消息就解决问题。
具体内容,请看后面的内容消息层(Message Formats)。


+-------------+----------------+-------------------+--------------+ 
| Basic header|Chunk Msg Header|Extended Time Stamp|   Chunk Data | 
+-------------+----------------+-------------------+--------------+

                   (图1.包头header 构成)

0  1 2  3  4 5 6  7 
+-+-+-+-+-+-+-+-+       
|fmt|       cs id     | 
+-+-+-+-+-+-+-+-+  

Baisc header 是1-3个字节,第一个字节的高2位表示包头的格式,低6位表示chunk stream ID

1)chunk stream ID决定了Basic header的字节数,首先查看低六位的取值:

  • 3及以上的则Basic header为一个字节
  • 0为两个字节,chunk stream id = 64 + 第二个字节值 (64-319)
  • 1为三个字节,chunk stream id = 第三字节*256 + 第二字节 + 64(64–65599)
  • 2为一个字节,Value 2 indicates its low-level protocol message

chunk stream id 含义
2: low level
3: high level like connect,createStream
4: control stream
5: video
6: audio
8: control stream

 

2)fmt取值决定了整个包头header的长度(以下表现的长度均不包含Basic header的长度)

      两位的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;

 

我们以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文档上说的相当的模糊,

 

message stream ID可以使任意值,不同的消息流复用成相同的chunk stream,基于它们的ID能够解复用。于chunk stream 是相关的,这个字段是一个不透明的值没有整明白什么意思,我的理解就是用来标识和服务器连接的flash端的序号。

长度是7 bytes 的chunk head,该类型不包含stream ID,该chunkstreamID和前一个chunkstream ID是相同的,变长的消息,例如视频流格式,在第一个新的chunk以后使用这种类型,注意其中时间戳部分是相对时间,为何上一个绝对时间之间的差值 如图所示:

++++++++++++++++++++++++++++++++++++++++++++++++++++++

    timestamp    delta    +    message length + message type id +   

++++++++++++++++++++++++++++++++++++++++++++++++++++++

        3 bytes的chunk head,该类型既不包含stream ID 也不包含消息长度,这种类型用于stream ID和前一个chunk相同,且有固定长度的信息,例如音频流格式,在第一个新的chunk以后使用该类型。如图所示:

                           ++++++++++++++++++++

                           +     timestamp    delta    + 

                           ++++++++++++++++++++

 

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

chunk的长度:

chunk的长度初始长度固定为128个字节,但是这个值并不是不可变的,在客户端和服务端建立连接以后,客户端和服务端都可以通过发送信令的方式来通知对端修改chunk的长度,理论上来说可以修改chunk的最长长度为65536。这里chunk的长度是指chunk的数据部分的长度,即chunk data(payload)的长度,如果一条Message的数据长度超过了chunk的长度,就必须把Message分割成多条chunk,即如果一条视频类型Message长度为2000个byte,chunk长度为1500,则该Message将会分割成两条chunk,第一条的chunk data长度为1500,第二条的chunk data长度为500。当然这两条chunk的chunk head肯定是不同的,其中第二条chunk的chunk head就是0字节的

 

  • Message Type ID:

0×01 Chunk Size changes the chunk size for packets
0×02 Unknown anyone know this one?
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 anyone know this one?
0×08 Audio Data packet containing audio
0×09 Video Data packet containing video data
0x0A - 0×11 Unknown anyone know?
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.

例子:

另一个:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hjwang1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值