新開發(fā)的組播播放器赦抖,發(fā)現(xiàn)在視頻源運動劇烈的時候會出現(xiàn)比較嚴重的花屏甸赃。開始以為是組播丟包導(dǎo)致的,但打印了丟包檢測的日志胸嘴,發(fā)現(xiàn)并沒有發(fā)生丟包的時候也會出現(xiàn)花屏。開始懷疑是視頻源發(fā)送的問題斩祭,于是在接收端把接收到的H.264數(shù)據(jù)寫成文件劣像,再用Elecard StreamEye顯示碼流圖像。發(fā)現(xiàn)StreamEye里面圖像也是花的摧玫,于是結(jié)合wireshark抓包繼續(xù)分析接收到的組播數(shù)據(jù)耳奕。結(jié)果在wireshark中看到,局域網(wǎng)內(nèi)有其他設(shè)備也會偶爾性的向組播組發(fā)送數(shù)據(jù)诬像,導(dǎo)致RTP聚包解析出錯屋群,于是根據(jù)抓包的結(jié)果,把其他發(fā)送組播的設(shè)備給關(guān)閉掉坏挠。
但是關(guān)閉后芍躏,依然有很嚴重的花屏現(xiàn)象。這時候開始檢查搭建的環(huán)境是否有問題降狠,浪費了一些時間对竣,結(jié)果發(fā)現(xiàn)其他環(huán)境上面也有花屏的問題庇楞。正當(dāng)完全沒有頭緒的時候,無意中錄了一段只有30幾幀的短碼流否纬。這段短碼流吕晌,用ffplay播放也是花屏的,但是用eseye_u.exe播放是正常的临燃!但奇怪的是睛驳,ffplay播放的時候并沒有出現(xiàn)什么報錯的信息,但是解出來的碼流就是花的谬俄。用StreamEye的SAnalyzer.exe分析錄下來的碼流柏靶,發(fā)現(xiàn)每一幀都是由多個NAL組成的。IDR幀由2個NAL組成溃论,P幀由4個NAL組成屎蜓。難道說ffmpeg的h.264解碼器有bug?于是嘗試更新ffmpeg版本钥勋,結(jié)果發(fā)現(xiàn)升級到4.2.1炬转,解碼依然是花的。又嘗試給ffplay更換解碼器算灸,用-vcodec libopenh264選項更換成openh264的解碼器扼劈。由于視頻源是high profile的,之前看到網(wǎng)上說openh264只支持baseline profile菲驴,本來估計會解碼失敗荐吵。結(jié)果解碼成功了,而且并沒有花屏赊瞬!
PS:這時候先煎,去翻了一下openh264的官方更新說明。早在2015發(fā)布的1.5.0版本巧涧,就有說明
- Decoder support of 'Constrained High Profile' of H.264
Note:
'Constrained High Profile' = 'Constrained Baseline Profile' plus:
CABAC
Intra 8x8 mode support
8x8 transform
QP scaling matrices
QP per chroma component
Mono 4:0:0 (experimental)
Weighted prediction
由于我們用的視頻流是實時直播的薯蝎,也沒有B幀,所以是符合'Constrained High Profile'的谤绳。而B幀的解碼占锯,是2019年發(fā)布的2.0.0版本才支持的,不過我還沒有測試過
- B-frame decoding support for Main and High Profile with two test cases
回到正題缩筛,這時候消略,只需要把解碼器換成libopenh264,花屏的問題就可以解決了瞎抛。但是總是有不甘心疑俭,沒道理ffmpeg自帶h264解碼器,會有這么嚴重的bug〕В回去看了下ffmpeg代碼啄寡,h264解碼器中AVOption也沒什么會導(dǎo)致花屏的參數(shù)。后面又錄了幾次組播接收到的碼流哩照,終于有一次ffmpeg解碼報錯了
[h264 @ 00929f40] reference picture missing during reorder
[h264 @ 00929f40] Missing reference picture, default is 2
[h264 @ 009902c0] reference picture missing during reorder
[h264 @ 009902c0] Missing reference picture, default is 65546
本身這一類報錯信息在解碼丟包的視頻流中會經(jīng)常出現(xiàn)挺物。但根據(jù)這些報錯信息,在stackoverflow中搜到一篇問答
https://stackoverflow.com/questions/27870545/decode-h264-video-using-libavcodec-c
Every input packet (avpkt) for avcodec_decode_video2 should contain full (and only) data for one frame i.e. it shouldn't be truncated in the middle of the frame NALs.
這句話一言驚醒了夢中人飘弧。于是回頭看识藤,eseye_u.exe中每一幀的長度是屬于該幀的所有NAL長度總和,而我送給avcodec的avpkt.size總是小于這個總長度次伶。想起來之前在SAnalyzer.exe中看到一幀是分成多個nal的痴昧,bug產(chǎn)生的原因已經(jīng)很清楚了,就是沒有把完整的一幀送給解碼器冠王,而是一個一個nal發(fā)送的赶撰。