首页 > 其他分享 >视频笔记软件JumpVideo技术解析一:Electron案例-调用VLC播放器

视频笔记软件JumpVideo技术解析一:Electron案例-调用VLC播放器

时间:2024-08-05 12:55:34浏览次数:11  
标签:播放器 console VLC Electron JumpVideo error const vlc

          大家好,我是TheGodOfKing,是 最强考研学习神器,免费视频笔记应用JumpVideo,可以快速添加截图时间戳,支持所有笔记软件,学习效率MAX!的开发者之一,分享技术的目的是想找到更多志同道合的人,如果有大学生加入,我们还允许他把项目作为毕设(只有一个名额哟)群(689978959),那么今天要给大家分享软件框架electron一个实用小案例: 调用vlc播放器播放视频并控制vlc播放器,支持生成时间戳、播放、暂停、截图、ab片段播放、ab循环播放、快进、快退等操作
image

业务说明

          还是简单说下需求:electron构建一个app,app主要可以打开本地视频播放,同时app支持设置快捷键来控制打开的播放器.比如使用快捷键截取当前帧并提取相关文字,播放,暂停,等
QQ_1722743926384.png

关于VLC

          VLC 媒体播放器(最初为 VideoLAN Client)是一款高度便携的多媒体播放器,可播放各种音频和视频格式(MPEG、DivX/Xvid、Ogg 等)以及 DVD、VCD 和各种流媒体协议。 不过,近年来它也成为了一个功能极其强大的服务器,可将多种格式的实时和点播视频流传输到我们的网络和互联网上。 VLC 由非营利基金会 VideoLAN 制作。
优点

  • 支持多种音视频格式
  • 跨平台,支持Window、Mac
    正因为VLC是跨平台的超强播放器,因此我才会选择VLC作为项目软件的本地视频播放器。

实战:核心代码一:使用系统调用api来打开vlc播放器

关于exec和spawn

          exec 和 spawn 是 Node.js 中 child_process 模块提供的两个方法,用于在子进程中执行命令。它们的主要区别在于它们如何处理输入输出数据以及适用的使用场景。

exec

          exec 方法用于执行一个 shell 命令并且将其输出(包括标准输出和标准错误)作为一个缓冲区返回。它适用于执行简单的、一次性的命令,并且不需要与子进程进行大量的交互。

使用示例:

const { exec } = require('child_process');

// 执行一个 shell 命令
exec('ls -l', (error, stdout, stderr) => {
  if (error) {
    console.error(`执行出错: ${error}`);
    return;
  }
  console.log(`标准输出:\n${stdout}`);
  console.error(`标准错误:\n${stderr}`);
});

特点:

  • 输出作为一个缓冲区(字符串)返回。
  • 默认情况下有一个 200KB 的输出限制,可以通过 maxBuffer 选项增加。
  • 适用于需要执行简单命令并一次性获取输出的场景。

spawn

          spawn 方法用于启动一个新的进程并且为其输入输出流提供一个接口。它更适合处理长时间运行的进程或者需要与子进程进行大量交互的场景。

使用示例:

const { spawn } = require('child_process');

// 启动一个新的进程
const ls = spawn('ls', ['-l']);

ls.stdout.on('data', (data) => {
  console.log(`标准输出: ${data}`);
});

ls.stderr.on('data', (data) => {
  console.error(`标准错误: ${data}`);
});

ls.on('close', (code) => {
  console.log(`子进程退出码: ${code}`);
});

特点:

  • 返回一个 ChildProcess 对象,提供了 stdout 和 stderr 流来实时处理输出。
  • 没有输出缓冲区大小限制。
  • 适用于需要实时处理输出或者与子进程进行交互的场景。

总结

  • 使用 exec 当你需要执行简单命令并获取其输出。
  • 使用 spawn 当你需要处理长时间运行的进程,或者需要实时处理进程输出和交互

核心代码二:打开播放器业务代码

  async openVLC(videoPath, seekTime = null) {
    try {
      const isVlcRunning = this.vlcProcess !== null
      console.log('vlc.isVlcRunning=', isVlcRunning)
      if (isVlcRunning) {
        return this.onOpenVideo(videoPath, seekTime)
      }

      const args = [videoPath]
      let selfSeekTime = false
      if (seekTime) {
        const {
          mode,
          times
        } = this.parseSeekTime(seekTime)
        if (mode === 'ab') {
          selfSeekTime = true
          // A-B片段
          args.push(
            `--start-time=${times[0]}`,
            // `--stop-time=${times[1]}`,
            // '--play-and-pause',
          )
        } else if (mode === 'ab-loop') {
          selfSeekTime = true
          args.push(
            `--start-time=${times[0]}`,
            // `--stop-time=${times[1]}`,
            // '--loop',
          )
        } else {
          args.push(`--start-time=${this.convertSeekTimeToSeconds(seekTime)}`)
        }
      }

      if (SystemConfig.isWindows) {
        args.push('--intf', 'qt')
      }


      console.log('vlc cmd:', this.vlcPath, args.join(' '))
      const vlcProcess = spawn(this.vlcPath, args, {
        detached: true,
        stdio: 'ignore',
      })

      vlcProcess.unref()
      vlcProcess.on('close', (code) => {
        console.log(`VLC process exited with code ${code}`)
        this.vlcProcess = null
        this.clearAbCheckTimeInterval()
        this.clearAbLoopCheckTimeInterval()
      })

      vlcProcess.on('spawn', () => {
        if (selfSeekTime) {
          this.seekTimeLoop(seekTime)
        }
        console.log('VLC opened successfully')
      })
      this.vlcProcess = vlcProcess
      return true
    } catch (error) {
      console.log(`Failed to open VLC: ${error.message}`)
      return false
    }
  }

代码解释:

  • 首先,它检查vlc是否已经在运行,如果是,则调用onOpenVideo方法并返回。
  • 然后,根据传入的seekTime参数来处理开始播放的时间。如果seekTime的模式是ab或ab-loop,则会处理A-B片段的播放,并将selfSeekTime设置为true。
  • 接下来,根据系统是否是Windows来添加相应的参数。
  • 在接下来,使用spawn方法创建一个新的vlc进程,并设置相应的参数和事件监听器。如果selfSeekTime为true,则会调用seekTimeLoop方法。
  • 最后,将创建的vlc进程赋值给this.vlcProcess,并返回true表示成功打开vlc。如果出现错误,则会打印错误信息并返回false。

到这里我们就打开了VLC播放器,然后这里在解释下vlc终端指令几个关键参数:

  • --start-time 指定开始播放的时间点
  • --stop-time 指定结束播放的时间点
  • --loop 循环播放
  • --intf qt 打开的播放器画面拥有功能栏、进度栏等丰富的界面元素,不加只会弹出一个播放器

基本上,我们现在通过终端指令已经可以实现打开本地任一视频播放了,而且也能实现a-b片段、ab片段循环,当然作者这里实际是放弃了指令实现的ab操作,具体实现有兴趣的朋友可以留言.接下来,我们继续看其他操作的实现.

实现播放、暂停、获取当前播放状态、快进、快退等操作

          对于vlc来讲,它已经为我们提供很好的对接方式,那就是vlc http api.因此我们便可以通过接口来实现我们的操作.

第一步:播放器设置http

          作者给出mac的设置(默认显示基本,就会有个http 密码设置),☑️启用并设置vlc密码.就开启了我们http接口.windows用户设置基本一样,具体看vlc软件.

Pasted image 20240804042154.png

显示基本

Pasted image 20240804042224.png

显示全部

第二步:查看官方文档

文档地址: VLC HTTP requests - VideoLAN Wiki

Pasted image 20240804042305.png

第三步: 封装一个请求方法

  // 获取 VLC 的当前状态
  async getVlcStatus() {
    const {
      port,
      password
    } = await this.getVlcConfig()
    const url = `http://${SystemConfig.vlcHttpHost}:${port}/requests/status.xml`
    try {
      const response = await axios.get(url, {
        auth: {
          username: '',
          password: password,
        },
      })
      const parseStringPromise = promisify(xml2js.parseString)
      const result = await parseStringPromise(response.data)
      return result
    } catch (error) {
      console.error(`Error fetching VLC status: ${error.message}`)
      throw error
    }
  }
  // 发送 VLC HTTP 请求的函数
  async sendVlcHttpCommand(command) {
    const {
      port,
      password
    } = await this.getVlcConfig()
    const url = `http://${SystemConfig.vlcHttpHost}:${port}/requests/status.xml?command=${command}`
    console.log('sendVlcHttpCommand:', url)
    try {
      const response = await axios.get(url, {
        auth: {
          username: '',
          password: password,
        },
      })
      //console.log('vlc http api result:', response.data)
      return response.data
    } catch (error) {
      console.error(`Error sending VLC http command: ${error.message}`)
      throw error
    }
  }

到这里,我们已经实现了electron 操作vlc播放器的大部分需求了. 那最后我们还要在实现一个截取当前播放帧画面.对于它我们来看下该如何实现

实现截图

          终端指令和vlc接口都不好使的情况下,我们能想到的是ffmpeg.那这样我们的实现方式就有了: 获取当前播放的视频信息->判断有没有在播的视频->存在信息拿到播放路径和当前播放时间->调用ffmpeg指令

          当然,我们这里的场景方案只针对单开的情况,如果vlc开启多开情况(好像可以)就不太对了,不过vlc接口获取的是一个播放列表,说不定可以操作.

  async takeScreenshot(videoPath, videoTime, outputDir) {
    const outputFilePath = path.join(outputDir, 'vlc-local-video-snapshot.png')
    return new Promise((resolve, reject) => {
      ffmpeg(decodeURIComponent(videoPath))
        .seekInput(videoTime)
        .outputOptions('-frames:v 1')
        .output(outputFilePath)
        .on('end', () => {
          console.log(`VlC Local Video Screenshot saved to ${outputFilePath}`)
          resolve(outputFilePath)
        })
        .on('error', (err) => {
          console.error(
            `VlC Local Video Error taking screenshot: ${err.message}`,
          )
          reject(err)
        })
        .run()
    })
  }

总结

          通过以上操作,我们完成了electron调用vlc播放器的需求,如果有大佬对项目感兴趣的可以加群(689978959)私信我,如果是大学生加入我们还允许他把项目作为毕设(只有一个名额哟) ,后续关于如何自己实现ab操作有感兴趣的朋友可以留言。下一期,小编将出一期 electron 调用 potPlayer播放器的文章。

原文

https://juejin.cn/post/7399273700116955186

标签:播放器,console,VLC,Electron,JumpVideo,error,const,vlc
From: https://www.cnblogs.com/YangJieCheng/p/18343006

相关文章

  • 探索 Electron:如何进行网址收藏并无缝收录网页图片内容?
    Electron是一个开源的桌面应用程序开发框架,它允许开发者使用Web技术(如HTML、CSS和JavaScript)构建跨平台的桌面应用程序,它的出现极大地简化了桌面应用程序的开发流程,让更多的开发者能够利用已有的Web开发技能来构建功能强大且跨平台的应用程序,这对于提升开发效率和应用程......
  • 招投标系统VUE网页编辑Word且兼容微软Office和金山WPS支持Electron
    随着信息技术的不断发展,电子政务已经非常普及,电子招投标行业市场规模不断扩大,电子招投标不仅可以减少繁琐的人工操作,提高工作效率,还能保证公开透明的招标流程,制作招标文件过程中,由于微软Office和金山WPS等办公软件无法直接内嵌到浏览器中,有的招标制作工具用的Electron,需要在纯内网......
  • Electron学习笔记(二)Hello World
    目录前言运行主进程创建界面使用窗口打开界面管理窗口的生命周期关闭所有窗口时退出应用(Windows&Linux)​如果没有窗口打开则打开一个窗口(macOS)使用预加载脚本访问渲染器的Node.js添加你自己的功能完整代码展示效果展示前言接上一篇文章Electron学习笔......
  • 快速开启react+electron应用,搭建启动问题
    注意:React本地启动在3000端口Electron在创建BrowserWindow的时候,可以读取本地的文件或者是url开发环境读取localhost:3000生产环境需要加载本地成型以后的本地文件,打包的时候再考虑一react脚手架create-react-app快速搭建reactnpxcreate-react-appmy-ap......
  • 解决npm安装electron失败的问题
    1.问题描述使用npm创建项目后,添加electron依赖npminstallelectron--save-dev一直报错,部分报错日志如下484sillyauditerror[objectObject][email protected]{code:1,signal:null}487verbosestac......
  • IM跨平台技术学习(十三):从理论到实践,详细对比Electron和Tauri的优劣
    本文由京东技术王泽知分享,原题“基于Web的跨平台桌面应用开发”,下文进行了排版和内容优化。1、引言近些年来,跨平台跨端一直是比较热门的话题,Writeonce,runanywhere一直是开发者所期望的,跨平台方案的优势十分明显。对于开发者而言,可以做到一次开发、多端复用,一套代码就能够......
  • electron TodoList网页应用打包成linux deb、AppImage应用
    这里用的是windows的wsl的ubuntu环境electron应用打包linux应用需要linux下打包,这里用windows的wsl的ubuntu环境进行操作1)linuxubuntu安装nodejs、electron安装nodejs:sudoaptupdatesudoaptupgrade##快捷安装curl-fsSLhttps://deb.nodesource.com/setup_20.x......
  • Electron 和 React 开发桌面应用程序
    目录书籍推荐ElectronReact在线资源和教程官方文档在线教程综合学习路径经典开发案例VisualStudioCodeHyperTuskNotableBeekeeperStudio开源项目和示例代码ElectronReactBoilerplateElectronForge+ReactElectronReactTemplate学习和实践使用El......
  • Electron 结合 Selenium + chromedriver 驱动服务实现浏览器多开
    背景在调研浏览器多开的过程中,electron 有自带的 browserview,webview,但是上面两个受制于 electron 内核版本限制,升级不够灵活,对新版的网页支持可能不及时,甚至不兼容,必须通过发布新的客户端版本才能解决,此外,这两个组件本身也不稳定,经常内存溢出,如果能改为 chrome 自己开......
  • Electron 应用关闭突出程序坞
    在Electron应用中,处理窗口关闭并使其最小化到Mac系统的程序坞(Dock)而不是完全退出应用,通常涉及到监听窗口的关闭事件(close事件)并在适当时机阻止其默认行为。以下是一些步骤和关键点,帮助实现这一功能:1.监听窗口关闭事件在Electron的主进程(mainprocess)中,你需要为窗口(Browse......