Electron中利用fluent-ffmpeg进行视频推流

安装

1
npm install --save fluent-ffmpeg

或者添加

1
2
3
"dependencies": {
"fluent-ffmpeg": "^2.1.2"
}

之后

1
npm install

报错

This relative module was not found:

./lib-cov/fluent-ffmpeg in ./node_modules/fluent-ffmpeg/index.js

解决方法

1
npm install git+https://gitee.com/suniv/node-fluent-ffmpeg.git

或者

1
2
3
"dependencies": {
"fluent-ffmpeg": "https://gitee.com/suniv/node-fluent-ffmpeg.git"
}

当然也可以使用Github上的地址

https://github.com/fluent-ffmpeg/node-fluent-ffmpeg.git

我这里用Github地址下载不下来,才用的镜像地址。

在Windows上无法安装依赖的问题 Code 128

解决方法:

升级Git版本,node-fluent-ffmpeg项目下有部分文件的名称有[]导致Git无法Clone,网上的方法我都试了都不行,但是同事的电脑却可以,所以就怀疑是Git版本的问题,果然升级后就解决了。

视频文件推流

引用及变量

1
2
3
4
5
6
const ffmpeg = require('fluent-ffmpeg');

const ffmpegPath = "/Users/zhangjian/psvmc/app/me/electron/zjclass/libs/ffmpeg_mac/ffmpeg";
const inputPath = '/Users/zhangjian/psvmc/app/me/electron/zjclass/libs/mv.mp4';
const logo = '/Users/zhangjian/psvmc/app/me/electron/zjclass/libs/logo.png'; //水印
const outputPath = 'rtmp://119.3.212.205:1935/live/xiaoming';

具体的推流代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
var command = ffmpeg(inputPath)
.setFfmpegPath(ffmpegPath)
.inputOptions('-re')
.inputOptions('-ac 2')
.addInput(logo)
.complexFilter([{
filter: 'scale',
options: [600, -1],
inputs: '[0:v]',
outputs: 'video'
}, {
filter: 'scale',
options: [60, -1],
inputs: '[1:v]',
outputs: 'logo'
}, {
filter: 'overlay',
options: {
x: 'main_w-overlay_w-15',
y: 15
},
inputs: ['video', 'logo']
}])
.on('start', function (commandLine) {
console.log('[' + new Date() + '] Vedio is Pushing !');
console.log('commandLine: ' + commandLine);
})
.on('error', function (err, stdout, stderr) {
console.log('error: ' + err.message);
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
})
.on('end', function () {
console.log('[' + new Date() + '] Vedio Pushing is Finished !');
})
.addOptions([
'-vcodec libx264',
'-preset veryfast',
'-crf 22',
'-maxrate 1000k',
'-bufsize 3000k',
'-acodec libmp3lame',
'-ac 2',
'-ar 44100',
'-b:a 96k'
])
.format('flv');
command
.output(outputPath, {
end: true
})
.run();

桌面及麦克风推流(MAC)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
const ffmpeg = require('fluent-ffmpeg');
const ffmpegPath = "/Users/zhangjian/psvmc/app/me/electron/zjclass/libs/ffmpeg_mac/ffmpeg";
const outputPath = 'rtmp://119.3.212.205:1935/live/xiaoming';

let audioStream;
function getAudioStream() {
navigator.mediaDevices.getUserMedia({audio: true, video: false})
.then(function (stream) {
audioStream = stream;
pushStream();
stream.onended = () => {
console.log('Micro audio ended.')
}
})
.catch(function (error) {
console.log('getUserMedia() failed.')
});
}


var command;
function pushStream() {
command = ffmpeg("1:0")
.setFfmpegPath(ffmpegPath)
.inputOptions('-f avfoundation')
.inputOptions('-framerate 30')
.inputOptions('-video_size 640x480')
.on('start', function (commandLine) {
console.log('[' + new Date() + '] Vedio is Pushing !');
console.log('commandLine: ' + commandLine);
})
.on('error', function (err, stdout, stderr) {
console.log('error: ' + err.message);
console.log('stdout: ' + stdout);
console.log('stderr: ' + stderr);
})
.on('end', function () {
console.log('[' + new Date() + '] Vedio Pushing is Finished !');
})
.addOptions([
'-vcodec libx264',
'-preset ultrafast',
'-acodec libmp3lame'
])
.format('flv');
command
.output(outputPath, {
end: true
})
.run();
}

document.querySelector(".start_action").addEventListener("click", function () {
// 只是获取麦克风录制权限
getAudioStream();
});

document.querySelector(".stop_action").addEventListener("click", function () {
if(command){
command.kill();
}
});

桌面+麦克风推流(Win)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
const ffmpeg = require('fluent-ffmpeg');
const ffmpegPath = __dirname+"\\..\\libs\\ffmpeg.exe";
let command = null;

command = ffmpeg()
.setFfmpegPath(ffmpegPath)
.input('desktop')
.inputFormat('gdigrab')
.input('audio=麦克风 (2- High Definition Audio 设备)')
.inputFormat('dshow')
.addOptions([
'-vcodec libx264',
'-preset ultrafast',
'-acodec libmp3lame',
'-pix_fmt yuv422p'
])
.format('flv')
.output(outputPath, {
end: true
})
.on('start', function (commandLine) {
console.log('[' + new Date() + '] Vedio is Pushing !');
console.log('commandLine: ' + commandLine);
})
.on('error', function (err, stdout, stderr) {
console.log('error: ' + err.message);
})
.on('end', function () {
console.log('[' + new Date() + '] Vedio Pushing is Finished !');
});
command.run();

注意audio=麦克风 (2- High Definition Audio 设备)后面的中文名称不要用双引号括起来,括起来后推流是报错的!

引用的文件路径中的反斜杠也要注意。

这样其实生成的命令如下

1
ffmpeg -f gdigrab -i desktop -f dshow -i audio=麦克风 (2- High Definition Audio 设备) -vcodec libx264 -preset ultrafast -acodec libmp3lame -pix_fmt yuv422p -f flv rtmp://live.psvmc.cn:1935/live/xiaoming

但是这样的命令直接在cmd中无法运行 要把麦克风名字用双引号括起来才能运行

1
ffmpeg -f gdigrab -i desktop -f dshow -i audio="麦克风 (2- High Definition Audio 设备)" -vcodec libx264 -preset ultrafast -acodec libmp3lame -pix_fmt yuv422p -f flv rtmp://live.psvmc.cn:1935/live/xiaoming

这两个地方不一样真是折腾死我了,花了大半天才找到原因。

获取Windows音视频输入设备

设备管理器

此电脑=>管理=>设备管理器

FFMpeg方式获取

该方式获取的设备如果包含中文则乱码 并且没法在代码中获取到,只能在控制台打印。

1
ffmpeg -list_devices true -f dshow -i dummy

JS获取音视频设备

本来打算用C++获取设备生成DLL,用Node-ffi调用DLL获取,后来发现js就能获取,真是绕了个大圈。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
* 获取音频视频设备
* let ePromise = navigator.mediaDevices.enumerateDevices
*
* 获取到音频设备的属性
* deviceId 设备属性
* label 设备名称
* kind 设备种类
* groupId 两个设备groupId相同, 说明是同一个物理设备
*/

getDeviceList: function() {
if (!navigator.mediaDevices || !navigator.mediaDevices.enumerateDevices) {
console.log("menumerateDevices is not supported!");
} else {
let devicelist = {
audioinput: [],
videoinput: [],
audiooutput: []
};
navigator.mediaDevices
.enumerateDevices()
.then(deviceInfos => {
deviceInfos.forEach(e => {
if (devicelist[e.kind]) {
devicelist[e.kind].push(e);
}
});
console.info("devicelist:", devicelist);
})
.catch(err => {
console.log(`${err.name}:${err.message}`);
});
}
},

获取默认的音频输入设备的名称

注意默认设备的名称的前面被添加上了Default -

"Default - 麦克风 (Realtek High Definition Audio)",要进行移除。

1
2
3
4
5
6
7
for (let i = 0; i < devicelist.audioinput.length; i++) {
let ainput = devicelist.audioinput[i];
if (ainput.deviceId === "default") {
let defaultname = ainput.label.replace("Default - ", "");
that.pushStream(defaultname);
}
}
1
ffmpeg -f gdigrab -i desktop -f dshow -i audio="麦克风 (Realtek High Definition Audio)" -vcodec libx264 -preset ultrafast -acodec libmp3lame -pix_fmt yuv422p -f flv rtmp://live.psvmc.cn/class/110