有任何问题,欢迎站内私信博主交流。
正文开始
- 前言
- 一、多方案对比
- 二、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各插件简介
-
ffmpeg插件:这是真正的录屏插件,windows系统中以exe可执行文件形式存在,其它所有插件都是围绕它开发。
-
@ffmpeg-installer/ffmpeg插件:一个维护下载ffmpeg的插件,可以帮助我们便捷地下载更新对应版本的ffmpeg,并且在下载后,可以暴露出exe可执行文件的地址,方便我们操作ffmpeg。一般情况下,我们只需要使用@ffmpeg-installer/ffmpeg插件,就可以不用直接下载ffmpeg插件了。
-
ffmpeg-static插件:功能类似于上面的插件,但是实现原理不同,在ffmpeg-static插件中,自带某个版本的ffmpeg,ffmpeg-static插件并不提供下载维护ffmpeg的功能,但是下载ffmpeg-static,就会顺带下载ffmpeg,并帮助我们完成一些基础工作,引入ffmpeg-static插件也可以直接获取ffmpeg插件的地址,方便我们操作。
-
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代码预览功能都完成后,会在博主的桌面端工具中发布,免费使用,下面有软件获取链接。
获取资源,查看代码示例,可以通过私信博主来获取。