RTMP 协议详解

又拍直播云产品已上线一年多,随着功能不断丰富,客户逐渐积累,平台一直稳定运行。

RTMP 协议是直播中非常重要的传输协议,互联网的各个直播产品都离不开这个非常可靠的伙伴,今天就让我们来认识认识他。

什么是 RTMP 协议

RTMP 是 Real Time Messaging Protocol(实时消息传输协议)的首字母缩写。该协议是由 Adobe 公司提出的一种应用层的协议,基于 TCP,是一个协议族,包括 RTMP 基本协议及 RTMPT/RTMPS/RTMPE 等多种变种。用来解决多媒体数据传输流的多路复用(Multiplexing)和分包(packetizing)的问题。随着 VR 技术的发展,视频直播等领域逐渐活跃起来,RTMP 作为业内广泛使用的协议也重新被相关开发者重视起来。

1.总体介绍

RTMP 协议是应用层协议,是要靠底层可靠的传输层协议(通常是 TCP )来保证信息传输的可靠性的。在基于传输层协议的链接建立完成后,RTMP 协议也要客户端和服务器通过“握手”来建立基于传输层链接之上的 RTMP Connection 链接,在 Connection 链接上会传输一些控制信息,如 SetChunkSize ,SetACKWindowSize。其中 CreateStream 命令会创建一个 Stream 链接,用于传输具体的音视频数据和控制这些信息传输的命令信息。RTMP 协议传输时会对数据做自己的格式化,这种格式的消息我们称之为 RTMP Message,而实际传输的时候为了更好地实现多路复用、分包和信息的公平性,发送端会把 Message 划分为带有 Message ID的 Chunk,每个 Chunk可能是一个单独的 Message,也可能是 Message的一部分,在接受端会根据 chunk 中包含的data的长度,message id和 message 的长度把 chunk 还原成完整的 Message,从而实现信息的收发。 

2.握手过程

要建立一个有效的 RTMP Connection 链接,首先要“握手”:客户端要向服务器发送 C0,C1,C2(按序)三个 chunk,服务器向客户端发送 S0,S1,S2(按序)三个 chunk,然后才能进行有效的信息传输。RTMP 协议本身并没有规定这6个 Message 的具体传输顺序,但 RTMP 协议的实现者需要保证这几点:

客户端要等收到 S1 之后才能发送 C2

客户端要等收到 S2 之后才能发送其他信息(控制信息和真实音视频等数据)

服务端要等到收到 C0 之后发送 S1

服务端必须等到收到 C1 之后才能发送 S2

服务端必须等到收到 C2 之后才能发送其他信息(控制信息和真实音视频等数据) 

如果每次发送一个握手 chunk 的话握手顺序会是这样:

理论上来讲只要满足以上条件,如何安排6个 Message 的顺序都是可以的,但实际实现中为了在保证握手的身份验证功能的基础上尽量减少通信的次数,一般的发送顺序是这样的,这一点可以通过 wireshark 抓 ffmpeg 推流包进行验证: 
|client|Server | 
|---C0+C1—->| 
|<--S0+S1+S2– | 
|---C2----> |

3.RTMP MESSAGE HEAR

在 RTMP 协议中信令和媒体数据都称之为 Message,在网络中传输这些 Message ,为了区分它们肯定是要加一个 Message head 的,所以RTMP协议也有一个 Message head ,还有一个问题因为 RTMP 协议是基于 TCP 的,由于 TCP 的包长度是有限制的(一般来说不超过1500个字节),而 RTMP 的 Message 长度是有可能很大的,像一个视频帧的包可能会有几十甚至几千 K ,这个问题就必然有一个分片的问题,在 RTMP 协议中对应的说法就是 chunk ,每一个 Message + head 都是由一个和多个 chunk 组成的。

RTMP 的 head 组成:RTMP 的 head 在协议中的表现形式是 chunk head ,前面已经说到一个 Message + head 可以分成一个和多个 chunk,为了区分这些 chunk,肯定是需要一个 chunk head 的,具体的实现就把 Message head 的信息和 chunk head 的信息合并在一起以 chunk head 的形式表现。

一个完整的 chunk 的组成如下图所示:

Chunk basic header:

该字段包含 chunk 的 stream ID 和 type 。chunk 的 Type 决定了消息头的编码方式。该字段的长度完全依赖于 stream ID,该字段是一个可变长的字段。

Chunk Msg Header:0, 3 ,7, 11

该字段包含了将要发送的消息的信息(或者是一部分,一个消息拆成多个chunk的情况下是一部分)该字段的长度由 chunk basic heade r中的 type 决定。

Extend Timestamp: 0 ,4 bytes

该字段发送的时候必须是正常的时间戳设置成 0xffffff 时,当正常时间戳不为 0xffffff 时,该字段不发送。当时间戳比 0xffffff 小该字段不发送,当时间戳比 0xffffff 大时该字段必须发送,且正常时间戳设置成 0xffffff。

Chunk Data(块数据): 

用户层面上真正想要发送的与协议无关的数据,长度在(0,chunkSize]之间

4.RTMP MESSAGE

Command Message (命令消息,Message Type ID=17或20):表示在客户端盒服务器间传递的在对端执行某些操作的命令消息,如 connect 表示连接对端,对端如果同意连接的话会记录发送端信息并返回连接成功消息,publish 表示开始向对方推流,接受端接到命令后准备好接受对端发送的流信息,后面会对比较常见的 Command Message 具体介绍。当信息使用 AMF0 编码时,Message Type ID=20,AMF3 编码时 Message Type ID=17. 
– Data Message(数据消息,Message Type ID=15或18):传递一些元数据(MetaData,比如视频名,分辨率等等)或者用户自定义的一些消息。当信息使用AMF0编码时,Message Type ID=18,AMF3编码时Message Type ID=15. 
– Shared Object Message(共享消息,Message Type ID=16或19):表示一个Flash类型的对象,由键值对的集合组成,用于多客户端,多实例时使用。当信息使用AMF0编码时,Message Type ID=19,AMF3编码时Message Type ID=16. 
– Audio Message(音频信息,Message Type ID=8):音频数据。 
– Video Message(视频信息,Message Type ID=9):视频数据。 
– Aggregate Message (聚集信息,Message Type ID=22):多个RTMP子消息的集合 
– User Control Message Events(用户控制消息,Message Type ID=4):告知对方执行该信息中包含的用户控制事件,比如 Stream Begin 事件告知对方流信息开始传输。和前面提到的协议控制信息(Protocol Control Message)不同,这是在RTMP协议层的,而不是在RTMP chunk流协议层的,这个很容易弄混。该信息在 chunk 流中发送时,Message Stream ID=0,Chunk Stream Id=2,Message Type Id=4。 

5.推流流程

6.播流流程

 

附:RTMP协议规范(中文翻译):https://wenku.baidu.com/view/882f1e48c850ad02de804195.html

留下一个评论