计算机 · 2021年8月19日 0

RTMP

RTMP specification

https://wwwimages2.adobe.com/content/dam/acom/en/devnet/rtmp/pdf/rtmp_specification_1.0.pdf

introduction

RTMP(Real Time Messaging Protocol)基于可靠传输(如TCP)提供服用的传输通道,并且为传输的数据(chunk)提供timestamp,以及所有传输的chunk按timestamp有序。

Action Message Format (AMF): A compact binary format that is used to serialize ActionScript object graphs. AMF has two versions: AMF0 and AMF3.
字节序:使用big endian。
对齐:byte-aligned,即一个16位的数字可能起始地址为奇数。
timestamp:使用32位整数毫秒级时间戳,通信双方需要使用相同的起始时间(同一个epoch)。并且使用RTMP协议的程序需要能够处理时间戳的wraparound。
RTMP Chunk Stream:类似QUIC里的QuicStream,每个Chunk都携带了timestamp和标记了payload类型。RTMP Chunk Stream可以选用任意支持流式传输的协议进行传输,如果是选用TCP这种可靠传输通道的话,RTMP Chunk Stream可以保证所有的Rtmp Chunk按timestamp可靠有序到达。RTMP Chunk Stream不提供优先级控制,需要应用自己实现。

RTMP Chunk Stream

Message Format

Message Format:Message可以被拆分成Chunk进行传输,Message需要具有以下信息:

  • timestamp, 4字节的时间戳;
  • length, payload的长度,3字节,包含在length里;
  • type id,1字节,表示消息类型;
  • Message Stream ID,4字节,保存在chunk header中,little endian;

Handshake

client需要发送c0,c1,c2共3个包,server需要发送s0,s1,s2共3个包,时序要求如下:

 The client MUST wait until S1 has been received before sending C2.
 The client MUST wait until S2 has been received before sending any
 other data.
 The server MUST wait until C0 has been received before sending S0 and
 S1, and MAY wait until after C1 as well. The server MUST wait until
 C1 has been received before sending S2. The server MUST wait until
 C2 has been received before sending any other data.
  • c0和s0:只有1个字节,用于client和server之间进行RTMP版本的协商。按照此specification描述,现在只有3可用,0-2已经obsolete。
  • c1和s1:各有1536字节,包含4字节时间戳+4字节0+1528字节随机数据,随机数用来区分不同的握手过程。时间戳为epoch。
  • c2和s2:各有1536字节,分别包含4字节time+4字节time2+1528字节随机数据。time是之前收到的c1或者s1包里的time,tim2是自己的收到c1或者s1的时间戳,即这两个字段用于协商各自的epoch。1528字节随机数据是之前收到的c1和s1里的随机数据,用于区分不同的握手过程。整个c2和s2就相当于是c1和s1的response/echo。
    理解了这6个包的内容也就自然理解了这6个包的发送顺序,不需要去死记硬背上面写的发送这6个包的时序要求了。

Chunking

一个RTMP连接里包含了多个chunk stream,每个chunk都包含了所属chunk stream的ID。chunk在传输的时候必须有序到达。
chunk的大小可用配置,可以通过Set Chunk Size control message来配置,server和client的chunk size独立。

chunk format

chunk分header(Basic Header + Message Header + Extended Timestamp)和data:

  1. Basic Header(1到3字节):包含了chunk stream ID和chunk type。chunk type决定了里面编码的message header的格式。Basic Header的长度则由chunk stream ID(chunk stream ID的长度是不固定的)决定。
  2. Message Header(0,3,7,或者11字节):包含了所编码的message的信息(是部分还是整个message),长度由chunk header决定。
  3. Extended Timestamp(0或者4字节)。

Basic Header的编码

Basic Header的第一个字节高2位为fmt,在解析/编码Message Header时需要用到。
低6位暂且称之为cs id,

  1. 如果cs id为0,则第一个字节后面还有1个字节,后面的字节保存Chunk Stream ID – 64。
  2. 如果cs id为1,则第一个字节后面还有2个字节,保存Chunk Stream ID – 64。具体计算Chunk Stream ID方式为第三个字节*256+第二个字节+64。
  3. 如果cs id为2-63,则Basic Header总共只有1个字节,Chunk Stream ID为cs id。
    Chunk Stream ID保留,用于传输rtmp的控制消息和命令。RTMP支持3-65599的65597个应用层可用的Chunk Stream ID。
    Chunk Stream ID可以用2字节也可以用3字节的Basic Header,但是按照使用最少字节数的原则,最好还是用2字节。
    Chunk Stream ID没有用上0和1保留。

Chunk Message Header的编码

根据Basic Header中的fmt,Chunk message header相应地分成4种类型。
Type 0:chunk message header有11字节长,在chunk stream开始的时候或者chunk stream里的timestamp想要回退的时候(因为seek操作导致的回退),必须要使用这种类型的chunk message header。
Type 1:7字节长,不包含message stream id,message stream ID使用前一个chunk的message stream id。
Type 2:3字节长,message stream ID和message length都使用前一个chunk的message stream ID和message length。只包含timestamp delta,一般用于传输固定消息长度的音频。
Type 3:0字节,message stream ID,message length和timestamp delta都用同一个chunk stream里前一个chunk的。把一个message拆分成多个chunk进行传输时,可用使用这种类型的Message Header(除了第一个Chunk)。如果在Type 0类型的Chunk后面跟了一个Type 3类型的chunk,那么这个Type 3 chunk的timestamp delta使用Type 0类型那个chunk的timestamp。

Message Header中通用的字段:
timestamp delta(3字节): 对于type 1和type 2类型,表示和前一个chunk的timestamp的差,如果值大于等于了0xffffff,则需要启用Extended Timestamp字段,并且timestamp delta设置为0xffffff。
message length(3字节):对于type 0和type 1,表示发送的message的长度。
message type id(1字节):message 类型。
message stream id(4字节, little endian):一般一个chunk stream里只传输同一个message stream,如果要在一个chunk stream里multiplex多个message stream的话,前面讲的压缩header的编码方式就不容易起效果(因为不能省略message stream id了,各个message stream传输的chunk大小也可能不一样)。

Extended Timestamp

在Chunk Message Header中的timestamp或者timestamp delta为0xffffff时,会存在Extended Timestamp(4字节)保存完整的时间戳。

Protocol Control Messages

RTMP Chunk Stream Protocol用1,2,3,5,6这几个message type来表示protocol control message。传送Protocol Control Messages时,message stream ID必须为0,而chunk stream ID必须为2。

1. Set Chunk Size(1)

chunk size默认128字节,但是server或者client可用通过发Set Chunk Size消息修改设置(不能低于128字节)。Set Chunk Size消息的Payload为一个4字节int,这个4字节int的最高位必须为0。由于Message length只用3个字节保存,所以实际上这个Set Chunk Size最多把max chunk size设置成0xffffff。

2. Abort Message(2)

告诉对端不要再等当前这个message了,直接丢弃掉当前这个message。payload为chunk stream ID。

3. Acknowledgement(3)

在每收满window size字节后,接收端必须要给发送端发送一个Acknowledgement消息,告诉对端自己总共收了多少字节。Payload为目前所收字节数(4字节)。
发送端可用在收到Acknowledgement消息之前最多发送window size字节的数据。

4. Window Acknowledgement Size (5)

用于告诉对端自己采用的window size,payload为4字节window size。

5. Set Peer Bandwidth(6)

Payload为4字节的Acknowledge Window Size加1个字节的Limit Type。
没看出与Window Acknowledgement Size消息的区别在哪里?

6. RTMP Message Formats

RTMP Message是位于RTMP Chunk Stream上层的协议,RTMP Message不一定非得用RTMP Chunk Stream传输。

6.1 RTMP Message Format

RTMP Message包括header和payload两部分。
RTMP Message Header的构成:

  0                   1                   2                   3
  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 | Message Type  | Payload length                                |
 | (1 byte)      | (3 bytes)                                     |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 | Timestamp                                                     |
 | (4 bytes)                                                     |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 | Stream ID                                     |
 | (3 bytes)                                     |
 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
 Message Header
  • Message Type: 1-6这6个类型被保留用于protocol control message。
  • Length:big endian。
  • Timestamp:big endian。
  • Message Stream ID:big endian。

payload:实际要传输的数据,没啥好说的。

6.2 User Control Messages(4)

RTMP用message type ID 4来表示User Control messages,1,2,3,5,6则被RTMP Chunk Stream Protocol占用,用于传RTMP Chunk Stream Protocol的控制消息。
User Control messages应该用ID为2的RTMP Chunk Stream中的message stream ID为0的message stream发送。User Control messages到达即生效,忽略其携带的时间戳。
User Control messages的payload组成:

 +------------------------------+-------------------------
 | Event Type (16 bits)         | Event Data
 +------------------------------+-------------------------
 Payload for the ‘User Control’ protocol message

7. RTMP Command Messages