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

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


正文开始


前言

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

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


一、多方案对比

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

c 复制代码
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,录制视频流:

c 复制代码
 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插件。

第一步------下载:

c 复制代码
npm i ffmpeg-static

第二步------引入:

c 复制代码
  const pathToFfmpeg = require('ffmpeg-static')

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

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

四、使用fluent-ffmpeg插件

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

第一步------下载:

c 复制代码
npm i fluent-ffmpeg

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

c 复制代码
 const ffmpeg = require('fluent-ffmpeg');
 const pathToFfmpeg = require('ffmpeg-static')

第三步------使用:

c 复制代码
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"后面的参数。

下面是最原始的命令行:

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

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

c 复制代码
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

相关推荐
守城小轩17 小时前
Chromium127编译指南 Mac篇(五)- 编译Chromium
chrome·chrome devtools·指纹浏览器·浏览器开发
S. Dylan21 小时前
Edge浏览器打开PDF无法显示电子签章
edge·pdf
福大大架构师每日一题1 天前
文心一言 VS 讯飞星火 VS chatgpt (384)-- 算法导论24.5 4题
算法·文心一言
过去式的马马马1 天前
文多多AIPPT
ai作画·aigc·文心一言·ai编程·dall·e 2
gqkmiss2 天前
Chrome 130 版本开发者工具(DevTools)更新内容
前端·chrome·chrome devtools·开发者工具·chrome 130
守城小轩2 天前
Chromium127编译指南 Mac篇(二)- 安装Xcode
chrome·chrome devtools·指纹浏览器·浏览器开发
像风一样自由20203 天前
Edge 浏览器插件开发:图片切割插件
服务器·edge·插件
守城小轩3 天前
Chromium127编译指南 Mac篇(一)- 环境准备详解
chrome·chrome devtools·指纹浏览器·浏览器开发
守城小轩4 天前
Chromium127编译指南 Linux篇 - 同步第三方库以及Hooks(六)
chrome·chrome devtools·指纹浏览器·浏览器开发
企业通用软件开发4 天前
提示工程:GPT写一篇短篇小说~文心一言
人工智能·gpt·文心一言