lwille / node-gphoto2

A Node.js wrapper for libgphoto2
MIT License
298 stars 91 forks source link

How to use live preview from example #64

Closed gabrielstuff closed 9 years ago

gabrielstuff commented 9 years ago

Hi !

Very nice work. I've been trying to run the examples, but I'm not able to see the live preview : http://localhost:1337/preview returns nothing on Chrome and bad image on firefox (the image can not be displayed because it contains error)

What is the process to look at the liveview in the browser ?

Thanks

emmanuelgeoffray commented 9 years ago

Same here :) npm test says it's fine with livestream and I can get it with gphoto.

@lpinca is there anything to activate for the livestream? Is it working on your side?

Best, e

lpinca commented 9 years ago

I don't know, it has been a long time since I used this module and I think I never looked at the examples. You could get some hints reading issue #48. Try with this:

camera.takePicture({
  preview: true,
  targetPath: __dirname + '/foo.XXXXXX'
}, function (er, tmpname) {
  fs.renameSync(tmpname, __dirname + '/picture.jpg');
});

It is the same API used here https://github.com/lwille/node-gphoto2/blob/master/examples/server.coffee#L102 with the difference that the live view is not returned in a buffer but in a temp file.

emmanuelgeoffray commented 9 years ago

Thanks @lpinca ! I'm going to try this. I'll let you know best e

jatpatel1 commented 9 years ago

@emmanuelgeoffray Did you get anywhere with this? I'm trying to do the same thing. Thanks

emmanuelgeoffray commented 9 years ago

hey @jatpatel1 I did succeed to get a preview video stream, but ith a different method. I repeatly write a preview file to disk, and use mjpg_streamer to process htis as a video stream. Check this folder: https://github.com/soixantecircuits/zhaoxiangjs

jatpatel1 commented 9 years ago

@emmanuelgeoffray thanks for getting back to me. I thought that was the only way to do it. Previously I did the same thing in python but as I'm a web developer I thought it would be easier if I wrote it with a web language(php or js). I just had a quick look at mjpg_streamer and it looks promising.

Can I ask what your logic was to repeatedly write a preview file to disk? Did you have to think about fps or anything? With my camera, once the getPreview is called, I can't call it again as the camera locks and I have turn it on and off. Any help would be appreciated. Thanks

lwille commented 9 years ago

I can only recommend to use sockets for preview. It's proven to get the best performance, tested with an EOS 550D (Rebel t2i) (snippet ripped out of a production app, freely translated from CoffeeScript):


/**
 * @var app your express app
 */
var socketPath = '/tmp/preview.sock';

app.get('/preview.jpg', function( req, res ) {
    var previewServer = net.createServer(function ( c ) {
      res.contentType('image/jpeg');
      c.on('end', function () {
        server.close();
        res.end();
      });
      c.pipe(res); // pipes preview stream to HTTP client
    }); 
    previewServer.listen(socketPath, function () {
        camera.takePicture({preview:true, socket: socketPath}, function(er){
            // some logging, error handling
        });
    });
});

Here's the client code, which is basically loading the preview image over and over and drawing it to a 2D canvas for optimal performance:

$((function(_this) {
  return function() {
    var previewRunning;
    previewRunning = false;
    /** @var canvas $("#someCanvasElement")[0]
    */
    _this.startPreview = function(canvas, reload, cb) {
      var callback, context, image, loadImage, onload, ref;
      if (!cb) {
        ref = [reload, true], cb = ref[0], reload = ref[1];
      }
      previewRunning = true;
      context = canvas.getContext("2d");
      image = new Image();
      loadImage = function() {
        return image.src = '/camera/preview.jpg?' + Date.parse(new Date());
      };
      onload = (function(_this) {
        return function() {
          if (previewRunning) {
            context.drawImage(image, 0, 0, canvas.width, canvas.height);
            if (reload) {
              return loadImage();
            }
          }
        };
      })(this);
      loadImage();
      $(image).bind('load', onload);
      callback = function() {
        if (cb) {
          cb();
        }
        return $(image).unbind('load', callback);
      };
      $(image).bind('load', callback);
      $(image).bind('error', (function(_this) {
        return function() {
          return setTimeout(loadImage, 1000);
        };
      })(this));
      return onload();
    };
    return _this.stopPreview = function() {
      return previewRunning = false;
    };
  };
})(this));
jatpatel1 commented 9 years ago

Thanks @lwille. I'm a newbie to this so will have to read up on sockets. I'll try it out and let you know how I get on.

lwille commented 9 years ago

Cool 😊 meanwhile, I'll think about an easier to use way of getting a preview stream directly out of gphoto. Involving sockets or the file system always comes with a performance impact.

Maybe it's possible to do a live transcoding from MPEG to some streaming Codec, but I'm not an expert on that topic 😊

jatpatel1 commented 9 years ago

Awesome! thanks for the response. Ideally I would like to use the gphoto2 --capture-preview command and take a preview for x number of seconds(using a for or while loop or something). Also I've noticed that the gphoto capture preview is limited to certain pixels opposed to capture image.

I guess it's going to be a trail and error thing.... :dizzy_face:

kanzelm3 commented 9 years ago

Hey @lwille is there any way you can share the url to where you found your example? I am having a hard time understanding how to do it, as there is some stuff missing from the server side. I'm sorry, I am just having a hard time figuring out a good solution for this!

lwille commented 9 years ago

@kanzelm3, It's ripped from a private project of my former employer. I can't disclose it.

I think the Preview functionality would be a good example on general usage, so I'll try to grab a camera and hack a small webapp (which would be published separately).

gabrielstuff commented 9 years ago

We hack something involving mjpeg streamer. I do not see in the example where the stream got update. on gphoto side preview just capture an image from the preview feed. Meanwhile you need to update manualy, nah ? Or does gphoto handle it internally and the socket got update with the new content and thus directly streamed to the front ?

thanks

lwille commented 9 years ago

Unfortunately, we have to fetch individual preview images from libgphoto. So what I did so far is not about a real "stream" in the MJPEG sense, but rather about streaming individual bytes of each preview picture instead of sending them en block. Streaming saves a lot of time here, as data is being sent as soon it becomes available on USB. I think MJPEG streaming should be implemented on the C++ side for performance reasons, as context switches between Node and C++ are really expensive.

kanzelm3 commented 9 years ago

@lwille awesome man, I would really appreciate that, I'm working on a photo booth app where it would be nice if I could use the DSLR as the live view instead of using an additional webcam that can be accessed via navigator.getUserMedia

maaqoul commented 5 years ago

Cool 😊 meanwhile, I'll think about an easier to use way of getting a preview stream directly out of gphoto. Involving sockets or the file system always comes with a performance impact.

Maybe it's possible to do a live transcoding from MPEG to some streaming Codec, but I'm not an expert on that topic 😊

i am having a lot of trouble implementing this, i hope you did came up with an easier approach