RTMP协议是一个互联网TCP/IP五层体系结构中应用层的协议。RTMP协议中基本的数据单元称为消息(Message)。当RTMP协议在互联网中传输数据的时候,消息会被拆分成更小的单元,称为消息块(Chunk)。
消息头MessageHeader
- 消息类型:1byte,Message Type ID取值含义:
-
A协议控制消息,Message Type ID = 1~6,主要用于协议内的控制。
-
1,Set Chunk Size 设置块的大小,通知对端用使用新的块大小,共4 bytes
-
2,Abort Message 取消消息,用于通知正在等待接收块以完成消息的对等端,丢弃一个块流中已经接收的部分并且取消对该消息的处理,共4 bytes。
-
3,Acknowledgement 确认消息,客户端或服务端在接收到数量与窗口大小相等的字节后发送确认消息到对方。窗口大小是在没有接收到接收者发送的确认消息之前发送的字节数的最大值。服务端在建立连接之后发送窗口大小。本消息指定序列号。序列号,是到当前时间为止已经接收到的字节数。共4 bytes。
-
4,User Control Message 用户控制消息,客户端或服务端发送本消息通知对方用户的控制事件。本消息承载事件类型和事件数据。消息数据的头两个字节用于标识事件类型。事件类型之后是事件数据。事件数据字段是可变长的。
-
5,Window Acknowledgement Size 确认窗口大小,客户端或服务端发送本消息来通知对方发送确认(致谢)消息的窗口大小,共4 bytes.
-
6,Set Peer Bandwidth 设置对等端带宽,客户端或服务端发送本消息更新对等端的输出带宽。发送者可以在限制类型字段(1 bytes)把消息标记为硬(0),软(1),或者动态(2)。如果是硬限制对等端必须按提供的带宽发送数据。如果是软限制,对等端可以灵活决定带宽,发送端可以限制带宽?。如果是动态限制,带宽既可以是硬限制也可以是软限制。
-
B数据消息,Message Type ID = 8 9 18;8: Audio 音频数据;9: Video 视频数据;18: Metadata 包括音视频编码、视频宽高等信息;
-
C命令消息,Message Type ID为15-20的消息用于发送AMF编码的命令,负责用户与服务器之间的交互,比如播放,暂停等。
- 消息负载长度:3byte,消息负载的长度。
- 时间戳:4byte,单位毫秒。超过最大值后会翻转。
- 消息流ID:3byte,Message Stream ID,用于区分不同流的消息。每个消息的唯一标识,划分成Chunk和还原Chunk为Message的时候都是根据这个ID来辨识是否是同一个消息的Chunk的,4个字节,并且以小端格式存储
消息块头MessageChunkHeader
块头由块基本头、块消息头和扩展时间戳组成。
- timestamp:3个字节,因此它最多能表示到16777215=0xFFFFFF=2^24-1, 当它的值超过这个最大值时,这三个字节都置为1,实际的timestamp会转存到Extended Timestamp字段中,接受端在判断timestamp字段24个位都为1时就会去Extended timestamp中解析实际的时间戳。
- message length:3个字节,表示实际发送的消息的数据如音频帧、视频帧等数据的长度,单位是字节。注意这里是Message的长度,也就是chunk属于的Message的总数据长度,而不是chunk本身Data的数据的长度。
- message type id:1个字节,表示实际发送的数据的类型,如8代表音频数据、9代表视频数据。就是上面的消息头的MessageType值。
- msg stream id:4个字节,表示该chunk所在的流的ID,和Basic Header的CSID一样,它采用小端存储的方式。
块基本头
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;
cs id: 是chunk stream id的缩写,同一个RTMP消息拆成的 chunk 块拥有相同的 cs id, 用于区分chunk所属的RTMP消息, chunk basic header 的类型cs id占用的字节数来确定。0、1、2作为保留。
- csid在3~63的范围内时
- csid在64~319的范围内时,第二个字节+64
- csid在64~65599的范围内时,第三个字节*256+第二个字节+64
消息头与块头关系
分块例子
- 在拆分到多个Chunk中的时候,第一个Chunk携带完整的Message Header信息
- 因为一个流当中可以传输多个Chunk,那么多个Chunk怎么标记同属于一个Message的呢?
- 是通过Chunk Stream ID区分的,同一个Chunk Stream ID必然属于同一个Message