rtmpdump的librtmp时间戳有问题,服务器会断开连接

探讨RTMP协议中Extended Timestamp字段的发送机制及其在不同软件实现中的差异,包括FMLE、nginx-rtmp和librtmp等。分析了如何处理Extended Timestamp以确保长时间推流的稳定性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

# header
0x44    
0xff    0xff    0xff    0x00    0x01    0x19    0x08
# extended timestamp
0x7f    0xff    0xf8    0x00    
# body 
0xaf    0x01    0x01    0x40
0x22    0x80    0xa3    0x7f    0xf8    0x85    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    
#header
0xc4    
# extended timestamp
# error here
#body
0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d
0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d    0x2d


对于0xC这种后续的chunk包的extended timestamp该不该发,rtmp协议中说是不发,但是FMLE是发的,推流超过4.5小时就需要用extended timestamp了。

rtmpdump里面的librtmp,不会发这个包,(ffmpeg里面用--enable-librtmp就会使用这个rtmp的库),而且是在开始就会发这个包。

6.1.3. Extended Timestamp

This field is transmitted only when the normal time stamp in the
chunk message header is set to 0x00ffffff. If normal time stamp is
set to any value less than 0x00ffffff, this field MUST NOT be
present. This field MUST NOT be present if the timestamp field is not
present. Type 3 chunks MUST NOT have this field.

有可能是adobe变更了这个协议,也就是说,FMLE给FMS,FMS给flash-player,都是带这个时间戳的。

收包时,服务器端则需要检测下,若接下来的4字节不是extended timestamp,那么就忽略就好了。

发包时,只能采取配置,要么发,要么不发。默认发就好了。

看nginx-rtmp代码:

ngx_rtmp_recv(ngx_event_t *rev)
{
    for( ;; ) {
        /* parse headers */
        if (b->pos == b->start) {
            /* chunk basic header */
            fmt  = (*p >> 6) & 0x03;
            csid = *p++ & 0x3f;
            if (fmt <= 2 ) {
                /* timestamp: big-endian 3b -> little-endian 4b */
                pp = (u_char*)timestamp;
                ext = (timestamp == 0x00ffffff);
                if (fmt <= 1) {
                    /* size: big-endian 3b -> little-endian 4b type*/
                    pp = (u_char*)&h->mlen;
                    h->type = *(uint8_t*)p++;
                    if (fmt == 0) {
                        /* stream: little-endian 4b -> little-endian 4b */
                        pp = (u_char*)&h->msid;
                    }
                }
            }
            /* extended header */
            if (ext) {
                pp = (u_char*)timestamp;
                pp[3] = *p++;
                pp[2] = *p++;
                pp[1] = *p++;
                pp[0] = *p++;
            }
可见,不管是什么chunk,只要有extended-timestamp,nginx-rtmp都会读这个。所以nginx-rtmp对接FMLE是没有问题的,对接librtmp有问题。

更好的做法是判断下读出来的extended timestamp是否是和之前的一样,如果不是一样说明没有发,就忽略。

nginx-rtmp发包的逻辑:

ngx_rtmp_prepare_message
{
    /* create fmt3 header for successive fragments */
    thsize = p - out->buf->pos;
    ngx_memcpy(th, out->buf->pos, thsize);
    th[0] |= 0xc0;
    /* message header */
    if (fmt <= 2) {
    }

    /* extended header */
    if (ext_timestamp) {
        pp = (u_char*)&ext_timestamp;
        *p++ = pp[3];
        *p++ = pp[2];
        *p++ = pp[1];
        *p++ = pp[0];

        /* This CONTRADICTS the standard 
         * but that's the way flash client
         * wants data to be encoded;
         * ffmpeg complains */
        if (cscf->play_time_fix) {
            ngx_memcpy(&th[thsize], p - 4, 4);
            thsize += 4;
        }
    }

nginx-rtmp还特意说明了flash客户端就是和rtmp规范不一样。

out->buf->pos就是指向包的第一个chunk,若有extended-timestamp,那么肯定会在第一个包加上extended timestamp;后面还有个th和thsize,就是给后续的type=3的chunk包的,会加上这4字节的extended timestamp:

        /* This CONTRADICTS the standard 
         * but that's the way flash client
         * wants data to be encoded;
         * ffmpeg complains */
        if (cscf->play_time_fix) {
            ngx_memcpy(&th[thsize], p - 4, 4);
            thsize += 4;
        }

    /* append headers to successive fragments */
    for(out = out->next; out; out = out->next) {
        out->buf->pos -= thsize;
        ngx_memcpy(out->buf->pos, th, thsize);
    }


所以nginx-rtmp收发包都是需要这个extended-timestamp,对于chunk type为3的包。

另外,把chunksize设置大一点,最大是65536,避免发type=3的chunk包,也是一个很好的方法。不过视频的I帧一般较大,超过64KB也有可能。

The maximum chunk size can be 65536 bytes and minimum 128 bytes.

按照这种规则,即type=3的chunk也发extended-timestamp,是没有问题:



FMLE一直没有断开,客户端也没有断开。

服务器端是srs(simple rtmp server),也没有断开:


时间已经超过了24位,使用extended-timestamp:

(gdb) p /x 21039918
$1 = 0x1410b2e


而nginx呢,是采用第一个包发完全的extended-timestamp,但是后续都是发type=1的chunk,即时间戳差值。


完毕。

评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

winlinvip

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值