2017-02-07 3 views
1

Я пытаюсь программировать конвертер, который может взять любой источник видео и преобразовать его в mp3. MP3 должен быть сохранен на моем жестком диске или в буфере, чтобы отправить его по телеграмме.NodeJS - многопроцессорные процессы FFMPEG

Это хорошо работает, единственная проблема, с которой я столкнулся, заключается в том, что она может принимать только одно видео за раз, и я не знаю почему.

// 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 поток остается открытым, но ничего не делает, и программа узла застряла в ожидании (я думаю, так), чтобы она что-то послала.

Я надеюсь, что кто-то может помочь мне :)

ответ

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 URL доступен. Это не должно иметь значения.

Я переместил spawn и args переменных из объекта, потому что они не меняются. Я также не использую 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.

Надеюсь, это поможет!

- EDIT -

Хорошо, я понял. Проблема в коде эта линия:

self = this; 

Оно должно быть:

var self = this; 

Без var спецификатором, вы создаете глобальную переменную. Итак, во второй раз, когда вы вызываете new StreamHandler, вы переписываете переменную self.Вот почему файл test1.mp3 зависает, и файл test2.mp3 является единственным, кто заканчивает. Добавив var, ваш оригинальный скрипт теперь работает для меня.

+0

Спасибо. Посмотрим позже. Я действительно надеюсь, что кто-то еще знает, почему это не сработает, поэтому я могу уклониться от этой проблемы в будущем. – Alaska

+0

@Alaska См. Вышеизложенное. –

+0

Спасибо. Это сработало! – Alaska

Смежные вопросы