新一代直播传输协议SRT_清流_46837673的博客-程序员秘密

技术标签: 算法  java  网络  人工智能  编程语言  

SRT协议是基于UDT的传输协议,保留了UDT的核心思想和机制,抗丢包能力强,适用于复杂的网络。在LiveVideoStack线上分享中,新浪音视频架构师 施维对SRT协议的原理、优缺点特性以及在流媒体中的应用进行了详细解析。

文 / 施维整理 / LiveVideoStack视频回放 https://www2.tutormeetplus.com/v2/render/playback?mode=playback&token=a1564111ef934005b4b1acf2105128e3

1. 为什么选择SRT?

毋庸置疑,现今存量最大的直播协议是RTMP,但随着新技术的不断发展与使用场景的不断拓展,继续使用RTMP会令人感到有些力不从心。RTMP协议的缺陷主要有以下四个方面:RTMP协议缺陷image

首先,RTMP协议太老,且最后一次更新是在2012年;同时HEVC/H.265/AV1等视频格式都没有官方定义,以至于需要国内CDN厂商自行定义。RTMP连接过程较长,由于RTMP基于TCP(TCP存在三次握手),除此之外,其本身又存在c0/s0到c2/s2的三次握手,再加上connection,createstream,play/publish,总地来说RTMP完成一次建连需要进行9次会话,用于PC端勉强能够接受,对于移动端网络质量的要求则很高。RTMP的拥塞控制完全依赖传输层,即完全依赖于TCP传输层的拥塞控制算法来进行拥塞管理,几乎没有什么优化;RTMP本身基于TCP传输,无法提供带宽自适应的算法。在此背景下,众多厂商开始着手提供一些新的直播协议供行业参考。如QUIC、SRT等。本次我们将重点讲述SRT的特点与应用。

SRT协议的特点

image.gif

Haivision联手Wowza在UDT的基础上针对音视频实时性提出了SRT协议。SRT是基于UDT的协议(UDT协议是基于UDP的传输协议,在IETF已经提交了4个版本),具有非常良好的丢包重传机制,丢包重传的控制消息非常丰富,同时支持ACK、ACKACK、NACK。我们都知道音视频对于时间这一点非常在意,而SRT基于时间的报文发送,使其具有良好的防止流量突发的能力。SRT对上层提供了丰富的拥塞控制统计信息,包括RTT、丢包率、inflight、send/receive bitrate等。利用这些丰富的信息,我们可以实现带宽预测,并根据带宽的变化在编码层去做自适应动态编码与拥塞控制。

2. SRT协议原理分析

2.1 SRT基本思想

image.gif

上图可以涵盖SRT的基本思想:对比编码后的视音频码流(左侧绿色折线“Source”)与经过公网传输后的码流(红色折线“NetworkTransmission”),可以看到编码后的源视音频码流具有固定的帧间隔与一定特性的可变比特率,但经过公网传输后的码流,其帧间隔变得不固定且码率特性也被完全改变,解码这样的信号是一项十分艰巨的挑战,甚至根本无法解码。而如果使用加入纠错的SRT协议进行公共互联网传输,尽管编码后的视音频码流经过公网传输帧间隔变得不固定,但由于SRT协议封装中包含精准的时间戳,解码接收端可以通过该时间戳重现固定的帧间隔。更重要的是,通过规定延时量,同时划定了send buffer(发送端缓冲区)与receive buffer(接收端缓冲区),来自接收端的反馈信号(可以理解为后向纠错)通过一系列的设置、纠错、流量控制,使编码后的视音频码流拥有与原码流几乎一样的码率特性。Encoder编码器处理完成的数据会被输入send buffer,send buffer会对数据进行时间校验,也就是按照一定的时间顺序编码并通过internet发送至receivebuffer,receive buffer按照报文上的时间戳一点点处理,确保生成的数据与源码流基本一致。整个SRT协议的思想基于编码,具有抗丢包、抗拥塞、抗抖动等特性。

2.2 SRT报文基础

交互过程

image

SRT的报文基础也就是其交互过程依次为以上五个步骤:握手(Handshake)、重要信息(Capability)、媒体(Media)、控制信息(Control)与关闭(Shutdown)。与RTMP的九次握手不同,SRT的建连过程仅需两个RTT。也就是Handshake Request与Capability Announce。Caller与Listener之间的进行的Handshake Request是一个简化版的握手,用以提高效率;握手之后Caller与Listener间进行重要信息的交换,整个SRT的第一项关键步骤就是Caller与Listener在这里交换了延时量与缓冲区的大小;随后Caller与Listener之间开始媒体数据的传输,同时也传输了为恢复帧间隔而封装的精准时间戳;SRT的第二项关键步骤是Listener向Caller同步控制信息,用以对抗公网中的抖动、丢包等一系列突发状况;最后,待至媒体数据传输完毕之后关闭传输。

数据报文

image.gif

SRT的报文格式较为简单,分为数据报文与控制报文。上图展示了数据报文的数据结构,观察结构我们可以发现上方两层为UDP部分,而在这之下是UDT部分。如果初始化为0,则认为其是数据报文。FF表示报文的序列, 0b10是分片的第一个报文,0b00是分片的中间报文,0b01是分片的最后一个报文,0b11表示单个报文并没有分片。KK表示是否加密,R表示是否属于重传报文,Timestamp表示时间戳,Destination Socket ID是SRT自定义的一个socket id。由该数据结构我们可以看出:SRT的数据报文拥有精准的32位时间戳,package sequence number绝对够用,且结构非常简单。下图展示的则是控制报文的数据结构,右侧表格展示了控制报文的常规类型,其中值得重点关注的有ACK、NACK、ACKACK等。

控制报文

image.gif

2.3 SRT丢包重传

2.3.1 Send/Receive Buffer

image.gif

SRT在接收和发送端都有receive buffer与send buffer,send Buffer严格按照时间戳间隔来发送,定时器默认10毫秒。

2.3.2 ACK

image

丢包重传最常见的便是ACK机制。以上图为例,假设发送端缓冲区发送五个数据包:1、2、3、4、5给接收端缓冲区,接收端缓冲区成功接收到这些数据包之后会向发送端缓冲区发送ACK——肯定应答已表示数据包被成功接收,发送端接收到ACK——肯定应答之后回收空间,删除1、2、3、4、5这五个数据包并准备发送数据包6。send buffer完全按照时间戳间隔处理数据,在确定的间隔(与ACKs,ACKACKs 和 Round Trip Time相关),接收方发送ACK给发送方,使得发送方把收到ack的packet从sender buffer中移除,其在buffer中的空间点将被回收。接收端的receivebuffer中存在Latency Window也就是延迟窗口,其作用为按照时间戳一点点上送数据。并严格按照时间戳检测,检测周期默认为10毫秒。

2.3.3 ACK/ACKACK/RTT

image

接收端在收到数据包后会向发送端反馈表示成功接收的ACK,例如上图左侧,接收端在收到第十一个数据包后向发送端反馈ACK(11),而发送端在收到来自接收端的ACK(11)之后会向对端再发送一个ACKACK用以表示收到ACK(11)。这一过程最大的意义在于可让接收端计算出RTT,ACK发送的时间与对应ACKACK收到的时间之差就是RTT——Round Trip Time(RTT)是时间的度量,表示报文一个来回的耗时。SRT不能测量单方向的耗时,所以只能用RTT/2来表示单方向耗时。一个ACK(从接收方)会触发ACKACK(从发送方)的发送,几乎不带其他延时。RTT可评估当前网络质量,RTT高表示整个网络的延迟很大,RTT低则说明网络延迟较低。RTT由接收端计算而出,计算得出的RTT会通过ACK发送至发送端,发送端就可获知当前网络的质量如何。带宽情况是不断变化的,因此RTT也是一个随网络环境不断变化的实时动态值。

2.3.4 ACK信息

image.gif

ACK报文包含了丰富的关键信息。其中Last Acknowledge Packet Sequence Number表示当前收到第几个包,RTT信息便于发送端评估网络的质量,RTT的变化表示网络变化情况。Available Buffer Size表示接收端缓存可用率,SRT是可以用作文件传输的,Available Buffer Size对文件传输的拥塞控制非常有用。当文件传输过快时接收端的内存缓存无法成功接收,此时发送端除了考虑网络还需要考虑接收端的性能与缓存是否有足够的空间与能力在短时间内接收庞大的文件。Packets Receiving Rate表示每秒钟的收包率,这里统计的是包的个数;而ReceivingRate表示接收包的比特率。总而言之,接收端以10毫秒为周期向发送端发送ACK,其中包括网络RTT信息、接收端缓存信息、接收端比特率等关键数据,其中以上三个数据至关重要,直接反映出发送端到接收端之间的网络环境状态。

2.3.5 NACK

image.gif

常规情况下QUIC或TCP仅提供ACK方式,也就是接收端向发送端反馈哪些包成功接收;而WebRTC的RTP或RTCP常用选择NACK,也就是接收端向发送端反馈哪些包没有成功接收。NACK回传的是接收端没收到的数据包的列表。SRT同时支持ACK与NACK,这样设定的原因在我看来是带宽抢占的强势。例如,接收端向发送端发送ACK表示该数据包已经成功接收,不排除该ACK报文本身丢失,导致发送端以为数据报文丢失而要超时重发,实际接收端对该数据包已经成功接收了。还有一种情况是:NACK的周期性发送可能会造成发送端多发报文,例如发送端成功发送5号与6号数据包,却一直未收到来自接收端的ACK消息,当达到重发的时间时发送端再次发送5号与6号数据包,在此之后发送端收到了来自接收端的NACK消息,表示接收端未成功接收5号数据包与6号数据包;于是发送端第三次发送5号数据包与6号数据包。一个周期下来,发送端发了两次数据包。从协议原理角度分析,我们发现 SRT在丢包过程中对带宽的消耗比QUIC与其他协议要高。 一旦出现丢包,SRT的重传要多于其他协议,SRT以此来抢占带宽从而达到音视频的同步效果。

2.4 SRT基于时间发送

image

按时间发送是一个标准的音视频传输特性。我们知道编码器发送是以编码器的速度向外发送数据,但有时编码器会太乐观,完全按照编码输出向外发送会导致输出超过预期过高的比特率。在这种情况下SRT Packet就不会足够快地输出,因为SRT会最终被过低的错误配置影响到。

2.5 可配置比特率

image

SRT中包含三个配置选项:INPUTBW表示编码器输入带宽,MAXBW表示最大带宽,以及OVERHEAD(%)表示过载率,配置原则如上图所示:如果不配置INPUTBW与OVERHEAD(%)而仅配置MAXBW,则当前编码器输出的比特率是也就是MAXBW;如果不配置MAXBW与INPUTBW而仅配置OVERHEAD(%),则当前编码器输出的比特率是(1080+)/100,默认为25%;第三种情况是不配置MAXBW而配置OVERHEAD(%)与INPUTBW,最大输出比特率便为(100+)/100。SRT最大的特点便是可配置。在有配置的情况下按照配置来做,在无配置的情况下按实际测量的比特率来做。常规情况下我们不选择进行配置,尤其是针对互联网而言,因为单一配置无法保证能够在不同时段应对不同境况的网络。通常我们选择使用实际测量出的编码比特率计算:*(1080+)/100。

2.6 SRT简单拥塞控制——简单,太简单

接下来我们讨论一下SRT的流控。我们知道在丢包重传机制下,如果报文在网络传输中丢失,则发送端会重新发送。例如在某网络环境下发送端与接收端之间的带宽仅有1M,现在由于背景流量与噪声等影响,原来1M的带宽减少100k变成了900k,此时就会出现10%的丢包;发送端未收到来自接收端的ACK或者收到NACK认为出现丢包,于是尝试重传这10%的数据;但实际上发送端与接收端之间的带宽就剩下900k了,而加上丢包重传的发送量是1.1M,带宽变窄发送的流量不降反增,就会导致网络情况越来越糟糕,最后造成网络拥塞卡顿频繁,最后网络崩溃。SRT单纯地丢包重传不能解决网络拥塞的问题,出现网络拥塞的最好解决方案是限流,降低带宽流量压力。image.gif

SRT的拥塞控制过于简单,仅在congctrl.cpp中实现。其包括以下几个变量:M_iFlowWindowSize表示接收方的缓存大小,m_dCWndSize等于1秒内发送的bytes数据 / (RTT + 10),sendbufer表示发送方未发送buffer大小。其中这里的1秒内发送的bytes数据,具体是指一个RTT内发送的数据。总结算法如下:m_iFlowWindowSize用以衡量接收方缓存是否耗尽,同时监测发送方每RTT发送数据size是否大于发送buffer大小。接收方缓存一般在传输文件时起作用。在我看来,SRT在拥塞控制方面做得还远远不够。

2.7 SRT协议总结

image.gif

SRT在快速连接方面有明显优势,两次握手成功即可建连;SRT的丢包重传策略出色,ACK、ACKACK、NACK等提供了丰富的控制消息,还有RTT、Receive比特率等。但是同时我们经过测试也发现SRT在丢包时,发送数据的带宽占用率还是有些大,丢包率越高发送带宽占用越大。SRT按照时间发送音视频数据,根据实际的编码比特率来发送音视频数据;但SRT的拥塞控制过于简单,只针对接收方缓存是否有能力接收与编码比特率是否发送过快。

3. SRT在SRS4.0中的方案用

image

3.1 SRT在SRS4.0中的方案应用

3.1.1 最后一公里——SRT推流

image

我们推荐从编码器到推流至边缘节点的部分使用SRT。其目的主要有两个:提高源流质量与基于SRT自适应比特率编码,发送端和接收端配合从而解决最后一公里的推流问题。是自己对srt的理解。SRS支持 SRT的接收端推流,边缘SRS在接收到来自推流端的SRT推流之后会将其转为RTMP并分发给中央节点,而后所有的边缘节点都可以进行RTMP拉流。

3.1.2 SRT地址格式

image.gif

作为一个传输协议,SRT的一个弊端在于给出一个未定义的地址,我们不清楚这究竟是推流地址还是拉流地址,那么如何进行匹配?image.gif

为方便SRT编码器推流,SRS4.0支持编码器的简单配置。如服务器IP、服务器Port以及streamid。根据SRT的官方文档,SRT通过StreamID进行标识,简配地址格式如上图所示,带有vhost虚拟主机配置的地址格式如下图所示,其中m=publish/request表示推/拉流地址。显而易见的是,对比RTMP,SRT地址的可读性并不好,地址长而冗杂。image.gif

3.1.3 SRT各种网络情况下的测试

image.gif

测试各种网络情况下的SRT我们不难发现,丢包率增加导致带宽消耗增加,网络状况不良或发生拥塞时,发送端会发送更多的数据,这便会导致网络状况愈发恶化,丢包率变得更高,并以此恶性循环;除此之外,RTT增加也会导致延时增加,一样会导致丢包率增加,带宽消耗更大。这里我们提出的解决方案是预测网络带宽——通过当前的send bitrate、RTT、inflight等数据预测网络带宽;同时动态调整编码比特率,根据预测的带宽动态调整编码比特率1来适应实时的带宽,避免发生拥塞并提高视频流畅度。

3.1.4 GCC算法自适应编码架构

image.gif

上图展示的就是谷歌拥塞控制算法GCC的架构图。如图所示:发送端将报文发给接收端,接收端由几个部分组成,其中计算接收报文Delay,也就是计算基于D(i,j) = (Rj-Sj) - (Ri-Si) 的变化的导数,得到m(ti)。除此之外,接收端设置的卡曼滤波算法会计算出一个门限值,通过该卡曼滤波的计算与比对,决定是增加码率还是降低码率,最终得出下一次网络带宽的预估值(Ar),并将数据返回给发送方。

3.2 自适应码率的SRT推流

3.2.1基于SRT自适应码率编码

image

基于SRT自适应码率编码的关键参数如上图左侧所示:rtt_min表示1s内的RTT最小值,send_bitrate_max表示1s内最大的发送bitrate,常规情况我们大概200~300毫秒统计一次;inflight表示已经发送出去但还未接收到ACK的报文的个数,这种情况可能意味着报文还在传输链路的途中;BDP(bandwidth-delay product) BDP = send_bitrate_max*rtt_min表示一个RTT内发送的最大字节数。如果BDP大于(1.2 x inflight)表示网络状况良好,可以增加编码码率;如果BDP小于(0.8 x inflight)则意味着网络状况不佳需要减少编码码率,其他情况则维持现有编码码率不变。这样便能较为有效地避免网络拥塞的情况发生。

3.2.2 基于SRT自适应码率编码——实例

image.gif

我们以测试实例来验证效果:通过Internet推流,来自于美国的SRT编码器的数据推至杭州的节点,建立SRS4.0。该测试开源地址如图中所示,使用FFmpeg配置编码码率为1000kbps,传输过程中根据实际出口带宽动态调整编码码率。由上图右侧图线1我们可以看到自适应码率最高可达到1400kbps,有良好的自适应效果;实际测试感受来看,视频播放平滑无明显卡顿,即便偶尔出现带宽抖动也能够迅速恢复。

4. SRT与QUIC

接下来我们对比SRT与QUIC,总结二者特点。

4.1 SRT1.4的优缺点

image.gif

SRT1.4的优缺点可以简单概括为以下内容:SRT的优点在于基于音视频按照时间戳进行收发,可有效保证音视频,同时ACK/ACKACK/NACK多种丢包纠正机制可有效降低延时与丢包率。SRT对上层提供丰富的传输层数据信息如RTT、lost packet rate、receive rate等。当然,SRT的缺点也不容忽视,如SRT的拥塞控制过于简单,需要在传输层合入BBR算法,原生SRT不支持连接迁移等。基于以上特点,我认为SRT更加适合编码器到最近节点的传输,也就是通过SRT探测出的RTT等相关信息实现自适应码率编码;除此之外,SRT也适合网络节点固定、网络情况固定的环境,合理配置lantency、send/recv buffer、ohead rate等SRT参数可达到事半功倍的效果。

4.2 QUIC的优缺点

image.gif

QUIC的优点是连接快,同时具有可插拔的拥塞控制,包括CUBIC、BBR;另外在丢包重传方面,QUIC拥有更多的ACK block,最大可达256个,并且对于RTT的计算更加准确(QUIC中存在独立的Packet number,包括重传包在内的Packet number也都不相同,非常有利于RTT的精确计算);最后还有QUIC支持连接迁移。当然,QUIC同样存在缺点:第一,报文头大在发送报文中所占比例较高。第二,丢包重传只有ACK原生;第三,QUIC不支持丢包,一旦出现丢包,若没有在timeout前恢复就会断开连接。基于以上优缺点,我认为QUIC更适合运用在网络丢包率较高的环境,因为QUIC具有0RTT快速连接能力、丢包重传中ACK回复的block较大并且在拥塞控制方面表现非常优秀。除此之外QUIC也适合用于长距离传输当中,因为网络传输RTT较高,QUIC在连接断开后重连是0RTT,传输数据更加高效。

4.3mediago服务:rtmp over quic

image

Mediago具有支持QUIC协议来传输RTMP直播流的特性,如RTMP over TCP推拉流、RTMP over QUIC推拉流以及对FLV的支持。服务器之间则支持基于TCP服务器间RTMP回源与基于QUIC服务器间RTMP回源,上图中有测试链接,感兴趣的朋友可以自己尝试一下。

服务推荐

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_46837673/article/details/105364669

智能推荐

PC端浏览器兼容_pc端兼容_愿为浪漫渡此劫的博客-程序员秘密

浏览器生态丰富,不同厂商甚至不同版本之间差异性都很大,经历过IE6~8版本兼容处理的开发都懂得。Web开发很难做到所有版本的浏览器都兼容,而且不同的用户群体使用的浏览器版本趋势不同,所以在开发前有必要先收集用户使用浏览器的统计数据,再确定兼容策略。...

教你利用铁威马NAS轻松搭建网站服务器_Noont的博客-程序员秘密

在铁威马NAS中,你可以将TNAS架设成一个网站服务器。如需启用网站服务器功能,需要开启网站服务器。1.登录TOS系统;2.单击TOS桌面-控制面板-网络服务-网站服务器;3.勾选启用网站服务器;4.设置网站服务器端口号,设置网站根目录;5.如需强制使用80 端口,请勾选 强制使用80 端口;6.如需使用SSL 联机,请勾选“使用安全联机(SSL)”,并设置端口;若强制使用8...

web.config 中SessionState的配置讲解_weixin_34377919的博客-程序员秘密

web Form 网页是基于HTTP的,它们没有状态, 这意味着它们不知道所有的请求是否来自 同一台客户端计算机,网页是受到了破坏,以及是否得到了刷新,这样就可能造成信息的 丢失。 于是, 状态管理就成了开发网络应用程序的一个实实在在的问题。     在ASP中能够通过Cookie 、查询字符串、 应用程序、会话(Session) 等轻易解决这些问题。 现在在ASP.NET环境中,我们依然可以使用...

Android数据库框架 GreenDao 3.2.0 的基本使用_蔡小波的博客-程序员秘密

前言Android开发中我们或多或少都会接触到数据库。Android中提供了一个占用内存极小的关系型数据库-SQLite。虽然Android系统中提供了许多操作SQLite的API,但是我们还是需要手动去编写SQL语句,这经常会出现一些莫名其妙的问题(

Report Builder应用中的一些错误及其处理_creportbugs错误报告怎么处理_Baconxu的博客-程序员秘密

 QQ:16441708MSN:[email protected]一、打开Report时报错 提示:REP-0736:此处存在未编译的单元。 原因:Report builder尚未连接到数据库。 处理:选择文件——>连接,连接到数据库。二、编译Reprot程序块时报错 提示:错误 0 发生在第m行,第n列 SQL Statement ignored. 原

随便推点

WMIC 命令行管理方式_fantasylf的博客-程序员秘密

<br />上期的专栏里,NP给大家写了一篇很精彩也很有实际应用效果的批处理教程。这期,我给大家讲一下最近我学习wmic的体会。在这篇文章里也许你看不 到很多奇特有用的的实际例程,但是呢,授人以鱼不如授人以渔,希望我的文章能让你通俗易懂的了解一些wmic的基本知识,可以有一个学习的兴趣,让自己继 续深研一下wmic。<br />在WINDOWS/Help目下,wmic.chm文档是这样解释wmi的:Windows Management Instrumentation (WMI) 是“基于 Web 的企业管理

I2C—读写EEPROM学习笔记之软件模拟IIC原理_宇智波 · 赵四的博客-程序员秘密

软件模拟I2C原理:内核直接控制2个GPIO引脚电平,模仿SDA和SCL两根线与外部设备进行通讯。中间抽空做了一下TDA2030功放的仿真实验。心态有些崩,做出来的波形好像一坨shit,难受。算了,继续学一下模拟I2C。...

在listctrl中添加edit和combox控件_aa1991的博客-程序员秘密

1.定义成员变量: CComboBox m_Cmb;  、、将它与组合框控件关联, CEdit m_Edit;、、将它与编辑框控件关联, int m_row,m_col;  //记录用户点击的那个单元格所在的行与列号 2.添加listctrl的单击响应消息主要是完成了单击后将控件显示出来。添加代码如下void CControllerDialogAdd::OnClickListD

HDU-ACM2004_夏小弥的博客-程序员秘密

成绩转换Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 117513    Accepted Submission(s): 51558Problem Description输入一个百分制的成绩t,将其转换成对应的

matlab示波器如何反白,stc12单片机写的简易示波器代码,求大神答疑_lnstagram优选的博客-程序员秘密

#include #include#includesbit RS=P0^0; //并行的指令/数据选择信号, H数据, L命令sbit RW=P0^1; //并行读写选择信号, H读, L写sbit E=P0^2; //并行使能端, H有效, L无效sbit jiakey=P3^0;sbit jiankey=P3^1;sbit res=P0^3;sbit PSB=P0^4;#defineLcd...

烟雾传感器的matlab程序,单片机烟雾传感器proteus仿真+程序+PCB原理图_不要芝麻酱的博客-程序员秘密

利用ADC0832对烟雾传感器进行仿真并报警烟雾探测元件清单仿真原理图如下(proteus仿真工程文件可到本帖附件中下载)Altium Designer画的原理图和PCB图如下:(51hei附件中可下载工程文件)单片机源程序如下:#include //包含单片机寄存器的头文件#include //包含_nop_()函数定义的头文件#define uchar unsigned c...

推荐文章

热门文章

相关标签