【问题标题】:NodeJS - piping multiple FFMPEG processesNodeJS - 管道多个 FFMPEG 进程
【发布时间】:2017-02-07 19:08:54
【问题描述】:

我正在尝试编写一个转换器,它可以获取任何视频源并将其转换为 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 线程保持打开状态,但什么也不做,节点程序卡住等待(我猜是这样)它发送一些东西。

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

【问题讨论】:

    标签: node.js process ffmpeg pipe converter


    【解决方案1】:

    使用您的代码,我遇到了同样的问题。它会在最后挂起并且只输出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
    

    另外,只是一个提示。如果您想在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,您的原始脚本现在可以为我工作了。

    【讨论】:

    • 谢谢。以后会看的。我真的希望其他人知道为什么它不能按我的方式工作,这样我以后就可以避开这个问题
    • 你知道如何让这些进程并行运行吗? -> 请看看我的新问题 :)
    猜你喜欢
    • 2015-04-27
    • 2011-09-22
    • 1970-01-01
    • 1970-01-01
    • 2015-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多