转自:流媒体:RTMP 协议完全解析 - 知乎 (zhihu.com)

  • 背景

RTMP(Real Time Messaging Protocol) 是由 Adobe 公司基于 Flash Player 播放器对应的音视频 flv 封装格式提出的一种,基于TCP 的数据传输协议。本身具有稳定、兼容性强、高穿透的特点。常被应用于流媒体直播、点播等场景。常用于推推流方(主播)的稳定传输需求。

一、RTMP 的传输:消息块 & 消息封包传输

RTMP 协议为了维持稳定连续传递,避免单次传输数据量问题,采用了传输层封包,数据流切片的实现形式。被用来对当前带宽进行划分和复用的最小传输单位,被称为 Chunk 即消息块。通常情况下,一个有效的消息,如果数据量超出当前 Chunk Size 的话,则会被拆分成多个分块来分批传输。通过指定首个 Chunk 和后续 Chunk 类型,以及 Chunk Header 其他标志性数据,来使当前被切割的消息,能够在对端得到有效的还原和执行。我们以 MetaData 类型消息(Data AFM3 16)举例:

图1-1 一则有效消息拆分发送示意图

例子 中用来作为演示的 MetaData 高达 400 Bytes(不会吧?不会吧?不会吧?),而我们用 RTMP 的默认 Chunk Size 为 128 bytes。因此,当我们使用 Message Type 为 16 的 Data AFM3 类型的数据消息,通知对端当前元数据信息的时候,就需要切片了。即如图1-1 所示。

二、RTMP 的传输:消息块的组成

想要了解 RTMP 则必须对其使用的网络传输数据封装格式有一定的了解。RTMP 协议是以分组形式传送数据包。一个完整的数据块包含两个部分:Chunk Header 和 Chunk Data,这两者组合在一起,构成了一个有效的消息类型,结构如下:

图2-1 完整消息块

基础数据头(Basic Header):保存 CS ID、Chunk Type(决定 Msg Header 类型)
消息数据头(Message Header):包含被发送消息的相关信息,类型Chunk Type决定
扩展时间戳(Extended Timestamp)(32-bits):消息头携带的时间戳扩展位

基础数据头

基础数据头,Chunk stream ID 可以配置为3~65599 这 65597 个不同标志中的其中一种。根据持有 Chunk stream ID 的长度,RTMP 规格将基础数据头分为3种:ID 在 2~63 范围内的 1-Byte 版;ID 在 64~319 范围内的 2-Byte 版;ID 在 64~65599 范围内的 3-Byte 版。基础数据头组成,也包含三个部分。

图3-1 Basic Header 0~3 Byte

format message type 标志位 fmt(2-bits):用来标志消息类型,也被称为 Chunk Type
cs id 字段(6-bits):用来表示 63 以内的ID的标志位,0、1两个标记被占用做扩展标记cs id - 64字段(8 or 16-bits):用来根据扩展标志扩充的,广范围标志位

需要注意的是,Chunk stream ID 是用来区分消息信道的。因为 RTMP 协议,所有的通信都是通过同一个 TCP 来完成的,因此所有类型的通信信道需要由 Chunk stream ID 来进行区分,从而判断当前收到的消息所属的信道类型。当然,这个是由用户定义的,不做区分其实也不影响实际操作(虽然 Adobe 官方有预留,但是规范约束是一种手段,自己做双端协定的时候也可以不按这种规范来,虽然那样就要做一系列的配套实现了),Adobe 建议及目前市面上大部分采用如下的分类以便于操作分割:

每个前后都有预留编号,以便扩充使用。

消息数据头

消息数据头的类型,是由基础数据头中的 fmt 字段来标记的。总共分为4种类型:

其格式划分如下:

图3-2 Message Header 0~3 Type

timestamp 消息时间戳(3-Bytes):标记当前消息绝对时间戳,有效位 24 bits,如果超出16777215(0xFFFFFF)则启用扩展时间戳(Extended Timestamp)。扩展位启用时,timestamp 位恒定为 16777215,通过还原 32 bits 的扩展位,加合为有效时间戳数据。时间戳在运用上对于不同消息类型会有区分,type 0 时为绝对时间戳,type 1/2 时为相对时间戳(时间差值)。

msg length 消息头长度(1-Byte):携带 Chunk Header 数据长度信息(单位:Byte)
msg length (cont) 消息体长度(2-Bytes):携带 Chunk Data 数据长度信息(单位:Byte)
msg type 消息类型(1-Byte):携带消息类型信息,这是实际消息的类型,区别于消息头。 
ms id 字段(1-Byte):消息归属消息流 ID 标志位,指定当前消息所属信道分类
ms id (cont) 字段(3-Bytes):消息内容对应数据流 ID 标志位,指定数据所属数据流信道

需要阐明的是, Chunk Data 实际归属对应为 ms_id (cont)。ms_id (cont) 才是数据流对应的流标记,这个标记是我们定义的。通常服务端会需要 ms_id (cont) 来指定我们当前的数据流。以便于 RTMP 链接建立后,指定数据通道。进一步理解的话,cs_id、ms_id、ms_id (cont) ,这三者之间并不存在强关联,仅仅作为不同信息层区分使用。数据和消息头可以毫无关联;也可以消息头根据c-s协定指定与引用关联数据。

一般情况下,单用 cs_id + ms_id (cont) 就够双端交互和信道分割了。

那么4种 Message Header 一般都在什么情况使用呢?我们可以参考下表:

扩展时间戳

扩展时间戳(Extended Timestamp)(32-bits)主要是配合 Message Header 内的时间戳使用,用来扩展可用时间范围。具体见上文 Message Header 消息时间戳说明。

三、RTMP 的数据:可用消息类型

需要注意的是,消息往往都需要分块发送。消息的类型只是消息本身格式的设定,和分块传输的传输过程是不同的概念。理解上,应该把消息格式理解为消息的信息排列样式;把传输过程理解为物理上发送数据的方案。

RTMP 消息的头(RTMP Message Header,不是 Message Header,两个不是同一个东西)有自己的统一格式,当然这部分也是会被切割到 Chunk 里传输的。不过,因为实际意义和 Chunk Header 内容重复,实际的实现上也可以不需要考虑这个(得约定好)。统一消息头样式如下:

图4-1 RTMP Message Header 格式示意图

消息头包含以下:

Message Type 消息类型(1-Byte):类型 ID 1 - 6 被保留用于协议控制消息。
Length 长度(3-Bytes):表示有效负载的字节数。以大端格式保存。
Timestamp 消息时间戳(4-Bytes):包含了当前消息的 timestamp。以大端格式保存。
Message Stream Id 消息流(3-Bytes):消息归属消息流 ID 标志位。以大端格式保存。

不同的消息对应不同的数据体,应该由具体的消息来制定其中数据体所携带的信息。所有类型消息都被列在下表中,以便于统一讲解:

接下来,我们来分别看一下各大消息类型(下文图文中的RTMP统一消息头省略)。

协议控制类消息

协议控制类消息(Protocol Control Messages)是用来控制通信过程中,整个基础通信配置的消息。用来负责协议双端的通信控制。总共有 5 种类型,以大分类的形式存在于可用消息列表中,各自格式如下(整合到一张图里了,注意区别):

图4-2 协议控制类消息格式

chunk size 数据包最大可接受长度(31-bits):取值范围 1~2147483647 (0x7FFFFFFF) ,但因为消息总长度取值上限为16777215 (0xFFFFFF) ,因此不能超过该值(单位:Bytes)
chunk stream id 截停的信道 ID(4-Bytes):Abort 消息想要停止的信道ID
sequence number 已接收的数据长度(4-Bytes):发送后,对应长度的本地数据将会被标为已应答(Acked)(单位:Bytes)
Ack window size 应答窗口大小(4-Bytes):设置的应答窗口大小(单位:Bytes)
Limit Type 带宽配置模式(1-Byte):带宽配置模式有三种如下:

用户控制消息

用户控制消息(User Control Messages)被用来实时通知对端,以进行一些相关操作。其通用格式如下:

图4-3 用户控制消息格式

这些操作大多都是一些状态通知类型消息,或者网络状态测量类型的消息。官方在自己的开源实现里,定义了7种:

如有额外的操作协定,也可以在当前官方类型之外,自行定义其他类型。不过这样的话就需要双端都去做配套实现了。官方源代码这一块儿可以参考:

官方源码直通车​repo.or.cz

命令消息

命令消息(Command Messages)是用于 C-S 进行直接交互应答的一类消息。一般情况下,命令消息的发送对端,是需要对端进行应答信号反馈的。反馈消息规定以

[ 命令消息 ] + _result 或者 [ 命令消息 ] + _error

的形式由接收命令的一方(receiver),将结果信息发送回命令的发送方(sender)。以完成一次有效的命令操作。命令构成相对简单,其中携带的复杂数据则通过AMF编码的形式,存放在命令的消息体中。

一般情况下,命令消息的消息体的通用描述内容有,name 仅用做称谓:

这个命令体系很重要,详情请参考作者的精讲:

流媒体:RTMP 命令消息与流管理​zhuanlan.zhihu.com

数据消息

客户端或者服务器端通过发送这些消息以发送元数据或者任何用户数据到对端。元数据包括数据 (音频,视频等等) 的详细信息,比如创建时间,时长,主题等等。这些消息可以进行 AMF0 编码生成消息类型 18 的 Data AMF0,也可以进行 AMF3 编码生成消息类型 15 的 Data AMF3。

一般情况下,数据消息的消息体的通用描述内容有,name 仅用做称谓:

音视频消息

音视频消息在结构上是一致的,本质都是纯粹的数据传输用途,即直接将音视频 Bytes 数据分块发送即可。没有多余的信息数据。

共享对象消息

共享对象消息是持有 Flash 对象,一种为了在多端多实例保持同步而设计的名-值对的集合对象,的消息类型。消息可以进行 AMF0 编码生成消息类型 19 的 Shared Object Message AMF0,也可以进行 AMF3 编码生成消息类型 16 的 Shared Object Message AMF3。每个共享消息对象,都可以包含有多个不同的共享事件。其通用格式如下:

图4-4 共享对象消息格式

统一描述信息主要携带共享对象名、版本和标记数据,共享事件名-值对集合则携带对应共享对象的一系列指定操作。共享对象消息的可用共享事件类型有:

因为共享对象消息是基于 Flash 类型的消息,在 Adobe 停止Flash 的支持后,在现在的音视频处理中,不太经常使用此类共享消息事件(也因为没有太多重要的大同步操作)。

整合消息

整合消息(Aggregate Message)被用来以消息包的形式来发送一系列上文中消息类型的集成表单。相当于用一个大的消息,将一些经过可回溯标记标示后的消息,按照指定的顺序编排后发出。整合消息对应的 ms id 将会覆盖持有子消息的 ms id(官方建议)。

图4-5 整合消息格式

统计消息里的 timestamp 和第一个子消息的 timestamp 的不同点在于子消息的 timestamp 被相对流时间标调整了偏移。每个子消息的 timestamp 都被加入偏移,以达到一个统一时间流。第一个子消息的 timestamp 应该和统计消息的 timestamp 一样,所以这个偏移量应该为 0。

Back Pointer 反向指针包含有前一个消息的大小 (包含前一个消息的头)。这样子匹配了 FLV 文件的格式,用于反向查找。

使用统计消息具有以下性能优势:

  1. 块流可以在一个块中以至多一个单一完整的消息发送。因此,增加块大小并使用统计消息减少了发送块的数量。
  2. 子消息可以在内存中连续存储。在网络中系统调用发送这些数据时更高效。

四、总结

至此,RTMP 基本梳理完毕。这些规格实际上都可以自行改动,但是需要双端一致。本质上,这套 RTMP 规范更多的是 Adobe 根据 Flash 的一系列特性制定的。所以使用中,还是会涉及到一些定制化的事情。不过,也可以直接使用。

参考文献:
[1] RTMP 官方规范(https://www.adobe.com/devnet/rtmp.html)

流媒体:RTMP 协议完全解析相关推荐

  1. 流媒体-RTMP协议-rtmpdump-flv封装解析(一)

    流媒体-RTMP协议-rtmpdump-flv封装解析(一) 流媒体-RTMP协议-librtmp库学习(二) 流媒体-RTMP协议-librtmp库学习-c++多线程实现rtmp推流flv文件(三) ...

  2. RTMP协议深度解析:从原理到实践,掌握实时流媒体传输技术

    目录标题 1. 引言 1.1 流媒体传输技术的重要性 1.2 为什么选择RTMP协议 1.3 RTMP协议的发展与应用 2. RTMP协议基础 2.1 RTMP协议简介 2.2 RTMP协议与其他流媒 ...

  3. (转)rtmp协议简单解析以及用其发送h264的flv文件

    Adobe公司太坑人了,官方文档公布的信息根本就不全,如果只按照他上面的写的话,是没法用的.按照文档上面的流程,server和client连接之后首先要进行握手,握手成功之后进行一些交互,其实就是交互 ...

  4. 通过 wireshark 抓包了解直播流媒体 RTMP 协议基本过程

    作者:Elias Zhang 声网资深工程师,拥有从Iaas层的基础信息存储服务到paas层的云服务的职业经历,喜欢python语言,习惯使用C#,熟悉基于和结合CDN的业务产品架构,点播.直播.云导 ...

  5. 流媒体协议HLS解析

    参考资料:https://www.cnblogs.com/jimodetiantang/p/9133564.html https://cloud.tencent.com/developer/artic ...

  6. nginx搭建rtmp协议流媒体服务器总结

    最近在 ubuntu12.04+wdlinux(centos)上搭建了一个rtmp服务器,感觉还挺麻烦的,所以记录下. 大部分都是参考网络上的资料. 前提: 在linux下某个目录中新建一个nginx ...

  7. RTMP 流媒体系统协议 简介

    什么是RTMP协议 RTMP(Real-Time Messaging Protocol实时消息传送协议)的缩写,它是Adobe Systems公司为Flash播放器和服务器之间音频.视频和数据传输开发 ...

  8. 利用nginx搭建http和rtmp协议的流媒体服务器

    利用nginx搭建http和rtmp协议的流媒体服务器 一.准备工作 1.安装依赖包: yum install gcc glibc glibc-devel libtool make openssl-d ...

  9. 基于RTMP协议的Flash流媒体网页直播播放器

    本文记录一些基于Flash技术的网页播放器.基于Flash的网页播放器相比于其他网页播放器来说最大的优势就是"免插件安装"了,这一点可以很大的提高用户的体验质量. 主要是几种常用的 ...

  10. 流媒体-H264协议-编码-x264学习-相关概念x264编译及文件解析(一)

    流媒体-H264协议-编码-x264学习-相关概念x264编译及文件解析(一) 流媒体-H264协议-编码-x264学习-主要结构体(二) 流媒体-H264协议-编码-x264学习-主要函数(三) 流 ...

最新文章

  1. 数字孪生城市应用【案例集】,附下载
  2. 邪恶改装2:用单片机实现一次简单的wifi密码欺骗
  3. MySQL5.7.17源码编译安装与配置
  4. 洛谷1052——过河(DP+状态压缩)
  5. 基于C#的计时管理器
  6. 《Pytorch简要安装指导》
  7. oracle10g自带的公共同义词,Oracle10g实战教程第07讲视图、同义词、序列
  8. Bezier(贝塞尔)曲线的轨迹规划在自动驾驶中的应用(一)
  9. 铁路12306网站App服务时间延长 退票业务可24小时全天候办理
  10. 采用DCT进行图像压缩
  11. 第十二章 采购管理 采购合同类型以及其区别 合同类型与风险分担 自制与外购分析 招标文件 工作说明书(SOW) 工作大纲 (TOR) 投标人会议 采购谈判 检查 审计 索赔管理 采购合同争议解决方式对
  12. 我为什么学习设计模式
  13. 微前端 Micro-Frontnds - Single-SPA Application API
  14. 2020杭电多校赛 Multi-University Training Contest
  15. Arch 使用 i3 美化桌面
  16. 20211003:数字滤波器前置知识,sinc函数与Sa函数
  17. 异常处理(六)--------SpringBoot+Maven项目运行异常:Unable to find a single main class from the following candidat
  18. python为什么叫大蟒蛇_Python(大蟒蛇)与云计算
  19. webDav之jackrabbit-webdav基础操作
  20. 前端环境安装遇到的问题

热门文章

  1. ModelAndView
  2. java soap服务_「java调用webservice」java调用webservice接口 三种方法 - seo实验室
  3. 15 分钟 教你搞一个专属于你的域名邮箱
  4. 软件质量管理体系 type:pdf_普宁iso14001环境管理体系AAA信用等级认证
  5. ati显卡驱动安装linux,在debian下安装ati显卡驱动教程
  6. 智慧环卫车辆监控管理系统方案
  7. 计算机课程设计 校园网规划设计与实现,校园网的规划与实现.doc
  8. 基于NB-IOT的智能烟感应用方案
  9. cs服务器网页管理端,sXe服务器端怎么管理
  10. 利用计算机发布调度命令时必须严格遵守,调度命令规范格式(22页)-原创力文档...