网络流媒体协议之——RTMP协议(Part I)

今天来整理一下直播中经常用到的RTMP协议,由于内容较多,分两部分来写。本篇写第一部分,主要内容是RTMP Message的格式;第二部分主要是RTMP的一些重要信令交互等。主要参考英文协议文档http://wwwimages.adobe.com/www.adobe.com/content/dam/acom/en/devnet/rtmp/pdf/rtmp_specification_1.0.pdf,并根据自己的理解梳理了一下相关内容的顺序。

RTMP — Real Time Messaging Protocol(实时消息传输协议),是Adobe公司为Flash播放器和服务器之间开发的音视频数据传输的开放协议,一般传输flv或f4v格式的媒体流。RTMP是工作在TCP之上的明文协议,使用端口1935,能够保持长连接,并为用户提供低延时通信。由于基于flash,因此RTMP无法在iOS浏览器上播放,但其实时性较HLS好。RTMP是一个协议族,包括RTMP基本协议及RTMPT / RTMPS / RTMPE等多种变种:

  • RTMPT封装在HTTP请求之中,可穿透防火墙;
  • RTMPS类似于RTMPT,但使用的是HTTPS连接,增加了TLS/SSL安全功能;
  • RTMPE在RTMP的基础上增加了加密功能;
  • RTMFP(Real-Time Media Flow Protocol)使用UDP替代TCP传输RTMP数据,能够实现终端之间的直连和通信,适合P2P业务。

RTMP定义了几种收发packets的虚拟通道,每个通道的操作都独立于其他通道,例如处理RPC请求和响应的通道,视频数据通道,音频数据通道,以及带外控制信息(例如实现分段大小的协商)通道,等等。在一个典型的RTMP会话中,多个通道可能在给定的任何时间同时激活。当编码生成RTMP数据时,会有一个packet header随之产生,packet header指定通道的ID、包生成的时间戳,以及packet payload的大小。而为了最大限度并且流畅地传输媒体数据,RTMP会对这些packets进行分段。Packet header之后紧跟按约定大小分段的payload内容,packet header不参与分段,并且其大小也不计入该包的第一个分段大小,也就是说,只有实际的packet payload(也就是媒体数据)才参与分段。

在RTMP中,收发的packet被称为Message,相应的分段称为Chunk。

RTMP Message

RTMP传输时会对数据做相应的格式化,这种格式的消息称为RTMP Message,而在实际传输中,为了更好地多路复用、分包以及不同媒体流的Message收发的公平性,发送端会把Message切分成一个一个的Chunk,每个Chunk可能是一个单独的Message,也可能是某个Message的一部分。在接收端,根据Chunk中包含的Message Length、Message ID和Payload size等把Chunk还原成完整的Message。在发送过程中,为了实现来自不同Stream的Message能够按照时间戳先后有序传输,不同的Chunk是交织在一起发送的,每一个Chunk都有一个与所在媒体流相关的Chunk Stream ID。

1.  Message Format

这里的Message是指满足RTMP协议格式的,并可以切分成Chunk发送的消息。Message 包含两个部分:message header和message body。

Message header包含的字段如下:


  • Message Type:1字节的消息类型,指明当前Message是音频、视频还是控制消息等,如8代表音频数据,9代表视频数据,message type 1~6保留为协议控制消息使用;
  • Payload length:3字节的Message Payload长度,即消息所携带的音视频数据等信息的长度。该字段为大端序;
  • TimeStamp:4字节的时间戳,大端序;
  • Message Stream ID:3字节的消息流ID,大端序。

Message Header后面紧跟的部分为Message Payload,也就是Message中携带的实际有效数据,例如,音频采样数据或压缩视频数据,其格式不在RTMP规定的格式范围内。

2.  Chunk Format

前面我们提到,Message在网络上传送之前,会被拆分成一个一个的chunks,并将来自不同流的chunks交织在一起发送,这样的机制允许将大的Message分成多个较小的Messages,可以防止低优先级的大Message(例如Video数据)阻塞高优先级的较小Message(例如audio和control数据),亦可减小一些较小message的发送开销,因为chunk header可以选择压缩的方式来表示。

chunk size是可配置的,默认是128 bytes,通过Set Chunk Size命令消息进行配置。较大的chunk size可以降低CPU的使用,但是由于发送时间较长,在带宽较低时会增加其他内容的延迟;而较小的chunksize则不太适合高码率的码流。每个传输方向独立维护自己的chunk size。

Chunk格式如下:


每个chunk包含chunk header和chunk data,chunk header又包含三个部分,分别是Basic Header,Message Header和Extended Timestamp。

2.1  Chunk Basic Header

Basic Header占1~3 bytes,该域存储的是chunk type (fmt,2 bits)和chunk stream ID (CSID)。chunk type决定message header的格式,共有4种格式,放在后面讲。Basic Header域可能有1,2,3 bytes,取决于CSID,在能完整表示CSID的前提下,使用尽量少的字节以减少Header的开销。

由于fmt域占2位,因此在Basic Header分别为1,2,3 bytes时,对应的CSID长度分别是6 bits、14 bits或22 bits。RTMP协议支持的CSID范围是3~65599,0~2为协议保留用作特殊信息,0表示Basic Header占2个字节,CSID范围是[64~319],即最大为(2^8 - 1) + 64 = 319;1表示Basic Header占3个字节,CSID范围是[64~65599],最大值为 (2^16 - 1) + 64 = 65599;而第一个字节的6 bits的值在[3~63]之间时,本身就表示了完整的CSID,此时Basic Header占1个字节;2表示一些保留的low-level协议控制信息和命令。

下面分别是chunk basic header分别占1 byte、2 bytes、3 bytes时的格式:




2.2  Chunk Message Header

下面我们来看chunk header的第二部分:Chunk Message Header。

该域的可能长度为0,3,7或11 bytes,取决于Basic Header中chunk type (fmt域)的值。

2.2.1  type 0

Type 0 Chunk Message Header占11 bytes。在一个Chunk Stream开始时,以及Timestamp回退(例如回退播放)时必须采用这种形式的MessageHeader。格式如下,其内容基本就是前面第一部分Message Format中讲到的未经chunk的message header,不同的是,这里的timestamp是用3 bytes表示的,而不是原来的4 bytes。


timestamp:3 bytes,能表示的最大时间戳为2^24 – 1 = 0xFFFFFF,若时间戳的值超过该最大值时,这三个字节都置1,这样实际的timestamp会转存到32位的Extended Timestamp字段中。接收端在检测到该域的24位全为1时,就会去Extended TimeStamp字段中解析实际的时间戳;否则,从该域解析出实际的时间戳。

2.2.2  type 1

Type 1 Chunk Message Header占7个字节。不包含stream ID,其stream ID与上一个Chunk的stream ID相同,在收发两端只有一个流连接时,尽量采取这种格式。


timestamp delta:3 bytes,与type 0 不同,这里存储的是当前chunk与上一个chunk的时间戳的差值。在存储与计算方式上与type 0相同,当存储的值超过0xFFFFFF时,该域的24位都被置1,实际的时间戳差值存入32位的ExtendedTimestamp字段中。

2.2.3  type 2

Type 2的chunk header只有3个字节,在type 1的基础上进一步省略了stream ID和message length,表示当前chunk与上一chunk有相同的stream ID和message length。具有相同message size的流(例如一些audio和数据格式)可用这种格式。该chunk header中的timestamp delta与type 1中的存储和计算方式相同。


2.2.4  type 3

0字节!表示当前chunk的Chunk Message Header与上一个chunk完全相同。当type 3的chunk跟在type 0 chunk后面时,表示和前一个chunk的时间戳相同,一般在一个Message被拆分成多个chunk时会存在这种情况,比如一个较大的video message,可能会被拆分成多个chunk,而每个chunk的时间戳都相同。当type 3的chunk跟在type 1或type2的chunk后面时,表示与前一个chunk的时间戳的差值相同。

2.3  Extended Timestamp

该域长度为0或4 bytes。前面我们提到,当Message Header中的24 bits timestamp或timestamp delta域的值超过0xFFFFFF(16777215)时(该24 bits全部被置1),该域用来存储实际的32bits的timestamp或者timestamp delta。当type 0,1,2的Message Header中的timestamp或timestamp delta域的24 bits都被置1时,启用32 bits的Extended Timestamp域,否则Extended Timestamp域不存在。如果是type 3,该域存在的条件是,其前一个具有相同stream ID的type 0, 1,或2的chunk指示了extended timestamp域存在。

2.4  Chunk Data

可变长度的payload,例如实际的音频数据、视频数据或控制信息,默认长度为128 bytes,长度可通过Set Chunk Size命令进行配置,最大长度不超过配置的最大chunk size。

2.5  Chunk Examples

为了更好地理解前面我们介绍的chunk格式,让我们用两个例子来结束本节的内容。

2.5.1  audio chunk example

下表中是一个audio message的序列,每个message有相同的message stream ID,message type ID,message length,以及增量相同的timestamp。


将以上message序列封装成chunk序列后,每个chunk的格式如下,


可以看到,将以上4个audio message通过chunk封装后,形成1个type 0 chunk + 1个type 2 chunk + 2个type 3 chunk,由于其他message header信息都相同,第二个chunk相对于第一个chunk,只有20的timestamp delta,且CSID为3,只需1 Byte的Basic Header即可表示,因此第二个chunk的header只需1 byte的Basic Header + 3 bytes的timestamp delta,共4 bytes;第三和第四个chunk的chunk message header则与第二个chunk的完全相同,因此只需1 Byte的Basic Header即可。

2.5.2  video chunk example

下表中表示一个video message,由于数据量较多,无法通过一个chunk(默认大小128 bytes)发送,因此需要切分成多个chunks。


切分之后的chunks序列如下,由于对于video message来说,切分后的chunks具有完全相同的头信息(一般一个video message是同一帧数据,具有相同的timestamp),因此切分之后是一个type 0 chunk + 若干 type 3 chunks,除了最后一个chunk之外,其他chunk的size都是最大chunk size。


3.  Message Types

最后,我们来简单介绍一下RTMP的message类型,RTMP中有如下一些Message types:

  • User Control Message (message typeID = 4):用户控制消息,告知对端执行该信息中包含的用户控制事件。
  • Command Messages (message typeID = 20 / 17):命令消息,表示服务器和客户端之间传递的一些特定操作的命令消息,例如connect,publish,play等,AMF0编码时,message type ID = 20,AMF3编码时,message type ID = 17。
  • Data Message (message type ID =18 / 15):传递一些元数据的消息,例如视频名、分辨率等,或某些用户自定义消息,AMF0编码时,message type ID = 18,AMF3编码时,message type ID = 15。
  • Shared Object Message (message type ID = 19 /16):共享消息,当使用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 typeID = 22):聚合消息,多个RTMP子消息的集合。

猜你喜欢

转载自blog.csdn.net/DeliaPu/article/details/79229720