Hey folks! In this post I will show you how to access the device’s cameras on a web page, via JavaScript, with support for multiple browsers and without the need for external libraries.
How to access the camera
To access the user’s camera (and/or microphone) we use the JavaScript MediaStream API. This API allows to access the video and audio captured by these devices through streams.
The first step is to check if the browser supports this API:
if (
"mediaDevices" in navigator &&
"getUserMedia" in navigator.mediaDevices
) {
// ok, browser supports it
}
Support is decent in modern browsers (no Internet Explorer, of course).
Capturing the video stream
To capture the video stream generated by the camera, we use the getUserMedia
method of the mediaDevices
object.
This method receives an object with the types of media we are requesting (video or audio) and some requirements. To start, we can just pass {video: true}
to get the video from the camera.
const videoStream = await navigator.mediaDevices.getUserMedia({ video: true });
This call will ask the user for permission to access the camera. If the user denies it, it throws an exception and does not return the stream. So it must be done inside a try/catch block to handle this case.
Note that it returns a Promise, so you have to use async/await or a then
block.
Video requirements
We can improve the requirements of the video by passing information about the desired resolution and minimum and maximum limits:
const constraints = {
video: {
width: {
min: 1280,
ideal: 1920,
max: 2560,
},
height: {
min: 720,
ideal: 1080,
max: 1440,
},
},
};
const videoStream = await navigator.mediaDevices.getUserMedia(constraints);
That way the stream comes in the correct proportion of width and height. If it is a cell phone in portrait mode it takes care of inverting the dimensions.
Displaying the video on the page
Okay, now that we have the stream, what can we do with it?
We can display the video on the page, in a video
element:
// considering there is a
// <video autoplay id="video"></video>
// tag in the page
const video = document.querySelector("#video");
const videoStream = await navigator.mediaDevices.getUserMedia(constraints);
video.srcObject = videoStream;
Note the autoplay
attribute in the video
tag. Without it, you need to call video.play()
to actually start displaying the image.
Accessing the phone’s front and rear cameras
By default getUserMedia
will use the system’s default video recording device. In the case of a cell phone with two cameras, it uses the front camera.
To access the rear camera, we must include facingMode: "environment"
in the video requirements:
const constraints = {
video: {
width: { ... },
height: { ... },
facingMode: "environment"
},
};
The default is facingMode: "user"
, which is the front camera.
Be aware that, if you want to change the camera with the video already playing, you will need to stop the current stream before replacing it with the stream from the other camera:
videoStream.getTracks().forEach((track) => {
track.stop();
});
Taking screenshots
Another cool thing you can do is capture images (screenshots) of the video.
You can draw the current video frame on a canvas, for example:
// considering there is a
// <canvas id="canvas"></canvas>
// tag in the page
const canvas = document.querySelector("#canvas");
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
canvas.getContext("2d").drawImage(video, 0, 0);
You can also display the canvas content in an img
element.
In the example I created for this tutorial, I added a button that creates images dynamically from the canvas and adds them to the page. Something like:
const img = document.createElement("img");
img.src = canvas.toDataURL("image/png");
screenshotsContainer.prepend(img);
Conclusion
See the running example here: https://doug2k1.github.io/javascript-camera/
And the complete source code is here: https://github.com/doug2k1/javascript-camera
Top comments (6)
Sadly does not work in Firefox for mobile.
Hi, Grzegorz. I've tested in the latest version for Android and it worked.
Anyway, here is the compatibility table: caniuse.com/#feat=stream
Support is pretty decent.
Yeah it seems that Firefox for iOS sucks. It doesn’t even appear in the compatibility table of Mozilla which is odd. Currently trying to get it working with falling back to
navigator.mozGetUserMedia
Really helpful! Thanks Douglas 😃
Thanks for the feedback!
Our pleasure!