WebRTC is constantly evolving and with it, it’s most known function getUserMedia()
. With it you can get access to 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’ve 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 this object is sent 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 2 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 just 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
}
If true
is specified for video or audio, the resulting stream is required to have that particular media track in it, else the call to getUserMedia()
will result in an NotFoundError
error (see common getUserMedia() Errors for more details).
MediaTrackConstraints
The audio and video properties can take 2 types of values:
- a Boolean value (true or false) as above
- a
MediaTrackConstraints
object which provides specific properties like width and height that must be met by the track.
Video Track Constraints: Resolution
One can use the width
and height
properties to request a certain 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 the constraints were overridden by another getUserMedia()
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 WebRTC camera resolution finder to see what resolutions are supported by your browser and webcam combo.
Keywords
If the resolution is important to you and the device and browser can not 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 absolutely 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 of 1280×720 resolution but 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 2 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 absolutely come from the back camera:
{
audio: true,
video: {
width: 640,
height: 480,
facingMode: {
exact: "environment"
}
}
}
I am not sure how well these are supported by mobile browsers.
Video Track Constraints: Frame Rate
Since frame rate has a direct impact on video quality but also bandwidth, in some cases, like 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 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 which) which should be used for capturing that stream. The device ID is unique and will be the same across browsing sessions on the same origin. You will need to first 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 by 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 have not been changed 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 will write in page the result of track.getSettings()
for your browser.
The function has been added in Chrome 59 and it’s also supported by Firefox and Safari 11.
Old Constraints
The specifications for the constraints object has 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 new spec through adapter.js
Firefox 38+ (May 2015) and Safari 11 both support the new video constraints spec.