rtmp推流时间戳兼容问题_移动开发_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > 移动开发 > rtmp推流时间戳兼容问题

rtmp推流时间戳兼容问题

 2017/9/29 16:43:13  水上云天  程序员俱乐部  我要评论(0)
  • 摘要:一直用简单的librtmp或者其他开源推流实现方式。没有太关注细节问题。直到最近一次测试长时间推流。遇到了3字节时间戳溢出问题,即时间戳超过0xffffff,服务器断开。复现方式:用yasea推流到SRS或者Nginx-rtmp。yasea版本要求2017-08-30以及以前的版本。SRS不做特殊要求,本次使用v2.0.243release版。Nginx-rtmp版本不做特殊要求,本次使用Nginx:1.13.3。yasea推流到srs,超过4.5小时,当时间戳超过0xffffff,srs报错
  • 标签:问题 兼容

一直用简单的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);
注释掉下面一行:

class="pl-smi">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的代码如下:

if (extendedTimestamp > 0) {
Util.writeUnsignedInt32(out, extendedTimestamp);
}

推流时间戳超过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

发表评论
用户名: 匿名