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

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


正文开始

  • 前言
  • 一、多方案对比
  • 二、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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【NumPy】全面解析NumPy的astype函数:高效数据类型转换指南

🧑 博主简介:阿里巴巴嵌入式技术专家,深耕嵌入式人工智能领域,具备多年的嵌入式硬件产品研发管理经验。 📒 博客介绍:分享嵌入式开发领域的相关知识、经验、思考和感悟,欢迎关注。提供嵌入式方向…

VUE-watch和watchEffect的区别

区别简短扼要地说: watch-官方定义:侦听一个或多个响应式数据源,并在数据源变化时调用所给的回调函数。是需要指定监听的数据,并且只有在响应式数据变化的时候去执行 watchEffect-官方定义:立即运行一个函数&#xff0…

mybatis关联查询使用resultMap查询到了多条,结果返回一条。

今天在写代码时候,遇到了一个很让我费解的问题,在使用关联查询的时候,在明明数据库里面,已经查到了两条数据,结果resultMap这个集合里面,就只返回一条数据。 数据库的SQL: mybatis的xml里面的r…

公告:关于博主的重要通知

大家好,我是博主夏目。 本期不分享知识,博主想说明一下博主的一些重要提示。 分享的内容,从不收费,也未向任何人进行收费。 意在分享知识,传播文化,结交更多志同道合的朋友。 截至目前,从未…

多系统集成的项目周期为何普遍较长?

在现代企业的运营中,各种信息系统的集成已成为提升效率和竞争力的关键。然而,当工厂的ERP系统需要与MES、SRM、WMS、CRM等其他系统集成时,项目周期往往长达一年以上,这不仅耗费时间、人力和财力,还可能影响企业的正常运…

【GD32F303红枫派使用手册】第一节 RCU-时钟配置及输出实验

1.1 实验内容 通过本实验主要学习以下内容: RCU时钟原理及配置; RCU时钟输出验证。 1.2 实验原理 1.2.1 RCU时钟树原理 GD32F303系列MCU的时钟树如下图所示,由该图可知,GD32F303系列MCU的时钟树可大致分为三个部分&#xff…

外卖系统源码解读:校园外卖APP开发全攻略

外卖系统源码解读:校园外卖APP开发全攻略 今天,小编将深入解读外卖系统的源码,详细介绍如何开发一款功能齐全的校园外卖APP,帮助开发者快速上手,打造出高质量的外卖应用。 一、需求分析 应具备以下基本功能&#xff…

C++之对象的使用

1、static成员 2、static成员优点 2、static成员函数 静态成员函数不能访问非静态成员原因:因为没有this指针。也不可以访问非静态成员函数。 可以通过对象来访问静态成员,但是不推荐这么使用,会让人误解成这个x_是属于对象的,但…

使用prometheus监测MySQL主从同步状态方案

说明:本文介绍如何使用prometheus、alertmanager监测MySQL主从,当从节点中断同步时,发送邮箱报警,并使用grafana将数据视图化。 结构图如下: 安装 (1)安装应用 首先,来安装promet…

svg画简单的立方体

开发背景 要开发一个拖拽的大屏项目,其中涉及到一个装饰组件,是一个立方体cube,要求颜色可以修改,大小可以拖拽改变。 效果如下 分析 经过我一番奇思妙想,决定用svg实现,因为对svg比较熟悉。那就先来在草…

LabVIEW中实现Trio控制器的以太网通讯

在LabVIEW中实现与Trio控制器的以太网通讯,可以通过使用TCP/IP协议来完成。这种方法包括配置Trio控制器的网络设置、使用LabVIEW中的TCP/IP函数库进行数据传输和接收,以及处理通讯中的错误和数据解析。本文将详细说明实现步骤,包括配置、编程…

职责链设计模式

职责链设计模式(Chain of Responsibility Design Pattern)是一种行为设计模式,使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合。这些对象被链接成一条链,沿着这条链传递请求,直到有一…

【Vue】自动导入组件

1. 下载插件 npm install unplugin-vue-components 2. 修改vite.config.js import { fileURLToPath, URL } from node:urlimport { defineConfig } from vite import vue from vitejs/plugin-vue import Components from unplugin-vue-components/vite // 按需加载自定义组件/…

2、PHP 8.1.0-dev 后门远程命令执行漏洞复现

1、青少年ctf,题目PHP后门 2、页面 3、bp抓包发现PHP版本为8.1.0-dev 4、尝试使用以前爆出过的漏洞(网上查相关案例) User-Agentt: zerodiumvar_dump(5*5); User-Agentt: zerodiumsystem("cat /flag"); 5、查找flag User-Agentt: z…

3.游戏中自定义数据类型的解读分析

知识来源于腾讯课堂易道云 结构的解释: 计算机里的所有东西都是用二进制表示的,二进制是数字,我们用的阿拉伯数字0-9这个数字是十进制,计算机用的是二进制只有0或1,然后都是一堆0或1的数字,游戏中怎么把这…

路径规划算法--BFS

系列文章目录 文章目录 系列文章目录一、BFS二、BFS伪代码BFS与Dijkstra区别 一、BFS BFS(Breadth First Search)为广度优先搜索,是一种用于遍历或搜索树或图的搜索算法,适用于无权图的遍历。BFS从根节点开始,探索其相…

AI大模型:大数据+大算力+强算法

前言:好久不见,甚是想念,我是辣条,我又回来啦,兄弟们,一别两年,还有多少老哥们在呢? 目录 一年半没更文我干啥去了? AI大模型火了 人工智能 大模型的理解 为什么学习…

【Python】 Python中__slots__的妙用:提升性能与内存管理

基本原理 在Python中,每个类默认都会继承自object类,而object类在Python中是一个动态类,允许动态地添加属性和方法。这种灵活性使得Python在某些情况下非常强大和灵活,但同时也带来了一些性能和内存使用上的开销。 为了解决这个…

简化跨网文件传输摆渡过程,降低IT人员工作量

在当今数字化时代,IT企业面临着日益增长的数据交换需求。随着网络安全威胁的不断演变,网关隔离成为了保护企业内部网络不受外部威胁的重要手段。然而,隔离的同时,企业也需要在不同网络间安全、高效地传输文件,这就催生…

ubuntu strace命令

strace 是 Linux 系统中的一个调试工具,用于跟踪并记录系统调用(system calls)和信号(signals)。在 Ubuntu 中,strace 命令可以帮助开发者和系统管理员了解一个程序在运行时如何与操作系统内核进行交互&…