流媒体服务器二:2.RTMP协议学习

news2024/11/15 9:22:27

一 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,从⽽实现信息的收发。

RTMP 是 Real Time Messaging Protocol( 实时消息传输协议) 的首字母缩写。该协议基于 TCP,是一个协议族,包括 RTMP 基本协议及 RTMPT/RTMPS/RTMPE 等多种变种。

RTMP 与 HTTP 一样, 都属于 TCP/IP 四层模型的应用层。

上述红色部分的含义如下图:

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---->| 

握手完成后,就可以发送数据了,那么这个数据的形式是什么样子的呢? 是 RTMP Chunk Stream,那么这个RTMP Chunk Stream 具体是啥呢?

3. RTMP Chunk Stream (重点)

Chunk Stream是对传输RTMP Chunk的流的逻辑上的抽象,客户端和服务器之间有关RTMP的信息都在 这个流上通信。这个流上的操作也是我们关注RTMP协议的重点。

3.1 Message(消息)

这⾥的Message是指满⾜该协议格式的、可以切分成Chunk发送的消息,消息包含的字段如下:

  • Timestamp(时间戳):消息的时间戳(但不⼀定是当前时间,后⾯会介绍),4个字节
  • Length(⻓度):是指Message Payload(消息负载)即⾳视频等信息的数据的⻓度,3个字节
  • TypeId(类型Id):消息的类型Id,1个字节
  • Message Stream ID(消息的流ID):每个消息的唯⼀标识,划分成Chunk和还原Chunk为Message 的时候都是根据这个ID来辨识是否是同⼀个消息的Chunk的,4个字节,并且以⼩端格式存储 (Message Stream ID如何产⽣?audio和video使⽤不同的Message Stream ID)

3.2 Chunking(Message分块)

    RTMP在收发数据的时候并不是以Message为单位的,⽽是把Message拆分成Chunk发送,⽽且必须 在⼀个Chunk发送完成之后才能开始发送下⼀个Chunk。每个Chunk中带有MessageID代表属于哪个 Message,接受端也会按照这个id来将chunk组装成Message。

    为什么RTMP要将Message拆分成不同的Chunk呢?通过拆分,数据量较⼤的Message可以被拆分成 较⼩的“Message”,这样就可以避免优先级低的消息持续发送阻塞优先级⾼的数据,⽐如在视频的传输过 程中,会包括视频帧,⾳频帧和RTMP控制信息,如果持续发送⾳频数据或者控制数据的话可能就会造成 视频帧的阻塞,然后就会造成看视频时最烦⼈的卡顿现象。同时对于数据量较⼩的Message,可以通过对 Chunk Header的字段来压缩信息,从⽽减少信息的传输量。(具体的压缩⽅式会在后⾯介绍)

    Chunk的默认⼤⼩是128字节,在传输过程中,通过⼀个叫做Set Chunk Size的控制信息(⻅ spec 5.4.1 )可以设置Chunk数据量的最⼤值,在发送端和接受端会各⾃维护⼀个Chunk Size(srs流媒 体服务器默认是60000),可以分别设置这个值来改变⾃⼰这⼀⽅发送的Chunk的最⼤⼤⼩。⼤⼀点的 Chunk减少了计算每个chunk的时间从⽽减少了CPU的占⽤率,但是它会占⽤更多的时间在发送上,尤其 是在低带宽的⽹络情况下,很可能会阻塞后⾯更重要信息的传输。⼩⼀点的Chunk可以减少这种阻塞问 题,但⼩的Chunk会引⼊过多额外的信息(Chunk中的Header),少量多次的传输也可能会造成发送的间 断导致不能充分利⽤⾼带宽的优势,因此并不适合在⾼⽐特率的流中传输。在实际发送时应对要发送的数 据⽤不同的Chunk Size去尝试,通过抓包分析等⼿段得出合适的Chunk⼤⼩,并且在传输过程中可以根据 当前的带宽信息和实际信息的⼤⼩动态调整Chunk的⼤⼩,从⽽尽量提⾼CPU的利⽤率并减少信息的阻塞 机率。

3.3 Chunk Format(块格式)Chunk的默认⼤⼩是128字节

3.3.1 Basic Header(基本的头信息):

Basic Header是变⻓的,Basic Header的⻓度可能是1,2,或3个字节。也就是8/16/24位.

包含了 chunk type(chunk的类型)和 chunk stream ID(流通道Id,也叫做CSID)

CSID 为0,1,2,

当CSID 为0时,表示了Basic Header占⽤2个字节

当CSID 为1时,表示了Basic Header占⽤3个字节

当CSID 为2时,表示了Basic Header占⽤1个字节 ,代表该chunk是控制信息和⼀些命令信息,后⾯会有详细的介绍。(这块不确定,还需要再往后看)

当Basic Header为1个字节时,CSID占6位,6位最多可以表示64个数,因此这种情况下CSID在 [0, 63] 之间,其中⽤户可⾃定义的范围为 [3,63] ,实际是可以⽤2开始⽤。

当Basic Header为2个字节时,CSID占只占8位,第⼀个字节除chunk type占⽤的bit都置为0,第⼆ 个字节⽤来表示CSID-64,8位可以表示 [0, 255] 共256个数,ID的计算⽅法为(第⼆个字节+64),范围为 [64,319]。

注意如果不加64,那么就和 Basic Header为1个字节 时表示的数据重复了,因此规定了要加64

当Basic Header为3个字节时,以在此字段⽤3字节版本编码。ID的计算⽅法为(第三字节 *256+第⼆字节+64)(Basic Header是采⽤⼩端存储的⽅式),范围为 [64,65599]

可以看到2个字节和3个字节的Basic Header所能表示的CSID是有交集的 [64,319],但实际实现时还 是应该秉着最少字节的原则使⽤2个字节的表示⽅式来表示 [64,319] 的CSID。

3.3.2 Message Header(消息的头信息)

包含了要发送的实际信息的描述信息。(这个实际信息 可能是完整的,也可能是⼀部分)

Basic Header的chunk type 决定了Message Header的格式和 ⻓度 。

共有4种不同的格式。

由上⾯所提到的Basic Header中的fmt 字段控制。

其中第⼀种格式可以表示其他三种表示的所有数据,

但由于其他三种格式是基于对之前chunk 的差量化的表示,因此可以更简洁地表示相同的数据,实际使⽤的时候还是应该采⽤尽量少的字节表示相 同意义的数据。以下按照字节数从多到少的顺序分别介绍这4种格式的Message Header。

Type=0: 占⽤11个字节

type=0时Message Header占⽤11个字节,其他三种能表示的数据它都能表示,但在chunk stream的 开始的第⼀个chunk和头信息中的时间戳后退(即值与上⼀个chunk相⽐减⼩,通常在回退播放的时候会出 现这种情况)的时候必须采⽤这种格式。

  •     timestamp(时间戳):占⽤3个字节,因此它最多能表示到16777215=0xFFFFFF=2 -1, 当它的值超过这个最⼤值时,这三个字节都置为1,这样实际的timestamp会转存到Extended Timestamp字段中,接受端在判断timestamp字段24个位都为1时就会去Extended timestamp中解析 实际的时间戳。

  •     message length(消息数据的⻓度):占⽤3个字节,表示实际发送的消息的数据如⾳频帧、视频帧 等数据的⻓度,单位是字节。注意这⾥是Message的⻓度,也就是chunk属于的Message的总数据⻓ 度,⽽不是chunk本身Data的数据的⻓度。 message type id(消息的类型id):占⽤1个字节,表示实际发送的数据的类型,如8代表⾳频数据、9 代表视频数据。

  •     msg stream id(消息的流id):占⽤4个字节,表示该chunk所在的流的ID,和Basic Header的CSID ⼀样,它采⽤⼩端存储的⽅式,

Type = 1:占⽤7个字节

type=1时Message Header占⽤7个字节,省去了表示msg stream id的4个字节,表示此chunk和上 ⼀次发的chunk所在的流相同,如果在发送端只和对端有⼀个流链接的时候可以尽量去采取这种格式。

  • timestamp delta:占⽤3个字节,注意这⾥和type=0时不同,存储的是和上⼀个chunk的时间差。类 似上⾯提到的timestamp,当它的值超过3个字节所能表示的最⼤值时,三个字节都置为1,实际的时间戳差值就会转存到Extended Timestamp字段中,接受端在判断timestamp delta字段24个位都为1时 就会去Extended timestamp中解析时机的与上次时间戳的差值。
Type = 2:占⽤3个字节

type=2时Message Header占⽤3个字节,相对于type=1格式⼜省去了表示消息⻓度的3个字节和表示消 息类型的1个字节,表示此chunk和上⼀次发送的chunk所在的流、消息的⻓度和消息的类型都相同。余下 的这三个字节表示timestamp delta,使⽤同type=1。

Type = 3:占⽤0字节

0字节!!!好吧,它表示这个chunk的Message Header和上⼀个是完全相同的,⾃然就不⽤再传输 ⼀遍了。当它跟在Type=0的chunk后⾯时,表示和前⼀个chunk的时间戳都是相同的。什么时候连时间戳 都相同呢?就是⼀个Message拆分成了多个chunk,这个chunk和上⼀个chunk同属于⼀个Message。⽽ 当它跟在Type=1或者Type=2的chunk后⾯时,表示和前⼀个chunk的时间戳的差是相同的。⽐如第⼀个 chunk的Type=0,timestamp=100,第⼆个chunk的Type=2,timestamp delta=20,表示时间戳为 100+20=120,第三个chunk的Type=3,表示timestamp delta=20,时间戳为120+20=140

4种type对⽐

(type 3⽆字段就不画上去了)

3.3.3 Extended Timestamp(扩展时间戳)

上⾯我们提到在chunk中会有时间戳timestamp和时间戳差timestamp delta,并且它们不会同时存 在,只有这两者之⼀⼤于3个字节能表示的最⼤数值0xFFFFFF=16777215时,才会⽤这个字段来表示真正 的时间戳,否则这个字段为0。扩展时间戳占4个字节,能表示的最⼤数值就是0xFFFFFFFF=4294967295。当扩展时间戳启⽤时,timestamp字段或者timestamp delta要全置为0xFFFFFF,表示 应该去扩展时间戳字段来提取真正的时间戳或者时间戳差。注意扩展时间戳存储的是完整值,⽽不是减去 时间戳或者时间戳差的值。

3.3.4 Chunk Data(块数据):

⽤户层⾯上真正想要发送的与协议⽆关的数据,⻓度在(0,chunkSize]之间。

3.3.5 chunk表示例1

这个例⼦显示了⼀个简单的⾳频信息流。这个例⼦演示了信息的冗余。

    ⾸先包含第⼀个Message的chunk的Chunk Type为0,因为它没有前⾯可参考的chunk,timestamp 为1000,表示时间戳。type为0的header占⽤11个字节,假定chunkstreamId为3<127,因此Basic Header占⽤1个字节,再加上Data的32个字节,因此第⼀个chunk共44=11+1+32个字节。

    第⼆个chunk和第⼀个chunk的CSID,TypeId,Data的⻓度都相同,因此采⽤Chunk Type=2, timestamp delta=1020-1000=20,因此第⼆个chunk占⽤36=3+1+32个字节。

    第三个chunk和第⼆个chunk的CSID,TypeId,Data的⻓度和时间戳差都相同,因此采⽤Chunk Type =3省去全部Message Header的信息,占⽤33=1+32个字节。

    第四个chunk和第三个chunk情况相同,也占⽤33=1+32个字节。 最后实际发送的chunk如下:

3.3.6 chunk表示例2

此示例说明了⼀个消息因为太⻓,以⾄于⽆法适⽤⼀个128字节的chunk,从⽽被分解成多个 chunk。

    注意到Data的Length=307>128,因此这个Message要切分成⼏个chunk发送,第⼀个chunk的Type= 0,Timestamp=1000,承担128个字节的Data,因此共占⽤140=11+1+128个字节。

    第⼆个chunk也要发送128个字节,其他字段也同第⼀个chunk,因此采⽤Chunk Type=3,此时时间 戳也为1000,共占⽤129=1+128个字节。

    第三个chunk要发送的Data的⻓度为307-128-128=51个字节,还是采⽤Type=3,共占⽤1+51=52 个字节。 最后实际发送的chunk如下:

从两个例⼦中注意到,类型3的chunk可以⽤在两种不同的⽅式中。第⼀种是指定消息的继 续。第⼆种是指定⼀个新的消息的开始,它的头可以来⾃于现有的状态数据。

3.4 协议控制消息(Protocol Control Message)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2054526.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ES6之Promise对象

【图书介绍】《Node.jsMongoDBVue.js全栈开发实战》-CSDN博客 《Node.jsMongoDBVue.js全栈开发实战&#xff08;Web前端技术丛书&#xff09;》(邹琼俊)【摘要 书评 试读】- 京东图书 (jd.com) Promise是ES 6中新增的一种异步编程的解决方案&#xff0c;它可以将异步操作队列…

【电路笔记】-无源衰减器总结

无源衰减器总结 文章目录 无源衰减器总结1、概述2、L-型无源衰减器设计3、T-型无源衰减器设计4、桥接 T 型衰减器设计5、π型无源衰减器设计无源衰减器是一个纯电阻网络,可用于控制输出信号的电平。 1、概述 无源衰减器是一种纯电阻网络,用于削弱或“衰减”传输线的信号电平…

基于ssm+vue+uniapp的二手物品交易平台小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…

银河麒麟V10早期版本安装deb包解决方案

银河麒麟V10早期版本安装deb包解决方案 1、安装kylin-installer2、注意 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏不迷路&#x1f496; 在银河麒麟V10&#xff08;0710版本前&#xff09;&#xff0c;双击.deb包无法直接安装。但只需简单几步&#xff0c;你…

PyTorch深度学习实战(23)—— 用高级索引实现卷积

在深度学习中,最常用的操作是卷积操作。除了调用PyTorch封装好的函数,读者也可以自行编写一个函数实现卷积功能。根据卷积的定义,只需要遍历整个图像,依次获取与卷积核相乘的子块,相乘求和后就可以得到卷积的结果。为了进一步简化计算,可以采用img2col的思路,将整张图像…

基于web的物流管理系统--论文pf

TOC springboot473基于web的物流管理系统--论文pf 第1章 绪论 1.1 课题背景 二十一世纪互联网的出现&#xff0c;改变了几千年以来人们的生活&#xff0c;不仅仅是生活物资的丰富&#xff0c;还有精神层次的丰富。在互联网诞生之前&#xff0c;地域位置往往是人们思想上不可…

k8s基础概念以及部署

kubernetes基础概念 来历 kubernetes以谷歌borg为前身&#xff0c;基于谷歌15年生产环境经验开源的一个项目。k8s是一个开源&#xff0c;的分布式的容器编排技术。 k8s的优势 对比对象 裸容器 例如docker&#xff0c;直接将容器部署在宿主机的方式被称为裸容器。 缺点 纯粹的裸…

性能测试之中间件:什么是 kafka 和 MQ ?

在如今这个数据驱动的时代&#xff0c;中间件在性能测试中扮演着至关重要的角色。你是否曾听说过Kafka和MQ&#xff0c;却不清楚它们在实际应用中具体的作用是什么&#xff1f;让我们一起来揭开它们的神秘面纱。 Kafka和MQ究竟是什么&#xff1f;它们在性能测试中如何发挥作用…

C#基于SkiaSharp实现印章管理(6)

除了文本&#xff0c;印章设计模块的绘图功能已经差不多了。在实现文本绘制之前&#xff08;主要是文本绘制相对比较麻烦&#xff09;&#xff0c;本文先实现将印章导出为pdf或图片的功能。   不论是在控件中绘制&#xff0c;还是在图片或pdf文件中绘制印章&#xff0c;对Ski…

基于web网上村委会业务办理系统pf

TOC springboot472基于web网上村委会业务办理系统pf 绪论 1.1 研究背景 当前社会各行业领域竞争压力非常大&#xff0c;随着当前时代的信息化&#xff0c;科学化发展&#xff0c;让社会各行业领域都争相使用新的信息技术&#xff0c;对行业内的各种相关数据进行科学化&…

电话机器人解决销售难题

电销机器人简单理解就是替电销人员打电话的机器人&#xff0c;都说是机器人了&#xff0c;全天保持无休状态肯定是不在话下的。智能外呼电话机器人每日通话量大概在800-1000通&#xff0c;一个AI电话机器人就能顶3个销售人员的日通话量了&#xff0c;电话营销机器人能在批量上传…

高校中的电能消耗管理

2013年1月&#xff0c;住建部发布《绿色建筑行动方案》&#xff08;国办发「2013」1号&#xff09;。要求学校、医院等大型公共建筑全面执行绿色建筑标准。安全耐久、生活便利不再是绿色建筑的评价唯一指标&#xff0c;资源节约、环境宜居和健康舒适同样也是绿色建筑的评价指标…

5G+工业互联网产教融合创新实训室解决方案

一、建设背景 随着第五代移动通信技术&#xff08;5G&#xff09;的快速普及和工业互联网的迅猛发展&#xff0c;全球制造业正面临着前所未有的深刻变革。5G技术凭借其超高的传输速率、极低的延迟以及大规模的连接能力&#xff0c;为工业自动化、智能制造等领域带来了革命性的…

【NXP-MCXA153】PWM驱动移植

介绍 ‌PWM&#xff08;‌Pulse Width Modulation&#xff09;‌&#xff0c;‌脉冲宽度调制&#xff0c;‌是一种数字量控制模拟量的技术&#xff0c;‌常用于电机驱动、显示屏背光控制、逆变控制等&#xff1b;NXP-MCXA153开发板上有多路CTimer定时器&#xff0c;可以用来生…

6. 数据结构—串的匹配算法

1.BF算法(暴力算法) //模式匹配(暴力算法) int Index(SString S,SString T){int i1,j1;while(i<S.length&&j<T.length){if(S[i]T[i]){i;j;}else{ii-j2; //最开始匹配的位置的后一个j1; //从头匹配 }}if(j>T.length)return i-T.length;return return 0…

【Vue3】配置路由规则props

【Vue3】配置路由规则props 背景简介开发环境开发步骤及源码总结 背景 随着年龄的增长&#xff0c;很多曾经烂熟于心的技术原理已被岁月摩擦得愈发模糊起来&#xff0c;技术出身的人总是很难放下一些执念&#xff0c;遂将这些知识整理成文&#xff0c;以纪念曾经努力学习奋斗的…

Ubuntu启用root用户

1.1 命令行的组成 在启用 root 用户之前&#xff0c;先来了解一下&#xff0c;ubuntu 命令的组成。 打开 ubuntu 的终端&#xff0c;可以看到命令行是由 topeetubuntu:~$ 这几个字母组成&#xff0c;如下图所示&#xff1a; 对应的说明框图如下&#xff1a; 1.2 由普通用户切…

基于机器视觉的智能图像处理与分析系统(MATLAB图片处理,GUI界面)

灰度&#xff0c;二值&#xff0c;去噪&#xff0c;均衡&#xff0c;锐化&#xff0c;截取&#xff0c;边缘检测&#xff0c;都可做。 ☆图像灰度化&#xff0c;二值化 ☆图像相加&#xff0c;相减等 ☆图像旋转&#xff0c;图像裁剪 ☆图像灰度变换&#xff0c;gamma变换&…

Github 2024-08-19 开源项目周报Top15

根据Github Trendings的统计,本周(2024-08-19统计)共有15个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Python项目7JavaScript项目3TypeScript项目3Dart项目2HTML项目1PowerShell项目1Clojure项目1C++项目1Rust项目1Bootstrap 5: Web上开发响应式、…

微服务:微服务保护

&#x1f4a5; 该系列属于【SpringBoot基础】专栏&#xff0c;如您需查看其他SpringBoot相关文章&#xff0c;请您点击左边的连接 目录 一、引言 1. 什么是雪崩问题 2. 雪崩问题产生的原因 3. 解决思路 二、微服务保护 1. 服务保护方案 &#xff08;1&#xff09;请求限…