您当前的位置是:  首页 > 资讯 > 文章精选 >
 首页 > 资讯 > 文章精选 >

拆解SRT:新UDP视频传输协议

2019-12-10 13:36:27   作者:文 / Alex Converse 译 / Adrian Ng   来源:CTI论坛   评论:0  点击:


  本文来自Twitch视频工程师Alex Converse在San Francisco Video Technology Meetup 2019 的分享。其分享集中于SRT协议的起源,以及如何在颇具挑战的网络上基于UDP传输实时视频。讲师也介绍了UDT、open source、SRT联盟和SRT的技术概述,最后分析了SRT数据包、SRT数据包缓冲区和Nak数据包如何容忍packet loss及处理延迟这些问题。
  大家好,我是Twitch的视频工程师,今晚我的演讲主题是SRT协议的内幕。在过去,我看过许多关于支持SRT功能的软解的精彩演讲以及它的各种潜能。但是今天,我将掀开幕布,看看SRT协议背后的东西。
  此SRT(Secure Reliable Transport)非彼SRT(SubRip Subtitle:它是一种字幕格式),这个视频传输协议可以在具有挑战性的网络之下进行直播。它基于UDP的单播(一对一的形式),注重contribution而不是delivery。此外,它也带来亚秒可调的constant latency。
  这么说吧,可调(tunable)意味着你可以配置协议并调整延迟,可以在数据包的丢失与延迟中做出权衡(trade-off)。一旦开始广播的时候,延迟即被锁定,所以不会因为不同的网络的情况而累积更多的延迟,同时,该系统也提供content encryption。
  为什么我觉得SRT有趣?我们知道RTMP是公共互联网上直播视频的事实标准;但RTMP已经存在了很长一段时间,其标准在2012年最后一次更新过后就被放弃了。新的Codec标准诸如HEVC或AV1一般都没有RTMP标准支持。退一步来说,即使有人在RTMP中hack了这些Codec的支持,在移动网络上RTMP仍然工作的不大好。
  SRT作为RTMP潜在替换技术的一种,最近正获得不错的增长势头。SRT联盟现在有250多名成员,而在最近的一些展会上,似乎每个展位都具有 SRT 联盟成员或 SRT-Ready贴纸。
  SRT功能在VLC,Gstreamer和Ffmpeg中基本开箱即用,对于 OBS Studio 等工具则有些patches正在流程中。SRT 的源于一个称为 UDT 的旧协议。UDT在2001年创建,仍然在Source Forge上有网页,但UDT的设计目标是在公共网络上以最短时间传输大型的文件。
  UDT开发者向IETF提交过几份草案去描述UDT工作原理。总共有四份草案,最终的IETF草案是在2010年发布的。之后,UDT的主要开发者继续在此协议工作了3年,其实现的最终版本停留在了2013年。
  Haivision,一家编码器供应商,采用UDT且将它由file protocol变成一个live video协议。在2013年,他们首次在 IBC大会上使用了UDT,主要是为了演示HEVC的编码器。
  过了四年,他们觉得自己的自定义协议可能不是创建interoperable ecosystem的最好方式。因此在2017年,他们开源了SRT。
  Haivision 与Wowza 联合创建了SRT联盟,以促进发展及开发SRT。
  2018年初,他们发布了SRT的v1.3.0更新版本。这是自最初的开源以来,对protocol最大型的修改。同时,其版权协议改成了MPL(Mozilla public license);重新把文件传输模式加了回来。
  在2018年,他们也发布了SRT Technical Overview(SRT技术概述),但实际上更像规范(specification)。该文档共有89页,与此对应的RTMP Spec则是52页。该文档描述了各种细节信息,即使是一些竞争对手也承认SRT规范做得非常不错。
  从高层看,SRT使用的一个双向UDP socket,它可以通过同一个socket复用数据和控制流。因为没有使用TCP,SRT自行实现了可靠性、有序性和拥塞控制。SRT使用 selective retransmit的方式处理数据包丢失,另外了基于标准加密原语(standard primitives)(而不是DTLS)构建了其独特的 “unique”加密系统,
  SRT Data Payload支持可分片的有效负载(payload)。在实践中,我仅仅看过它与MPEG transport stream一起使用。整个传输流引入SRT包,每个传输流包都有自己的同步字节和传输流头。我确信这些sync byte 用以对抗丢包以及重新同步。
  在1500-byte Ethernet MTU情况下,如果你试图放入188-byte的数据包,会发现并没有足够的空间可以容纳8个TS包,这也是使用7个TS包的原因。与此同时,这也可以给SRT Header留出足够的空间。
  上图概述了SRT数据包的布局。初起是UDP header, 还有UDT header,实际上SRT header改自UDT header。
  第一bit是0,表示的是数据包,之后是packet sequence number,它是从握手过程中确定的random value开始的,随后每一个packet值都会增加1。该值用于标识数据包、packet acknowledgement和数据包丢失消息。有个message number, message number从0算起,会在我的视频中每增加一条消息时候加一,但看起来没什么用,怎么回事呢?
  我们可以看见一个微秒单位的时间戳,这是发送端的运行时间(elapsed time)。在接收端,它将这个packet从SRT的缓冲区中播放到下游的TST MUX RN 视频解码器中。这个实时视频的片段与顺序总会是“1 1 0”。1 1 指的的是独立编号,而消息编号是针对跨多个数据包分段的信息。但在实时视频模式下,我们只需要尽可能多地填充TS,我们称之为standalone message。
  Ordering flag下的两个标志是encryption和retransmission flags;如果出现了什么问题,ordering flag可以将其信息无序交付。Encryption flag会提醒你正使用的key,而retransmit flag会告诉你这是否是第一次发送还是一个重复的步骤。Retransmitted packets 通常会保留原始序列号,原始信息号和原始时间戳。
  SRT的核心理念是发送方和接收方都同意延迟缓冲时间,并且他们试图在数据包开始流出接收方时同步其内容。目前VLC支持现成的SRT,OBS也有了SRT的patch,发送方所创建的数据包,同时会将其放在延迟缓冲区,因为在网络中,该包到达接收方需要一段时间。
  发送方不断生成数据包,接收方最终获得数据包。发送方再不断地生成,接收方也继续接收。如此往复。
  这里展示了一个不妙的情况,上图的packet 3已被丢失,到目前为止,没人发现了数据的差错。本来期待packet 3,竟然收取了packet 4,它随即生成negative acknowledgement packet,将packet 4 放入缓冲区,为packet 3 留下一个空位(hole)。
  发送方继续分发packet,直到下一个packet送达。突然间sender得到NACK,它发现接受者丢失了packet 3,因为它把之前发送的数据包都保存在了buffer,结果,发送方重新发送数据包3,它继续生成数据包;接收方继续接收数据包。注意,此时发送者的buffer现在已装满了数据包。
  Packet 1被吐出,直接被丢掉。接收端终于收取到packet 3,它马上填补之前的空洞(hole),操作恢复正常。接收端buffer最终填满了指定的packet,随后把packet 1给了 TS deuxers 和解码器。
  这是协议概述中Nak的表示图。首先有SRT header,因为它是一个控制包所以1开头,最后是丢失包的列表。
  每一个丢失list包含一个或多个条目。每个条目要么是一个single packet,要么是一个范围(range),你可在一条消息内说丢失了packet 5、9以及11直到15的所有包。
  除了negative acknowledgment,SRT也有positive acknowledgment。接收器每10毫秒发送一次acknowledgment。每一次收到 ACK,发送者立即确认ACK以响应之前的ACK,你可以据此估算往返时间。如果确认之间的数据速率超过64个数据包,则接收器将发送lightweight acknowledgement。此Ack不会被重新确认,也不包含Ack所接受的元数据类型。
  RTT有点不寻常,因为似乎没有办法在不启动新广播的情况下调整延迟缓冲区的大小,所以对于广播场景有些限制。
  以上是acknowledgement packet所显示的Ack/AckAck包。最重要的是最后接收到的packet包序列号,当然还有的是往返时间,往返时间的方差,缓冲统计available size和packets,数据包接受速率及数据接收速率。在lightweight Ack,你只需得到序列号,Ack的acknowledgment将会显示它正在确认的Ack,以便于你知道在正确的时间戳做出扣除。
  我们都知道握手(handshake)非常简单。在这个GIF中,Bill Maher 不断地误读Snoop Dogg (史努比。狗狗)的手势,Snoop Dogg也不断地尝试配合Bill,这场景是body language misinterpretation的一个例子,我认为它适合隐喻SRT handshake的过程。
  SRT在sender和receiver之间有四次handshakes(因为后向兼容,所以所有版本都支持)。V4 和V5的rendezvous handshake (汇合握手)比较特殊,不在这次讲解。
  V5 以及v4最大的区别在于数据包交换的数量。v4共有四次往返;在v5只有两次往返。
  图中是packets的布局,其核心思想是左边的v4使用了未修改的UDT包加上SRT扩展,接着是一个包含所需延迟和初始序列号的SRT握手包,其后的密钥素材用于对于数据有效载荷进行加密,右边的v5则更将这些信息smush (合拼) 到一个包中(指V5直接修改了原始UDT包的布局)。
  之后,我们将看到两方尝试v5握手,发起方创建handshake induction packet (握手感应包)。
  其版本号设置为4,但cookie字段并未设置,它将提示初始端在短时间内获得cookie,使得响应端不必处理混乱的数据包,而是需要解析其数据包以将某些内容发送回去;实际上,响应端接收到该包之后,创建一个版本5的induction packet,并设置Cookie。
  此时,v4 initiator将忽略v5,并继续填充v4以及重复改cookie。但是,如果initiator是通过v5运行,所以它会在version字段中填写 v5程序,加上SRT handshake extension values包括延迟值等。
  Initiator可能在握手的第二个包产生stream ID,首先填充加密握手,然后responder会使用latency value 和cyypto handshake进行响应。
  在于Stream ID,这是在handshake的第二个包中所发送的可选标识符,因为第一个包是有可能被抛弃掉的。在此会有个application-specific parameter,用于通知你initiator想干什么。
  这与RTMP形成一些对比,在RTMP中,你执行TCP握手和RTMP握手。然后,执行带宽估计之后调用一组RPCs来设置RTMP媒体流。
  我之前提到过SRT不使用DTLS。它以自定义方式使用industry standard primitives,可看见它受到到了DVB scrambling的重大影响。DVB是欧洲广播标准,keying material是由共享密码短语生成。随着这些retransmits和密钥旋转,一次有两个密钥有效。你有一个偶数键和一个奇数键,在这两个键中你交替使用哪一个,你就在更新。如果你得到重发,你可以参考旧的密钥。
  规范中的小注释说:‘嘿,全数据包加密看起来是最安全的选择,但实际上,加密header在暴力破解时候却有点脆弱。最初的MPEG TS 同步字节,其设计可能是不让你把TS头加密。事实上,我们会尝试使用快速的key rotation来获得更高的加密强度。
  你可以使用Wireshark 来分析包,我们会有个加密数据包,有效载荷的第一个字节是12(十六进制)。你可能已知道如果是一个未加密的TS 同步字节,那它将是47(十六进制)。
  如果想进一步了解其中的协议,你可以前往SRT GitHub repository,以及technical overview Wireshark的SRT解析器。
  如果你想了解更多关于SRT生态系统,或者有关于SRT的产品或信息请前往srtalliance.org。
 




 
【免责声明】本文仅代表作者本人观点,与CTI论坛无关。CTI论坛对文中陈述、观点判断保持中立,不对所包含内容的准确性、可靠性或完整性提供任何明示或暗示的保证。请读者仅作参考,并请自行承担全部责任。

相关阅读:

专题

CTI论坛会员企业