使用WebSocket+ffmpeg转码+flvjs于前端播放rtmp视频流

使用nodejs简单配置后端

// 引入必要的库
import webSocketStream from 'websocket-stream'  // WebSocket流处理库
import ffmpegInstaller from '@ffmpeg-installer/ffmpeg'  // FFmpeg安装器
import ffmpeg from 'fluent-ffmpeg'  // FFmpeg命令构建器
import { WebSocketServer } from 'ws'  // WebSocket服务器实现

// 设置FFmpeg路径
ffmpeg.setFfmpegPath(ffmpegInstaller.path)

// 创建WebSocket服务器配置
const WS_CONFIG = {
  port: 8888,
  perMessageDeflate: false  // 禁用压缩以降低延迟
}

// 初始化WebSocket服务器
const wss = new WebSocketServer(WS_CONFIG)

// 监听客户端连接事件
wss.on('connection', handleConnection)

/**
 * 处理客户端连接
 * @param {WebSocket} ws - WebSocket客户端实例
 * @param {Request} req - HTTP请求对象
 */
function handleConnection(ws, req) {
  // 从URL路径获取视频流地址(去掉前导斜杠)
  const streamUrl = req.url.slice(1)
  
  // 创建WebSocket二进制流
  const wsStream = webSocketStream(ws, { 
    binary: true,  // 启用二进制传输
    highWaterMark: 1024 * 1024  // 增加缓冲区大小
  })

  // 配置FFmpeg转码命令
  const ffmpegCommand = ffmpeg(streamUrl)
    // 输入参数配置
    .addInputOption(
      '-analyzeduration', '100000',  // 增加分析时长
      '-max_delay', '1000000'       // 增加最大延迟
    )
    // 事件监听
    .on('start', () => console.log(`转码开始: ${streamUrl}`))
    .on('codecData', (data) => console.log('编解码信息:', data))
    .on('error', (err) => {
      console.error('转码错误:', err.message)
      wsStream.end()  // 出错时关闭流
    })
    .on('end', () => {
      console.log('转码结束')
      wsStream.end()  // 正常结束时关闭流
    })
    // 输出配置
    .outputFormat('flv')  // FLV容器格式
    .videoCodec('copy')   // 视频流直接复制(不重新编码)
    // .noAudio()         // 可选: 禁用音频输出

  // 监听WebSocket关闭事件
  wsStream.on('close', () => {
    console.log('客户端断开连接')
    ffmpegCommand.kill('SIGKILL')  // 强制终止FFmpeg进程
  })

  try {
    // 将FFmpeg输出管道连接到WebSocket流
    ffmpegCommand.pipe(wsStream)
  } catch (error) {
    console.error('管道连接失败:', error)
    wsStream.end()
  }
}

前端多个播放器

import { onMounted, ref, nextTick } from 'vue'
import flvjs from 'flv.js';
const initFlvPlayer = (videoElement, url) => {
  if (url.startsWith('rtmp://')) {
    if (flvjs.isSupported()) {
      const player = flvjs.createPlayer(
        {
          type: "flv",
          url: "ws://localhost:8088/" + url,
          isLive: true,
        }
      )
      player.on(flvjs.Events.ERROR, (errType, errDetail) => {
        console.error("播放错误:", errType, errDetail);
        // 尝试重新连接
        setTimeout(() => {
          destroyPlayer(player); //销毁
          initFlvPlayer(videoElement, url);
        }, 3000);
      });
      player.attachMediaElement(videoElement)
      player.load()
      player.play()
      return player
    }
  }
}
// 销毁播放器
const destroyPlayer = (player) => {
  try {
    if (player && typeof player.destroy === 'function') {
      player.pause()
      player.unload()
      player.detachMediaElement()
      player.destroy()
    }
  } catch (e) {
    console.error('销毁播放器时出错:', e)
  }
}
onMounted(() => {
//需要监控多个视频流
//测试链接可用
//rtmp://ns8.indexforce.com/home/mystream
//rtsp://stream.strba.sk:1935/strba/VYHLAD_JAZERO.stream
  nextTick(() => {
    const videoElements = document.querySelectorAll('.task-data-item video')
    videoElements.forEach((videoElement, index) => {
      const task = taskDataSum.value[index]
      if (task && task.videoUrl) {
        // if (task.videoUrl.includes('rtmp://') || task.videoUrl.includes('rtsp://')) {
        initFlvPlayer(videoElement, task.videoUrl)
        // }
      }
    })
  })
})

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值