纯前端ELECTRON+VUE+FFMPEG实现多路播放RTSP流

近期有项目需求前端播放rtsp视频流,项目是由electron+vue3搭建,没有后端,因此需要在前端实现解析rtsp流及播放,经过多方考察最后选用了ffmpeg+jsmpeg方案实现,具体实现是参考了@牧也の旅行 大佬的这篇文章 原文地址 实现的,感谢@牧也の旅行 一直在回复我的各种小白问题,这里记录一下做这个功能时遇到的问题和解决方法:
主进程中的程序及其他配置参见原文,这里就不赘述了。
1,原文是单路播放,我的需求需要多路播放:
本来预想是展示16路,查资料也是说可以显示16路,但实际发现浏览器中只能稳定显示8路,超过后浏览器经常会报WARNING: Too many active WebGL contexts. Oldest context will be lost.并自动从第一路开始销毁,无法恢复(这里一直没有找到解决办法):
采用的方式是在vue组件中预先设置好canvas,id就是rtsp流的通道号

<div  v-for="i in 8" :key="i" style="padding:5px;" >   
       <canvas class="preview-video-canvas" :id="'chn'+(i-1).toString(16)"></canvas>      
  </div>

编写一个video.js 来播放多路

const {ipcRenderer} = require('electron');
import MpegPlayer from 'jsmpeg-player'

export class videoRtspPlayer {
    #pc;
    constructor(elements, opts = {}) {
        this.opts = opts;
        this.#pc = [];
        this.videoElement = Array.from(elements);
        this.baseUrl = this.init(this.opts);
    }
    /**
     * 创建视频播放url
     * @param {Object} opts 传入rtsp地址
     * @return {Promise<void>}
     */
    init(opts){
        return `rtsp://${opts.addr}:666/live/`;
    }
    /**
     * 播放
     * @return {Promise<void>}
     */
     play() {
           this.videoElement.forEach(async (video,index)=>{
               setTimeout(()=>{
                let pc;
                const url =`${this.baseUrl}${video.id}`;
                const res = ipcRenderer.sendSync('openRtsp', url,index);
                if (res.code === 200) {
                   //  pc = new MpegPlayer.VideoElement(video, res.ws); 这里由于我的播放位置是固定的,因此使用 MpegPlayer.Player方法 ,与原文不同
                    pc = new MpegPlayer.Player(res.ws,{
                        canvas:video,
                        videoBufferSize:1024*1024, //增加一些缓存
                    })
                    pc['rtsp'] = url;
                 }
                pc && this.#pc.push(pc);
               },index*100)
            })
    }
    /**
     * 停止
     */
    stop() {
        console.log(this.#pc)
        this.#pc.forEach(pc=>{
            pc.stop();
            ipcRenderer.sendSync('closeRtsp', pc.rtsp);   
        })
        this.#pc = [];
    }
}

electron/main.js中稍作改动,端口改为固定8个,不再使用addPort++;
vue中调用

import {videoRtspPlayer} from "../../common/Video";
let videoPlayer;
const netState = {
   addr: 你的rtsp地址
}
const initVideo = () =>{
      //开启视频预览
      let videos = document.getElementsByClassName('preview-video-canvas');
      videoPlayer = new videoRtspPlayer(videos,netState);
    }

onMounted(() => {
  initVideo();
  videoPlayer.play() 
})
onUnmounted(()=>{
  videoPlayer.stop();
})

至此,在开发环境,我可以正常开启8路rtsp视频预览了,通过配置Stream的尺寸,减小播放窗口,我的内存和cpu占用还算理想。

2、接着我就遇到了这个项目最大的坑:打包。打包后的程序,安装完运行起来一直报:

A JavaScript error occurred in the main process
Uncaught Exception:Error: spawn D: ldeaProjects md scs dist electron ffmpeg.exe ENOENTat ChildProcess.handle.onexit (node:internal/child process:283:19)at onErrorNT (node:internal/child process:478:16)at process.processTicksAndRejections (node:internal/process/task queues:83:21),

总的意思就是找不到 ffmpeg.exe 这个文件,查了一整天资料研究打包修改配置,我是使用electron-builder打包,配置文件在vue.config.js中,关键步骤如下:
1)将 ffmpeg.exe 拷贝到项目根目录;
2)配置中添加:

 electronBuilder: {
          ...
            builderOptions:{
              ...
                "asar": true,               
                "extraResources":['ffmpeg.exe'],
                ...
                }
        ...
 }

这样打包安装后,ffmpeg.exe就会出现在安装目录的resources/下,
electron/main.js中下面这句需要修改

// ffmpegPath: app.isPackaged ? ffmpegPath.replace('app.asar', 'app.asar.unpacked') : ffmpegPath, //改为下面那句
 ffmpegPath: app.isPackaged ? ffmpegPath.replace('app.asar', '') : ffmpegPath,

之后打包-安装-播放成功~

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值