前言:做音視頻的小伙伴們多少都遇到過奇怪的BUG(如:卡頓、花屏、綠屏、變聲等),表象上矛盾點(diǎn)頗多,推理得出的結(jié)論都是:“不應(yīng)該??!”,最終你抽絲剝繭,發(fā)現(xiàn)真相只有一個(gè):“事出反常必有妖”! 作者:安果,阿里云高級技術(shù)專家,從事阿里云 RTC 服務(wù)器研發(fā) 奇怪現(xiàn)象背景:RTC 互動(dòng)中增加對 RTMP 的支持,實(shí)現(xiàn) RTC 與 RTMP 相互訂閱。 遇到一個(gè)奇怪的 BUG,遮擋住 RTC 端的攝像頭,有的 RTMP 播放端(iPad air 2,iPad mini 2/4)會(huì)偶發(fā)綠屏。 要不先發(fā)版?初步分析問題后,我們認(rèn)為這是:一個(gè)偶發(fā)的終端兼容性問題,有很大概率需要修改 RTC 端的編碼來適配,耗時(shí)不好評估。 “距離發(fā)版本的時(shí)間不到 2 周,要不就先發(fā)版本吧?” 這個(gè)請求被產(chǎn)品無情的拒絕了(這次真的感謝你們的堅(jiān)持),測試也反饋了新的情況:iPhone 6 也出現(xiàn)了綠屏,關(guān)閉 RTC 端的攝像頭也可能綠屏,Mac 攝像頭對著白色墻面也可能綠屏(測試的同學(xué)們也太能折騰了),同時(shí)確認(rèn)了 RTMP 編碼 RTMP 播放時(shí)相同場景不綠屏。 編碼還是封裝的坑?疑難雜癥先會(huì)診,同編解碼的同學(xué)一起討論完后確認(rèn)兩個(gè)可能的點(diǎn): 1.編碼的 264 碼流不兼容。 我們制定了后續(xù)的排查方案: 1.錄制 RTMP 編碼和 RTC 編碼的碼流做對比。 1.碼流對比我們錄制了一個(gè)完整測試過程中的碼流供編解碼同學(xué)分析,通過粗略的對比發(fā)現(xiàn)一個(gè)重要的區(qū)別 vui 中色域相關(guān)信息不一致,色域會(huì)影響 yuv->rgb 的轉(zhuǎn)換。下圖是不綠屏碼流的 vui 通過這個(gè)線索,我們做了兩個(gè)驗(yàn)證測試: 1.我們的 vui 是否會(huì)造成黑色顯示異常,通過攝像頭采集一個(gè)黑色手機(jī),在圖像中形成大面積黑色。驗(yàn)證結(jié)果:正常顯示。 2.按照正常碼流修改 vui。驗(yàn)證結(jié)果:偶發(fā)綠屏。 算法的同學(xué)接著做更深入的分析。 2.封裝對比FFmpeg 發(fā)布 RTMP 的示例: 測試結(jié)果:正常顯示測試中綠屏的場景。 封裝對比結(jié)論:封裝層問題,編解碼的同學(xué)可以休息了(感謝你們一起填坑)。 封裝填坑記1.懷疑一切對于這種黑盒問題,我們只能抱著懷疑一切的態(tài)度,開始各種猜測。 Metadata 排查背景描述:我們沒有發(fā) Metadata(不是我們懶,RTC 場景音視頻不一定都存在,沒有準(zhǔn)確的 Metadata),是不是 Metadata 造成的(雖然我們有自己的答案,Metadata 就算影響也是全局的,怎么會(huì)是特定場景,還偶發(fā))。 驗(yàn)證方法:先用 FFmpeg 確認(rèn)下,不發(fā) Metadata 是否正常,如果正常再加 Metadata。(為什么不先加 Metadata?這次是真懶)
驗(yàn)證結(jié)果:沒有綠屏,一切正常,Metadata 是無辜的。 SPS、PPS 排查背景描述:RTC 場景 SPS、PPS 是可能變化的(屏幕共享,橫豎屏切換等),所以我們將 SPS、PPS 通過 Sequence Header 和 IDR 幀進(jìn)行了發(fā)送,F(xiàn)Fmpeg 在這塊可能是有區(qū)別的。 驗(yàn)證方法:Wireshark 抓包,確認(rèn) FFmpeg 只發(fā)送了一次 Sequence Header, SPS、PPS 也隨 IDR 幀發(fā)送(錄制碼流中 IDR 前都有 SPS、PPS)。按 FFmpeg 的修改進(jìn)行測試。 驗(yàn)證結(jié)果:還是綠屏,不過概率有所下降。 驗(yàn)證外延:SPS、PPS 全用 Sequence Header 發(fā)送,不再隨 IDR 幀發(fā)送。 驗(yàn)證結(jié)果:還是綠屏,概率比前一方案更低。 警告:SPS、PPS 全用 Sequence Header 發(fā)送,兼容性差,F(xiàn)Fplay 有概率播放失敗,vlc 無法成功播放。我們保留了 FFmpeg 相同的做法,繼續(xù)排查。 2.蛛絲馬跡各種猜測驗(yàn)證都失敗了,只好跟測試同學(xué)不斷溝通,希望可以尋找到些許線索,多次溝通和鎖定一個(gè)比較有價(jià)值的線索:Mac 在關(guān)閉攝像頭時(shí),RTMP 端播放綠屏概率較高。 定點(diǎn)排查排查全部轉(zhuǎn)移到 Mac 關(guān)閉攝像頭這個(gè)場景,從埋點(diǎn)數(shù)據(jù)中確認(rèn):Mac 關(guān)閉攝像頭后, RTMP 發(fā)送的視頻數(shù)量不再增加。 用 Wireshark 抓包確認(rèn)關(guān)閉攝像頭時(shí) Mac 端是否有發(fā)送視頻包,意外發(fā)現(xiàn)不僅有視頻包,還有一些 seq 不變的視頻 Padding 包(有效內(nèi)容為 0),突然感覺黎明就在前方了,Review 完代碼確認(rèn) Padding 包影響了組幀邏輯,受 Padding 包影響大部分視頻幀被丟棄了,滿懷信心的修改完代碼。 所謂希望越大,失望越大。綠屏依舊存在,而且嚴(yán)重了很多,多次測試下來,它成了必現(xiàn)問題,雖然很失望,但是從偶發(fā)問題到必現(xiàn)問題也是一個(gè)很大的“進(jìn)步”。 3.黎明之前最黑暗的時(shí)刻,問題終于畢現(xiàn)了,卻沒了有效的排查手段。 由于 TCP 粘包問題,Wireshark 并不能完全正確的解析出每一個(gè) RTMP 包,沒有一個(gè)高效的辦法查看 RTC 轉(zhuǎn)換的 RTMP 包。 在忘籬同學(xué)的幫助下,通過 SRS 的 srs_rtmp_dump, 將 RTMP 數(shù)據(jù)保存為了 FLV 文件,具體用法:
通過 FFmpeg 發(fā)布 FLV 文件,綠屏問題重現(xiàn)了,莫名的興奮。
雖然知道了 FLV 有問題,可是接下來對于 FLV 的分析卻犯難了,首先 FLV 格式分析的結(jié)果并沒有任何問題,用 FFmpeg 抽取出 FLV 中的 264,再發(fā)布時(shí)也正常。這個(gè) FLV 文件用 FFplay 播放也是有錯(cuò)誤信息的。 4.完美解決當(dāng)你無計(jì)可施,看著代碼發(fā)呆的時(shí)候,休息一下可能是個(gè)解決問題的好辦法。上班的地鐵上,終于有了頭緒:mark bit、stap,組幀邏輯判斷條件,導(dǎo)致了兩幀放到了一個(gè) FLV 的 frame 中,造成部分終端不兼容。最終測試通過,版本正常發(fā)布,感謝這個(gè)過程中每一位同學(xué)的支持與配合。 總結(jié)
福利SRS 的 srs_flv_parser 中增加了 h264 video frame 中每個(gè) nalu 的信息打印,希望對大家以后填坑有所幫助,提前發(fā)布預(yù)覽效果,看看綠屏妖的原形。
|
|