NodeJS - 管理多个FFMPEG流程

时间:2017-02-07 19:08:55

标签: node.js process ffmpeg pipe converter

我正在尝试编程一个可以接收任何视频源并将其转换为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进程: enter image description here

在转换test2.mp3之后,其他ffmpeg线程保持打开状态,但什么都不做,并且节点程序等待(我猜是这样),以便它发送内容。

我希望有人可以帮助我:)。

1 个答案:

答案 0 :(得分:2)

使用您的代码,我遇到了同样的问题。它会挂在最后,只输出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网址的示例视频。它不应该有所作为。

我将spawnargs变量移出对象,因为它们不会发生变化。我也不使用this来存储局部变量。我只是使用普通的闭包。最后,我将exit事件处理代码移到了对象中。我认为将所有这些内容组合在一起会更好 - 而且,它只会被声明一次而不是您创建的每个新进程。

运行它会给我以下输出(我将脚本保存为ffmpeg.js):

$ node ffmpeg.js
test2.mp3 received data
Finished: test2.mp3
test1.mp3 received data
Finished: test1.mp3

另外,只是一个提示。如果您想使用this内的StreamHandler对象,如果您的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,您的原始脚本现在适用于我。