Как закрыть дочерний процесс Node.js FFMPEG, который активно транслируется из источника захвата в реальном времени?

Я новичок в Node.js и понял, как использовать child.spawn для запуска экземпляра FFMPEG, который используется для захвата живого видео и отправки его на Adobe Media Server через rtmp.

Каждый пример использования FFMPEG в сочетании с Node.js, который я видел, был с образцом, ограниченным по времени, поэтому дочерний процесс закрывается, как только FFMPEG достигает конца файла, который он преобразует.

В этом случае нет "конца файла".

Если я создам экземпляр:

    var ffmpeg = child.spawn('ffmpeg.exe', [args]);

он создает прямую трансляцию.

Я попытался немедленно закрыть дочерний процесс с помощью:

    setTimeout(function() {
        ffmpeg.stdin.resume();
        ffmpeg.stdin.write('insert command to echo q to close FFMPEG');
        ffmpeg.stdin.end();
    });

Однако, похоже, это не работает. Я продолжаю видеть свой rtmp-канал на своем тестовом блоке.

Есть ли способ передать FFMPEG команду выключения через стандартный ввод в Node.js?

Заранее спасибо!

Рик


person RickZ    schedule 07.01.2013    source источник


Ответы (4)


Следующий код загружается моим основным app.js как модуль с использованием метода child_process.fork():

    var spawn = require('child_process').spawn;

    var ffmpeg = spawn('C:\\Program Files (x86)\\ffmpeg\\bin\\ffmpeg.exe', ['-y', '-threads', '-0', '-re', '-rtbufsize', '204800000', '-probesize', '4096', '-vsync', '2', '-async', '30', '-f', 'dshow', '-s', '320x240', '-i', 'video=Integrated Webcam:audio=Microphone Array (IDT High Defi', '-c:a', 'libvo_aacenc', '-ab', '48000', '-ar', '22050', '-ac', '2', '-c:v', 'libx264', '-s', '400x300', '-g', '96', '-x264opts', 'bitrate=1200', '-preset', 'ultrafast', '-profile:v', 'baseline', '-pix_fmt', 'yuv420p', '-aspect', '4:3', '-f', 'flv', 'rtmp://server']);

    setTimeout(function() {
        ffmpeg.stderr.on('data', function() {
            ffmpeg.stdin.setEncoding('utf8');
            ffmpeg.stdin.write('q');
            process.exit();
        });
    }, 10000);

Это было гораздо менее сложно, чем я делал. Основной app.js — это базовая HTML-страница, которая обслуживается и использует socket.io для получения события и соответствующих данных. В этом случае «истинное» событие загружает файл module.js, который запускает сеанс захвата FFMPEG в реальном времени, передает его на сервер RTMP и корректно завершает работу FFMPEG по тайм-ауту в 10 секунд.

Моя следующая задача — выключить его через событие, инициированное из веб-интерфейса, в отличие от текущего метода тестирования тайм-аута.

Глядя на диспетчер задач в Windows, процесс FFMPEG закрывается, как и процесс вторичного узла.

Причина этого в том, что ни один из модулей node-ffmpeg, которые я нашел, не поддерживает прямую трансляцию через ввод захвата. Похоже, они в первую очередь предназначены для перекодирования существующего контента. Конечным результатом этого в идеале будет веб-интерфейс, который может запускать и останавливать FFMPEG. Наш вариант использования заменит Adobe Flash Media Live Encoder в качестве источника для нашего Adobe Media Server из-за его невозможности сохранять стандартные файлы mp4.

person RickZ    schedule 10.01.2013

Вы можете просто убить его.

ffmpeg.kill(SIGHUB)

или любой другой сигнал уничтожения, который вы хотите, см. http://en.wikipedia.org/wiki/Unix_signal


Если я правильно понимаю ваш пример, вы передаете все аргументы процесса node в ffmpeg, включая поток. Чтобы заставить ваш ffmeg.end() работать, вам нужно будет выполнять потоковую передачу непосредственно из процесса вашего узла. Я думаю, что ffmpeg не останавливается, когда он непрерывно получает данные с вашей камеры.

person topek    schedule 07.01.2013
comment
Я говорю, что мне понадобится какая-то промежуточная функция, которая считывает входящий поток и передает его на Adobe Media Server, а не напрямую, если это делает ffmpeg child_process? Если это так, то я думаю, что смогу закончить этот промежуточный поток. Однако разве это не оставит исходный процесс работающим 24 часа в сутки 7 дней в неделю? - person RickZ; 08.01.2013
comment
На самом деле я не знаю ваших точных требований, и немного сложно дать правильный ответ. Почему вы не используете .kill для завершения процесса chlid? - person topek; 08.01.2013
comment
Я только что попробовал это. В итоге я использовал «SIGTERM», так как «SIGHUP» не поддерживается в Windows. Это определенно сработало с завершением потока. Поскольку конечная цель состоит в том, чтобы в конечном итоге предоставить несколько разных потоков с разной скоростью передачи данных, а также файл mp4, мне нужно проверить, не усекается ли mp4. Большое спасибо за Вашу помощь! - person RickZ; 08.01.2013
comment
К сожалению, использование команды .kill не позволяет FFMPEG завершить файл mp4, в результате чего он становится невоспроизводимым. Если у кого-то еще есть какие-либо дополнительные предложения относительно того, как передать/передать 'q' или 'q\n' обратно в экземпляр FFMPEG, который был создан с помощью метода spawn через Node.js, я был бы признателен. Тем временем я продолжу ковыряться, чтобы посмотреть, что я могу найти. Спасибо! - person RickZ; 08.01.2013

Далее следует более или менее окончательное решение проблемы запуска и закрытия сеанса FFMPEG в реальном времени с использованием Node.js:

    var     spawn = require('child_process').spawn
,   fs = require('fs');


    function ffmpeg(cmd, opts, callback) {
    var p;
    //console.log(callback());
    if(p == undefined) {
        var p = spawn(cmd, opts);

        p.stderr.on('data', function(data) {
            /*p.stdin.setEncoding('utf8');
                p.stdin.write('q');
                process.exit()
            */
            fs.readFile(__dirname + '/server-state.json', function(error, data) {
                if(error) {
                        console.log(error); 
                    } else {
                        content = JSON.parse(data);
                        console.log(content['State']);

                        if(content['State'] == 'false') {
                            p.stdin.setEncoding('utf8');
                            p.stdin.write('q');
                            process.exit()
                        }
                    }
            });

        });

        return p;
    }

}

    ffmpeg_var = ffmpeg('C:\\Program Files (x86)\\ffmpeg\\bin\\ffmpeg.exe', ['-y', '-threads', '-0', '-re', '-rtbufsize', '204800000', '-probesize', '4096', '-vsync', '2', '-async', '30', '-f', 'dshow', '-s', '320x240', '-i', 'video=Integrated Webcam:audio=Microphone Array (IDT High Defi', '-c:a', 'libvo_aacenc', '-ab', '48000', '-ar', '22050', '-ac', '2', '-c:v', 'libx264', '-s', '400x300', '-g', '96', '-x264opts', 'bitrate=1200', '-preset', 'ultrafast', '-profile:v', 'baseline', '-pix_fmt', 'yuv420p', '-aspect', '4:3', '-f', 'mp4', __dirname + '/IntegrityTest.mp4'], function() {


    });

Этот код инкапсулирован в файле «module.js», который создается с помощью child_process.fork() в корневом файле application.js. Он читает текстовый файл, в котором хранится «состояние». Это состояние переключается с помощью метода записи/чтения в корневом приложении. В событии on('data') он считывает файл и, если обнаруживает, что состояние изменилось на false, затем отключает FFMPEG, записывая команду q в стандартный ввод.

Помимо уточнения с помощью базы данных, если бы я реализовал его в большем масштабе, я более чем открыт для отзывов относительно более элегантного способа кодирования.

person RickZ    schedule 10.01.2013

вам нужно отправить EOF после того, как файл будет передан в ffmpeg. тогда ffmpeg закончит работу и выключится правильно

person Deez Gz    schedule 01.06.2013