【流媒体】RTMP协议的数据格式

RTMP相关记录:
【流媒体】RTMP协议概述

1. 消息(Message)

在RTMP协议中,定义的数据格式称为消息(Message),消息是网络传输的数据载体,其中会携带RTMP协议命令、用户控制命令和传输的数据等等,是client和server之间进行交流通信的核心

RTMP消息分为2个部分:RTMP Message Header和RTMP Message Payload

1.1 消息头(Message Header)

消息的头部主要包括以下几个部分:
(1)消息类型(Message Type)
长度为1字节,描述了当前消息的类型

(2)载荷长度(Payload Length)
长度为3字节,描述了消息当中载荷的长度,以大端格式保存

(3)时间戳(Timestamp)
长度为4字节,描述了当前消息的时间戳,以大端格式保存

(4)流编号(Stream ID)
长度为3字节,描述了当前消息所在的流编号,以大端格式保存
在这里插入图片描述

1.2 消息载荷(Message Payload)

消息载荷长度不固定,可能是音频数据,或者是视频数据

2. 块(Chunk)

前面提到RTMP协议传输的数据包称为消息,包含了所要传输的各式各样的信息,但是考虑到数据冗余,数据优先级,数据传输效率,容错控制等一系列的问题,在实际网络传输时,message会被拆分成为更小的数据单元,这个数据单元称之为chunk,每个chunk的大小默认为128个字节。chunk的格式如下图所示
在这里插入图片描述Chunk可以分为Chunk Header和Chunk Data两个部分

2.1 块头(Chunk Header)

块头分成三个部分,基本头(Basic Header),消息头(Message Header)和扩展时间戳(Extended Timestamp),它们的定义为:

2.1.1 基本头(Basic Header)

该字段占据1到3个字节,描述了块类型(fmt)和块流ID(cs_id)两个内容,其中fmt决定了当前chunk中message header的编码格式,cs_id用于识别同一个消息内的不同数据块。fmt长度固定为2个比特,而cs_id这个字段是可变长的,需要先对cs_id这个属性进行描述

2.1.1.1 块流ID(cs_id)

根据cs_id长度的不同,Basic Header可以分为3种类型:

2.1.1.1.1 类型1

如果cs_id的值属于 [3, 63],则Basic Header的长度为1字节,其中cs_id占据5个比特,如下图所示
在这里插入图片描述

2.1.1.1.2 类型2

如果cs_id的值属于 [64, 319],则Basic Header的长度为2字节,如下图所示。第1个字节中除了存储fmt之外,其余位均为0;第2个字节中存储的值为cs_id - 64。在计算流ID时,streamID = 第2个字节值 + 64
在这里插入图片描述

2.1.1.1.3 类型3

如果cs_id的值属于 [320, 65599],则Basic Header的长度为3字节,如下图所示。第1个字节中除了存储fmt之外,其余均为1;第2、3个字节中存储的值为cs_id - 64。在计算流ID时,streamID = 第3个字节值 * 256 + 第2个字节值 + 64
在这里插入图片描述

2.1.1.2 块类型(fmt)

块类型fmt这个属性固定占据2个比特,表明了当前chunk中message header的编码格式,共有4种取值,每种取值对应不同的message header格式:

取值说明
fmt = 0message header长度为11字节
fmt = 1message header长度为7字节
fmt = 2message header长度为3字节
fmt = 3message header长度为0字节

2.1.2 消息头(message header)

消息头格式由基本头中的fmt决定,共有4种类型

2.1.2.1 类型0(fmt = 0)

如果fmt为0,表明message header的长度为11字节,如下图所示
在这里插入图片描述
其中的字段为:

(a)时间戳(timestamp)
占据3字节,描述当前chunk的时间戳,如果 timestamp 大于或者等于 16777215 (十六进制 0xFFFFFF),这一字段必须是 16777215,表明有扩展 timestamp 字段来补充完整的 32 位 timestamp。否则的话,这一字段必须是整个的 timestamp

(b)消息长度(message length)
占据3字节,描述当前chunk的消息长度

(c)消息类型ID(message type id)
占据1字节,描述当前chunk的消息类型编号

(d)消息流ID(message stream id)
占据4字节,描述当前chunk的消息流编号

2.1.2.2 类型1(fmt = 1)

如果fmt为1,表明message header长度为7字节,其中不包含消息流 ID,因为这一块使用前一块一样的流 ID。格式如下图所示
在这里插入图片描述
其中的字段为:

(1)时间戳偏移(timestamp delta)
占据3字节,表示和上一个chunk之间距离的时间差

(2)消息长度(message length)
占据3字节,描述当前chunk的消息长度

(3)消息类型编号(message type id)
占据1字节,描述当前chunk的消息类型编号

2.1.2.3 类型2(fmt = 2)

如果fmt为2,表明message header长度为3字节,这种类型的message header只包含时间戳偏移量。如果使用这种类型,streamID、stream type id和message length与前面的chunk一致
在这里插入图片描述

2.1.2.4 类型3(fmt = 3)

如果fmt为3,message header长度为0字节,表明这个chunk的message header和上一个chunk是一致的,不需要额外再传输一次。如果第一个消息和第二个消息之间的 delta 和第一个消息的 timestamp 一样的话,那么在类型 0 的块之后要紧跟一个类型 3 的块,因为无需再来一个类型 2 的块来注册 delta 了。如果一个类型 3 的块跟着一个类型 0 的块,那么这个类型 3 块的 timestamp delta 和类型 0 块的 timestamp 是一样的

2.1.3 扩展时间戳(Extended Timestamp)

占据0或4字节,该字段用于对大于 16777215 (0xFFFFFF) 的 timestamp 或者 timestamp delta 进行编码;可以通过设置类型 0 块的 timestamp 字段、类型 1 或者 2 块的 timestamp delta 字段 16777215 (0xFFFFFF) 来启用这一字段。当最近的具有同一块流的类型 0、1 或 2 块指示扩展 timestamp 字段出现时,这一字段才会在类型为 3 的块中出现

2.2 块数据(Chunk Data)

占据 [0, chunkSize] 长度,是RTMP协议所携带的实际数据,例如音视频数据

3. 消息与块之间的关系

前面提到消息与块两者的关系是,通过将消息分成多个块,之后在网络上进行传输,那么消息是按照何种方式分成多个块的呢?先借用雷博的图展示,随后借用RTMP标准文档的介绍进行解释
在这里插入图片描述
下面引用参考文档中的解释

有如下一个数据包需要传输,stream ID为12346,message type id为9(视频数据),发送时间戳为1000,长度为307个字节
在这里插入图片描述
由于数据长度为307,超过了默认chunk大小128,所以需要分成若干个chunk进行传输,划分的结果如下
在这里插入图片描述
对每个chunk的信息进行分析:
(1)Chunk 1
chunk header一共占12字节,其中basic header占1字节,message header长度为11字节。chunk data占128字节,所以一共占140字节

属性长度取值
basic header1字节fmt = 0 (即 chunk type = 0)
cs_id = 4 (即 chunk stream id = 4)
message header11字节delta = 1000(即 timestamp = 1000)
length = 307(即 message length = 307)
type = 9(即 message type id = 9)
stream ID = 12346(即 message stream id = 12346)

(2)Chunk 2
chunk header一共占1字节,其中basic header占1字节,basic header中的fmt为3,表示当前chunk中message header当中的数据与前面一致,所以message header不占任何字节。chunk data占128字节,所以共占129字节

(3)Chunk 3
chunk header占1字节,chunk data占51字节,所以共占52字节

通过上面的拆分方式,将一个message分成若干个chunk进行发送了。另外还可以注意到,通过设置basic header中的fmt字段,去除了Chunk 2和Chunk 3当中的冗余字段(message header字段),节省了传输的比特数

4. 结束语

本文记录了RTMP协议中的数据格式,包括消息格式和块格式当中的字段,但是缺少对其中一些字段的取值进行描述,例如stream id的取值和cs_id的取值,如何取值决定了当前传输消息的具体功能,后续需要记录

  • 19
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值