FFmpeg推流结束后WebSocket提前断开,如何保证视频完整播放?
解决FFmpeg推流结束后WebSocket提前断开导致视频播放不完整的问题
问题背景
使用FFmpeg将MP4视频推流至RTMP服务器,前端通过WebSocket结合flv.js播放时,整体流程正常,但视频接近尾声时WebSocket连接会提前断开,导致视频无法完整播放。原因是FFmpeg完成推流后立即断开RTMP连接,而前端因播放延迟尚未展示全部帧。
解决方案
方法1:FFmpeg推流后追加空流延迟断开
通过FFmpeg将原视频与一段静音黑屏的空流拼接,延长推流时长,给前端足够的缓冲时间播放完原视频内容。
修改Node.js端的FFmpeg推流命令,添加空流拼接逻辑:
const path = require('path'); // 补充缺失的path模块引入 const ffmpegPath = require('@ffmpeg-installer/ffmpeg').path; const fluent = require('fluent-ffmpeg'); fluent.setFfmpegPath(ffmpegPath); const executeFfmpeg = args => { let command = fluent().output(' '); command._outputs[0].isFile = false; command._outputs[0].target = ""; command._global.get = () => { return typeof args === "string" ? args.split(' ') : args; }; return command; }; function streamVideo() { const videoPath = path.join(__dirname, '..', 'test.mp4'); // 拼接原视频和10秒黑屏静音流,可根据实际延迟调整时长(-t 10) const ffmpegArgs = `-re -i ${videoPath} -f lavfi -i anullsrc=r=44100:cl=stereo -t 10 -f lavfi -i color=c=black:s=1920x1080:r=25 -t 10 -filter_complex "[0:v][0:a][1:a][2:v][2:a]concat=n=2:v=1:a=1[v][a]" -map "[v]" -map "[a]" -c:v libx264 -preset veryfast -tune zerolatency -c:a aac -ar 44100 -f flv rtmp://localhost:1935/live/test`; executeFfmpeg(ffmpegArgs) .on('start', commandLine => console.log('start', commandLine)) .on('codecData', codecData => console.log('codecData', codecData)) .on('error', error => console.log('error', error)) .on('stderr', stderr => console.log('stderr', stderr)) .on('end', commandLine => console.log('video_live end', commandLine)) .run(); } streamVideo()
说明:-t 10表示空流时长为10秒,可根据前端实际播放延迟调整该值,确保原视频所有帧都能被播放完毕。
方法2:调整Node Media Server配置延长连接超时
修改Node Media Server的配置,延长RTMP流检测和WebSocket连接的超时时间,避免流结束后立即断开前端WebSocket连接。
更新后的配置代码:
const NodeMediaServer = require('node-media-server'); const config = { rtmp: { port: 1935, chunk_size: 60000, gop_cache: true, ping: 30, ping_timeout: 120, // 延长RTMP超时至120秒 stream_timeout: 120 // 流断开后保留连接120秒 }, http: { port: 8000, allow_origin: '*', websocket: { port: 8000, allow_origin: '*', ping_interval: 30, ping_timeout: 120 // 延长WebSocket超时至120秒 } } }; var nms = new NodeMediaServer(config) nms.run();
说明:通过增大超时参数,让服务器在FFmpeg推流结束后,仍保持WebSocket连接一段时间,给前端足够时间播放剩余帧。
方法3:前端配合监听播放状态(辅助)
在前端添加播放结束监听,即使WebSocket断开,也确保当前已加载的帧播放完毕:
<script src="https://cdn.bootcss.com/flv.js/1.5.0/flv.min.js"></script> <video id="streamElement" autoplay> </video> <script> if (flvjs.isSupported()) { var streamElement = document.getElementById('streamElement'); var flvPlayer = flvjs.createPlayer({ type: 'flv', url: 'ws://localhost:8000/live/test.flv' }); flvPlayer.attachMediaElement(streamElement); flvPlayer.load(); flvPlayer.play(); // 监听视频播放结束事件,完成后销毁播放器 streamElement.addEventListener('ended', () => { flvPlayer.destroy(); }); // 监听WebSocket断开事件,优先播放缓存内容 flvPlayer.on('error', (err) => { if (err.code === flvjs.ErrorTypes.NETWORK_ERROR && !streamElement.ended) { streamElement.play(); } }); } </script>
内容的提问来源于stack exchange,提问作者seriously
相关产品推荐
相关产品推荐

