video_replay如何捕获和回放WebRTC视频流
視頻編碼問題常常是最難解決的問題之一,video_replay工具可以幫助分析定位故障。視頻協(xié)作平臺(tái)pixip的工程師Stian Selnes撰文,詳解了如何通過video_replay來捕獲、分析視頻的。LiveVideoStack對(duì)本文進(jìn)行了摘譯。
文 / Stian Selnes
譯 / 劉慶超
在數(shù)據(jù)包有丟失的環(huán)境下進(jìn)行視頻解碼不是一件容易的事。Chrome 58中引入了一種新的視頻抖動(dòng)緩沖區(qū),這導(dǎo)致最新版的Chrome在視頻顯示時(shí)一直有問題。由于該問題只在某些數(shù)據(jù)包丟失時(shí)才會(huì)出現(xiàn),因此調(diào)試難度很大。為此,webrtc.org提供了一個(gè)名為video_replay的工具來復(fù)現(xiàn)和分析這些棘手問題。
當(dāng)看到Stian Selnes提交的一個(gè)版本中視頻顯示仍然有問題時(shí),我將這個(gè)工具告訴了他。將視頻流輕松重現(xiàn)后,谷歌的WebRTC視頻團(tuán)隊(duì)很快就解決了這個(gè)bug。不過,這一過程的記錄做得不是很好,所以我們請(qǐng)Stian重現(xiàn)了抓取必要數(shù)據(jù)和使用該工具進(jìn)行操作的過程。Stian目前在pexip工作,他有超過10年的實(shí)時(shí)通信處理經(jīng)驗(yàn)。他在媒體協(xié)議棧領(lǐng)域有非常豐富的經(jīng)驗(yàn),特別是在視頻編解碼以及其他類型的信號(hào)處理、網(wǎng)絡(luò)協(xié)議和錯(cuò)誤恢復(fù)能力等方面。
WebRTC包含了一個(gè)非常好用但鮮為人知的工具——video_replay。事實(shí)證明,在調(diào)試視頻解碼問題時(shí),這個(gè)工具非常好用。它的目的是什么呢?為了在發(fā)現(xiàn)異常行為之后能容易地重復(fù)捕獲WebRTC呼叫,video_replay將捕獲的RTP流視頻作為輸入文件,然后離線使用WebRTC框架來解碼數(shù)據(jù),最后在屏幕上顯示輸出的結(jié)果。
例如,最近我正在研究一個(gè)問題,有一個(gè)版本的Chrome顯示輸入的視頻時(shí)突然出了上面這樣的問題。最終,使用video_replay調(diào)試后,WebRTC的團(tuán)隊(duì)發(fā)現(xiàn),Chrome中實(shí)現(xiàn)抖動(dòng)緩沖區(qū)的部分出現(xiàn)了一個(gè)錯(cuò)誤,這導(dǎo)致視頻流在某些情況下顯示會(huì)有異常。這種看似隨機(jī)數(shù)據(jù)導(dǎo)致的錯(cuò)誤其實(shí)是VP8解碼器的內(nèi)部狀態(tài)引起的。
?
視頻編碼問題常常是最難解決的問題之一。最初,我自己寫了一個(gè)測(cè)試方法,每20次調(diào)用中大約復(fù)現(xiàn)1次這樣的問題。使用這種方法重現(xiàn)問題是非常耗時(shí)的,效果通常也不好,最終也沒有給WebRTC團(tuán)隊(duì)解決該問題起到什么作用。
為了可以多次重現(xiàn)這個(gè)問題,我設(shè)法使用wireshark捕獲到一個(gè)失敗的呼叫,然后使用video_replay工具來分析。這樣我就有了一個(gè)每次都能重現(xiàn)這個(gè)罕見的問題測(cè)試用例。當(dāng)一個(gè)問題具有重復(fù)性的時(shí)候,解決問題和打補(bǔ)丁就非常輕松啦!這是典型的雙贏局面。
在這篇文章中,我將通過一個(gè)例子來演示如何使用video_replay,包括如何來捕捉一個(gè)WebRTC呼叫的RTP通信數(shù)據(jù),識(shí)別和提取接收到的視頻流,最后如何導(dǎo)入到video_replay中來實(shí)現(xiàn)在屏幕上顯示捕獲的視頻。
捕獲未加密的RTP數(shù)據(jù)
video_replay將輸入的文件導(dǎo)入到RTP協(xié)議棧、協(xié)議包解析設(shè)備和解碼器中,不過目前還沒有能力解密加密呼叫使用的SRTP包。Chrome和Firefox都支持加密呼叫,但是解密WebRTC呼叫卻不是一個(gè)簡(jiǎn)單的過程。尤其是SRTP進(jìn)行秘鑰分發(fā)時(shí)使用DTLS來保密共享,因此該秘鑰難以獲得。為此,最好用Chromium或Chrome Canary,因?yàn)樗鼈冇幸粋€(gè)可以禁用SRTP加密的選項(xiàng)。啟動(dòng)瀏覽器時(shí)添加命令行標(biāo)志–disable-webrtc-encryption即可,如果在窗口的頂部看到警告信息,說明你使用的瀏覽器不支持命令行標(biāo)志。注意,這要求雙方在通話都不能加密,否則會(huì)話將無法連接。
首先,使用Wireshark捕獲數(shù)據(jù)包。在會(huì)話開始發(fā)送媒體數(shù)據(jù)之前就要打開捕獲功能,這一點(diǎn)很重要,因?yàn)檫@可以將整個(gè)流都能記錄下來。如果捕獲的數(shù)據(jù)中丟失了流的開頭,視頻解碼器將無法解碼。
第二,打開一個(gè)選項(xiàng)卡,進(jìn)入chrome://webrtc-internals (或者Fippo最新的webrtc-externals).。呼叫之前首先做這個(gè),以獲取所有需要的信息,特別是SDP協(xié)商信息(如果想深入分析該問題,請(qǐng)見webrtchacks SDP分析指導(dǎo))。
最后,就是呼叫了。我們以appr.tc為例,但適用于任何使用WebRTC的呼叫。打開第二標(biāo)簽進(jìn)入https://appr.tc/?IPv6 = false。由于目前video_replay尚沒有IPv6相關(guān)的解決方案,因此在這個(gè)例子中,我將其禁用,希望該問題能很快解決。
現(xiàn)在,加入一個(gè)直播室。當(dāng)?shù)诙€(gè)參與者加入同一個(gè)房間時(shí),RTP將開始流動(dòng)。不管誰先加入,除非chrome://webrtc-internals看起來有異常。下面的截圖是在撥號(hào)進(jìn)入現(xiàn)有房間時(shí)拍攝的。
收集信息
為了從接收到的流中成功獲得RTP包,并能順利使用video_replay播放,我們需要收集一些關(guān)于RTP流的細(xì)節(jié)信息。有幾種方法可以做到這一點(diǎn),我堅(jiān)信最重要的是下面這幾個(gè):
Video codec 視頻編碼
RTP SSRC ?RTP SSRC
RTP payload types RTP 載荷類型
IP address and port ?IP地址和端口
使用webrtc-internals來收集統(tǒng)計(jì)信息?
首先,擴(kuò)大接收到的視頻流的統(tǒng)計(jì)表,給一個(gè)類似于ssrc_4075734755_recv這樣的命名。統(tǒng)計(jì)表可能不止一個(gè),一般第二個(gè)是音頻流,還可能有一對(duì)以_send為后綴的表,里面是發(fā)送流的等效統(tǒng)計(jì)信息。視頻流接收的統(tǒng)計(jì)表可以根據(jù)_recv后綴和mediaType=video來識(shí)別出來。分別記下ssrc、googCodecName 和transportId屬性,例如4075734755、VP9和channel-audio-1。
你可能會(huì)問為什么的視頻流和音頻通道有相同的transportid?這表示使用了BUNDLE來使音頻和視頻共享通道。如果BUNDLE沒有協(xié)商和使用,音頻和視頻將使用單獨(dú)的通道。
?
下一步,我們將查看協(xié)商的SDP以獲得RTP有效載荷類型(PT)。除了PT使用的視頻編解碼器,我們還必須找到RED的PT標(biāo)記,這個(gè)PT是WebRTC用來封裝的視頻包的。SDP描述了視頻客戶端的接收能力,因此為了找到接收到的有效負(fù)載類型,我們必須查看瀏覽器向另一個(gè)參與者提供的SDP類型。
這可以通過擴(kuò)展的setlocaldescription API調(diào)用找到,找到M =video的部分和后面每個(gè)支持的編解碼器的PT的rtpmap定義。由于我們的視頻編解碼器的VP9,我們會(huì)關(guān)注的屬性是a=rtpmap:98 / 90000和a= rtpmap:102 red/9000,這告訴我們,VP9和RED的有效載荷類型分別為98和102。
?
如果你正在尋找發(fā)送流而不是接收的信息,你應(yīng)該看看其他參與者通過setRemoteDescription的擴(kuò)展字段標(biāo)記了什么。事實(shí)上,載荷字段的類型應(yīng)該是對(duì)稱的,所以無論你看setlocaldescription或setremotedescription無關(guān)緊要,但在實(shí)時(shí)視頻通信的世界,沒人什么都知道,所以最好是都看一下。
為了在Wireshark中快速確定正確的RTP流,需要知道IP地址和使用端口。遠(yuǎn)程或本地地址并不重要,只要使用適當(dāng)?shù)膚ireshark過濾就行。對(duì)于這個(gè)示例,我們將使用本地地址,因?yàn)槲覀兿M崛∷邮盏牧?#xff0c;所以它是數(shù)據(jù)包的目的地。在chrome://webrtc-internals 的Conn-audio ?和 Conn-video部分包含了連接的統(tǒng)計(jì)信息。處于活躍狀態(tài)的用粗體突出顯示,根據(jù)上一步提到的transportid我們就可以知道要看視頻還是音頻通道。
為了在我們的例子中找到本地地址,我們需要擴(kuò)大conn-audio-1-0,并且注意googlocaladdress,其值為10.47.4.245:52740。
Wireshark中的RTP標(biāo)記
現(xiàn)在,為了在我們的呼叫中方便地識(shí)別和提取所接收的視頻流,我們已經(jīng)收集了所有必要的信息。Wireshark可能會(huì)將捕獲的RTP數(shù)據(jù)包簡(jiǎn)單地以UDP數(shù)據(jù)包來顯示。我們想告訴Wireshark這些是RTP包,所以我們可以將其導(dǎo)出為rtpdump格式。
首先,使用地址和端口顯示過濾器,例如ip.dst = = 10.47.4.245和udp.dstport = = 52740。然后,右擊一個(gè)數(shù)據(jù)包,選擇解碼為,然后選擇RTP。
其次,選擇菜單電話→RTP →RTP流,列出列表中的所有RTP流。我們接收到的視頻流中的SSRC連同其他流的一起列出來,選擇并導(dǎo)出為rtpdump格式。(video_replay還支持PCAP格式,但由于其對(duì)各種鏈路層的支持非常有限,我一般推薦使用rtpdump。)最后我們有一個(gè)文件只包含接收的視頻數(shù)據(jù)包,可以將其導(dǎo)入到video_replay中。
建立WebRTC 和 video_replay
使用之前,需要從WebRTC源碼生成video_replay。如何設(shè)置環(huán)境、獲取代碼和編譯等一般性的說明可以從https://webrtc.org/native-code/development中查到。注意,為了能生成video_replay工具,在編譯時(shí)需要將其明確指定為一個(gè)目標(biāo)。總之,在確定必要的軟件已經(jīng)安裝了之后,下面的命令可以獲得代碼和生成video_replay:
1mkdir webrtc-checkout
2cd webrtc-checkout/
3fetch --nohooks webrtc
4gclient sync
5cd src
6gn gen out/Default
7ninja -C out/Default video_replay
使用video_replay重放捕捉信息
最后重播捕獲的流,并希望之前它是如何在appr.tc中的狀態(tài)可以準(zhǔn)確地顯示出來。我們的示例做到這一點(diǎn)的最小命令行是:
(注意:媒體payload_type參數(shù)之前命名為payload)
根據(jù)之前的說明, 命令行的參數(shù)也非常容易理解。
video_replay參數(shù)
如果你的目標(biāo)是重現(xiàn)WebRTC出現(xiàn)問題后的bug,對(duì)于某些問題,將rtpdump連同命令行參數(shù)一起進(jìn)行重放將有巨大的幫助。如果你想多做一些自己的video_replay調(diào)試,有幾個(gè)命令行選項(xiàng)可能會(huì)很有用。
讓我們看看當(dāng)前的幫助文本并解釋不同選項(xiàng)的作用。編寫這一文件時(shí),../../webrtc/video/replay.cc的標(biāo)記有如下:
1-abs_send_time_id (RTP extension ID for abs-send-time) type: int32 default: -1
2-codec (Video codec) type: string default: "VP8"
3-decoder_bitstream_filename (Decoder bitstream output file) type: string default: ""
4-fec_payload_type (ULPFEC payload type) type: int32 default: -1
5-input_file (input file) type: string default: ""
6-out_base (Basename (excluding .yuv) for raw output) type: string default: ""
7-payload_type (Payload type) type: int32 default: 123
8-payload_type_rtx (RTX payload type) type: int32 default: 98
9-red_payload_type (RED payload type) type: int32 default: -1
10-ssrc (Incoming SSRC) type: uint64 default: 12648429
11-ssrc_rtx (Incoming RTX SSRC) type: uint64 default: 195939069
12-transmission_offset_id (RTP extension ID for transmission-offset) type: int32 default: -1
下面是關(guān)于它們的更多解釋:
快捷方法
當(dāng)你熟悉上面的過程時(shí),你可以使用一些快捷方式來提高效率。首先,你可以使用Wireshark中查看RTP視頻包而不必使用chrome://webrtc-internals。大多數(shù)視頻包通常超過1000字節(jié),而音頻數(shù)據(jù)包一般也就幾百字節(jié)。將解碼的視頻數(shù)據(jù)包使用RTP協(xié)議在Wireshark中處理,可以同時(shí)顯示SSRC和有效載荷類型。Wireshark不能自動(dòng)確定是RED有沒有用,但是可以從經(jīng)驗(yàn)中猜到,因?yàn)橛行лd荷類型一般不會(huì)在通話之間改變。
其次,如果你的video_replay支持pcap,你可以將原有pcap直接導(dǎo)入video_replay中。由于忽略了所有未知的數(shù)據(jù)包,命令行輸出可能會(huì)有很多錯(cuò)誤,但它可以解碼并顯示指定的流。
WebRTCon 2018 8折報(bào)名
WebRTCon希望與行業(yè)專家一同分享、探討當(dāng)下技術(shù)熱點(diǎn)、行業(yè)最佳應(yīng)用實(shí)踐。如果你擁有音視頻領(lǐng)域獨(dú)當(dāng)一面的能力,歡迎申請(qǐng)成為講師,分享你的實(shí)踐和洞察,請(qǐng)聯(lián)系 speaker@livevideostack.com。更多詳情掃描下圖二維碼。
總結(jié)
以上是生活随笔為你收集整理的video_replay如何捕获和回放WebRTC视频流的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: FFmpeg 硬件加速方案概览 (上)
- 下一篇: 5月19-20日的上海 来一次纯粹的We