NodeJS - 管道多个 FFMPEG 进程
NodeJS - piping multiple FFMPEG processes
我正在尝试编写一个可以将任何视频源转换为 mp3 的转换器。 mp3 应该保存在我的硬盘上,或者在缓冲区中以通过电报发送它。
到目前为止效果很好,我面临的唯一问题是一次只能拍摄一个视频,我不知道为什么。
// IMPORTS
var fs = require('fs');
var https = require('https');
var child_process = require('child_process');
// EVENTEMITER (Not used so far)
var util = require('util');
var EventEmitter = require('events').EventEmitter;
// STREAMHANDLER
var StreamHandler = function(url, name){
// VARIABLES
self = this;
this.url = url;
this.name = name;
// CREATE FFMPEG PROCESS
var spawn = child_process.spawn;
var args = ['-i', 'pipe:0', '-f', 'mp3', '-ac', '2', '-ab', '128k', '-acodec', 'libmp3lame', 'pipe:1'];
this.ffmpeg = spawn('ffmpeg', args);
// GRAB STREAM
https.get(url, function(res) {
res.pipe(self.ffmpeg.stdin);
});
// WRITE TO FILE
this.ffmpeg.stdout.pipe(fs.createWriteStream(name));
//DEBUG
this.ffmpeg.stdout.on("data", function (data) {
console.error(self.name);
});
}
util.inherits(StreamHandler, EventEmitter);
// TESTING
var test1 = new StreamHandler(vidUrl, "test1.mp3");
test1.ffmpeg.on("exit", function (code, name, signal) {
console.log("Finished: " + test1.name);
});
var test2 = new StreamHandler(vidUrl, "test2.mp3");
test2.ffmpeg.on("exit", function (code, name, signal) {
console.log("Finished: " + test2.name);
});
它跳过了test1.mp3,只转换了test2.mp3,但是创建了2个ffmpeg进程:
转换 test2.mp3 后,另一个 ffmpeg 线程保持打开状态,但什么也不做,节点程序卡住等待(我猜是这样)它发送一些东西。
希望有人能帮助我:)
使用你的代码,我遇到了同样的问题。它会挂在最后,只输出 test2.mp3
文件的数据。我不确定是什么导致了这个问题,但我稍微改变了一下,这对我有用:
// IMPORTS
var fs = require('fs');
//var https = require('https');
var http = require('http');
var child_process = require('child_process');
// EVENTEMITER (Not used so far)
var util = require('util');
var EventEmitter = require('events').EventEmitter;
// These never change...
var spawn = child_process.spawn;
var args = ['-i', 'pipe:0', '-f', 'mp3', '-ac', '2', '-ab', '128k', '-acodec', 'libmp3lame', 'pipe:1'];
// STREAMHANDLER
var StreamHandler = function(url, name){
// CREATE FFMPEG PROCESS
var ffmpeg = spawn('ffmpeg', args);
// GRAB STREAM
http.get(url, function(res) {
res.pipe(ffmpeg.stdin);
});
// WRITE TO FILE
ffmpeg.stdout.pipe(fs.createWriteStream(name));
ffmpeg.on("exit", function() {
console.log("Finished:", name);
});
//DEBUG
ffmpeg.stdout.on("data", function(data) {
console.error(name, "received data");
});
}
util.inherits(StreamHandler, EventEmitter);
// TESTING
var vidUrl = 'http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4';
var test1 = new StreamHandler(vidUrl, "test1.mp3");
var test2 = new StreamHandler(vidUrl, "test2.mp3");
我正在使用 http
而不是 https
,因为我在 https
url 处没有可用的示例视频。应该没什么区别。
我将 spawn
和 args
变量移出了对象,因为它们不会改变。我也不使用 this
来存储局部变量。我只是使用普通的闭包。最后,我将 exit
事件处理代码移到了对象内部。我只是认为最好将所有这些东西组合在一起——另外,它只声明一次而不是为你创建的每个新进程声明。
运行 这给了我以下输出(我将脚本保存为 ffmpeg.js
):
$ node ffmpeg.js
test2.mp3 received data
Finished: test2.mp3
test1.mp3 received data
Finished: test1.mp3
此外,只是一个小费。如果您想在 StreamHandler
中使用 this
对象,如果您的 Node 版本支持它们,我建议您使用箭头函数。此代码也有效:
var StreamHandler = function(url, name){
// CREATE FFMPEG PROCESS
this.ffmpeg = spawn('ffmpeg', args);
// GRAB STREAM
http.get(url, (res) => {
res.pipe(this.ffmpeg.stdin);
});
// WRITE TO FILE
this.ffmpeg.stdout.pipe(fs.createWriteStream(name));
this.ffmpeg.on("exit", () => {
console.log("Finished:", name);
});
//DEBUG
this.ffmpeg.stdout.on("data", (data) => {
console.error(name, "received data");
});
}
请注意,使用箭头函数,我不必使用 var self = this;
避免这种情况几乎是将箭头函数添加到 javascript.
的原因
希望对您有所帮助!
-- 编辑--
好的,我明白了。您的代码中的问题是这一行:
self = this;
应该是:
var self = this;
没有 var
说明符,您将创建一个全局变量。因此,第二次调用 new StreamHandler
时,您将覆盖 self
变量。这就是为什么 test1.mp3
文件挂了, test2.mp3
文件是唯一一个整理的原因。通过添加 var
,您的原始脚本现在适用于我。
我正在尝试编写一个可以将任何视频源转换为 mp3 的转换器。 mp3 应该保存在我的硬盘上,或者在缓冲区中以通过电报发送它。
到目前为止效果很好,我面临的唯一问题是一次只能拍摄一个视频,我不知道为什么。
// IMPORTS
var fs = require('fs');
var https = require('https');
var child_process = require('child_process');
// EVENTEMITER (Not used so far)
var util = require('util');
var EventEmitter = require('events').EventEmitter;
// STREAMHANDLER
var StreamHandler = function(url, name){
// VARIABLES
self = this;
this.url = url;
this.name = name;
// CREATE FFMPEG PROCESS
var spawn = child_process.spawn;
var args = ['-i', 'pipe:0', '-f', 'mp3', '-ac', '2', '-ab', '128k', '-acodec', 'libmp3lame', 'pipe:1'];
this.ffmpeg = spawn('ffmpeg', args);
// GRAB STREAM
https.get(url, function(res) {
res.pipe(self.ffmpeg.stdin);
});
// WRITE TO FILE
this.ffmpeg.stdout.pipe(fs.createWriteStream(name));
//DEBUG
this.ffmpeg.stdout.on("data", function (data) {
console.error(self.name);
});
}
util.inherits(StreamHandler, EventEmitter);
// TESTING
var test1 = new StreamHandler(vidUrl, "test1.mp3");
test1.ffmpeg.on("exit", function (code, name, signal) {
console.log("Finished: " + test1.name);
});
var test2 = new StreamHandler(vidUrl, "test2.mp3");
test2.ffmpeg.on("exit", function (code, name, signal) {
console.log("Finished: " + test2.name);
});
它跳过了test1.mp3,只转换了test2.mp3,但是创建了2个ffmpeg进程:
转换 test2.mp3 后,另一个 ffmpeg 线程保持打开状态,但什么也不做,节点程序卡住等待(我猜是这样)它发送一些东西。
希望有人能帮助我:)
使用你的代码,我遇到了同样的问题。它会挂在最后,只输出 test2.mp3
文件的数据。我不确定是什么导致了这个问题,但我稍微改变了一下,这对我有用:
// IMPORTS
var fs = require('fs');
//var https = require('https');
var http = require('http');
var child_process = require('child_process');
// EVENTEMITER (Not used so far)
var util = require('util');
var EventEmitter = require('events').EventEmitter;
// These never change...
var spawn = child_process.spawn;
var args = ['-i', 'pipe:0', '-f', 'mp3', '-ac', '2', '-ab', '128k', '-acodec', 'libmp3lame', 'pipe:1'];
// STREAMHANDLER
var StreamHandler = function(url, name){
// CREATE FFMPEG PROCESS
var ffmpeg = spawn('ffmpeg', args);
// GRAB STREAM
http.get(url, function(res) {
res.pipe(ffmpeg.stdin);
});
// WRITE TO FILE
ffmpeg.stdout.pipe(fs.createWriteStream(name));
ffmpeg.on("exit", function() {
console.log("Finished:", name);
});
//DEBUG
ffmpeg.stdout.on("data", function(data) {
console.error(name, "received data");
});
}
util.inherits(StreamHandler, EventEmitter);
// TESTING
var vidUrl = 'http://www.sample-videos.com/video/mp4/720/big_buck_bunny_720p_1mb.mp4';
var test1 = new StreamHandler(vidUrl, "test1.mp3");
var test2 = new StreamHandler(vidUrl, "test2.mp3");
我正在使用 http
而不是 https
,因为我在 https
url 处没有可用的示例视频。应该没什么区别。
我将 spawn
和 args
变量移出了对象,因为它们不会改变。我也不使用 this
来存储局部变量。我只是使用普通的闭包。最后,我将 exit
事件处理代码移到了对象内部。我只是认为最好将所有这些东西组合在一起——另外,它只声明一次而不是为你创建的每个新进程声明。
运行 这给了我以下输出(我将脚本保存为 ffmpeg.js
):
$ node ffmpeg.js
test2.mp3 received data
Finished: test2.mp3
test1.mp3 received data
Finished: test1.mp3
此外,只是一个小费。如果您想在 StreamHandler
中使用 this
对象,如果您的 Node 版本支持它们,我建议您使用箭头函数。此代码也有效:
var StreamHandler = function(url, name){
// CREATE FFMPEG PROCESS
this.ffmpeg = spawn('ffmpeg', args);
// GRAB STREAM
http.get(url, (res) => {
res.pipe(this.ffmpeg.stdin);
});
// WRITE TO FILE
this.ffmpeg.stdout.pipe(fs.createWriteStream(name));
this.ffmpeg.on("exit", () => {
console.log("Finished:", name);
});
//DEBUG
this.ffmpeg.stdout.on("data", (data) => {
console.error(name, "received data");
});
}
请注意,使用箭头函数,我不必使用 var self = this;
避免这种情况几乎是将箭头函数添加到 javascript.
希望对您有所帮助!
-- 编辑--
好的,我明白了。您的代码中的问题是这一行:
self = this;
应该是:
var self = this;
没有 var
说明符,您将创建一个全局变量。因此,第二次调用 new StreamHandler
时,您将覆盖 self
变量。这就是为什么 test1.mp3
文件挂了, test2.mp3
文件是唯一一个整理的原因。通过添加 var
,您的原始脚本现在适用于我。