rtmp推流時間戳兼容問題

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

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

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

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個小時,實在不該該。
因而找到對應時間戳的地方,加一個初始值。對應於:ide

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

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

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

第一次嘗試:
去掉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

相關文章
相關標籤/搜索