您當(dāng)前的位置是:  首頁(yè) > 資訊 > 文章精選 >
 首頁(yè) > 資訊 > 文章精選 >

拆解SRT:新UDP視頻傳輸協(xié)議

2019-12-10 13:36:27   作者:文 / Alex Converse 譯 / Adrian Ng   來(lái)源:CTI論壇   評(píng)論:0  點(diǎn)擊:


  本文來(lái)自Twitch視頻工程師Alex Converse在San Francisco Video Technology Meetup 2019 的分享。其分享集中于SRT協(xié)議的起源,以及如何在頗具挑戰(zhàn)的網(wǎng)絡(luò)上基于UDP傳輸實(shí)時(shí)視頻。講師也介紹了UDT、open source、SRT聯(lián)盟和SRT的技術(shù)概述,最后分析了SRT數(shù)據(jù)包、SRT數(shù)據(jù)包緩沖區(qū)和Nak數(shù)據(jù)包如何容忍packet loss及處理延遲這些問(wèn)題。
  大家好,我是Twitch的視頻工程師,今晚我的演講主題是SRT協(xié)議的內(nèi)幕。在過(guò)去,我看過(guò)許多關(guān)于支持SRT功能的軟解的精彩演講以及它的各種潛能。但是今天,我將掀開(kāi)幕布,看看SRT協(xié)議背后的東西。
  此SRT(Secure Reliable Transport)非彼SRT(SubRip Subtitle:它是一種字幕格式),這個(gè)視頻傳輸協(xié)議可以在具有挑戰(zhàn)性的網(wǎng)絡(luò)之下進(jìn)行直播。它基于UDP的單播(一對(duì)一的形式),注重contribution而不是delivery。此外,它也帶來(lái)亞秒可調(diào)的constant latency。
  這么說(shuō)吧,可調(diào)(tunable)意味著你可以配置協(xié)議并調(diào)整延遲,可以在數(shù)據(jù)包的丟失與延遲中做出權(quán)衡(trade-off)。一旦開(kāi)始廣播的時(shí)候,延遲即被鎖定,所以不會(huì)因?yàn)椴煌木W(wǎng)絡(luò)的情況而累積更多的延遲,同時(shí),該系統(tǒng)也提供content encryption。
  為什么我覺(jué)得SRT有趣?我們知道RTMP是公共互聯(lián)網(wǎng)上直播視頻的事實(shí)標(biāo)準(zhǔn);但RTMP已經(jīng)存在了很長(zhǎng)一段時(shí)間,其標(biāo)準(zhǔn)在2012年最后一次更新過(guò)后就被放棄了。新的Codec標(biāo)準(zhǔn)諸如HEVC或AV1一般都沒(méi)有RTMP標(biāo)準(zhǔn)支持。退一步來(lái)說(shuō),即使有人在RTMP中hack了這些Codec的支持,在移動(dòng)網(wǎng)絡(luò)上RTMP仍然工作的不大好。
  SRT作為RTMP潛在替換技術(shù)的一種,最近正獲得不錯(cuò)的增長(zhǎng)勢(shì)頭。SRT聯(lián)盟現(xiàn)在有250多名成員,而在最近的一些展會(huì)上,似乎每個(gè)展位都具有 SRT 聯(lián)盟成員或 SRT-Ready貼紙。
  SRT功能在VLC,Gstreamer和Ffmpeg中基本開(kāi)箱即用,對(duì)于 OBS Studio 等工具則有些patches正在流程中。SRT 的源于一個(gè)稱為 UDT 的舊協(xié)議。UDT在2001年創(chuàng)建,仍然在Source Forge上有網(wǎng)頁(yè),但UDT的設(shè)計(jì)目標(biāo)是在公共網(wǎng)絡(luò)上以最短時(shí)間傳輸大型的文件。
  UDT開(kāi)發(fā)者向IETF提交過(guò)幾份草案去描述UDT工作原理。總共有四份草案,最終的IETF草案是在2010年發(fā)布的。之后,UDT的主要開(kāi)發(fā)者繼續(xù)在此協(xié)議工作了3年,其實(shí)現(xiàn)的最終版本停留在了2013年。
  Haivision,一家編碼器供應(yīng)商,采用UDT且將它由file protocol變成一個(gè)live video協(xié)議。在2013年,他們首次在 IBC大會(huì)上使用了UDT,主要是為了演示HEVC的編碼器。
  過(guò)了四年,他們覺(jué)得自己的自定義協(xié)議可能不是創(chuàng)建interoperable ecosystem的最好方式。因此在2017年,他們開(kāi)源了SRT。
  Haivision 與Wowza 聯(lián)合創(chuàng)建了SRT聯(lián)盟,以促進(jìn)發(fā)展及開(kāi)發(fā)SRT。
  2018年初,他們發(fā)布了SRT的v1.3.0更新版本。這是自最初的開(kāi)源以來(lái),對(duì)protocol最大型的修改。同時(shí),其版權(quán)協(xié)議改成了MPL(Mozilla public license);重新把文件傳輸模式加了回來(lái)。
  在2018年,他們也發(fā)布了SRT Technical Overview(SRT技術(shù)概述),但實(shí)際上更像規(guī)范(specification)。該文檔共有89頁(yè),與此對(duì)應(yīng)的RTMP Spec則是52頁(yè)。該文檔描述了各種細(xì)節(jié)信息,即使是一些競(jìng)爭(zhēng)對(duì)手也承認(rèn)SRT規(guī)范做得非常不錯(cuò)。
  從高層看,SRT使用的一個(gè)雙向UDP socket,它可以通過(guò)同一個(gè)socket復(fù)用數(shù)據(jù)和控制流。因?yàn)闆](méi)有使用TCP,SRT自行實(shí)現(xiàn)了可靠性、有序性和擁塞控制。SRT使用 selective retransmit的方式處理數(shù)據(jù)包丟失,另外了基于標(biāo)準(zhǔn)加密原語(yǔ)(standard primitives)(而不是DTLS)構(gòu)建了其獨(dú)特的 “unique”加密系統(tǒng),
  SRT Data Payload支持可分片的有效負(fù)載(payload)。在實(shí)踐中,我僅僅看過(guò)它與MPEG transport stream一起使用。整個(gè)傳輸流引入SRT包,每個(gè)傳輸流包都有自己的同步字節(jié)和傳輸流頭。我確信這些sync byte 用以對(duì)抗丟包以及重新同步。
  在1500-byte Ethernet MTU情況下,如果你試圖放入188-byte的數(shù)據(jù)包,會(huì)發(fā)現(xiàn)并沒(méi)有足夠的空間可以容納8個(gè)TS包,這也是使用7個(gè)TS包的原因。與此同時(shí),這也可以給SRT Header留出足夠的空間。
  上圖概述了SRT數(shù)據(jù)包的布局。初起是UDP header, 還有UDT header,實(shí)際上SRT header改自UDT header。
  第一bit是0,表示的是數(shù)據(jù)包,之后是packet sequence number,它是從握手過(guò)程中確定的random value開(kāi)始的,隨后每一個(gè)packet值都會(huì)增加1。該值用于標(biāo)識(shí)數(shù)據(jù)包、packet acknowledgement和數(shù)據(jù)包丟失消息。有個(gè)message number, message number從0算起,會(huì)在我的視頻中每增加一條消息時(shí)候加一,但看起來(lái)沒(méi)什么用,怎么回事呢?
  我們可以看見(jiàn)一個(gè)微秒單位的時(shí)間戳,這是發(fā)送端的運(yùn)行時(shí)間(elapsed time)。在接收端,它將這個(gè)packet從SRT的緩沖區(qū)中播放到下游的TST MUX RN 視頻解碼器中。這個(gè)實(shí)時(shí)視頻的片段與順序總會(huì)是“1 1 0”。1 1 指的的是獨(dú)立編號(hào),而消息編號(hào)是針對(duì)跨多個(gè)數(shù)據(jù)包分段的信息。但在實(shí)時(shí)視頻模式下,我們只需要盡可能多地填充TS,我們稱之為standalone message。
  Ordering flag下的兩個(gè)標(biāo)志是encryption和retransmission flags;如果出現(xiàn)了什么問(wèn)題,ordering flag可以將其信息無(wú)序交付。Encryption flag會(huì)提醒你正使用的key,而retransmit flag會(huì)告訴你這是否是第一次發(fā)送還是一個(gè)重復(fù)的步驟。Retransmitted packets 通常會(huì)保留原始序列號(hào),原始信息號(hào)和原始時(shí)間戳。
  SRT的核心理念是發(fā)送方和接收方都同意延遲緩沖時(shí)間,并且他們?cè)噲D在數(shù)據(jù)包開(kāi)始流出接收方時(shí)同步其內(nèi)容。目前VLC支持現(xiàn)成的SRT,OBS也有了SRT的patch,發(fā)送方所創(chuàng)建的數(shù)據(jù)包,同時(shí)會(huì)將其放在延遲緩沖區(qū),因?yàn)樵诰W(wǎng)絡(luò)中,該包到達(dá)接收方需要一段時(shí)間。
  發(fā)送方不斷生成數(shù)據(jù)包,接收方最終獲得數(shù)據(jù)包。發(fā)送方再不斷地生成,接收方也繼續(xù)接收。如此往復(fù)。
  這里展示了一個(gè)不妙的情況,上圖的packet 3已被丟失,到目前為止,沒(méi)人發(fā)現(xiàn)了數(shù)據(jù)的差錯(cuò)。本來(lái)期待packet 3,竟然收取了packet 4,它隨即生成negative acknowledgement packet,將packet 4 放入緩沖區(qū),為packet 3 留下一個(gè)空位(hole)。
  發(fā)送方繼續(xù)分發(fā)packet,直到下一個(gè)packet送達(dá)。突然間sender得到NACK,它發(fā)現(xiàn)接受者丟失了packet 3,因?yàn)樗阎鞍l(fā)送的數(shù)據(jù)包都保存在了buffer,結(jié)果,發(fā)送方重新發(fā)送數(shù)據(jù)包3,它繼續(xù)生成數(shù)據(jù)包;接收方繼續(xù)接收數(shù)據(jù)包。注意,此時(shí)發(fā)送者的buffer現(xiàn)在已裝滿了數(shù)據(jù)包。
  Packet 1被吐出,直接被丟掉。接收端終于收取到packet 3,它馬上填補(bǔ)之前的空洞(hole),操作恢復(fù)正常。接收端buffer最終填滿了指定的packet,隨后把packet 1給了 TS deuxers 和解碼器。
  這是協(xié)議概述中Nak的表示圖。首先有SRT header,因?yàn)樗且粋(gè)控制包所以1開(kāi)頭,最后是丟失包的列表。
  每一個(gè)丟失list包含一個(gè)或多個(gè)條目。每個(gè)條目要么是一個(gè)single packet,要么是一個(gè)范圍(range),你可在一條消息內(nèi)說(shuō)丟失了packet 5、9以及11直到15的所有包。
  除了negative acknowledgment,SRT也有positive acknowledgment。接收器每10毫秒發(fā)送一次acknowledgment。每一次收到 ACK,發(fā)送者立即確認(rèn)ACK以響應(yīng)之前的ACK,你可以據(jù)此估算往返時(shí)間。如果確認(rèn)之間的數(shù)據(jù)速率超過(guò)64個(gè)數(shù)據(jù)包,則接收器將發(fā)送lightweight acknowledgement。此Ack不會(huì)被重新確認(rèn),也不包含Ack所接受的元數(shù)據(jù)類型。
  RTT有點(diǎn)不尋常,因?yàn)樗坪鯖](méi)有辦法在不啟動(dòng)新廣播的情況下調(diào)整延遲緩沖區(qū)的大小,所以對(duì)于廣播場(chǎng)景有些限制。
  以上是acknowledgement packet所顯示的Ack/AckAck包。最重要的是最后接收到的packet包序列號(hào),當(dāng)然還有的是往返時(shí)間,往返時(shí)間的方差,緩沖統(tǒng)計(jì)available size和packets,數(shù)據(jù)包接受速率及數(shù)據(jù)接收速率。在lightweight Ack,你只需得到序列號(hào),Ack的acknowledgment將會(huì)顯示它正在確認(rèn)的Ack,以便于你知道在正確的時(shí)間戳做出扣除。
  我們都知道握手(handshake)非常簡(jiǎn)單。在這個(gè)GIF中,Bill Maher 不斷地誤讀Snoop Dogg (史努比。狗狗)的手勢(shì),Snoop Dogg也不斷地嘗試配合Bill,這場(chǎng)景是body language misinterpretation的一個(gè)例子,我認(rèn)為它適合隱喻SRT handshake的過(guò)程。
  SRT在sender和receiver之間有四次handshakes(因?yàn)楹笙蚣嫒荩运邪姹径贾С郑。V4 和V5的rendezvous handshake (匯合握手)比較特殊,不在這次講解。
  V5 以及v4最大的區(qū)別在于數(shù)據(jù)包交換的數(shù)量。v4共有四次往返;在v5只有兩次往返。
  圖中是packets的布局,其核心思想是左邊的v4使用了未修改的UDT包加上SRT擴(kuò)展,接著是一個(gè)包含所需延遲和初始序列號(hào)的SRT握手包,其后的密鑰素材用于對(duì)于數(shù)據(jù)有效載荷進(jìn)行加密,右邊的v5則更將這些信息smush (合拼) 到一個(gè)包中(指V5直接修改了原始UDT包的布局)。
  之后,我們將看到兩方嘗試v5握手,發(fā)起方創(chuàng)建handshake induction packet (握手感應(yīng)包)。
  其版本號(hào)設(shè)置為4,但cookie字段并未設(shè)置,它將提示初始端在短時(shí)間內(nèi)獲得cookie,使得響應(yīng)端不必處理混亂的數(shù)據(jù)包,而是需要解析其數(shù)據(jù)包以將某些內(nèi)容發(fā)送回去;實(shí)際上,響應(yīng)端接收到該包之后,創(chuàng)建一個(gè)版本5的induction packet,并設(shè)置Cookie。
  此時(shí),v4 initiator將忽略v5,并繼續(xù)填充v4以及重復(fù)改cookie。但是,如果initiator是通過(guò)v5運(yùn)行,所以它會(huì)在version字段中填寫(xiě) v5程序,加上SRT handshake extension values包括延遲值等。
  Initiator可能在握手的第二個(gè)包產(chǎn)生stream ID,首先填充加密握手,然后responder會(huì)使用latency value 和cyypto handshake進(jìn)行響應(yīng)。
  在于Stream ID,這是在handshake的第二個(gè)包中所發(fā)送的可選標(biāo)識(shí)符,因?yàn)榈谝粋(gè)包是有可能被拋棄掉的。在此會(huì)有個(gè)application-specific parameter,用于通知你initiator想干什么。
  這與RTMP形成一些對(duì)比,在RTMP中,你執(zhí)行TCP握手和RTMP握手。然后,執(zhí)行帶寬估計(jì)之后調(diào)用一組RPCs來(lái)設(shè)置RTMP媒體流。
  我之前提到過(guò)SRT不使用DTLS。它以自定義方式使用industry standard primitives,可看見(jiàn)它受到到了DVB scrambling的重大影響。DVB是歐洲廣播標(biāo)準(zhǔn),keying material是由共享密碼短語(yǔ)生成。隨著這些retransmits和密鑰旋轉(zhuǎn),一次有兩個(gè)密鑰有效。你有一個(gè)偶數(shù)鍵和一個(gè)奇數(shù)鍵,在這兩個(gè)鍵中你交替使用哪一個(gè),你就在更新。如果你得到重發(fā),你可以參考舊的密鑰。
  規(guī)范中的小注釋說(shuō):‘嘿,全數(shù)據(jù)包加密看起來(lái)是最安全的選擇,但實(shí)際上,加密header在暴力破解時(shí)候卻有點(diǎn)脆弱。最初的MPEG TS 同步字節(jié),其設(shè)計(jì)可能是不讓你把TS頭加密。事實(shí)上,我們會(huì)嘗試使用快速的key rotation來(lái)獲得更高的加密強(qiáng)度。
  你可以使用Wireshark 來(lái)分析包,我們會(huì)有個(gè)加密數(shù)據(jù)包,有效載荷的第一個(gè)字節(jié)是12(十六進(jìn)制)。你可能已知道如果是一個(gè)未加密的TS 同步字節(jié),那它將是47(十六進(jìn)制)。
  如果想進(jìn)一步了解其中的協(xié)議,你可以前往SRT GitHub repository,以及technical overview Wireshark的SRT解析器。
  如果你想了解更多關(guān)于SRT生態(tài)系統(tǒng),或者有關(guān)于SRT的產(chǎn)品或信息請(qǐng)前往srtalliance.org。
 




 
【免責(zé)聲明】本文僅代表作者本人觀點(diǎn),與CTI論壇無(wú)關(guān)。CTI論壇對(duì)文中陳述、觀點(diǎn)判斷保持中立,不對(duì)所包含內(nèi)容的準(zhǔn)確性、可靠性或完整性提供任何明示或暗示的保證。請(qǐng)讀者僅作參考,并請(qǐng)自行承擔(dān)全部責(zé)任。

相關(guān)閱讀:

專題

CTI論壇會(huì)員企業(yè)