RTMP 协议 (Real-Time Messaging Protocol)
协议简介
RTMP协议是一个互联网TCP/IP五层体系结构中应用层的协议.
RTMP协议中基本的数据单元称为消息(Message).
当RTMP协议在互联网中传输数据的时候,消息会被拆分成更小的单元,称为消息块(Chunk)
RTMP有几个变种版本
1.原始版本
基于TCP,默认端口1935
2.RTMPS RTMP over TLS/SSL
3.RTMPE
4.RTMPT 封装于HTTP请求中
5.RTMFP RTMP over UDP
RTMP 将传输的流(stream)分成片段(fragment),其大小由服务器和客户端之间动态协商,
默认的fragment大小为:
音频数据: 64 bytes
视频数据: 128 bytes
PS:以下内容如无特殊说明 数据 均为 大端表示法
RTMP Chunk(RTMP消息块)
数据的发送并不是以message为单位的,而是将message拆分成chunk(>=1),chunk按序发送,接收端再根据 MsgStreamID 还原成1个message
在网络上传输数据时,消息需要被拆分成数据块(Chunk).
| ChunkHeader |
+------------------------------------------------------------------------------------+
| ChunkBasicHeader | ChunkMsgHeader | ExtendedTimeStamp | ChunkData |
+-----------------------------------------------------------------------------------+
解释:
ChunkBasicHeader: 块基本头, 包含 『块流ID』和『块类型』(4中类型),每种类型的块**必须包含**
块基本头示意:
+-----------------------------------+
| fmt(2 bits) | csid(变长) |
+-----------------------------------+
ftm: 表示块类型
csid: chunk stream id (小端表示法) 块流ID 范围[3, 65599] [0,2]为RTMP协议保留表示特殊信息
块基本头长度可能为1、2、3字节
1). ChunkBasicHeader 为 1 字节时, fmt占2 bits,csid占6 bits
csid in [0, 63]
2). ChunkBasicHeader 为 2 字节时, 第一字节除去fmt外全置0, 剩下 1 字节用来表示csid
csid in [64, 2^8 + 64 = 319]
3). ChunkBasicHeader 为 3 字节时,第一字节除去fmt外全置1, 剩下2字节用来表示csid
csid in [64, 2^16 + 64 = 65599]
对于出现重叠的情况,应当使用使header**尽可能小**的实现
代码逻辑上可以这样处理:
1).先接收1字节,分别取高两位和低六位保存起来,
2).判断低六位是全0还是全1,如果是全0,表示ChunkBasicHeader长度为2字节,那么再接收1个字节,
并且csid需要加上64,如果全为1,则表示长度为3字节,需要在接收2字节
ChunkMsgHeader: 块消息头, 发送消息的信息,依据块基本头中的『块类型』分为4种:
块类型0: 11 bytes 流开始的第一个块必须使用这种类型,流时间戳回退时也必须使用这种类型头(backward seek)
+------------------------------------------------------------------------+
| TimeStamp(3 bytes) | MsgLength(3 bytes) | MsgTypeID(1 byte) |
+------------------------------------------------------------------------+
| MsgStreamID(4 bytes)|
+-----------------------+
块类型1: 7 bytes 省去了MsgStreamID 表示此chunk和上一次发送的chunk属于同一个流
message大小变化的流的第一个消息块之后的每一个消息的第一个块应该使用这种头
+-------------------------------------------------------------------------------+
| TimeStampDelta(3 bytes) | MsgLength(3 bytes) | MsgTypeID(1 byte) |
+-------------------------------------------------------------------------------+
块类型2: 3 bytes 表示此chunk和上一次发送的chunk的 MsgTypeID, MsgLength, MsgStreamID 相同,
message大小不变的流的第一条message之后的每条message的第一个chunk
+-------------------------------+
| TimeStampDelta(3 bytes) |
+-------------------------------+
块类型3: 0 byte
没有头 表示此chunk的 ChunkMsgHeader 和上一个完全一样, 表示此chunk时上一个chunk的分块
TimeStamp: 时间戳
MsgLength: 此chunk所属Message总长度,而非 ChunkData 长度
MsgTypeID: 消息类型
MsgStreamID: 消息流ID (小端表示法)
TimeStampDelta: 时间戳增量,溢出时该字段全置1并使用 ExtendedTimeStamp 字段 存储的是完整值
ExtendedTimeStamp: 扩展时间戳,TimeStamp溢出时使用
ChunkData: 块数据 大小在 [0, chunksize] 之间 chunksize由控制消息 set chunk size 决定(见后面描述)
消息分块
消息过长时需要进行分块,消息负载(PayLoad)部分被分割成大小固定的数据块(Chunk)(128 by default),并在其首部加上消息块首部(ChunkHeader).
1.分块前
| 307 |
+-----<