8

Using Motion on linux, every webcam is served up as a stream on its own port. I now want to serve up those streams, all on the same port, using Node.js.

  • Edit: This solution now works. I needed to get the boundary string from the original mjpeg stream (which was "BoundaryString" in my Motion config)

app.get('/motion', function(req, res) {

    var boundary = "BoundaryString";

  var options = {
    // host to forward to
    host:   '192.168.1.2',
    // port to forward to
    port:   8302,
    // path to forward to
    path:   '/',
    // request method
    method: 'GET',
    // headers to send
    headers: req.headers
  };

  var creq = http.request(options, function(cres) {

        res.setHeader('Content-Type', 'multipart/x-mixed-replace;boundary="' + boundary + '"');
        res.setHeader('Connection', 'close');
        res.setHeader('Pragma', 'no-cache');
        res.setHeader('Cache-Control', 'no-cache, private');
        res.setHeader('Expires', 0);
        res.setHeader('Max-Age', 0);

    // wait for data
    cres.on('data', function(chunk){
      res.write(chunk);
    });

    cres.on('close', function(){
      // closed, let's end client request as well 
      res.writeHead(cres.statusCode);
      res.end();
    });

  }).on('error', function(e) {
    // we got an error, return 500 error to client and log error
    console.log(e.message);
    res.writeHead(500);
    res.end();
  });

  creq.end();

});

I would think this serves up the mjpeg stream at 192.168.1.2:8302 as /motion, but it does not. Maybe because it never ends, and this proxy example wasn't really a streaming example?

Jelle De Loecker
  • 20,999
  • 27
  • 100
  • 142

2 Answers2

2

Streaming over HTTP isn't the issue. I do that with Node regularly. I think the problem you're having is that you aren't sending a content type header to the client. You go right to writing data without sending any response headers, actually.

Be sure to send the right content type header back to the client making the request, before sending any actual content data.

You may need to handle multipart responses, if Node's HTTP client doesn't already do it for you.

Also, I recommend debugging this with Wireshark so you can see exactly what is being sent and received. That will help you narrow down problems like this quickly.

I should also note that some clients have a problem with chunked encoding, which is what Node will send if you don't specify a content length (which you can't because it's indefinite). If you need to disable chunked encoding, see my answer here: https://stackoverflow.com/a/11589937/362536 Basically, you just need to disable it: response.useChunkedEncodingByDefault = false;. Don't do this unless you need to though! And make sure to send a Connection: close in your headers with it!

Community
  • 1
  • 1
Brad
  • 159,648
  • 54
  • 349
  • 530
  • The chunk-thing IS a problem for the mjpeg stream. I see a normal jpeg stream is always served as one whole part. So I should wait for an entire frame and only then send it to the client. – Jelle De Loecker Dec 26 '12 at 15:19
  • 1
    Ah, found it! In my response header I needed to set the multipart boundary used in the original mjpeg stream (which, in motion, is always the same "BoundaryString") That way I could forward the chunks without adding any data to it myself. – Jelle De Loecker Dec 26 '12 at 15:34
0

What you need to do is request the mjpeg stream when it's necessary just in one thread and response each client with mjpeg or jpeg (if you need IE support).

Karén
  • 215
  • 1
  • 7