即時音視頻領域UDP才是王道
在 Internet 上進行音視頻即時互動採用的傳輸層方案有TCP(如:RTMP)和UDP(如:RTP)兩種。TCP協議能為兩個端點間的資料轉送提供相對可靠的保障,這種保障是通過一個握手機制實現的。當資料傳給接收者時,接收者要檢查資料的正確性。寄件者只有接到接收者的正確性認可才能發送下一個資料區塊。如果沒有接到確認報文,這個資料區塊就得重傳。儘管這種機制對傳送資料來說是非常合理的,但當用它在Internet傳輸即時音視頻資料時就會引發很多問題。首先就是延遲問題,在傳輸通道丟包率較高時,TCP的傳輸品質下滑嚴重,重傳擁塞導致音視頻延時非常大,失去即時互連的意義。特別是無線通道(WIFI、4G、3G)下,使用TCP做雙向互連通訊穩定性欠佳,易出現音視頻長時間卡住不動然後快放的現象。
更多的產品選擇採用的協議是UDP(一般上層應用程式層協議為RTP,以提供序號和音視頻同步的服務)。UDP同 TCP 相比能提供更高的輸送量和較低的延遲,非常適合低延時的音視頻互動場合。
UDP傳輸存在的問題:
UDP效能的提高是以不能保障資料完整性為代價的,它不能對所傳資料提供擔保,常見的問題有包亂序、包丟失、包重複。無線通道(WIFI、4G、3G)下,UDP包亂序和包丟失可以說是常態。
關於包亂序和包丟失的原因,參考諸多文獻總結如下:
亂序原因:
(A) 路由器的儲存隊列導致的包亂序。
(B) UDP包據經過不同的路由造成了發送資料的混亂。
丟包原因:
(A) 當路由器和網關發生擁塞時,某些包可能被丟棄,發生這種情況一般是由於網路中傳輸的資料包大於網路通道的承載能力。
(B) 分組資料在傳送時有存留時間限制以避免路由中死迴圈的出現,網路狀況惡劣時,分組可能逾時丟失。
(C) 接收端工作超載運行時可能因調度困難而不能及時處理網口資料。
視頻碼流的少量丟失都會導致解碼後的視頻出現花屏的現象。H264、HEVC這樣的高壓縮率視頻壓縮標準使得壓縮的冗餘度非常低,碼流的丟失除了影響本幀的解碼外,還將影響以此為參考的視訊框架解碼,導致花屏的累積擴散,直至下一個主要畫面格的到來視頻畫面方能恢複。雖然解碼器內部會做一定的錯誤掩蓋處理,但效果並不理想,特別是採用ffmpeg這類開源的解碼器,其錯誤掩蓋演算法做得比較簡單。為此,在很多產品中不得不採用較小的GOP(較小的I幀間隔),以期在出現丟包花屏後能儘快的用I幀碼流重新整理畫面。這種方法副作用較大,而且某些場合下甚至會適得其反。因為I幀壓縮效率遠不如P幀、B幀,I幀往往比P幀、B幀大很多,頻繁的I幀將給傳輸通道帶來持續的波動壓力,造成更嚴重的丟包、亂序。另外,因為編碼器碼率控制的緣故,I幀佔用較多的碼流後,緊接著的P、B幀將不得不採用較大的QP量化參數(較差的映像品質)以保證碼率的局部可控,這樣帶來的直觀感受是映像隨著I幀間隔周期性的發虛、馬賽克。亂序的UDP包不經過順序恢複直接送解碼器同樣會導致解碼花屏,因為解碼器內部會將遲到的資料包丟棄。
綜上所述,工程中急需一種抗丟包、抗亂序的增強型UDP方案來提升即時音視頻傳輸效果,經過多年的積累與完善,我們推出了一套基於RTP並採用FEC前向錯誤修正和後端QOS處理的完整解決方案,效果非常明顯。
使用FEC\QOS武裝RTP
對於丟包,我們採用改進型的vandermonde矩陣FEC(Forward Error/Erasure Correction)前向錯誤修正技術來進行丟包恢複,由發送方進行FEC編碼引入冗餘包,接收方進行FEC解碼並恢複丟失的資料包。
對於包亂序和包重複,我們採用QOS亂序恢複處理,該QOS方案特點是在沒有丟包的情況下,不引入任何系統延時,並且可以通過可控的丟包等待時延來適應不同的通道亂序程度。QOS需要在接收端進行FEC解碼前進行,確保送FEC解碼模組的資料包序號是正確的(不存在亂序,僅存在丟包)。
眾多產品案例表明:採用FEC+QOS+RTP的組合,能顯著提升UDP傳輸的丟包、亂序抵抗力,為上層音視頻服務提供有力保障。下圖1是各模組在系統中的位置說明。
圖1 FEC、QOS在RTP系統中的位置
需要說明如下幾點:
(A)從差錯控制角度看,傳輸通道可以分為隨機通道、突發通道和混合通道。在隨機通道中,丟包出現是隨機的,且相互統計獨立,滿足常態分佈。在突發通道中,丟包是集中出現的,在一些短促的時間區間會出現大量的丟包,而在這些時間區間之外又存在較長的無丟包區間。混合通道則是上述二者的合體。本方案側重於對具備隨機通道特性的傳輸鏈路進行改進最佳化。
對 Internet通道的丟包特性研究發現,大多數情況下其滿足隨機通道的特點,丟失的都是單個包。連續兩個或以上包同時丟失的機率雖然比純隨機過程要高,但發生的機率還是要比單包丟失低,發生連續丟失10個以上包的機率就更低了。由於單包丟失出現的最頻繁,我們的抗丟包方案主要側重於對單包丟失的修複,同時也應該兼顧連續丟失的少量包的修複。對大量連續丟失的包的修複相對來說就顯得不那麼重要了(出現機率低,修複的代價大)。
(B)當然,任何差錯控制方案都是有其最大錯誤修正能力限制,當丟包率超出當前系統的錯誤修正能力時,丟包無法恢複,對於視頻應用來說意味著視頻將出現花屏。
為了改善系統在高丟包率下的使用者體驗,避免長時間花屏無法重新整理的現象,我們建議使用者採用ARQ(自動請求重發)+FEC機制,這裡的ARQ請求並不是請求遠端重發丟失的資料包,因為那樣相當於走了TCP這類內嵌ARQ功能協議的老路,必然引入不可控的延時。這裡的ARQ只是請求遠端即刻編碼視頻主要畫面格,避免長時間花屏無法重新整理的現象,ARQ請求一般通過額外的TCP通道發出(在絕大多數的系統中,通訊雙方一般會有TCP的信令通道,用於雙方業務層信令的互動)。ARQ的發起是根據FEC解碼輸出視頻碼流是否丟包作為判斷依據,發送端和接收端都需要對ARQ的頻率做一定的保護措施,避免頻繁的發起和響應,造成過多的I幀(過多I幀的副作用前面已有列舉)。
測試效果
本方案為C++開發,提供PC、Android(JNI)、IOS跨平台的支援。為了方便測試,我們在PC下開發了幾個簡易測試DEMO用於驗證示範。
(A)資料驗證DEMO
下圖所示為資料驗證DEMO介面,它以指定的資料作為測試源,可協助使用者更好的理解處理流程。
圖2 資料流程驗證DEMO
測試載入器為點對點工作模式,可在兩台PC上各自運行(同時也支援單機模式,只需將收發IP地址均設定為本地IP即可),以實現雙方之間RTP(FEC+QOS)通訊。
軟體收發自訂的測試包資料,提供了類比丟包功能,支援按固定間隔丟包或者按隨機比率丟包;支援設定FEC冗餘度或者選擇冗餘度自適應,支援設定QOS丟包等待時延等參數。
測試載入器內部預設使用10個媒體包外加冗餘度(數量由選擇的冗餘度決定)作為一個GROUP,當選擇冗餘度20%時,一個GROUP由10個媒體包附加2個冗餘包組成。下圖是Wireshark的觀察情況,10個媒體包後面緊接著2個冗餘包。
圖3 Wireshark觀察冗餘包情況
需要說明的是:程式主動丟包是在UDP發送層進行,所以即可能丟媒體包也可能丟冗餘包。
下面我們以20%冗餘度為例說明系統對各類丟包率的抵抗能力。
當選擇每10個包丟1個包時(丟包率10%),一個GROUP中最多隻會丟棄1個包,20%的冗餘度足夠抵抗這一丟包率,測試結果也驗證了這一結論,接收到的所有媒體包序號均保持連續,丟包率從10%降為0%,實驗情況如上圖2所示。
當選擇每5個包丟棄1個包時(丟包率20%),丟包情況如下圖4所示:
圖4 每5個包丟棄1個包時的情況
對於第一個GROUP,一共丟棄了三個包,包括0號媒體包、5號媒體包、0號冗餘包。因為接收的媒體包數為8個加接收的冗餘包數1個,總數小於總媒體包數(10個),因此接收端FEC無法恢複。對於第二個GROUP,只丟失了兩個媒體包,可以正常恢複。實驗結果如下圖5所示,說明了推斷的正確性,0號媒體包、5號媒體包丟失,13號、18號媒體包被成功恢複,系統丟包率從20%降低到10%左右。
圖5 20%冗餘度時,每5個包丟棄1個包時的恢複情況
(B)音視頻實測DEMO
圖6 音視頻實測DEMO
本DEMO支援如下特性:
(1)使用Direct進行網路攝影機、麥克風的採集和輸出
(2)使用ffmpeg進行高效映像縮放等前置filter
(3)視頻H264 HighProfile編碼、解碼
(4)音頻AAC-LC、AAC-LD、AAC-ELD編碼、解碼(三種標準可選,44.1KHZ 16bit 2通道立體聲)
(5)音視頻RTP傳輸(帶FEC\QOS功能)
(6)人為丟包測試功能
(7)即時統計輸出線路丟包延時情況
DEMO的內部架構如下圖7所示:
圖7 DEMO內部線程架構
在視頻採集縮放線程與視頻編碼線程之間,我們採用高效的雙隊列機制(隊列元素為指標,進出隊列無資料拷貝),如果視頻編碼效能非常充足的情況下,我們也可以將二者合并為一個線程。編碼線程與網路發送線程分離,避免網路擁塞影響編碼線程(這個對於UDP來說不成立,但對於RTMP這類TCP系統來說,網路收發線程與音視頻編解碼線程的分離是必須的,因為網路的抖動將影響音視頻處理環節。站在系統設計的角度,我們為UDP和TCP統一使用上述架構)。
在音視頻發送模組內,我們都配有定時握手包發送線程,這個線程與音視頻使用相同的發送通道(連接埠),僅在包頭上予以區別。它的作用非常重要,主要包括兩個方面:為NAT穿越提供保障,當我們的用戶端(內網IP)向伺服器(公網IP)發送資料時,鏈路路由器會為該通訊鏈路映射“連接埠”,這樣伺服器(公網IP)向該用戶端發送資料時,只需將收到的資料包的IP地址和連接埠翻轉作為發送目標IP和連接埠便能向其發送資料。路由器在收到伺服器的資料包時,檢查本地存在對應的映射“連接埠”,予以允許存取,否則將丟棄這一資料包(這是基於安全的考慮,外網向內網發送資料不得不防)。值得注意的是,路由器上“連接埠”是有時效性的,超過一定時間即會失效,為了保證伺服器能持續有效向用戶端發送資料,用戶端必須以心跳包的方式向伺服器發送資料以保持“連接埠”的有效性(用戶端根據業務情況不一定向伺服器持續發送資料包,可能只作為接收者)。以上是對C/S模式下NAT的簡要描述,P2P模式等其他情況請參考專門的資料。定時握手包的另一個作用是傳輸自訂的通道統計資料,這個類似於RTCP協議,接收方統計出下行丟包率後可以通過本握手包告知發送方,以便通知對方調整發送甚至編碼策略。
音訊處理流程與視頻類似,因為音頻編碼耗時非常低,我們一般將音頻採集與編碼放到一個線程內進行。音訊輸出與視頻不同,因為它需要按固定的輸出頻率工作,驅動將發起定時輸出線程,我們只需要在該線程內向指定記憶體存入指定數量的PCM資料即可。(輸出頻率、存放數量由音訊輸出通道數、採樣率、採樣點位元組數的配置而定)
若本地IP與遠端IP設定一樣,DEMO則進入本地迴環模式,此時將不存在任何網路丟包,我們可以通過設定手動丟包來類比測試。若本地IP與遠端IP不同,且不屬於同一網段,我們可以使用開源的WANEM來進行類比丟包、延時、抖動、重複包等情況,這一方式後面我們將專門予以介紹。
注意:真實的視頻對比效果請跳轉視頻對比效果 觀看
圖8 使用4%隨機丟包,關閉FEC時經常性花屏,聲音間歇斷續
當使用4%隨機丟包時,若關閉發端FEC功能,接收端視頻將出現經常性花屏,聲音出現丟失斷續。若使用20%冗餘度,視頻花屏機率將大幅降低(不會完全消除,因為丟包是隨機的,短時間內可能出現連續大量丟包的情況,超過20%冗餘度的無失真抗丟包率是16.67%即會出現花屏)
若使用按間隔丟包,每6個包丟一個(丟包率將恒定為16.67%),此時選擇20%冗餘度可以實現無失真恢複,視頻流暢無花屏,音質良好無斷續。
圖7 使用16.67%恒定丟包,FEC使用20%冗餘度時音視頻效果良好
更多
更多FEC相關的文章請參考 www.mediapro.cc