rtmp推流時間戳兼容問題

一直用簡單的librtmp或者其他開源推流實現方式。沒有太關注細節問題。
直到最近一次測試長時間推流。遇到了3字節時間戳溢出問題,即時間戳超過0xffffff,服務器斷開。

復現方式:
用yasea推流到SRS或者Nginx-rtmp。
yasea版本要求2017-08-30以及以前的版本。
SRS不做特殊要求,本次使用v2.0.243 release版。
Nginx-rtmp版本不做特殊要求,本次使用Nginx: 1.13.3。

yasea推流到srs,超過4.5小時,當時間戳超過0xffffff,srs報錯:

chunk stream is fresh, fmt must be 0, actual is 1. cid=25, ret=2001(Resource temporarily unavailable)
read message header failed. ret=2001(Resource temporarily unavailable)
recv interlaced message failed. ret=2001(Resource temporarily unavailable)
thread process message failed. ret=2001(Resource temporarily unavailable)
thread recv cycle failed, ignored and retry, ret=2001
recv thread failed. ret=2001(Resource temporarily unavailable)
cleanup when unpublish
stream service cycle failed. ret=2001(Resource temporarily unavailable)

yasea推流到Nginx-rtmp,超過4.5小時,沒問題。

第一反應不禁懷疑,srs兼容性有問題。隨後用obs推流到srs和Nginx-rtmp,超過5個小時都沒問題。
仔細閱讀rtmp_specification_1.0.pdf 6.1.2 Chunk Message Header
page16開始。
yasea只發送了Type=0和Type=3的Chunks。
唯一不確定的環節就是extended timestamp的使用。

於是查看yasea代碼和srs代碼,既然是時間戳溢出處理的問題,就專注於這個角度。
每次測試都要等待4.5個小時,實在不應該。
於是找到對應時間戳的地方,加一個初始值。對應於:

audio.getHeader().setAbsoluteTimestamp(dts+0x00ffefff); 
video.getHeader().setAbsoluteTimestamp(dts+0x00ffefff);
rtmpPacket.getHeader().setAbsoluteTimestamp((int) chunkStreamInfo.markAbsoluteTimestampTx()+0x00ffefff);

這樣很快就運行到ffffff了。幾分鐘。

在分包發送的接口處打印時間戳日誌,extended timestamp對應於:
com/github/faucamp/simplertmp/packets/RtmpHeader.java中writeTo()中
case TYPE_0_FULL: 和 case TYPE_3_RELATIVE_SINGLE_BYTE:

第一次嘗試:
去掉Type=3中,Util.writeUnsignedInt32(out, extendedTimestamp);
註釋掉下面一行:

Util.writeUnsignedInt32(out, extendedTimestamp);
推流時間戳超過0xffffff,推srs正常,推Nginx-rtmp報錯。


第二次嘗試:
Type=3的extended timestamp保證在Type=0後使用
只需要更改下面一句:
if (absoluteTimestamp >= 0xffffff)
改成
if (extendedTimestamp >= 0)

推流時間戳超過0xffffff,推srs偶爾報錯,推Nginx-rtmp正常。
偶爾還是會出現問題。原因未明。

第三次嘗試:
Type=3的時間戳和同一包分chunk時Type=0的時間戳,保持一致。
在上一次基礎上改Type=3的代碼如下:

推流時間戳超過0xffffff,推srs正常,推Nginx-rtmp正常。

然而在rtmp_specification_1.0.pdf文檔中確實沒有明確的規定。這個時間戳應該怎麼做。

微信羣裏和srs、yasea兩個項目的作者溝通,發現確實是這個問題。
srs大神winlin科普了一下,考慮周全的話,兩種做法都要兼容。
如果Type=3有時間戳,這個時間戳就應該等於同一包中Type=0的時間戳。
如果Type=3沒有時間戳。就用同一包中Type=0的傳上來的時間戳。
實際上ffmpeg是這麼做的,srs也是這麼做的,Nginx-rtmp並沒有兼容兩者。
爲了簡單實用Type=1或者2,就不要發了。
所以是yasea引用的faucamp/simplertmp庫有bug。
相關的問題,winlin的博客也有提到。參考:http://blog.csdn.net/win_lin/article/details/13363699

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章