rcode
rcode

Reputation: 1888

FFMPEG hangs the whole nodejs process

What I am trying to do is to make a thumbnail of a video using ffmpeg. The video data is received in a HTTP request and then piped to ffmpeg. The problem is that once the ffmpeg child process exits I simply can't send the response back.

Here is the code:

var http = require('http'),
sys = require('sys'),
child = require('child_process')
http.createServer(function (req, res) {
    im = child.spawn('ffmpeg',['-i','-','-vcodec','mjpeg','-ss','00:00:03','-vframes','1','-s','100x80','./thumb/thumbnail.jpg']);
    im.on('exit', function (code, signal) {
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end('{"success":true}\n');
     });
    req.connection.pipe(im.stdin);
}).listen(5678, "127.0.0.1");

The problem is that calling:

res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('{"success":true}\n');

does nothing, the client never receives the response.

Upvotes: 4

Views: 4340

Answers (2)

rcode
rcode

Reputation: 1888

After two days of debugging and googling It seems like I have found the problem. There are two related open bugs in node.js responsible:

I will try to describe what I think the problem is with the 'pipe' method:

The request stream fails to invoke end on ffmpeg.stdin (probably bug #777), this causes a broken pipe error, but node.js doesn't handle the error because of bug #782, meanwhile the request stream remains paused - this blocks any response from being sent.

The hack/workaround is to resume the request stream once ffmpeg exits.

Here is the fixed code sample:

var http = require('http'),
sys = require('sys'),
child = require('child_process')
http.createServer(function (req, res) {
im = child.spawn('ffmpeg',['-i','-','-vcodec','mjpeg','-ss','00:00:03','-vframes','1','-s','100x80','./thumb/thumbnail.jpg']);
    im.on('exit', function (code, signal) {
        req.resume();
        res.writeHead(200, {'Content-Type': 'text/plain'});
        res.end('{"success":true}\n');
     });
  req.connection.pipe(im.stdin);
}).listen(5678, "127.0.0.1");

Please keep in mind that this is a hack/workaround and may lead to problems with future node.js releases once they do something about those bugs

Upvotes: 5

Tim P.
Tim P.

Reputation: 421

I would try something like this.

var http = require('http'):
var sys = require('sys'):
var child = require('child_process'):

http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    im = child.spawn('ffmpeg',['-i','-','-vcodec','mjpeg','-ss','00:00:03','-vframes','1','-s','100x80','./thumb/thumbnail.jpg']);
    im.on('exit', function (code, signal) {
        res.end('{"success":true}\n');
    });
    req.connection.pipe(im.stdin);
}).listen(5678, "127.0.0.1");

You are trying to pipe out data to the socket before sending the header.

Upvotes: 2

Related Questions