實戰排查|爲何遮擋推流攝像頭,會致使播放綠屏?

前言:作音視頻的小夥伴們多少都遇到過奇怪的BUG(如:卡頓、花屏、綠屏、變聲等),表象上矛盾點頗多,推理得出的結論都是:「不該該啊!」,最終你抽絲剝繭,發現真相只有一個:「事出反常必有妖」!git

做者:安果,阿里雲高級技術專家,從事阿里雲 RTC 服務器研發算法

奇怪現象

背景:RTC 互動中增長對 RTMP 的支持,實現 RTC 與 RTMP 相互訂閱。服務器

遇到一個奇怪的 BUG,遮擋住 RTC 端的攝像頭,有的 RTMP 播放端(iPad air 2,iPad mini 2/4)會偶發綠屏。ide

file

要不先發版?

初步分析問題後,咱們認爲這是:一個偶發的終端兼容性問題,有很大機率須要修改 RTC 端的編碼來適配,耗時很差評估。工具

「距離發版本的時間不到 2 周,要不就先發版本吧?」 這個請求被產品無情的拒絕了(此次真的感謝大家的堅持),測試也反饋了新的狀況:iPhone 6 也出現了綠屏,關閉 RTC 端的攝像頭也可能綠屏,Mac 攝像頭對着白色牆面也可能綠屏(測試的同窗們也太能折騰了),同時確認了 RTMP 編碼 RTMP 播放時相同場景不綠屏。測試

編碼仍是封裝的坑?

疑難雜症先會診,同編解碼的同窗一塊兒討論完後確認兩個可能的點:ui

1.編碼的 264 碼流不兼容。 2.封裝發送的 RTMP 數據不兼容。阿里雲

咱們制定了後續的排查方案:編碼

1.錄製 RTMP 編碼和 RTC 編碼的碼流作對比。 2.使用 FFmpeg 發送 RTC 編碼的碼流確認是否綠屏。code

1.碼流對比

咱們錄製了一個完整測試過程當中的碼流供編解碼同窗分析,經過粗略的對比發現一個重要的區別 vui 中色域相關信息不一致,色域會影響 yuv->rgb 的轉換。下圖是不綠屏碼流的 vui

file

經過這個線索,咱們作了兩個驗證測試:

1.咱們的 vui 是否會形成黑色顯示異常,經過攝像頭採集一個黑色手機,在圖像中造成大面積黑色。驗證結果:正常顯示。

2.按照正常碼流修改 vui。驗證結果:偶發綠屏。

算法的同窗接着作更深刻的分析。

2.封裝對比

FFmpeg 發佈 RTMP 的示例: ffmpeg -re -i green.h264 -c copy -f flv rtmp://localhost/live/livestream

測試結果:正常顯示測試中綠屏的場景。

封裝對比結論:封裝層問題,編解碼的同窗能夠休息了(感謝大家一塊兒填坑)。

封裝填坑記

1.懷疑一切

對於這種黑盒問題,咱們只能抱着懷疑一切的態度,開始各類猜想。

Metadata 排查

背景描述:咱們沒有發 Metadata(不是咱們懶,RTC 場景音視頻不必定都存在,沒有準確的 Metadata),是否是 Metadata 形成的(雖然咱們有本身的答案,Metadata 就算影響也是全局的,怎麼會是特定場景,還偶發)。

驗證方法:先用 FFmpeg 確認下,不發 Metadata 是否正常,若是正常再加 Metadata。(爲何不先加 Metadata?此次是真懶)

ffmpeg -re -i green.h264 -c copy -flvflags no_metadata -f flv rtmp://localhost/live/livestream

驗證結果:沒有綠屏,一切正常,Metadata 是無辜的。

SPS、PPS 排查

背景描述:RTC 場景 SPS、PPS 是可能變化的(屏幕共享,橫豎屏切換等),因此咱們將 SPS、PPS 經過 Sequence Header 和 IDR 幀進行了發送,FFmpeg 在這塊多是有區別的。

驗證方法:Wireshark 抓包,確認 FFmpeg 只發送了一次 Sequence Header, SPS、PPS 也隨 IDR 幀發送(錄製碼流中 IDR 前都有 SPS、PPS)。按 FFmpeg 的修改進行測試。

驗證結果:仍是綠屏,不過幾率有所降低。

驗證外延:SPS、PPS 全用 Sequence Header 發送,再也不隨 IDR 幀發送。

驗證結果:仍是綠屏,機率比前一方案更低。

警告:SPS、PPS 全用 Sequence Header 發送,兼容性差,FFplay 有機率播放失敗,vlc 沒法成功播放。咱們保留了 FFmpeg 相同的作法,繼續排查。

2.蛛絲馬跡

各類猜想驗證都失敗了,只好跟測試同窗不斷溝通,但願能夠尋找到些許線索,屢次溝通和鎖定一個比較有價值的線索:Mac 在關閉攝像頭時,RTMP 端播放綠屏機率較高。

定點排查

排查所有轉移到 Mac 關閉攝像頭這個場景,從埋點數據中確認:Mac 關閉攝像頭後, RTMP 發送的視頻數量再也不增長。

用 Wireshark 抓包確認關閉攝像頭時 Mac 端是否有發送視頻包,意外發現不只有視頻包,還有一些 seq 不變的視頻 Padding 包(有效內容爲 0),忽然感受黎明就在前方了,Review 完代碼確認 Padding 包影響了組幀邏輯,受 Padding 包影響大部分視頻幀被丟棄了,滿懷信心的修改完代碼。

file

所謂但願越大,失望越大。綠屏依舊存在,並且嚴重了不少,屢次測試下來,它成了必現問題,雖然很失望,可是從偶發問題到必現問題也是一個很大的「進步」。

3.黎明以前

最黑暗的時刻,問題終於畢現了,卻沒了有效的排查手段。

因爲 TCP 粘包問題,Wireshark 並不能徹底正確的解析出每個 RTMP 包,沒有一個高效的辦法查看 RTC 轉換的 RTMP 包。

在忘籬同窗的幫助下,經過 SRS 的 srs_rtmp_dump, 將 RTMP 數據保存爲了 FLV 文件,具體用法:

#編譯
git checkout 3.0release && ./configure --osx --with-librtmp --with-research && make -j8
#保存flv
./objs/research/librtmp/srs_rtmp_dump -r rtmp://127.0.0.1:1935/live/livestream -o output.flv > t.log

經過 FFmpeg 發佈 FLV 文件,綠屏問題重現了,莫名的興奮。

ffmpeg -re -i green.flv -c copy -flvflags no_metadata -f flv rtmp://localhost/live/livestream

雖然知道了 FLV 有問題,但是接下來對於 FLV 的分析卻犯難了,首先 FLV 格式分析的結果並無任何問題,用 FFmpeg 抽取出 FLV 中的 264,再發布時也正常。這個 FLV 文件用 FFplay 播放也是有錯誤信息的。

file

4.完美解決

當你機關用盡,看着代碼發呆的時候,休息一下多是個解決問題的好辦法。上班的地鐵上,終於有了頭緒:mark bit、stap,組幀邏輯判斷條件,致使了兩幀放到了一個 FLV 的 frame 中,形成部分終端不兼容。最終測試經過,版本正常發佈,感謝這個過程當中每一位同窗的支持與配合。

總結

  1. 即便 IDR 幀,也能夠很小,小到都填不滿一個 UDP 包。
  2. SPS、PPS 和很小的 IDR 能夠打到一個 STAP 的 RTP 包。
  3. 純 Padding 包必定認真對待,沒有實際數據的枷鎖,它們能夠作一些靈活的應用。
  4. 多幀封裝到一塊兒,有兼容性問題。
  5. 「事出反常必有妖」,代碼沒有玄學。
  6. 認真考慮數據的準確性,優先排查兩端的數據。
  7. 工具能夠顯著的提高效率。

福利

SRS 的 srs_flv_parser 中增長了 h264 video frame 中每一個 nalu 的信息打印,但願對你們之後填坑有所幫助,提早發佈預覽效果,看看綠屏妖的原形。

file

「視頻雲技術」你最值得關注的音視頻技術公衆號,每週推送來自阿里雲一線的實踐技術文章,在這裏與音視頻領域一流工程師交流切磋。

相關文章
相關標籤/搜索