前端时间用electron+ffmpeg开发了一个视频压缩软件,然后越熟悉ffmpeg越觉得它的牛叉,以前觉得视频处理需要高深莫测的技术,ffmpeg为我解开了视频处理的神秘面纱。然后决定做一个视频处理的工具,包括视频压缩、视频剪切、视频合并、视频格式转换、视频添加水印,先上效果图。

上一篇文章介绍的用electron做的视频压缩软件,没有用到前端框架,若遇到开发多页面时就比较头痛。个人对vue还比较熟悉,就想着用electron+vue3来开发,UI就用element-plus,还有electron-builder打包工具,然后就上网查资料学习,学习中遇到各种坑,网上资料有的很老,有的不会把遇到的问题都写出来,我先把遇到的坑和怕坑方法分享给大家。
一、Electron+vue 填坑之旅
1、由于electron-builder、webpack等更新和打包问题,nodejs版本不能用最新的,需要用v16,下载地址:https://nodejs.org/en/blog/release/v16.13.0
2、创建vue项目不要用vue官网教程里面的命令,要用 vue create project-name,命令执行后选择vue3版本。
3、使用electron-builder集成electron,执行命令:vue add electron-builder,命令执行后选择版本环节时选择13.0.0
4、运行命令 npm run electron:serve,这时若无意外能跑起来,若要在项目中用到 require 方式引入模块会报错,需要修改src/background.js代码

5、打包命令 npm run electron:build,不出意外有可能会出意外,打包中途会从github上下载electron文件,若github此时刚好不能访问就会下载失败。
解决方法:
①随时观察github访问情况,若能访问了,赶快试着打包 -_-!
②受不了方法一的,复制错误提示中的github地址创造条件到github上手动把这些文件下载下来,然后放到本地应用程序缓存目录,我的具体地址如下:C:\Users\admin\AppData\Local\electron\Cache
6、配置应用程序窗口标题栏图标
创建一个resources文件夹,放入logo图片

7、配置打包信息和打包图标
修改vue.config.js
const { defineConfig } = require('@vue/cli-service')
const webpack = require('webpack');
module.exports = defineConfig({
runtimeCompiler: true,
transpileDependencies: true,
pluginOptions: {
electronBuilder: {
nodeIntegration: true,
webSecurity: false,
builderOptions: {
productName: `Video Processing Assistant`,
appId: 'com.world0101.videoprocessingassistant',
asar: true,
linux: {
target: ['deb'],
category: 'Utility',
icon: './resources/icons/icon'
},
mac: {
icon: './resources/icons/icon.icns'
},
win: {
target: [{
target: 'nsis'
}],
icon: './resources/icons/icon.ico'
},
nsis: {
oneClick: false,
allowToChangeInstallationDirectory: true,
perMachine: true,
allowElevation: true,
runAfterFinish: true,
createDesktopShortcut: true,
createStartMenuShortcut: true,
deleteAppDataOnUninstall: true,
},
extraResources: {
// 拷贝静态文件到指定位置,否则打包之后出现找不到资源的问题.将整个resources目录拷贝到发布的根目录下
// 获取静态资源路径方式:process.env.NODE_ENV !== 'production'?'./resources/xxx':process.resourcesPath + '/xxx'
from: './resources/',
to: './'
}
}
}
},
configureWebpack: {
plugins: [
//运行时fluent-ffmpeg报错解决方案
new webpack.DefinePlugin({
'process.env.FLUENTFFMPEG_COV': false
})
]
}
})
8、把background.js中下面代码注释掉,不然开发中每次启动特慢

二、ffmpeg使用
1、到ffmpeg官网(ffmpeg.org)下载对应系统dll,或者从网盘下载:https://www.123pan.com/s/DTR6Vv-jnIO3.html
然后放入respurces,比如我windows版本如下

2、引入fluent-ffmepg包,npm install fluent-ffmpeg
3、创建一个ffmpeg帮助类
const os = require('os');
const path = require('path');
const ffmpeg = require('fluent-ffmpeg');
module.exports = class FfmpegClass {
constructor() {
this._ffmpegBinPath;
this._cutVideoCommand;
this._mergeVideoCommand;
this._compressVideoCommandArr;
this._videoFormatConvertCommandArr;
this._videoAddWatermarkCommandArr;
this.setFfmpegPath();
}
setFfmpegPath() {
const platform = os.platform()
const arch = os.arch()
const basePath = path.resolve(
process.env.NODE_ENV !== 'production'?'./resources/bin':process.resourcesPath + '/bin',
platform,
// arm64 is limit supported only for macOS
platform === 'darwin' && arch === 'arm64'
? 'arm64'
: 'x64',
)
var name='ffmpeg';
this._ffmpegBinPath = path.resolve(
basePath,
platform === 'win32' ? `${name}.exe` : name,
)
.replace(/\\/g,"/")
.replace('/src/js/bin/','/bin/');
ffmpeg.setFfmpegPath(this._ffmpegBinPath);
}
//获取媒体信息
getVideoOrAudioMetaData(videoPath,callback){
ffmpeg(videoPath).ffprobe((err, data) => {
//console.log(err)
if(err==null && callback!=null){
callback(data);
}
});
}
//压缩视频
compressVideo(input, output, opts, progressCallback,endCallback,errorCallback){
try{
var ffmpegCommand = ffmpeg(input)
if(opts.frameRate!=null){
ffmpegCommand = ffmpegCommand.fps(opts.frameRate);
}
if(opts.videoWidth!=null && opts.videoHeight!=null){
ffmpegCommand=ffmpegCommand
.size(opts.videoWidth+'x'+opts.videoHeight)
.autopad();
}
if(opts.crf!=null){
ffmpegCommand=ffmpegCommand.outputOptions('-crf '+opts.crf);
}
if(opts.bitRate!=null){
ffmpegCommand=ffmpegCommand.outputOptions(['-b:v',opts.bitRate+'k']);
}
ffmpegCommand = ffmpegCommand
.on('start', function (commandLine) {
console.log('Spawned Ffmpeg with command: ' + commandLine);
})
.on('progress', function (progress) {
if(progressCallback!=null){
progressCallback(progress);
}
})
.on('end', function (stdout, stderr) {
if(endCallback!=null){
endCallback();
}
})
.on('error', function (err, stdout, stderr) {
if(errorCallback!=null){
errorCallback();
}
})
.save(output);
if(this._compressVideoCommandArr==null)
this._compressVideoCommandArr=[];
this._compressVideoCommandArr.push(ffmpegCommand);
}catch(e){
console.log(e);
if(errorCallback!=null){
errorCallback();
}
}
}
//停止压缩
killCompressVideoCommand(){
for(var i=this._compressVideoCommandArr.length-1;i>=0;i--){
this._compressVideoCommandArr[i].kill();
this._compressVideoCommandArr.splice(i,1);
}
}
}
其他就是UI方面的了。