当前位置: 首页 > news >正文

【流媒体协议】RTMP协议概述

目录

  • 1.RTMP协议
    • 1.1 握手(Handshake)
      • 1.1.1 C0和S0
      • 1.1.2 C1和S1
      • 1.1.3 C2和S2
    • 1.2 建立通信信道(NetConnection)
    • 1.3 建立流通道(NetStream)
    • 1.4 播放(Play)
    • 1.5 结束语

最近一直在看流媒体中的RTMP协议,参考了多位前人的记录。考虑到RTMP协议内容比较多,同时也需要结合代码进行分析,所以会分成几个部分来记录,这里先记录RTMP实现的主要步骤

1.RTMP协议

RTMP(Real-Time Message Protocol)协议是由Adobe公司提出的一种专为实时音视频数据传输设计的专用网络协议,主要用于流媒体传输领域,如直播、在线视频播放等等。RTMP协议基于TCP,是一种有数据传输保障的协议,默认使用1935号端口,支持多种数据格式和传输方式,从而适用于不同的应用场景。RTMP能够应用于Windows、macOS、Linux、Android和iOS等不同的操作系统,进行高效的音视频数据传输。

熟悉RTMP协议,可以阅读官方的文档,这里我参考的是中文翻译:RTMP规范 adobe官网文档 中文版,版本是1.0(rtmp_specification_1.0.pdf)

RTMP协议是位于客户端和服务器之间的协议,并且是基于TCP协议的,在进行信息交互前,需要先进行几个步骤:
(1)client和server握手
(2)建立client和server之间通信信道(网络连接)
(3)建立client和server之间流通道(数据流连接)

1.1 握手(Handshake)

为了建立稳定的通信信道,RTMP基于TCP协议进行连接,而TCP协议是需要进行握手进行连接的,所以RTMP也需要进行握手连接。握手的流程图为
在这里插入图片描述

握手过程分为4个状态:
(1)Uninitialized(未初始化):
开始时,客户端和服务器都是 uninitialized (未初始化) 状态,会发送协议的版本号。客户端在数据包 C0 中将协议版本号发出。如果服务器支持这个版本,它将在回应中发送 S0 和 S1。如果不支持,服务器会才去适当的行为进行响应。在 RTMP 协议中,这个行为就是终止连接

(2)Version Sent (版本已发送):
随后,客户端和服务器都进入 Version Sent (版本已发送) 状态。客户端会等待接收数据包 S1 而服务器在等待 C1。一旦拿到期待的包,客户端会发送数据包 C2 而服务器发送数据包 S2。(客户端和服务器各自的)状态随即变为 Ack Sent (确认已发送)

(3)Ack Sent (确认已发送):
客户端和服务器分别等待 S2 和 C2

(4)Handshake Done (握手结束):
客户端和服务器可以开始交换消息了

1.1.1 C0和S0

C0和S0描述的是RTMP的版本号,长度为1字节。对于Client而言,发送的是C0,描述客户端要求的RTMP版本号;对于Server而言,发送的是S0,表示服务器选择的RTMP版本号。标准文档中规范的版本号为3,其中[0,2]这3个值是早期其他产品使用的,已被废弃;[4, 31]被保留为RTMP协议的未来版本使用;[32, 255]不允许使用。如果服务器收到的版本号无法被识别,则以版本3响应,收到这个响应的客户端可以将版本调整为3,或者放弃握手
在这里插入图片描述

1.1.2 C1和S1

C1和S1这两个字段通过校验时间戳来确认对端是否已经收到了发送过去的数据,这两个数据包可理解是反馈字段,长度为1536字节。其中字段的含义为:

(1)Time (4 Bytes)
该字段包含一个时间戳timestamp,用于本终端发送的所有后续块的时间起点。这个值可以是 0,或者一些任意值。要同步多个块流,终端可以发送其他块流当前的 timestamp 的值。

(2)Zero (4 Bytes)
该字段都是0

(3)Random data (1528 个字节)
该字段的值是随机生成的,终端需要区分出响应来自它发起的握手还是对端发起的握手,不需要对随机数进行加密保护,也不需要动态值
在这里插入图片描述

1.1.3 C2和S2

C2和S2的作用是告诉对方,我已经接收到你的反馈,现在可以进行后续操作了。其中,C2是S1的副本,S2是C1的副本,这两个数据包的长度都为1536个字节。下图中的几个字段分别的含义是:

(1)Time (4 Bytes)
该字段必须是对端发来的时间戳(对C2来说是S1的时间戳,对S2来说是C1的时间戳)

(2)Time2 (4 Bytes)
该字段必须是前面自己发送的C/S包里的时间戳

(3)Random echo (1528 Bytes)
该字段必须是对方发来的C1/S1包里携带的随机数据(对C2来说是S1,对S2来说是C1)。两端都可以一起使用 time 和 time2 字段再加当前 timestamp 以快速估算带宽和/或者连接延迟,但这不太可能是有多大用处
在这里插入图片描述

1.2 建立通信信道(NetConnection)

进行握手连接之后,可以建立通信信道(网络连接)来对接客户端和服务器,流程为:
在这里插入图片描述
(1)客户端发送命令消息 “connect” 到服务器端以请求对服务器端应用实例的连接

(2)收到 connect 命令后,服务器端发送协议消息 “Window Acknowledgement Size”(窗口确认大小) 到客户端。服务器端也会连接到 connect 命令中提到的应用

(3)服务器端发送协议消息 ‘Set Peer Bandwidth’ (设置对端带宽) 到客户端

(4)在处理完协议消息 ‘设置对端带宽’ 之后客户端发送协议消息 ‘窗口确认大小’ 到服务器端

(5)服务器端发送另一个用户控制消息 “StreamBegin”(流开始) 类型的协议消息到客户端

(6)服务器端发送结果命令消息告知客户端连接状态 “_result” (success/fail)

1.3 建立流通道(NetStream)

建立流通道时,根据数据流走向的不同,可以分成两种情况,第一种是client到server的流,第二种是server到client的流
(1)RTMP推流时的数据流连接
在这里插入图片描述
可以看到,在推流时,通过 “connect” 命令建立的流通道之后,client使用命令消息 “createStream” 建立流通道,server会反馈一个命令消息 “_result - createStream response” 来告诉client流通道建立是否成功
(2)RTMP拉流时的数据流连接
在这里插入图片描述
在建立流通道这一步骤上,拉流和推流的过程一致

1.4 播放(Play)

播放过程可以理解为是client拉流的过程,其主要步骤为:
(1)握手(Handshake)

(2)创建流(createStream),包括命令消息的发送(createStream)和接收(_result - createStream response)

(3)播放
 (a)client发送命令消息 “play”,表示我要播放你发送过来的视频,请把数据传输过来
 (b)server发送协议消息 “SetChunkSize”,表示我现在准备传输数据,先设置单个数据包chunk的大小
 (c)server发送用户控制消息 “StreamIsRecorded”,表示我现在传输过来的流是已录制好的
 (d)server发送用户控制消息 “StreamBegin”,表示我现在准备传输流,同时告诉client传输过去的流ID
 (e)如果client发送过来 “play” 消息中包括了 reset信息,server会发送命令消息 “onStatus-play reset”
 (f)server发送命令消息 “onStatus-play start”,表示网络流开始传输
 (g)server向client发送 “Audio Message” 和 “Video Message”
在这里插入图片描述

1.5 结束语

这里记录了RTMP协议的主要实现过程,包括握手(Handshake)、网络连接(NetConnection)、流连接(NetStream)和播放(Play)这几个步骤,其中对握手过程使用的数据包进行了详细的记录。但是,还有几个问题需要记录:
(1)对于其他步骤使用的命令格式(或消息格式)没有说明,例如 “Command Message”,"User Control"等
(2)这些命令(或消息)是按照何种方式在网络当中进行传输的
(3)在实际工程当中,这些过程是如何实现的

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • c++精品小游戏(无错畅玩版)
  • 一文打通pytorch中几个常见的张量操作
  • 第43集《大佛顶首楞严经》
  • 贪吃蛇游戏的实现:C++ 控制台版
  • PyTorch:从零实现一个双向循环神经网络
  • MySQL-MHA高可用配置及故障切换
  • 凸分析与凸优化精解【1】
  • Oracle-OracleConnection
  • JavaScript高阶笔记总结(Xmind格式):第三天
  • 如何在阿里云环境中通过 Jenkins 实现 .NET Core 应用的 Docker 化部署:从 GitLab 拉取代码到自动化 CI/CD 流程的完整指南
  • x264 编码器 SSIM 算法源码分析
  • 【Python】基础语法介绍
  • Github Copilot 使用技巧
  • 连锁店收银系统源码
  • 介绍springmvc-水文
  • 实现windows 窗体的自己画,网上摘抄的,学习了
  • java中的hashCode
  • open-falcon 开发笔记(一):从零开始搭建虚拟服务器和监测环境
  • Puppeteer:浏览器控制器
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • Python中eval与exec的使用及区别
  • Redis在Web项目中的应用与实践
  • Solarized Scheme
  • Vue官网教程学习过程中值得记录的一些事情
  • 分享几个不错的工具
  • 关于springcloud Gateway中的限流
  • 基于Javascript, Springboot的管理系统报表查询页面代码设计
  • 全栈开发——Linux
  • 日剧·日综资源集合(建议收藏)
  • 微服务入门【系列视频课程】
  • # centos7下FFmpeg环境部署记录
  • # Swust 12th acm 邀请赛# [ A ] A+B problem [题解]
  • #HarmonyOS:Web组件的使用
  • #includecmath
  • $分析了六十多年间100万字的政府工作报告,我看到了这样的变迁
  • (6)添加vue-cookie
  • (MIT博士)林达华老师-概率模型与计算机视觉”
  • (九)One-Wire总线-DS18B20
  • (每日一问)计算机网络:浏览器输入一个地址到跳出网页这个过程中发生了哪些事情?(废话少说版)
  • (一)Docker基本介绍
  • (一)VirtualBox安装增强功能
  • (一)认识微服务
  • (一)使用Mybatis实现在student数据库中插入一个学生信息
  • (转)jQuery 基础
  • .net core MVC 通过 Filters 过滤器拦截请求及响应内容
  • .NET Core WebAPI中使用swagger版本控制,添加注释
  • .NET 应用架构指导 V2 学习笔记(一) 软件架构的关键原则
  • .NET技术成长路线架构图
  • .NET开源快速、强大、免费的电子表格组件
  • .NET实现之(自动更新)
  • /var/log/cvslog 太大
  • :not(:first-child)和:not(:last-child)的用法
  • @Documented注解的作用
  • @select 怎么写存储过程_你知道select语句和update语句分别是怎么执行的吗?
  • [AIGC] CompletableFuture的重要方法有哪些?