RTMP 传输基本流程

RTMP 音视频数据流程

发送端:

  • Step 1: 把数据封装成消息(Message)。
  • Step 2: 把消息分割成消息块(Chunk, 网络中实际传输的内容)。
  • Step 3: 将分割后的消息块(Chunk)通过TCP协议发送出去。

接收端:

  • Step 1: 在通过TCP协议收到数据后, 先将消息块重新组合成消息(Message)。
  • Step 2: 通过对消息进行解封装处理就可以恢复出数据。

RTMP 设计思想

RTMP 设计思想

大而化小 轻车简行

RTMP 协议中基本的数据单元称为消息(Message)。
在互联网中传输数据时, 消息(Message)会被拆分成更小的单元, 称为消息块(Chunk).
大的 Message 被切割成利于在网络上传输的小 Chunk,个人认为这是 RTMP 之所以延时低的核心原因。

数据划分

切成小块, 还可防止大的数据块(如视频数据)阻塞小的数据块(如音频数据或控制信息)。

本是天涯同路人 你方唱罢我登场

RTMP 基于 TCP 协议,包括控制信息、视频数据、音频数据都共用同一个 TCP Connection。
也就是说路只有一条。而且同一时间只允许一辆车通过。
生成好的视频 Chunk 和音频 Chunk,依次上路。

数据发送

这就涉及到 RTMP 中一个非常重要的概念: 复用
指的就是将独立的音视频数据整合到一个数据流,让音视频流可以同步传输的过程。
RTMP 直播中,实时生成视频 Chunk 和音频 Chunk,依次加入到数据流,通过网络发送到客户端。
复用在RTMP中是传输方式,也是音视频同步的关键。

事分轻重缓急 军令最重 粮草次之

在 RTMP 中,消息(Message)主要分为两大类: 控制消息和数据消息。
数据消息中由包括 Video 消息和 Audio 消息等。
这些消息都是怎么进行管理的呢?
有点像车辆的管理问题,也就是说路,只有一条,到底谁先走呢,谁后走呢?
答案是: 分优先级,优先级高的先行。优先级低的不能阻塞优先级高的。
RTMP 协议可从整体分为两个层次:

RTMP 层级

Message stream 属于应用层次消息,Chunk stream 属于更底层 RTMP 协议层次。
RTMP Chunk Stream 层级没有优先级的划分,而是在高层次Message stream提供优先级的划分。
也就是说: 不同类型的消息会被分配不同的优先级,当网络传输能力受限时,优先级用来控制消息在网络底层的排队顺序。
比如当客户端网络不佳时,流媒体服务器可能会选择丢弃视频消息,以保证音频消息可及时送达客户端。
RTMP Chunk Stream 层级允许在 Message stream 层次,将大消息切割成小消息,这样可以避免大的低优先级的消息(如视频消息)阻塞小的高优先级的消息(如音频消息或控制消息)。

数据发送优先级

Protocol Control Messages 属于 RTMP Chunk Stream 层级的控制消息,用于该协议的内部控制。
User Control Messages (4)是 RTMP streaming layer(即Message stream层次)的消息。

军令最重

协议控制消息(Protocol Control Messages)和用户控制消息(User Control Messages)应该包含消息流 ID 0(控制流)和块流 ID 2,并且有最高的发送优先级。

粮草次之

数据消息(音频信息、音频消息)比控制信息的优先级低。
另外,一般情况下,音频消息比视频数据优先级高。

凡事好商量

发送端,在将 Message 切割成 Chunk 的过程中,是以 Chunk Size (默认值128字节)为基准进行切割的。
Chunk Size 越大,切割时 CPU 的负担越小;但在带宽不够宽裕的环境下,发送比较耗时,会阻塞其他消息的发送。
Chunk Size 越小,利于网络发送,但服务器 CPU 负担大。不适用于高码率数据流的情况。
Chunk Size 是可以实际情况进行改变的,即通过发送控制命令(Set Chunk Size)的方式进行更新。
充分考虑流媒体服务器、带宽、客户端的情况,通过 Set Chunk Size 可动态的适应环境,从而达到最优效果。

能偷懒时就偷懒

RTMP Chunk Header的长度不是固定的,分为: 12 Bytes、8 Bytes、4 Bytes、1 Byte 四种。

chunk_header_12byte

一般情况下,msg stream id 是不会变的,所以针对视频或音频, 除了第一个 RTMP Chunk Header 是 12Bytes 的,后续即可采用 8Bytes的。

chunk_header_8byte

如果消息的长度(message length)和类型(msg type id, 如视频为9或音频为8)又相同,即可将这两部分也省去,RTMP Chunk Header采用4Bytes类型的。

chunk_header_4byte

如果当前Chunk与之前的Chunk相比, msg stream id相同,msg type id相同,message length相同,而且都属于同一个消息(由同一个Message切割成),这类Chunk的时间戳(timestamp)也是相同的,故后续的也可以省去,RTMP Chunk Header采用1 Byte类型的。

chunk_header_1byte

当Chunk Size足够大时(一般不这么干),此时所有的Message都只能相应切割成一个Chunk,该Chunk仅msg stream id相同。此时基本上除了第一个Chunk的Header是12Bytes外,其它所有Chunk的Header都是8Bytes。

chunk_big_byte

总结

RTMP设计的核心思想: 分块 复用 分等级