Playing with getUserMedia

21 March 2012 | webrtc
Author johan

I will in this article go over the basics of how to build your own photo booth using a local webcam. To spice it up we will add some effects to the video in real-time to create a night vision effect using seriously.js.

The outcome will look something like this.

This article will focus on the getUserMedia functionality that is part of the WebRTC specification. The Peer-to-Peer part of the API I hope we will see more use of this Saturday at Protothon#2.

To get started get the latest version of either Chrome or Opera.

The JavaScript API is straight forward.

navigator.getUserMedia({audio: true, video: true}, gotStream, noStream);

First argument tells which devices we want to access, in this case both audio and video. Second parameter is a callback that's called when the stream is initialized. Third parameter is optional but if provided will be called if no stream is available e.g. when a user don't grant access to use the camera or microphone.

Chrome is not following the latest specification (I'm on Version 19.0.1068.1 dev) and uses another syntax.

navigator.webkitGetUserMedia("video, audio", gotStream, noStream);

Putting these two togheter our script would look like.

if (navigator.getUserMedia) {
  navigator.getUserMedia({audio: true, video: true}, gotStream, noStream);
} else {
  navigator.webkitGetUserMedia("video, audio", gotStream, noStream);
}

Next step for us is to create a video element on which the stream from the webcam will be shown.

<video id="source" autoplay></video>

To make the stream appear in video element we must implement the gotStream function which will give us a stream from the webcam. This is done by passing the stream parameter to the video element like this.

function gotStream(stream) {
  var video = document.getElementById('source');
  video.src = stream;
}

To make it a bit more fun we're going to use seriously.js which can add effects in real-time using the video stream. For this we need to create a canvas element that will be used for outputing the modified video stream.

<canvas id="target"></canvas>

The gotStream function below is using seriously.js to add a night vission effect, to get started with seriously their tutorial is a good start. Once again Chrome and Opera is handling things different, in Chrome we need to use webkitUrl to transform the stream into something that can be passed to the video element. With Opera we can pass the stream direct.

function gotStream(stream) {
  if (navigator.getUserMedia) {
    video.src = stream;
  } else {
    // Chrome is using a another syntax.
    video.src = webkitURL.createObjectURL(stream);
  }
  // Setup seriously and apply the night vission effect.
  var seriously, source, target;
  seriously = new Seriously();
  source = seriously.source('#source');
  target = seriously.target('#target');
  target.source = source;
  var nightvision = seriously.effect('nightvision');
  nightvision.source = source;
  target.source = nightvision;
  seriously.go();      
}

To get getUserMedia to work it requires to be run from a webserver. If the url in your browser starts with file:// and a error message saying Failed to load resource you need to run it from server instead. Running locally from localhost works fine though. If you have python installed you can start a local webserver within a directory using the following.

python -m SimpleHTTPServer

That's it.

Chrome exposes some metrics of the current stream at the following location chrome://media-internals/ that you might find interesting.

If you wonder, the noStream function could be implemented like this, requires a element similar to this to be present first, <p id="errorMessage"></p>.

function noStream() {
  document.getElementById('errorMessage').textContent = 'No camera available.';
}

Full code for the above demo is available here, https://gist.github.com/2275611.

Edit: Just found out that Internet Explorer also supports getUserMedia in a preview release. They following the specification, but you need to add the vendor prefix ms like this.

navigator.msGetUserMedia({audio: true, video: true}, gotStream, noStream);