当前位置:   article > 正文

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

electron ffmpeg

近期有项目需求前端播放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>
  • 1
  • 2
  • 3

编写一个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 = [];
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53

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();
})
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

至此,在开发环境,我可以正常开启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),
  • 1
  • 2

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

 electronBuilder: {
          ...
            builderOptions:{
              ...
                "asar": true,               
                "extraResources":['ffmpeg.exe'],
                ...
                }
        ...
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

这样打包安装后,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,
  • 1
  • 2

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

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/999002
推荐阅读
相关标签
  

闽ICP备14008679号