You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 19:55:19