RTMP 协议笔记

1,591 阅读11分钟
原文链接: www.zybuluo.com

@sheepbao 2016-09-12T13:56:52.000000Z 字数 8894 阅读 206

RTMP协议笔记

请用电脑或者手机横屏查看,不然会格式乱。

RTMP的背景和应用

每项技术都有起来源,RTMP也不例外,RTMP是Adobe公司公布的一项协议,Adobe是一家世界领先数字媒体和在线营销方案的供应商。在H5崛起之前,几乎所有的浏览器都用Flash player播放多媒体资源,而服务端和浏览器之间就是用RTMP协议或者在RTMP协议变种后的协议进行通信的。

RTMP协议概览

握手、消息块概念
握手的目的是为了确认对端RTMP的Version和确认对端能互相通信。
消息块就是消息的载体,是RTMP协议最重要的载体,这个载体是有一定格式的,如果把Client和Server端当作铁路的两个站点,那这个消息块就是火车,它负责运输货物。正如火车有火车头、车厢一样,消息块也有基本头,消息头和消息负载。RTMP协议当中,除了握手协议,其他的数据都是以消息块的方式发送的,发送一个消息时,当块大小比需要发送的消息的字节数更大时,一个消息块就相当于一个消息,否则消息需要分成多个消息块。

握手

  1. +-+-+-+-+-+-++-+-+-+-+-+-+
  2. |Client||Server|
  3. +-+-+-+-+-+-++-+-+-+-+-+-+
  4. |-------- C0C1 -------->|
  5. | S0S1S2 --------|
  6. |--------- C2 --------->|
  1. +-+-+-+-+-+-+-+-+
  2. | version |
  3. +-+-+-+-+-+-+-+-+
  1. +-+-+-+-+-+-+-+-+-+-+
  2. | time (4 bytes)|
  3. +-+-+-+-+-+-+-+-+-+-+
  4. | zero (4 bytes)|
  5. +-+-+-+-+-+-+-+-+-+-+
  6. | random bytes |
  7. +-+-+-+-+-+-+-+-+-+-+
  8. |random bytes(cont)|
  9. |....|
  10. +-+-+-+-+-+-+-+-+-+-+
time: 4 字节
本字段包含时间戳。该时间戳应该是发送这个数据块的端点的后续块的时间起始点。可以是 0 ,或其他的任何值。为了同步多个流,端点可能发送其块流的当前值。
zero: 4 字节
本字段必须是全零。
random bytes: 1528 字节。
本字段可以包含任何值。因为每个端点必须用自己初始化的握手和对端初始化的
  1. +-+-+-+-+-+-+-+-+-+-+
  2. | time (4 bytes)|
  3. +-+-+-+-+-+-+-+-+-+-+
  4. | time2(4 bytes)|
  5. +-+-+-+-+-+-+-+-+-+-+
  6. | random bytes |
  7. +-+-+-+-+-+-+-+-+-+-+
  8. |random bytes(cont)|
  9. |....|
  10. +-+-+-+-+-+-+-+-+-+-+
time: 4 字节
本字段必须包含对等段发送的时间(对C2来说是S1 ,对S2来说是C1)。
time2 : 4 字节
本字段必须包含先前发送的并被对端读取的包的时间戳。
random bytes: 1528 字节
本字段必须包含对端发送的随机数据字段(对C2来说是S1 ,对S2来说是C1)。  
  • 握手流程
    握手是一切的开始,Client和Server两个站点之前要运输货物,首先得先互相通知对方,确认铁轨是否符合火车运行,是否畅通无阻,是否能准确的运输货物到对端。
    • 实际的流程大概是这样的:
      1. Client发送带有1byte的C0和固定长度为1536byte的C1。
      2. Server发送S0S1S2给Client。
      3. Client发送C2。
  1. +-------------+----------------+-------------------+-----------+
  2. |Basic header|ChunkMsgHeader|ExtendedTimeStamp|ChunkData|
  3. +-------------+----------------+-------------------+-----------+
  1. +-+-+-+-+-+-+-+-+
  2. | fmt | cs id |
  3. +-+-+-+-+-+-+-+-+
fmt:表示块类型,决定了Chunk Msg Header的格式,  
它占第一个字节的0~1bit,2~7属于csid字节。
csid :表示块流id  
csid在64~319的范围内时,  
    csidTS=0,csid=(第二个字节的值)+64  
csid在64~65599的范围内时,  
    csidTS=0x3f,bit位全为1时,csid=(第二个字节的值×256)+(第三个字节的值)+64  
csid在3~63的范围内时,  
    csidTS=1~0x3e,即6位bit非全0也非全1时,csid=csidTS    

注意:这里第一个字节的2~7位暂时称为csidTS,协议里并没有这么说明,只是个人阐述需要
说明:BH的长度范围为1~3 byte,具体多少byte是csidTS决定的,csid的值范围3~65599,0~2作为保留。

  • Chunk Message Header (0,3,7,11 byte)
  1. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  2. | timestamp | message length |
  3. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  4. |message length (cont)|message type id| msg stream id |
  5. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  6. |message stream id (cont)|
  7. +-+-+-+-+-+-+-+-+-+-+-+-+-+
  1. fmt=0:长度11 byte,
    在一个块流的开始和时间戳返回的时候必须有这种块
  2. fmt=1:长度为7 byte,与fmt=0时,相比,该类型少了Message Stream Id
    具有可变大小消息的流,在第一个消息之后的每个消息的第一个块应该使用这个格式
  3. fmt=2:长度3 byte,不包含Message Stream IdMessage Length
    具有固定大小消息的流,在第一个消息之后的每个消息的第一个块应该使用这个格式
  4. fmt=3:长度为0 byte,
    当一个消息被分成多个块,除了第一块以外,所有的块都应使用这种类型

    • Extend Time Stamp (0,4 byte)
  1. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  2. | timestamp |
  3. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
只有当块消息头中的普通时间戳设置为 0x00ffffff 时,本字段才被传送。  
如果普通时间戳的值小于 0x00ffffff ,那么本字段一定不能出现。如果时间戳  
字段不出现本字段也一定不能出现。类型 3 的块一定不能含有本字段。本字段  
在块消息头之后,块时间之前  

* Chunk Data

  1. +-----------+
  2. |ChunkData|
  3. +-----------+
Chunk Data的实例就是Message  

消息-Message

  1. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  2. |MessageType|Payload length|
  3. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  4. |Timestamp|
  5. +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
  6. |Stream ID |
  7. +-+-+-+-+-+-+-+-+-+-+-+-+
  1. Message Type(1 byte)以下简写为MT
    消息类型很重要,它代表了这个消息是什么类型,当写程序的时候需要根据不同的消息,做不同的处理。
  2. Payload length(3 bytes)
    表示负载的长度(big-endian 格式)
  3. Timestamp (4 bytes)
    时间戳(big-endian 格式)
  4. Stream ID (3 bytes)
    消息流ID(big-endian 格式)
  5. Message Payload
    真实的数据

消息的分类

协议控制消息

协议控制消息是用来与对端协调控制的,**MT的范围1~7**.
1~2 用于chunk协议,3~6 用于rtmp协议本身,协议控制消息必须要求  
**Message Stream ID=0 和 Chunk Stream ID=2**.   

* MT=1, Set Chunk Size 设置块的大小,通知对端用使用新的块大小,共4 bytes。

  1. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. |BasicHeader|MessageHeader|ExTimestamp|Set chunk size |
  3. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  • MT=2, Abort Message 取消消息,用于通知正在等待接收块以完成消息的对等端,丢弃一个块流中已经接收的部分并且取消对该消息的处理,共4 bytes。
  1. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. |BasicHeader|MessageHeader|ExTimestamp|ChunkStream ID |
  3. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  • MT=3, Acknowledgement 确认消息,客户端或服务端在接收到数量与窗口大小相等的字节后发送确认消息到对方。窗口大小是在没有接收到接收者发送的确认消息之前发送的字节数的最大值。服务端在建立连接之后发送窗口大小。本消息指定序列号。序列号,是到当前时间为止已经接收到的字节数。
    共4 bytes。
  1. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. |BasicHeader|MessageHeader|ExTimestamp|SequenceNumber|
  3. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  • MT=4, User Control Message 用户控制消息,客户端或服务端发送本消息通知对方用户的控制事件。本消息承载事件类型和事件数据。消息数据的头两个字节用于标识事件类型。事件类型之后是事件数据。事件数据字段
    是可变长的。
  1. +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. |BasicHeader|MessageHeader|ExTimestamp|EventType|EventData|
  3. +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  • MT=5, Window Acknowledgement Size 确认窗口大小,客户端或服务端发送本消息来通知对方发送确认(致谢)消息的窗口大小,共4 bytes.
  1. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. |BasicHeader|MessageHeader|ExTimestamp|AcknowledgementWindow size |
  3. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  • MT=6, Set Peer Bandwidth 设置对等端带宽,客户端或服务端发送本消息更新对等端的输出带宽。发送者可以在限制类型字段(1 bytes)把消息标记为硬(0),软(1),或者动态(2)。如果是硬限制对等端必须按提供的带宽发送数据。如果是软限制,对等端可以灵活决定带宽,发送端可以限制带宽?。如果是动态限制,带宽既可以是硬限制也可以是软限制。
  1. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. |BasicHeader|MessageHeader|ExTimestamp|AcknowledgementWindow size |
  3. ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  4. |Limit type |
  5. ++++++++++++++++

音频数据消息

  • MT=8 Audio message, 客户端或服务端发送本消息用于发送音频数据。消息类型 8 ,保留为音频消息。

视频数据消息

  • MT=9 Video message, 客户端或服务端使用本消息向对方发送视频数据。消息类型值 9 ,保留为视频消息。

元数据消息

  • MT=15或者18 Data message, 客户端或服务端通过本消息向对方发送元数据和用户数据。元数据包括数据的创建时间、时长、主题等细节。
    消息类型为 18 的用 AMF0 编码,消息类型为 15 的用AMF3 编码。

共享对象消息

  • MT=16或者19 Shared object message, 共享对象是跨多个客户端,实例同步的 FLASH 对象(名值对的集合)。

命令消息

  • MT=17或者20,Command message
    命令消息都是用AMF编码的,AMF有两种,为AMF0和AMF3。命令消息有命令名,传输ID,和命名对象组成。
    而命名对象是由一系列参数组成的。
命令消息的类型
  • NetConnection:代表服务端和客户端之间连接的更高层的对象。包含4个命令类型。

    1. connect
      该命令是client先发送给server,意思是我要连接,能建立连接吗?server返回含“_result”或者“_error”命令名,
      返回“_result”,表示server能提供服务,client可以进行下一步。“_error”,很明显server端不能提供服务。
    2. call
      NetConnection 对象的调用方法在接收端运行远程过程调用。远程方法的名作为调用命令的参数。
    3. close
      不知道为何协议里没写这个命令的内容,我猜应该是close connect。
    4. createStream
      客户端发送本命令到服务端创建一个消息通讯的逻辑通道。音频,视频和元数据的发布是由创建流命令建立的流通道承载的。
      NetConnection 本身是默认的流通道,具有流ID 0。协议和一少部分命令消息,包括创建流,就使用默认的通讯通道。
  • NetStream:代表发送音频流,视频流和其他相关数据的通道的对象。我们也发送像播放,暂停等控制数据流动的命令。

  1. +-------------++----------+
  2. |PlayClient|||Server|
  3. +-------------+|+----------+
  4. ||Handshaking and Application||
  5. || connect done ||
  6. |||
  7. ---+----|---------CommandMessage(createStream)--------->|
  8. Create||
  9. Stream||
  10. ---+----|CommandMessage-----------------|
  11. |(_result- createStream response)|
  12. ||
  13. ---+----|------------CommandMessage(play)------------>|
  14. play ||
  15. ||SetChunkSize------------------|
  16. ||UserControl(StreamIsRecorded)----------|
  17. ||UserControl(StreamBegin)-------------|
  18. ||CommandMessage(onStatus-play reset)------|
  19. ||CommandMessage(onStatus-play start)------|
  20. ||------------------AudioMessage---------------->|
  21. ||------------------VideoMessage---------------->|
  22. |
  23. |
  24. Keep receiving audio and video stream till finishes
a. 客户端从服务端接收到流创建成功消息,发送播放命令到服务端。  
b. 接收到播放命令后,服务端发送协议消息设置块大小。  
c. 服务端发送另一个协议消息(用户控制消息),并且在消息中指定事件” streamisrecorded” 和流 ID 。消息承载的头 2 个字,为事件类型,后4 个字节为流 ID 。  
d. 服务端发送事件” streambegin” 的协议消息(用户控制),告知客户端流 ID 。 
e. 服务端发送响应状态命令消息`NetStream.Play.Start`&`NetStream.Play.reset` , 如果客户端发送的播放命令成功的话。只有当客户端发送的播放命令设置了 `reset`命令的条件下,服务端才发送`NetStream.Play.reset`消息。如果要发送的流 没有找的话,服务端发送`NetStream.Play.StreamNotFound`消息。在此之后服务端发送客户端要播放的音频和视频数据。  

2. play2

和播放命令不同,play2命令可以切换到不同的码率,而不用改变已经播放的内容的时间线。服务端对播放 2 命令可以请求的多个码率维护多个文件。  

3. deleteStream

当 NetStream 对象销毁的时候发送删除流命令。  

4. closeStream
5. receiveAudio

NetStream 对象发送接收音频消息通知服务端发送还是不发送音频到客户端。

6. receiveVideo

NetStream 对象发送 receiveVideo 消息通知服务端是否发送视频到客户端。  

7. publish

  1. +-------------++----------+
  2. |Client|||Server|
  3. +-------------+|+----------+
  4. ||Handshaking and Application||
  5. || connect done ||
  6. |||
  7. ---+----|---------CommandMessage(createStream)--------->|
  8. Create||
  9. Stream||
  10. ---+----|CommandMessage-----------------|
  11. |(_result- createStream response)|
  12. ||
  13. ---+----|---------CommandMessage(publish)------------>|
  14. publish ||
  15. ||UserControl(StreamBegin)-------------|
  16. ||----------DataMessage(Metadata)------------->|
  17. ||------------------AudioMessage---------------->|
  18. ||-----------------SetChunkSize----------------->|
  19. ||CommandMessage----------------|
  20. ||(_result- publish result)|
  21. ||------------------VideoMessage---------------->|
  22. |
  23. |
  24. Until the stream is complete
    客户端发送一个发布命令,发布一个命名流到服务端。使用这个名字,任何客户端可以播放该流并且接收音频,视频,和数据消息。  

8. seek

客户端发送搜寻命令在一个媒体文件中或播放列表中搜寻偏移。  

9. pause

客户端发送暂停命令告诉服务端暂停或开始一个命令。  

聚合消息

  • MT=22 Aggregate message, 聚合消息是含有一个消息列表的一种消息。消息类型值 22 ,保留用于聚合消息。
  1. +---------+-------------------------+
  2. |Header|AggregateMessage body |
  3. +---------+-------------------------+
  4. 聚合消息的格式
  5. +--------+--------------+--------------+--------+-------------+---------------+----
  6. |Header0|MessageData0|BackPointer0|Header1|MessageData1|BackPointer1|
  7. +--------+--------------+--------------+--------+--------------+--------------+----
  8. 聚合消息的body
Back Pointer包含了前面消息的大小(包括Header的大小)。这个设置匹配了 flv 文件格式,可用于后向搜索。  

PS

视智云-Sewise,流媒体云平台服务商。
Sewise提供最优秀的流媒体软件和技术服务,包括流媒体协议的接入、转换、封装、分析等;音视频的转码、裁剪、拼接、水印、抽帧、切片、元信息提取与处理、录制、HLS时移回播、编码、格式封装、加解密等;字幕的抽取、添加、匹配等。