I\'m trying to get highest video resolution as possible through JS navigator.getUserMedia
. I know about constraints, but don\'t know how to choose right in my c
I had varied success with defining ideal
dimensions and trying to force the 'back' camera.
$video = document.getElementById('video')
//declare ideal values
var constraints = {
audio: false,
video: {
width: { ideal: 1280 },
height: { ideal: 1024 },
facingMode: "environment"
}
};
// enumerate devices and select the first camera (mostly the back one)
navigator.mediaDevices.enumerateDevices().then(function(devices) {
for (var i = 0; i !== devices.length; ++i) {
if (devices[i].kind === 'videoinput') {
console.log('Camera found: ', devices[i].label || 'label not found', devices[i].deviceId || 'id no found');
videoConstraints.deviceId = { exact: devices[i].deviceId }
}
}
});
//first up the stream
navigator.mediaDevices.getUserMedia(constraints).then(function(stream) {
$video.srcObject = stream;
// log the real size
console.log($video.videoWidth, $video.videoHeight);
}).catch(function(err) {
console.log(err.name + ': ' + err.message);
});
You can always use applyConstraints()
combined with getCapabilities()
on the track.
Honza Kalfus' answer claims chrome now handles the ideal
prop right for resolution. I didn't test that, but Chrome 83 still screws up ideal value for frameRate and simply wont start the video if outside of the capable range... so I hope this helps someone.
stream = await navigator.mediaDevices.getUserMedia({ video: { width: 100, height: 100, frameRate: { min: 8, max:60 }, facingMode: 'environment' } });
track = stream.getTracks()[0];
var frIdeal = 35;
constrs = track.getConstraints();
frCap = track.getCapabilities().frameRate;
if (frCap && "min" in frCap && "max" in frCap) {
constrs.frameRate = Math.max(frCap.min, Math.min(frCap.max, frIdeal));
track.applyConstraints(constrs);
}
this will give me 30hz if that is the maximum (Chrome83).
see also the MDN docs
I still don't know correct answer, but I do the following:
video: {
optional: [
{minWidth: 320},
{minWidth: 640},
{minWidth: 1024},
{minWidth: 1280},
{minWidth: 1920},
{minWidth: 2560},
]
}
While single minWidth: 2560
expression resets resolution to default, series of minWidth
expression make browser always takes maximum resolution on tested hardware.
I agree with homm, his approach works fine: https://jsfiddle.net/evpozdniakov/c84ksucw/
var getUserMediaPrefixed,
videoStream,
videoTag;
setGumPrefix();
if (!getUserMediaPrefixed) {
logMessage('Sorry, your browser doesn\'t support getUserMedia interface');
}
else {
runCamera();
}
function dealWithStream(stream) {
videoStream = stream;
if (!videoTag) {
videoTag = document.createElement('video');
videoTag.addEventListener('resize', videoEventListener);
}
videoTag.src = window.URL.createObjectURL(stream);
videoTag.play();
}
function handleError(e) {
if (e.name == 'PermissionDeniedError') {
logMessage('It looks like you\'ve denied access to the camera.');
}
else if (e.name == 'SourceUnavailableError') {
logMessage('It looks like your camera is <b>used</b> by another application.');
}
else {
logMessage('The camera is unavailable. The error message is: ' +e.message);
}
}
function logMessage(msg) {
var p = document.createElement('p');
p.innerHTML = msg;
document.getElementById('output').appendChild(p);
}
function runCamera() {
var constraints = {
audio: false,
video: {
optional: [
{minWidth: 320},
{minWidth: 640},
{minWidth: 800},
{minWidth: 900},
{minWidth: 1024},
{minWidth: 1280},
{minWidth: 1920},
{minWidth: 2560}
]
}
};
navigator[getUserMediaPrefixed](constraints, dealWithStream, handleError);
}
function setGumPrefix() {
if (navigator.getUserMedia) {
getUserMediaPrefixed = 'getUserMedia';
}
else if (navigator.webkitGetUserMedia) {
getUserMediaPrefixed = 'webkitGetUserMedia';
}
else if (navigator.mozGetUserMedia) {
getUserMediaPrefixed = 'mozGetUserMedia';
}
else if (navigator.msGetUserMedia) {
getUserMediaPrefixed = 'msGetUserMedia';
}
}
function videoEventListener() {
if (videoTag.videoWidth) {
logMessage('Best captured video quality in your browser is ' +videoTag.videoWidth+ '×' +videoTag.videoHeight);
// stop stream
videoStream.stop();
videoTag.src = '';
}
}
In my case, Opera and Chrome offer max resolution 1280×720.
Firefox gives 640×480 by default, but you can improve his resolution as well up to 1280×720. Here you go:
You can check this utility to check the available resolutions of your devices:
https://webrtchacks.github.io/WebRTC-Camera-Resolution/
It is useful for troubleshooting purposes.
Hope you find it interesting!
Use:
var constraints = {
video: {
width: { ideal: 4096 },
height: { ideal: 2160 }
}
};
This will make the browser use the maximum resolution available, up to 4K. Works in Chrome 63, Edge 41 and Firefox 58.
Citing MDN regarding the use of ideal:
An ideal value, when used, has gravity, which means that the browser will try to find the setting (and camera, if you have more than one), with the smallest fitness distance from the ideal values given.