Accessing Your Webcam in HTML5

by kirupa   |   7 February 2013

Accessing your webcam via your browser used to involve a...pardon the profanity, a plugin. That's right. In order to connect to a webcam and gain access to its video stream, you had to rely on something primarily created in Flash or Silverlight. While that approach certainly worked for browsers that supported plug-ins, it didn't help for the increasing number of browsers that aim to be plugin-free. This inability to natively access the webcam without relying on 3rd party components was certainly a gap in the HTML development story. At least, that was the case until pretty recently.

The W3C has been attempting to fill this gap by encouraging browser vendors to implement the proposals outlined in the Media Capture and Streams spec. This spec defines, among various other things, how to communicate with a webcam device using just a little bit of JavaScript. The good news is, despite its newness, various browsers have already implemented support for accessing the webcam in their latest versions.

Note: Browser Support

Because accessing the webcam natively is a recent introduction, check out caniuse's statistics to see the level of support it has among the major browsers.) In writing this tutorial, I used the latest version of Google's Chrome where everything works swimmingly.

So...while the rest of the world is getting upgraded to browsers that support native webcam access, now is a great time for you to get ahead of the program and learn all about it. That's where this tutorial comes in. By the time you reach the bottom of this page, you will have learned how to take your webcam's video stream and display it using only some HTML and JavaScript.

Onwards.

The Example

Before proceeding further, let's first take a look at an example that is identical to what you will be creating. If you are on a browser that supports the getUserMedia function and you have granted permission for your browser to access the webcam, you should see a live version of yourself (or whatever your webcam is pointing at) in the gray box below:

If you do not give your browser permission to access the webcam, you will not see anything interesting. You will just see a beautiful gray box with a finely crafted dark gray border.

Attention Firefox 18 or 19 Users!

Firefox versions 18 and 19 do support the getUserMedia API...but that support is disabled by default. Read this to learn how to enable it.

 

If you didn't see a permissions notification, you may have just overlooked it or dismissed it because it appeared when you loaded the page. Different browsers do different things when they ask you for permission to use the webcam. For example, here is what Chrome's prompt looks like:

Chrome's prompt for using the webcam

If you denied permission accidentally (or intentionally), just reload this page to get a crack at acing this test again.

Overview of How This Works

To help make the code we will be writing...easier to write, let's look at an overview of how everything works using plain old English. There are two components that do all the heavy lifting in getting data from your webcam displayed on your screen. They are the HTML video element and the JavaScript getUserMedia function:

meet the stars

The video element is pretty straightforward in what it does. It is responsible for taking the video stream from your webcam and actually displaying it on the screen.

The interesting piece is the getUserMedia function. This function allows you to do three things:

  1. Specify whether you want to get video data from the webcam, audio data from a microphone, or both.
  2. If the user grants permission to access the webcam, specify a success function to call where you can process the webcam data further.
  3. If the user does not grant permission to access the webcam or your webcam runs into some other kind of error, specify a error function to handle the error conditions.

For what we are trying to do, we call the getUserMedia function and tell it to only retrieve the video from the webcam. I will cover the microphone in the future! Once we retrieve the video, we tell our success function to send the video data to our video element for display on our screen.

If this sounds pretty straightforward, that's because it actually is pretty. Let's put all of this straightforward English-sounding description into HTML and JavaScript in the next section.

Adding the Code

In this section, let's go ahead and display our webcam data to the screen. First, let's add the HTML and CSS:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="stuff, to, help, search, engines, not" name="keywords">
<meta content="What this page is about." name="description">
<meta content="Display Webcam Stream" name="title">
<title>Display Webcam Stream</title>
 
<style>
#container {
	margin: 0px auto;
	width: 500px;
	height: 375px;
	border: 10px #333 solid;
}
#videoElement {
	width: 500px;
	height: 375px;
	background-color: #666;
}
</style>
</head>
 
<body>
<div id="container">
	<video autoplay="true" id="videoElement">
	
	</video>
</div>
<script>

</script>
</body>
</html>

In a new document, go ahead and add all of the HTML and CSS that you see above. The important thing to note in this snippet is the video tag:

<video autoplay="true" id="videoElement">

</video>

Our video tag has an id value of videoElement, and its autoplay attribute is set to true. By setting the autoplay attribute to true, we ensure that our video starts to display automatically once we have our webcam video stream.

If you preview what your page looks like in your browser, what you will see will look as follows:

a giant gray box - yay!

Yes, this looks pretty plain and boring now. That is because we haven't added the JavaScript that ties together our video element with your webcam. We'll do that next!

Inside your script tag, add the following code:

var video = document.querySelector("#videoElement");

navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;

if (navigator.getUserMedia) {       
	navigator.getUserMedia({video: true}, handleVideo, videoError);
}

function handleVideo(stream) {
	video.src = window.URL.createObjectURL(stream);
}

function videoError(e) {
	// do something
}

Once you've added this code, save your HTML document and preview your page. Provided you are on a supported browser, you should see your webcam video stream after you've given your browser permission to access it.

Examining the Code

Now that you have a working example, let's go through our code line-by-line to understand how the verbal overview you saw earlier matches the code that you just added.

Let's start at the very top:

var video = document.querySelector("#videoElement");

We first declare a variable called video, and it is initialized to our video element that lives in the HTML. We get our paws on the video element by using querySelector and specifying the id selector that targets it.

 

Next up is our code for accessing the getUserMedia API:

navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;

The getUserMedia function is currently vendor prefixed. This means that each browser will expect a different variant of the function to actually work. To address this with the least amount of code, I took a technique I described in my Vendor Prefixes and JavaScript tutorial where we use the OR operator to check for the existence of a single, valid getUserMedia function.

 

Ok, things are getting pretty serious here:

if (navigator.getUserMedia) {       
	navigator.getUserMedia({video: true}, handleVideo, videoError);
}

Our if statement checks that navigator.getUserMedia does in fact contain something of value. If your browser doesn't support getUserMedia at all, this check will rightfully fail and prevent the all important call to getUserMedia from being made.

Speaking of which, that all important call looks like:

navigator.getUserMedia({video: true}, handleVideo, videoError);

This single line does quite a lot of things. By simply calling getUserMedia as a function as we are here, the first thing that happens is that your browser displays the prompt asking whether you want to give it permission to access your webcam. It knows how to word the prompt because we declared this function as only being used for video via the first argument which we set as { video: true }.

If you grant permission, the success callback which we defined as handleVideo gets called. If you deny permission to access the webcam, videoError (aka the error callback) gets called instead. Let's go ahead and look the two callbacks that will get called next.

 

The handleVideo function is called due to its full-time job as being the success callback for the getUserMedia function you saw a few lines earlier:

function handleVideo(stream) {
	video.src = window.URL.createObjectURL(stream);
}

The main thing that this function does is set the src property on our video element to the webcam's video stream. Because our video element has the autoplay attribute set to true, nothing else really needs to be done to show your webcam data on the screen.

In cases when there is an error in getting the video stream or the user refused to give your code permission to access the webcam, the error callback will get called. In our case, that is handled by the videoError function:

function videoError() {
	// do something
}

As you can see, I didn't flesh out what the behavior would be. You can do whatever you want here.

Conclusion

So, there you have it - a look at how you can access a user's webcam video stream and display it in the browser. Once you get the video displayed, you can then do all sorts of things that you can do to videos in general. You can apply crazy filters, you can take a snapshot and save the image to disk, etc. I may cover some of these in future tutorials.

Did You Like This?

Getting Help

If you have questions, need some assistance on this topic, or just want to chat - post in the comments below or drop by our friendly forums (where you have a lot more formatting options) and post your question. There are a lot of knowledgeable and witty people who would be happy to help you out

Share

Did you enjoy reading this and found it useful? If so, please share it with your friends:

If you didn't like it, I always like to hear how I can do better next time. Please feel free to contact me directly at kirupa[at]kirupa.com.

Cheers!

Kirupa Chinnathambi

 

Add Your Comment (or post on the Forums)

add your comment

  

Read-only Archive of Old comments

Below is an archive of old comments made on this article. To create new comments click on the Start or Continue Discussion text above to add to this list.

blog comments powered by Disqus

Creating high-quality content is a team effort that takes a boatload of time. If you found what you see here helpful, please consider sending a small tip:

While tipping is entirely optional, we'll be your bestest friend forever if you do.

More Details & Options