How do I close a Node.js FFMPEG child process that is actively streaming from a live capture source?

こ雲淡風輕ζ 提交于 2019-12-23 20:09:09

问题


I'm new to Node.js and have figured out how to utilize child.spawn to launch an instance of FFMPEG that is being used to capture live video and send it over to Adobe Media Server via rtmp.

Every example I've seen of FFMPEG being used in conjunction with Node.js has been with a time limited sample, so the child process closes once FFMPEG reaches the end of the file it is converting.

In this case, there is no "end of file".

If I instantiate:

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

it creates the live feed.

I have tried immediately shutting the child process down with a:

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

However, that does not seem to work. I continue to see my rtmp feed on my test box.

Is there any way to pass FFMPEG a shut down command via stdin in Node.js?

Thanks in advance!

Rick


回答1:


The following code is loaded by my main app.js as a module using the child_process.fork() method:

    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);

It was far less complicated than I was making it. The main app.js is a basic HTML page that is served up and uses socket.io to receive an event and its corresponding data. In this case, a 'true' event loads the module.js file which launches a live capture session of FFMPEG, feeds it into a RTMP server, and gracefully shuts down FFMPEG on a timeout of 10 seconds.

My next task is to shut it down via an event triggered from a web interface as opposed to the current testing method of a timeout.

Looking at the task manager in Windows, the FFMPEG process closes as does the secondary node process.

The reason for this is that none of the node-ffmpeg modules that I found supported live streaming via capture input. They appear to be primarily for transcoding existing content. The final outcome of this will ideally be a web based interface that can start and stop FFMPEG. Our use case will be replacing Adobe Flash Media Live Encoder as the source for our Adobe Media Server due to its inability to save standard mp4 files.




回答2:


You can simply kill it.

ffmpeg.kill(SIGHUB)

or any other kill signal you wish, see http://en.wikipedia.org/wiki/Unix_signal


If I understand your example correctly, you pass all args of the node process to ffmpeg including the stream. In order to get your ffmeg.end() to work you would have to stream directly from your node process. I think that ffmpeg does not stop when it continuously receives data from your camera.




回答3:


What follows is more or less a final solution to the problem of launching and closing a live FFMPEG session using 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() {


    });

This code is encapsulated in a "module.js" file that is instantiated via a child_process.fork() in the root application.js file. It reads a text file where the 'state' is stored. This state is toggled via a write/read method in the root application. In the on('data') event, it reads the file and if it detects that the state has changed to false, it then shuts down FFMPEG by writing the 'q' command to the stdin.

Outside of refining it by using a database if I were to implement it on a larger scale, I am more than open to feedback regarding a more elegant way to code this.




回答4:


you need to send EOF after the file is done streaming to ffmpeg. then ffmpeg will finish and shutdown correctly



来源:https://stackoverflow.com/questions/14204174/how-do-i-close-a-node-js-ffmpeg-child-process-that-is-actively-streaming-from-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!