6

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

RickZ
  • 141
  • 1
  • 12

4 Answers4

3

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.

RickZ
  • 141
  • 1
  • 12
0

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.

topek
  • 18,609
  • 3
  • 35
  • 43
  • Are saying that I would have to have some sort of intermediary function that reads the incoming stream and passes it off to Adobe Media Server rather than having the ffmpeg child_process do so directly? If that's the case, then I would imagine I could end that intermediary stream. However, wouldn't that leave the source process running 24/7? – RickZ Jan 07 '13 at 22:05
  • As a matter of fact I do not know your exact requirements and it is a bit hard to state the correct answer. Why do you not use `.kill`to end the chlidprocess? – topek Jan 07 '13 at 22:10
  • I just tried that. I ended up using 'SIGTERM' since 'SIGHUP' doesn't appear to be supported on Windows. It certainly worked with ending the stream. Since the end goal is to ultimately provide several different streams at various bit rates as well as an mp4 file, I'll need to check to see whether or not the mp4 ends up truncated. Thank you very much for your help! – RickZ Jan 07 '13 at 22:15
  • 1
    Unfortunately using the .kill command doesn't allow FFMPEG to "finish" the mp4 file resulting in it being unplayable. If anybody else has any additional suggestions as to how to communicate / pass 'q' or 'q\n' back to an FFMPEG instance that has been created through the spawn method through Node.js I would appreciate it. In the meantime, I'll continue to poke around to see what I can turn up. Thanks! – RickZ Jan 08 '13 at 14:01
0

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.

RickZ
  • 141
  • 1
  • 12
0

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