
getUserMedia() Video Constraints
WebRTC is constantly evolving, and with it, its most well-known function is getUserMedia()
. With it, you can access the device’s webcams and microphones and request a video stream, an audio stream, or both.
In this article, we will be focusing on the video constraints available to us when requesting a video stream through getUserMedia()
. In a previous blog post, we focused on the audio constraints.
MediaStreamConstraints
The getUserMedia()
function receives only one parameter, a MediaStreamConstraints
object used to specify what kind of tracks (audio, video, or both) to request, and, optionally, any requirements for each track.
Here’s a basic example of how you sent this object to the newer, promise-based, getUserMedia()
:
var constraints = {
audio: true,
video: true
}
navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
/* use the stream */
}).catch(function(err) {
/* handle the error */
});
The constraints
object can have one or both of these two properties:
- video – indicates whether or not a video track is required
- audio – indicates whether or not an audio track is required
Here’s how a basic constraint object that requires both an audio and a video stream looks like (the same one used above):
var constraints = { audio:true, video:true}
If you’re taking a picture and don’t need an audio track, just set the audio property to false like this:
var constraints = {
audio: false,
video: true
}
Suppose true
is specified for video or audio. In that case, the resulting stream requires to have that particular media track in it; else the call to getUserMedia()
will result in a NotFoundError
error (see common getUserMedia() Errors for more details).
MediaTrackConstraints
The audio and video properties can take two types of values:
- a Boolean value (true or false) as above
- a
MediaTrackConstraints
object which provides specific properties like width and height that the track must meet.
Video Track Constraints: Resolution
One can use the width
and height
properties to request a specific resolution from the webcam. In this example, the browser will request a 720p (1280×720) video stream:
{
audio: true,
video: {
width: 1280,
height: 720
}
}
The browser will try to honor this, but may return a different resolution stream. From my experience, this often happens because the webcam does not support the requested resolution (try requesting odd resolutions like 721×55 and see what happens). It might also be that another getUserMedia()
overrode the constraints call from a different app on Mac (where webcam access is shared) or a different Chrome tab (shared access). Other reasons might exist, too.
You can try the Webcam Resolution Tester to see what resolutions your browser and webcam combo support.
Keywords
If the resolution is important to you and the device and browser cannot guarantee it, then you can use the min
, max
, and exact
keywords to help you get the best resolution from any device. These keywords apply to any MediaTrackConstraint property.
If, for example, you’re doing image recognition in video streams and require 1280×720 resolution, use this constraint:
{
audio: true,
video: {
width: {
exact: 1280
},
height: {
exact: 720
}
}
}
In the example above, if no camera exists that supports the exact resolution, then the returned promise will be rejected with OverconstrainedError
, and the user will not be prompted (see common getUserMedia() Errors for details).
The following constraint also requests a resolution of 1280×720. Still, it also mentions 320×240 as the minimum resolution since not all webcams support 1280×720, and in some use cases, it’s better to get something rather than nothing:
{
audio: true,
video: {
width: {
min: 320,
max: 1280
},
height: {
min: 240,
max: 720
}
}
}
Values without the min
, max
, and exact
keywords are considered ideal
values, which itself is a keyword, but it is not mandatory. These two examples do the same thing:
{
audio: true,
video: {
width: 1280,
height: 720
}
}
{
audio: true,
video: {
width: {
ideal: 1280
},
height: {
ideal: 720
}
}
}
Video Track Constraints: Getting The Front Or Rear Camera On Mobile Devices
One can use the facingMode
property for the video track constraint. Accepted values are: user
(front camera), environment
(rear camera), left
, and right
.
Here’s how to request a video stream that should ideally come from the back camera:
{
audio: true,
video: {
width: 640,
height: 480,
facingMode: "environment"
}
}
or
{
audio: true,
video: {
width: 640,
height: 480,
facingMode: {
ideal: "environment"
}
}
}
Here’s how to request a video stream that should come from the back camera:
{
audio: true,
video: {
width: 640,
height: 480,
facingMode: {
exact: "environment"
}
}
}
I am not sure how well mobile browsers support these.
Video Track Constraints: Frame Rate
Since frame rate has a direct impact on video quality and bandwidth, in some cases, such as publishing a video stream over low-bandwidth connections, it might be a good idea to limit the frame rate. I was able to obtain a 60fps stream from the Logitech C925E by using:
{
audio: true,
video: {
width: 320,
height: 240,
frameRate: {
ideal: 60,
min: 10
}
}
}
Keep in mind that the frame rate of a stream coming from a webcam depends a lot on the light in the room.
Using a Certain Webcam or Microphone Device
There is one constraint property that applies to both audio and video tracks: deviceId
. It specifies the device ID (or an array of IDs) that you should use for capturing that stream. The device ID is unique and will be the same across browsing sessions on the exact origin. You will first need to obtain the device ID using MediaDevices.enumerateDevices()
.
Once you know the deviceId
, you can ask for a specific webcam or microphone:
{
audio: true,
video: {
deviceId: {
exact: "the_device_id"
}
}
}
There's also groupId
, a shared ID for all media sources that come from the same physical device. For example, a microphone and speaker that come from the same headset will share the same group ID.
This example allows you to switch between the available devices used for input (mic & cam) and output (speaker).
MediaDevices.getSupportedConstraints()
Chrome 53, Firefox 44, and Safari 11 added support for MediaDevices.getSupportedConstraints()
. The function returns a dictionary listing the constraints supported by the user agent.
Click here to run it for your current browser.
The function seems to return a lot of false positives; track.getSettings()
gives better results.
MediaStreamTrack.getSettings()
You can also check which constraints are supported by using track.getSettings()
. It returns an object containing all applicable constraints, including those supported by the browser but whose defaults didn't change through code.
Here's how to use the function and print the result to the console:
navigator.mediaDevices.getUserMedia(constraints).then(function success(stream) {
video.srcObject = stream;
stream.getTracks().forEach(function(track) {
console.log(track.getSettings());
})
});
This code pen writes on the page the result of track.getSettings()
for your browser.
Chrome 59 added the function, and Firefox and Safari 11 also support it.
Old Constraints
The specifications for the constraints object have changed in the past. Constraints using the old spec looked like this:
var constraints = {
audio: true,
video: {
mandatory: {
minWidth: 640,
maxWidth: 640,
minHeight: 480,
maxHeight: 480
}
}
}
The old spec was the only one supported by Chrome until Chrome 59 (June 2017), which added support for the new one. Older versions of Chrome can also use the latest spec through adapter.js
Firefox 38+ (May 2015) and Safari 11 both support the new video constraints spec.