Camera and Audio capture in web browsers

If you’ve ever built a web application that wanted access to the visitor’s camera you know what a painful experience that can be. If used to involve flash or silverlight plugins or clunky java. Thankfully, browsers have started providing new API’s which are collectively referred to as WebRTC or Web Real Time Chat. These new API’s make it quite simple to access audio and video capture hardware on the users’ machine. The API’s are still not fully standardized so some polyfilling is required. But the features are incredibly easy to use and very exciting, especially given that usage of the web is shifting to smaller devices that almost always have a camera. In my experience, camera and audio capture were the last major feature gap between native and web applications.

Excited by the prospects of having camera access in the browser I wanted to see how easy it was to build a simple prototype. It ended up being extremely simple. The very crude prototype I ended up with was:

Show Plain Text
  1. <!DOCTYPE html>
  2. <html>
  3.     <head>
  4.     <title>Camera test</title>
  5.     </head>
  6.  
  7.     <body>
  8.     <h1>Capture an image</h1>
  9.     <a href="#" id="start">Start</a>
  10.     <a href="#" id="capture">Capture</a>
  11.  
  12.     <video id="preview" autoplay></video>
  13.  
  14.     <canvas id="snapshot" ></canvas>
  15.  
  16.     <script>
  17. navigator.getUserMedia  = navigator.getUserMedia ||
  18.     navigator.webkitGetUserMedia ||
  19.     navigator.mozGetUserMedia ||
  20.     navigator.msGetUserMedia;
  21.  
  22. var localStream = null;
  23.  
  24. var canvas = document.querySelector('#snapshot');
  25. var video = document.querySelector('#preview');
  26.  
  27. var ctx = canvas.getContext('2d');
  28.  
  29. var start = document.querySelector('#start');
  30. start.addEventListener('click', function () {
  31.     startCaptureImage();
  32.     return false;
  33. }, false);
  34.  
  35. var capture = document.querySelector('#capture');
  36. capture.addEventListener('click', function () {
  37.     if (!localStream) {
  38.         return;
  39.     }
  40.  
  41.     var img = document.querySelector('#snapshot');
  42.     img.width = canvas.width = video.videoWidth;
  43.     img.height = canvas.height = video.videoHeight;
  44.  
  45.     ctx.drawImage(video, 0, 0);
  46.     img.src = canvas.toDataURL('image/webp');
  47. }, false);
  48.  
  49. function errorCallback(err) {
  50.     console.error('Failed', err);
  51. }
  52.  
  53. function startCaptureImage() {
  54.     navigator.getUserMedia({video: true}, function(data) {
  55.         video.src = window.URL.createObjectURL(data);
  56.         localStream = data;
  57.     }, errorCallback);
  58. }
  59.     </script>
  60.     </body>
  61. </html>

While the code is a bit ugly and gross with everything in global scope, it does serve to show how easy it is to get streaming video displayed on a web page. Not only can you capture video, but still images can captured into a canvas element. Once you’ve captured still images into a canvas element, you can copy the canvas contents into a file input or generate a mulit-part XmlHttpRequest and upload the image contents to your server. This makes features like taking profile photos or capturing images of documents possible without any additional plugins.

One slight against the camera features browsers provide is that they all require explicit permission on each access. In chrome this shows up as a notification bar that looks like:

I appreciate that browser vendors included this for privacy’s sake. I think that user’s will often miss the notification bar and have a much harder time successfully capturing video/images because of it. From the very basic research I’ve done WebRTC is already available in Chrome, Firefox and Safari. I expect that in the next year or so using these features will become more viable and file upload inputs will be augmented with camera capture as well.

Comments

test the codes in chrome ,but fail!

macnie on 3/21/14

Have your say: