signed

QiShunwang

“诚信为本、客户至上”

srs直播时复制子流,但损失了直播开始的20s数据

2021/3/21 10:03:15   来源:

srs分为两级:源站(origin-node)和分发(edge-node)节点
流程是源站负责接受主播推流(rtmp),forward一路流到edge-node,同时,利用ffmpeg产生(转码)
出两路子流,这样就有三路流(原始流,标准流和低画质流)。edge-node实现ts切片,产生hls流。
由三路hls流组成一路adaptive-hls流。播放器hls-player支持adaptive协议,根据客户端网络状况,
自动选择不同速率的子流来适应。
测试中发现,转码流启动速度太慢,导致开头的约20s时间内,无法产生切片文件,这个损失是致命的。
针对ff-transcoding-thread启动速度太慢的问题,有两个可能的原因:
1.启动thread的速度慢。这可以用线程池解决,实际是进程池。
2.拉到rtmp流data太慢。这个原因需要定位。
先用建立thread-pool方式测试看看效果。这需要预先分配好推流地址(rtmp-publish-url)。
因为ffmpeg转码进程需要取得拉流地址才行,如下:
    sprintf(sCmd,"./objs/ffmpeg -d -i %s -sc_threshold 0 -s %s -vcodec libx264 -b:v 800k -bufsize 800k -maxrate 1000k "
        "-profile:v high -preset faster -tune psnr "
        "-c:a copy -f flv %s 1>/dev/null 2>&1 &",p->inUrl,outSize.c_str(),p->outUrl);
    ret=system(sCmd);
有了输入地址,输出地址也就可以确定,建立一个映射关系即可。
测试时,却发现根本不可行!原因在于ffmpeg会不断尝试去拉流,srs几乎是被确认受到了攻击!
快速不断的Play请求发过来,间隔在30ms左右。由于这个流还没有进来,ffmpeg又不管不顾地拼命请求,
于是srs很快达到最大并发数量限制。
[2021-03-20 01:33:39.971][Trace][123006][29tj9m06] source url=/live/ap01-10215261, ip=127.0.0.1, cache=1, is_edge=0, source_id=[123006][]
[2021-03-20 01:33:39.971][Trace][123006][29tj9m06] create consumer, active=0, queue_size=0.00, jitter=30000000
[2021-03-20 01:33:39.971][Trace][123006][29tj9m06] set fd=16, SO_SNDBUF=2626560=>175000, buffer=350ms
[2021-03-20 01:33:39.971][Trace][123006][29tj9m06] start play smi=0ms, mw_sleep=350, mw_msgs=8, realtime=0, tcp_nodelay=0
[2021-03-20 01:33:39.971][Trace][123006][8nkw4bel] ignore AMF0/AMF3 command message.
[2021-03-20 01:33:39.971][Trace][123006][8nkw4bel] client identified, type=Play, vhost=127.0.0.1, app=live, stream=ap01-10215261, param=, duration=-1ms
[2021-03-20 01:33:39.971][Trace][123006][8nkw4bel] connected stream, tcUrl=rtmp://127.0.0.1:1935/live, pageUrl=, swfUrl=, schema=rtmp, vhost=__defaultVhost__, port=1935, app=live, stream=ap01-10215261, param=, a
rgs=null
[2021-03-20 01:33:39.971][Trace][123006][15l9o302] set fd=18, SO_SNDBUF=2626560=>175000, buffer=350ms
[2021-03-20 01:33:39.971][Trace][123006][15l9o302] start play smi=0ms, mw_sleep=350, mw_msgs=8, realtime=0, tcp_nodelay=0
[2021-03-20 01:33:40.296][Trace][123006][3708p0lv] complex handshake success
[2021-03-20 01:33:40.296][Trace][123006][334i81y4] complex handshake success
[2021-03-20 01:33:40.308][Trace][123006][94381115] complex handshake success
[2021-03-20 01:33:40.308][Trace][123006][24y2p065] complex handshake success
[2021-03-20 01:33:40.335][Trace][123006][3708p0lv] connect app, tcUrl=rtmp://127.0.0.1:1935/live, pageUrl=, swfUrl=, schema=rtmp, vhost=127.0.0.1, port=1935, app=live, args=null
[2021-03-20 01:33:40.336][Trace][123006][3708p0lv] protocol in.buffer=0, in.ack=0, out.ack=0, in.chunk=128, out.chunk=128
[2021-03-20 01:33:40.336][Trace][123006][334i81y4] connect app, tcUrl=rtmp://127.0.0.1:1935/live, pageUrl=, swfUrl=, schema=rtmp, vhost=127.0.0.1, port=1935, app=live, args=null
[2021-03-20 01:33:40.336][Trace][123006][334i81y4] protocol in.buffer=0, in.ack=0, out.ack=0, in.chunk=128, out.chunk=128
[2021-03-20 01:33:40.349][Trace][123006][94381115] connect app, tcUrl=rtmp://127.0.0.1:1935/live, pageUrl=, swfUrl=, schema=rtmp, vhost=127.0.0.1, port=1935, app=live, args=null
[2021-03-20 01:33:40.349][Trace][123006][94381115] protocol in.buffer=0, in.ack=0, out.ack=0, in.chunk=128, out.chunk=128
[2021-03-20 01:33:40.350][Trace][123006][24y2p065] connect app, tcUrl=rtmp://127.0.0.1:1935/live, pageUrl=, swfUrl=, schema=rtmp, vhost=127.0.0.1, port=1935, app=live, args=null
--More--
我修改了srs接入Play请求的code进行拒绝。但这也没用,在这个流被publish的瞬间,
无数阻塞在net sock中的消息汹涌而至,让srs进入假死状态。
这个测试结果也让我明白了,拉到rtmp流data太慢极可能也是这个原因。
于是,我把转码进程移到edge-node来实现,当edge收到这个流后,自然origin-edge上面的流服就
建立起来了,就可以拉到流了。经过修改和调测,直播开关头损失由20s降到2s。
1~2s本就是rtmp流服建立的时间,不可能再缩减了。并且,这个时间损失,是完全可以被用户接受的。