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

打印 上一主题 下一主题

主题 1038|帖子 1038|积分 3114

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

业务说明

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

关于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 命令并且将其输出(包括标准输出和标准错误)作为一个缓冲区返回。它适用于执行简朴的、一次性的命令,并且不需要与子进程进行大量的交互。
使用示例:
  1. const { exec } = require('child_process');
  2. // 执行一个 shell 命令
  3. exec('ls -l', (error, stdout, stderr) => {
  4.   if (error) {
  5.     console.error(`执行出错: ${error}`);
  6.     return;
  7.   }
  8.   console.log(`标准输出:\n${stdout}`);
  9.   console.error(`标准错误:\n${stderr}`);
  10. });
复制代码
特点:


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

          spawn 方法用于启动一个新的进程并且为其输入输出流提供一个接口。它更适合处理长时间运行的进程或者需要与子进程进行大量交互的场景。
使用示例:
  1. const { spawn } = require('child_process');
  2. // 启动一个新的进程
  3. const ls = spawn('ls', ['-l']);
  4. ls.stdout.on('data', (data) => {
  5.   console.log(`标准输出: ${data}`);
  6. });
  7. ls.stderr.on('data', (data) => {
  8.   console.error(`标准错误: ${data}`);
  9. });
  10. ls.on('close', (code) => {
  11.   console.log(`子进程退出码: ${code}`);
  12. });
复制代码
特点:


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


  • 使用 exec 当你需要执行简朴命令并获取其输出。
  • 使用 spawn 当你需要处理长时间运行的进程,或者需要实时处理进程输出和交互
核心代码二:打开播放器业务代码
  1.   async openVLC(videoPath, seekTime = null) {
  2.     try {
  3.       const isVlcRunning = this.vlcProcess !== null
  4.       console.log('vlc.isVlcRunning=', isVlcRunning)
  5.       if (isVlcRunning) {
  6.         return this.onOpenVideo(videoPath, seekTime)
  7.       }
  8.       const args = [videoPath]
  9.       let selfSeekTime = false
  10.       if (seekTime) {
  11.         const {
  12.           mode,
  13.           times
  14.         } = this.parseSeekTime(seekTime)
  15.         if (mode === 'ab') {
  16.           selfSeekTime = true
  17.           // A-B片段
  18.           args.push(
  19.             `--start-time=${times[0]}`,
  20.             // `--stop-time=${times[1]}`,
  21.             // '--play-and-pause',
  22.           )
  23.         } else if (mode === 'ab-loop') {
  24.           selfSeekTime = true
  25.           args.push(
  26.             `--start-time=${times[0]}`,
  27.             // `--stop-time=${times[1]}`,
  28.             // '--loop',
  29.           )
  30.         } else {
  31.           args.push(`--start-time=${this.convertSeekTimeToSeconds(seekTime)}`)
  32.         }
  33.       }
  34.       if (SystemConfig.isWindows) {
  35.         args.push('--intf', 'qt')
  36.       }
  37.       console.log('vlc cmd:', this.vlcPath, args.join(' '))
  38.       const vlcProcess = spawn(this.vlcPath, args, {
  39.         detached: true,
  40.         stdio: 'ignore',
  41.       })
  42.       vlcProcess.unref()
  43.       vlcProcess.on('close', (code) => {
  44.         console.log(`VLC process exited with code ${code}`)
  45.         this.vlcProcess = null
  46.         this.clearAbCheckTimeInterval()
  47.         this.clearAbLoopCheckTimeInterval()
  48.       })
  49.       vlcProcess.on('spawn', () => {
  50.         if (selfSeekTime) {
  51.           this.seekTimeLoop(seekTime)
  52.         }
  53.         console.log('VLC opened successfully')
  54.       })
  55.       this.vlcProcess = vlcProcess
  56.       return true
  57.     } catch (error) {
  58.       console.log(`Failed to open VLC: ${error.message}`)
  59.       return false
  60.     }
  61.   }
复制代码
代码表明:

  • 起首,它检查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软件.

显示根本

显示全部
第二步:查看官方文档

文档地址: VLC HTTP requests - VideoLAN Wiki

第三步: 封装一个哀求方法
  1.   // 获取 VLC 的当前状态
  2.   async getVlcStatus() {
  3.     const {
  4.       port,
  5.       password
  6.     } = await this.getVlcConfig()
  7.     const url = `http://${SystemConfig.vlcHttpHost}:${port}/requests/status.xml`
  8.     try {
  9.       const response = await axios.get(url, {
  10.         auth: {
  11.           username: '',
  12.           password: password,
  13.         },
  14.       })
  15.       const parseStringPromise = promisify(xml2js.parseString)
  16.       const result = await parseStringPromise(response.data)
  17.       return result
  18.     } catch (error) {
  19.       console.error(`Error fetching VLC status: ${error.message}`)
  20.       throw error
  21.     }
  22.   }
  23.   // 发送 VLC HTTP 请求的函数
  24.   async sendVlcHttpCommand(command) {
  25.     const {
  26.       port,
  27.       password
  28.     } = await this.getVlcConfig()
  29.     const url = `http://${SystemConfig.vlcHttpHost}:${port}/requests/status.xml?command=${command}`
  30.     console.log('sendVlcHttpCommand:', url)
  31.     try {
  32.       const response = await axios.get(url, {
  33.         auth: {
  34.           username: '',
  35.           password: password,
  36.         },
  37.       })
  38.       //console.log('vlc http api result:', response.data)
  39.       return response.data
  40.     } catch (error) {
  41.       console.error(`Error sending VLC http command: ${error.message}`)
  42.       throw error
  43.     }
  44.   }
复制代码
到这里,我们已经实现了electron 操作vlc播放器的大部分需求了. 那最后我们还要在实现一个截取当前播放帧画面.对于它我们来看下该如何实现
实现截图

          终端指令和vlc接口都不好使的环境下,我们能想到的是ffmpeg.那这样我们的实现方式就有了: 获取当前播放的视频信息->判断有没有在播的视频->存在信息拿到播放路径和当前播放时间->调用ffmpeg指令
          当然,我们这里的场景方案只针对单开的环境,如果vlc开启多开环境(好像可以)就不太对了,不外vlc接口获取的是一个播放列表,说不定可以操作.
  1.   async takeScreenshot(videoPath, videoTime, outputDir) {
  2.     const outputFilePath = path.join(outputDir, 'vlc-local-video-snapshot.png')
  3.     return new Promise((resolve, reject) => {
  4.       ffmpeg(decodeURIComponent(videoPath))
  5.         .seekInput(videoTime)
  6.         .outputOptions('-frames:v 1')
  7.         .output(outputFilePath)
  8.         .on('end', () => {
  9.           console.log(`VlC Local Video Screenshot saved to ${outputFilePath}`)
  10.           resolve(outputFilePath)
  11.         })
  12.         .on('error', (err) => {
  13.           console.error(
  14.             `VlC Local Video Error taking screenshot: ${err.message}`,
  15.           )
  16.           reject(err)
  17.         })
  18.         .run()
  19.     })
  20.   }
复制代码
总结

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

https://juejin.cn/post/7399273700116955186

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

饭宝

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表