• 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

  • 相关阅读:
    会计期间勿关闭后台打开
    动态创建VIEW
    约束变量
    JS 图片懒加载
    如何在Javascript中对数组的遍历使用异步函数
    JavaScript之闭包
    面试:数组去重你会几种呀?
    JavaScript重构技巧-降低函数复杂度
    JavaScript的内置对象
    js/jQuery获取data-*属性值
  • 原文地址:https://www.cnblogs.com/zzugyl/p/7611448.html
Copyright © 2020-2023  润新知