Search code examples
node.jsstreamingmjpeg

For an mjpeg stream created with node.js, how do I encode it in another format and then stream?


I create a little application with nodejs that stream a multipart/x-mixed-replace data to browser.

This data is created with image data, but the image data may change over time, so in the browser it looks like a video. The image data is created from a webcam, so in the browser it looks like live streaming.

But the performance isn't very good.

I've tried some other approaches: - First: Use socket.io to push images to browser, here i use the base64 data from the image (push this data) and in the browser i recreate the image (jpeg): works good, but only with one or two clients. _ Second: Use polling from browser to nodejs server.. this doesn't like me.

So this is the code: (some part of the code of my nodejs server) I use express to make the http server:

app.get('/videoStream',function(req,response){   
    response.writeHead(200,{
        'Content-Type': 'multipart/x-mixed-replace;boundary="' + boundary + '"',
        'Connection': 'keep-alive',
        'Expires': 'Fri, 01 Jan 1990 00:00:00 GMT',
        'Cache-Control': 'no-cache, no-store, max-age=0, must-revalidate',
        'Pragma': 'no-cache'
    });
    response.write('--'+boundary+'\n');

    events.addListener('imagen_recibida',function(){
        fs.readFile(__dirname + '/image.jpeg',function(err,data){
             if(err) return send404(response);
             response.write('Content-Type: image/jpeg\n Content-Length: '+data.length+'\n\n');
             response.write(data);
            response.write('\n--'+boundary+'\n');
           });
    });

When the event "imagen_recibida" rise, it reads the image from disk and write the data to browser.

So the two questions:

Is there any approach to improve the performance of this? (write the image to disk and then read to send to browser doesn't see like a good trick)

Is there a method to encode this into another format to improve performance?

Thanks a lot.

PD: The image is written to disk and then read to send to browser, because I receive the image data from another process in another function via RPC calls.


Solution

  • You could trying using socket.io to just push URLs of the generated files and then on the client use Javascript to replace the "src" attribute of the img tag showing the frame. In this case you could use a regular web server for server the static files or the connect module for serving static files. This is likely more efficient than pushing the base64 encoded data.

    If you are going to use the approach above, at least don't use fs.readFile... this brings the whole file into memory every time. Use util.pump() or manually use ReadStream/WriteStream with 'drain' events to minimize memory usage. Its possible that your performance issues are due to garbage collection when there are multiple clients connected.

    Another approach might be to have a background process that feeds the images to ffmpeg to encode a proper video stream and then to ffserver to stream it to a video player.