nodejs中使用ffmpeg零基础教程(electron+vue3)

news2024/11/28 4:40:40

同学们可以私信我加入学习群!


正文开始

  • 前言
  • 一、多方案对比
  • 二、ffmpeg各插件简介
  • 三、使用ffmpeg-static插件
  • 四、使用fluent-ffmpeg插件
  • 五、如果使用ai,可能会踩的坑
    • 5.1第一个坑
    • 5.2第二个坑
    • 5.3第三个坑
  • 总结


前言

最近想要把自己写的一些知识点,在写完demo后,除了形成博客记录笔记,还可以便捷地录屏形成视频教程。所以研究了好久如何在nodejs中完成录屏功能。本功能模块基于electron+vue3完成,原生nodejs也可以作为参考,原理是一致的。

踩了很多坑,否了很多方案后,终于形成了目前的方案。


一、多方案对比

1.最简单的就是使用electron的desktopCapturer.getSources获取屏幕源,大致代码如下:

const sources= await desktopCapturer.getSources({ types: ['window', 'screen'] })
    let sId=null
    for (const source of sources) {
        console.log(source.name);
        if (source.name.includes('整个')) {
            sId=source.id
        }
    }
    return sId

然后将屏幕id传递给渲染层vue中,利用浏览器提供的navigator.mediaDevices.getUserMedia,录制视频流:

 const stream = await navigator.mediaDevices.getUserMedia({
        audio: false,
        video: {
          mandatory: {
            chromeMediaSource: 'desktop',
            chromeMediaSourceId: sourceId,
            minWidth: 1280,
            maxWidth: 1280,
            minHeight: 720,
            maxHeight: 720
          }
        }
      })

这种方案舍弃,原因是录制特定区域内容形成视频,还是需要借助ffmpeg插件,多一步操作就多一些性能损耗。

2.又在网上查到一种方案,是利用canvas将屏幕形成图片,最终再由ffmpeg插件将图片形成视频,性能太差,舍弃!

3.借助ffmpeg插件,这里又有许多方案可供参考:

  • 直接下载ffmpeg,把它放到全局变量,然后使用ffmpeg命令行(不现实,不能要求每个人用录屏软件时,都要先等几十秒去下载插件)
  • 直接使用ffmpeg-static插件,然后获取到node_modules中的exe可执行文件,再使用命令行(可行,但不太方便,因为一致操作命令行,容易出错,对各类报错捕获也过于原始)
  • 使用@ffmpeg-installer/ffmpeg插件配合fluent-ffmpeg插件,理论可行,由@ffmpeg-installer/ffmpeg维护下载ffmpeg,由fluent-ffmpeg操作ffmpeg,但是我的@ffmpeg-installer/ffmpeg插件下载ffmpeg时,总是失败,不知道原因。
  • 最终采用ffmpeg-static配合fluent-ffmpeg的方式,完成录屏功能。

想要明白自己需要什么插件,首先要弄明白这些插件都在做什么,我第一次接触ffmpeg,简直被这几个插件搞懵了。都什么鬼插件,还那么高下载量。既然都是围绕ffmpeg插件展开的,就不能出个一统天下的插件,减少心智负担。

二、ffmpeg各插件简介

  1. ffmpeg插件:这是真正的录屏插件,windows系统中以exe可执行文件形式存在,其它所有插件都是围绕它开发。

  2. @ffmpeg-installer/ffmpeg插件:一个维护下载ffmpeg的插件,可以帮助我们便捷地下载更新对应版本的ffmpeg,并且在下载后,可以暴露出exe可执行文件的地址,方便我们操作ffmpeg。一般情况下,我们只需要使用@ffmpeg-installer/ffmpeg插件,就可以不用直接下载ffmpeg插件了。

  3. ffmpeg-static插件:功能类似于上面的插件,但是实现原理不同,在ffmpeg-static插件中,自带某个版本的ffmpeg,ffmpeg-static插件并不提供下载维护ffmpeg的功能,但是下载ffmpeg-static,就会顺带下载ffmpeg,并帮助我们完成一些基础工作,引入ffmpeg-static插件也可以直接获取ffmpeg插件的地址,方便我们操作。

  4. fluent-ffmpeg插件:正常操作ffmpeg是通过命令行的方式,ffmpeg-static插件把命令行的方式做了一层封装,让我们可以通过api的形式调用ffmpeg,写代码更简单方便一些。

三、使用ffmpeg-static插件

我们先来看如何简单地使用ffmpeg-static插件。

第一步——下载:

npm i ffmpeg-static

第二步——引入:

  const pathToFfmpeg = require('ffmpeg-static')

第三步——写命令行,运行ffmpeg插件

ffmpegCommand = `${pathToFfmpeg} -f gdigrab -r 30  -i desktop -c:v libx264 -preset ultrafast -t 10 output1111.mp4`

四、使用fluent-ffmpeg插件

fluent-ffmpeg插件只是简化了操作的步骤,仍然需要借助上面的ffmpeg-static插件。

第一步——下载:

npm i fluent-ffmpeg

第二步——引入,配合ffmpeg-static

 const ffmpeg = require('fluent-ffmpeg');
 const pathToFfmpeg = require('ffmpeg-static')

第三步——使用:

ffmpeg.setFfmpegPath(pathToFfmpeg);
const command = ffmpeg()
    .input(`desktop`) 
    .fromFormat('gdigrab')
    .videoCodec('libx264')
    .preset('divx') 
    .outputOptions('-t ' + 10) 
    .output(fileName) 
    .on('end', function () {
        console.log('桌面捕获完成!');
    })
    .on('error', function (err) {
        console.error('发生错误:', err);
    })
    .run(); // 执行命令

五、如果使用ai,可能会踩的坑

首先,这部分的网络资料不多,如果直接百度或谷歌,查到相关资料很多,但是正好是我写的这部分内容,可能不多。而如果使用ai工具辅助完成,可能会有一些bug。

5.1第一个坑

大部分使用fluent-static的资料,输入都是已存在视频文件的路径,而我们需要的是实时录制视频,所以input的参数网上没查到相应资料,如果问ai它可能会给你一个这样的参数:
gdigrab=framerate=${frameRate}:desktop,导致报错。

解决思路:

带大家简单看一下源码,fluent-ffmpeg插件中有一个input.js文件,里面有段代码是在定义input方法:
在这里插入图片描述
我们可以看到,这段方法接收的参数就是输入的源source,source最终push到了_inputs中。

再看一下processor.js中有下面一段代码:
在这里插入图片描述
这段代码可以看到,最终把inputs中的source参数赋值给了-i,看到这我们就能理解个差不多,原来input方法的参数就是ffmpeg插件中“-i”后面的参数。

下面是最原始的命令行:

ffmpegCommand = `${pathToFfmpeg} -f gdigrab -r 30  -i desktop -c:v libx264 -preset ultrafast -t 10 output1111.mp4`

-i参数后面的值是desktop,所以我们应该在input方法中输入“desktop”,也就是如下代码:

ffmpeg()
    .input('desktop') 

当然,从源码,我们还可以看到这个视频源应该还有流数据的格式,不过初次体验,就先不踩坑去尝试了。

5.2第二个坑

如果按照命令行的编码格式,参数preset后面是ultrafast,也就是说fluent-ffmpeg中preset 方法接收的参数应该是ultrafast,但是这么写后,会报错:

UnhandledPromiseRejectionWarning: Error: preset G:\c-private\lize-tools-pc\node_modules\.store\fluent-ffmpeg@2.1.3\node_modules\fluent-ffmpeg\lib\presets\ultrafast could not be loaded: Cannot find module 'G:\c-private\l ize-tools-pc\node_modules\.store\fluent-ffmpeg@2.1.3\node_modules\fluent-ffmpeg\lib\presets\ultrafast'

根据报错信息,我们可以知道在fluent-ffmpeg\lib\presets目录下,找不到ultrafast,也就是说fluent-ffmpeg不支持这种编码,查看对应目录,我们可以发现它只支持三种编码:
在这里插入图片描述

所以我们只能三选一,例如:.preset(‘divx’)。

可能有同学会有疑问,fluent-ffmpeg会不会阉割ffmpeg插件的部分功能?一般不会!通过看fluent-ffmpeg的源码,我们可以发现,它的功能核心十分简单,就是想办法把命令行变成api,或者说是通过api把我们的输入最终变成了ffmpeg能理解的命令行,留一个简单的api,能够把我们输入的任意字符串都拼进最终的命令行,就能兼顾最大自由度的命令行定制功能。

虽然我还没看,但是我猜测它一定有类似的api,其中可以写任意的命令行参数,来使用ffmpeg的所有功能。

5.3第三个坑

命令行中的参数-f gdigrab,在windows环境中,应该指定gdigrab为视频采集工具,mac环境中指定avfoundation为视频采集工具。我们继续找源码:
在这里插入图片描述
在output.js中,找到了和"-f"参数相关的代码,所以在windows环境中,我们应该加上一个方法.format(“gdigrab”),来指定视频采集工具。


总结

等视频录屏功能和vue代码预览功能都完成后,会在博主的桌面端工具中发布,免费使用,下面有软件获取链接。

获取资源,查看代码示例,或者联系我:

https://lizetoolbox.top:8080/#/qrCode_contact

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1708359.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

二十九、openlayers官网示例DeclutterGroup解析——避免矢量图层的文字重叠

官网demo地址: Declutter Group 这篇说的是如何设置矢量图层上多数据点文字不重叠。 主要是属性declutter ,用于处理矢量图层上重叠的标注和符号,为true时启用去重叠功能。所有矢量特征的标注和符号都会被处理以避免重叠。false则与之相反。…

java nio FileChannel堆内堆外数据读写全流程分析及使用(附详细流程图)

这里是小奏,觉得文章不错可以关注公众号小奏技术 背景 java nio中文件读写不管是普通文件读写,还是基于mmap实现零拷贝,都离不开FileChannel这个类。 随便打开RocketMQ 源码搜索FileChannel 就可以看到使用频率 kafka也是 所以在java中文件读写FileCh…

hexo静态博客 部署到xxx.github.io github 静态页

hexo安装 npm install hexo-cli -g hexo init blog cd blog npm install hexo server key配置 ssh-keygen -t ed25519 -C “emaile.com” 添加key到github err gitgithub.com: Permission denied (publickey). fatal: Could not read from remote repository. 配置GitHub仓…

LabVIEW通过以太网控制PLC程序开发

在使用LabVIEW通过以太网控制PLC程序开发时,需要综合考虑硬件、软件和通信协议的协调工作。以下是详细步骤、注意事项、重点和难点分析,以及几种实现方式及其特点的概述。 实现步骤 确定硬件和软件环境: 确定PLC型号和品牌(如西门…

民国漫画杂志《时代漫画》第29期.PDF

时代漫画29.PDF: https://url03.ctfile.com/f/1779803-1248635405-bf3c87?p9586 (访问密码: 9586) 《时代漫画》的杂志在1934年诞生了,截止1937年6月战争来临被迫停刊共发行了39期。 ps: 资源来源网络!

互联网的利

在互联网没发明之前,人类说话要近距离的说,玩游戏要近距离的玩,十分麻烦。于是,互联网解决了这个问题。聊天可以在电脑上聊,玩游戏可以用游戏软件查找玩家来玩,实现了时时可聊,时时可玩的生活。…

Euler 欧拉系统介绍

Euler 欧拉系统介绍 1 简介重要节点与版本EulerOS 特色EulerOS 与 openEuler 区别联系Euler 与 HarmonyOS 区别联系 2 openEuler特色支持 ARM,x86,RISC-V 等全部主流通用计算架构融入 AI 生态嵌入式实时能力提升引入 OpenHarmony 一些突出功能 参考 1 简…

基于51单片机简易温度计

一.硬件方案 本系统利用51单片机控制温度传感器DS18B20进行温度的实时检测并显示,能够实现快速测量环境温度。硬件以微控制器为核心,外接时钟电路、复位电路、温度测量电路、LED显示电路组成。 二.设计功能 (1)采用DS18B20温度…

python使用多种方法计算列表元素平方的技巧

新书上架~👇全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我👆,收藏下次不迷路┗|`O′|┛ 嗷~~ 目录 一、使用列表推导式进行元素平方 二、使用map函数进行元素平方 三、循环遍历列表进行元素平…

HTML 页面布局

慢慢生活,慢慢变好 —— 24.5.28 页面布局 盒子: 页面中所有的元素(标签),都可以看做是一个盒子,由盒子将页面中的元素包含在一个矩形区域内,通过盒子的视角更方便的进行页面布局 盒子模型组成: 内容区域(content)、内边距区域(pa…

大模型时代的具身智能系列专题(四)

google deepmind团队 谷歌旗下最大的两个 AI 研究机构——地处伦敦 DeepMind 与位于硅谷的 Google Brain 合并成立新部门 Google DeepMind。其将机器学习和系统神经科学的最先进技术结合起来,建立强大的通用学习算法。代表作有AlphaGo,AlphaStar&#x…

Vanna使用ollama分析本地MySQL数据库

上一章节中已经实现了vanna的本地运行,但是大模型和数据库都还是远程的,因为也就没办法去训练,这节一起来实现vanna分析本地mysql数据库,因为要使用本地大模型,所以开始之前需要给本地安装好大模型,我这里用…

Android性能优化方案

1.启动优化: application中不要做大量耗时操作,如果必须的话,建议异步做耗时操作2.布局优化:使用合理的控件选择,少嵌套。(合理使用include,merge,viewStub等使用)3.apk优化(资源文件优化&#…

浅揭秘:Java方法调用过程中栈内存到底干了什么

在深入Java编程的世界时,理解其方法调用背后的内存管理机制是至关重要的。 Java作为一种面向对象的语言,其内存管理自动化程度高,但背后涉及的原理却错综复杂,尤其是方法调用过程中的栈帧、堆、方法区等概念。 本文将通过代码示…

【踩坑】编译opencv将python (for build) python2.7改为python3

转载请注明出处:小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你,欢迎[点赞、收藏、关注]哦~ 出现问题 默认是2.7 解决方案 cmake时候添加: -D PYTHON_DEFAULT_EXECUTABLE$(which python3)

豪赌?远见?浙江东方的量子冒险

今年4月16日,量子通信概念异动,浙江东方(600120)拉升涨停。 量子和浙江东方,要把这两个词联系起来似乎并不太容易。 浙江东方,即浙江东方金融控股集团股份有限公司,系浙江省国资委下属浙江省国…

CCF- CSP 2018.12 - 1.2题 Java语言解题

2018.12-1 小明上学 import java.util.Scanner;public class text01_RedLight {public static void main(String[] args) {Scanner scanner new Scanner(System.in);int r scanner.nextInt();int y scanner.nextInt();int g scanner.nextInt();int n scanner.nextInt();in…

SpringBoot基础篇

1:parent 目的:减少依赖配置 开发SpringBoot程序要继承spring-boot-starter-parentspring-boot-starter-parent中定义了若干个依赖管理继承parent模块可以避免多个依赖使用相同技术出现依赖版本冲突继承parent的形式也可以采用引入依赖的i形式实现效果…

通过安全的云开发环境重新发现 DevOps 的心跳

云开发平台如何“提升” DevOps 首先,我来简单介绍一下什么是云开发环境:它通常运行带有应用程序的 Linux 操作系统,提供预配置的环境,允许进行编码、编译和其他类似于本地环境的操作。从实现的角度来看,这样的环境类…

零基础HTML教程(35)--网站的本地部署

文章目录 1. 背景2. 网站的本地部署3. 本地部署的步骤4. 服务器软件介绍5. 本地部署实操5.1 开发一个网站5.2 下载服务器软件5.3 将网站复制到服务器软件下5.4 启动服务器软件5.5 通过Http协议访问网站 6. 小结 1. 背景 我们之前开发的网页,都是编写完成后&#xf…