bilibili / flv.js

HTML5 FLV Player
Apache License 2.0
22.96k stars 3.38k forks source link

video缓存,延迟问题 #274

Open mwb-27 opened 6 years ago

mwb-27 commented 6 years ago

video标签本身有缓存机制,我使用mse播放实时流,currentTime永远比buffered.end要慢将近1.5,导致我直播有延迟,请问这个问题该怎么解决。我试过将currentTime设置为buffered.end 的事件,但是会触发waiting事件,表示下一帧不可播放。希望有懂的人给讲解下这里的机制并谈一下可行的解决方案

xqq commented 6 years ago

你减个0.5秒不就完了

mwb-27 commented 6 years ago

@xqq 这个我明白~~那也就是说这个将近1.5s的延迟是没有办法再进一步优化的是吧?我是希望在不卡顿的情况下尽可能的降低延迟

xqq commented 6 years ago

减0.5秒可以优化到0.5秒

xqq commented 6 years ago

另外可以尝试设置enableStashBuffer: false,会降低效率

mwb-27 commented 6 years ago

@xqq 好的,谢谢。我还想请教下我这里碰到的问题,就是这个waiting事件触发的条件,文档上看到是说下一帧不可播放时会触发。但是我看了buffered.end() 的时间明明比currentTime要多1.5秒时间,为什么就触发了waiting事件呢?这里的下一帧指的是I帧还是什么?这个让我很疑惑

mwb-27 commented 6 years ago

@xqq 这个是导致我无法降低延迟的关键,我必须让currentTime慢于buffered.end() 1.5s以上才能确保不触发waiting事件

xqq commented 6 years ago

不是很清楚,waiting事件抛出时视频有卡住么

mwb-27 commented 6 years ago

@xqq 是的,waiting抛出时视频会卡一下,因为触发waiting时currentTime是不会更新的,很快又会触发playing事件,应该是很快下一帧的数据解码完成是可播放的了。目前就是因为这个卡顿现象我没法再进一步优化延迟。

d02540220 commented 6 years ago

@mwb-27 你直播延时大概多少秒?

winshining commented 6 years ago

@d02540220 flv.js使用http-flv方式播放,1秒不到,我是最近有网友反馈使用flv.js播放我的直播服务器拉流有问题时,我调试时测试的(要开启gop_cache选项),flv.js播放的首屏时间比vlc少得多,flv.js表现非常优秀。

mwb-27 commented 6 years ago

@d02540220 我现在延迟控制在2s以内,大致在1.5s左右

mwb-27 commented 6 years ago

@winshining 我没有用flv.js,我直接调用的MSE的API实现的直播。我后端给的视频流是fmp4的

notedit commented 6 years ago

@mwb-27 现在确实有这个问题 延迟大概有1.5s ffplay no buffer 模式可以做到0.4s的延迟

chengsu commented 5 years ago

我测试ip摄像头,延迟大约在700ms左右,还有地方可以减少延迟吗?

服务端用node做代理通过websocket推到前端

ffmpeg命令

ffmpeg -rtsp_transport tcp -i rtsp://xxxxxxxx -c copy -f flv http://localhost:3004

前端代码

<script src="//cdn.bootcss.com/flv.js/1.5.0/flv.js"></script>
<video id="videoElement" width="1850"></video>
<script>
    if (flvjs.isSupported()) {
        var video = videoElement = document.getElementById('videoElement');
        var flvPlayer = flvjs.createPlayer({
            type: 'flv',
            isLive: true,
            url: 'ws://' + location.search.slice(1),
        }, {
            enableStashBuffer: false
        });
        flvPlayer.attachMediaElement(videoElement);
        flvPlayer.load();

        setTimeout(() => {
            flvPlayer.play();
        }, 2000)

        setInterval(() => {
            if (!video.buffered.length) {
                return;
            }
            let end = video.buffered.end(0);
            let diff = end - video.currentTime;
            if (diff >= 1.5) {
                video.currentTime = end;
            }
        }, 3000);
    }
</script>

对比 jsmpeg 延迟可以做到1s内,应该在300ms左右

DenySu commented 5 years ago

我测试ip摄像头,延迟大约在700ms左右,还有地方可以减少延迟吗?

服务端用node做代理通过websocket推到前端

ffmpeg命令

ffmpeg -rtsp_transport tcp -i rtsp://xxxxxxxx -c copy -f flv http://localhost:3004

前端代码

<script src="//cdn.bootcss.com/flv.js/1.5.0/flv.js"></script>
<video id="videoElement" width="1850"></video>
<script>
    if (flvjs.isSupported()) {
        var video = videoElement = document.getElementById('videoElement');
        var flvPlayer = flvjs.createPlayer({
            type: 'flv',
            isLive: true,
            url: 'ws://' + location.search.slice(1),
        }, {
            enableStashBuffer: false
        });
        flvPlayer.attachMediaElement(videoElement);
        flvPlayer.load();

        setTimeout(() => {
            flvPlayer.play();
        }, 2000)

        setInterval(() => {
            if (!video.buffered.length) {
                return;
            }
            let end = video.buffered.end(0);
            let diff = end - video.currentTime;
            if (diff >= 1.5) {
                video.currentTime = end;
            }
        }, 3000);
    }
</script>

对比 jsmpeg 延迟可以做到1s内,应该在300ms左右

这样不会出现跳帧的现象么?

chengsu commented 5 years ago

@DenySu 有跳帧,但是我的应用场景要求低延迟,可以容忍跳帧。这里也可以改成如果延迟太大,就加快播放速度,延迟降下来后再恢复正常播放速度,但是实测还是会有跳帧。

evilArsh commented 5 years ago

为啥我有1.8秒的延迟啊,我用的node-media-server

tianwen2976 commented 4 years ago

@mwb-27 请问这个currentTime与buffered.end()差1.5s的问题解决了么,我也遇到了。

chengsu commented 4 years ago

@evilArsh 1.8s应该是node-media-server内部缓存了关键帧。一般像机编码默认都是2s一个关键帧,如果你在这2s之内点播,node-media-server会直接发前一个关键帧,这个就可能延迟了几百毫秒,而且这个延迟播放时也不会追上来。如果要在浏览器上实现1s内的实时效果,最好还是用webassembly加载解码器直接解码视频,再由canvas画视频,基于video和mse的播放方案很难克服。

17Sdubin commented 4 years ago

@mwb-27 现在确实有这个问题 延迟大概有1.5s ffplay no buffer 模式可以做到0.4s的延迟

请问1.5s的延迟能再缩短吗?我现在也遇到这个问题

17Sdubin commented 4 years ago

@d02540220 flv.js使用http-flv方式播放,1秒不到,我是最近有网友反馈使用flv.js播放我的直播服务器拉流有问题时,我调试时测试的(要开启gop_cache选项),flv.js播放的首屏时间比vlc少得多,flv.js表现非常优秀。

请问大神,1s不到,怎么做到的,video自带的缓存,不是缩短到1.5秒就到极限了吗,你用什么办法解决的?

17Sdubin commented 4 years ago

@xqq 好的,谢谢。我还想请教下我这里碰到的问题,就是这个waiting事件触发的条件,文档上看到是说下一帧不可播放时会触发。但是我看了buffered.end() 的时间明明比currentTime要多1.5秒时间,为什么就触发了waiting事件呢?这里的下一帧指的是I帧还是什么?这个让我很疑惑

请问大神,你这个问题解决了吗?

ouzhou commented 4 years ago
video.currentTime = end;的方案关键是还会导致跳帧, 没有其他办法了吗
wjy18666 commented 4 years ago

我测试ip摄像头,延迟大约在700ms左右,还有地方可以减少延迟吗?

服务端用node做代理通过websocket推到前端

ffmpeg命令

ffmpeg -rtsp_transport tcp -i rtsp://xxxxxxxx -c copy -f flv http://localhost:3004

前端代码

<script src="//cdn.bootcss.com/flv.js/1.5.0/flv.js"></script>
<video id="videoElement" width="1850"></video>
<script>
    if (flvjs.isSupported()) {
        var video = videoElement = document.getElementById('videoElement');
        var flvPlayer = flvjs.createPlayer({
            type: 'flv',
            isLive: true,
            url: 'ws://' + location.search.slice(1),
        }, {
            enableStashBuffer: false
        });
        flvPlayer.attachMediaElement(videoElement);
        flvPlayer.load();

        setTimeout(() => {
            flvPlayer.play();
        }, 2000)

        setInterval(() => {
            if (!video.buffered.length) {
                return;
            }
            let end = video.buffered.end(0);
            let diff = end - video.currentTime;
            if (diff >= 1.5) {
                video.currentTime = end;
            }
        }, 3000);
    }
</script>

对比 jsmpeg 延迟可以做到1s内,应该在300ms左右

能提供下你的node.js转码代码吗?我的也是连接网络摄像头,延迟居然10-20s去了,也是用的ffmpeg,代码如下: var express = require('express') var expressWebSocket = require('express-ws') var ffmpeg = require('fluent-ffmpeg') var WebSocket = require('websocket-stream') var webSocketStream = require('websocket-stream/stream')

function localServer() { let app = express(); app.use(express.static(__dirname)); expressWebSocket(app, null, { perMessageDeflate: true }); app.ws("/rtsp/:id/", rtspRequestHandle) app.listen(8888); console.log("express listened") } function rtspRequestHandle(ws, req) { console.log("rtsp request handle"); const stream = webSocketStream(ws, { binary: true, browserBufferTimeout: 1000000 }, { browserBufferTimeout: 1000000 }); let url = req.query.url; console.log("rtsp url:", url); console.log("rtsp params:", req.params); try { ffmpeg(url) .addInputOption("-analyzeduration", "100000", "-max_delay", "1000000") // .addInputOption("-rtsp_transport", "tcp", "-buffer_size", "102400") // 这里可以添加一些 RTSP 优化的参数 .on("start", function () { console.log(url, "Stream started."); }) .on("codecData", function () { console.log(url, "Stream codecData.") // 摄像机在线处理 }) .on("error", function (err) { console.log(url, "An error occured: ", err.message); }) .on("end", function () { console.log(url, "Stream end!"); // 摄像机断线的处理 }) .outputFormat("flv").videoCodec("copy").noAudio().pipe(stream); } catch (error) { console.log(error); } }

localServer()

wjy18666 commented 4 years ago

@xqq 是的,waiting抛出时视频会卡一下,因为触发waiting时currentTime是不会更新的,很快又会触发playing事件,应该是很快下一帧的数据解码完成是可播放的了。目前就是因为这个卡顿现象我没法再进一步优化延迟。

这个你后来解决了吗?我现在也有这样的情况,设置时间过短也会触发waiting事件,感觉要不跳帧,要不卡主,大部分都是waiting的loading卡主

wjy18666 commented 4 years ago

你减个0.5秒不就完了

我的也是按照你的方案来,也会一直触发waiting,最少1.5s,但是业务需求是1s内,不能比rtmp延迟大

shady-xia commented 3 years ago

是会有这样的问题, 建议使用调整播放倍速的方式,比如延迟大于某个值,将video.playbackRate设为1.1,小于即恢复正常,这个是比较好的追帧方案