Get maximum video resolution with getUserMedia

50,234

Solution 1

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.

Solution 2

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.

Solution 3

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);
});

Solution 4

Still I haven't found any good API to get maximum video resolution with getUserMedia.

But here I am sharing my idea to get maximum supported video resolution of the connected device using Binary Search algorithm and it's working great.

Here are the steps to do this job,

  • Store some standard resolutions in an Array, maintaining ascending order .
  • Set leftIndex = 0 and rightIndex = size of resolution array.
  • Check midIndex = (left+right)/2 resolution supported or not, and modify left and right based on the result.

Here I am sharing my implementation:

var ResolutionsToCheck = [
                {width: 160, height:120},
                {width: 320, height:180},
                {width: 320, height:240},
                {width: 640, height:360},
                {width: 640, height:480},
                {width: 768, height:576},
                {width: 1024, height:576},
                {width: 1280, height:720},
                {width: 1280, height:768},
                {width: 1280, height:800},
                {width: 1280, height:900},
                {width: 1280, height:1000},
                {width: 1920, height:1080},
                {width: 1920, height:1200},
                {width: 2560, height:1440},
                {width: 3840, height:2160},
                {width: 4096, height:2160}
            ];

var left = 0;
var right = ResolutionsToCheck.length;
var selectedWidth;
var selectedHeight;
var mid;

function FindMaximum_WidthHeight_ForCamera()
{
    console.log("left:right = ", left, ":", right);
    if(left > right)
    {
        console.log("Selected Height:Width = ", selectedWidth, ":", selectedHeight);
        return;
    }

    mid = Math.floor((left + right) / 2);

    var temporaryConstraints = {
        "audio": true,
        "video": {
            "mandatory": {
            "minWidth": ResolutionsToCheck[mid].width,
            "minHeight": ResolutionsToCheck[mid].height,
            "maxWidth": ResolutionsToCheck[mid].width,
            "maxHeight": ResolutionsToCheck[mid].height
            },
        "optional": []
        }
    }

    navigator.mediaDevices.getUserMedia(temporaryConstraints).then(checkSuccess).catch(checkError);
}

function checkSuccess(stream)
{
    console.log("Success for --> " , mid , " ", ResolutionsToCheck[mid]);
    selectedWidth = ResolutionsToCheck[mid].width;
    selectedHeight = ResolutionsToCheck[mid].height;

    left = mid+1;

    for (let track of stream.getTracks()) 
    { 
        track.stop()
    }

    FindMaximum_WidthHeight_ForCamera();
}
function checkError(error)
{
    console.log("Failed for --> " + mid , " ", ResolutionsToCheck[mid],  " ", error);
    right = mid-1;

    FindMaximum_WidthHeight_ForCamera();
}

Just call function FindMaximum_WidthHeight_ForCamera(). When operation will be completed then maximum video resolution will be stored in selectedWidth and selectedHeight variables. Here I am also attaching console output for my device:

//Console Output
left:right =  0 : 17
Success for -->  8   Objectheight: 768width: 1280__proto__: Object
left:right =  9 : 17
Failed for --> 13   Objectheight: 1200width: 1920__proto__: Object   NavigatorUserMediaError
left:right =  9 : 12
Success for -->  10   Objectheight: 900width: 1280__proto__: Object
left:right =  11 : 12
Failed for --> 11   Objectheight: 1000width: 1280__proto__: Object   NavigatorUserMediaError
left:right =  11 : 10
Selected Height:Width =  1280 : 900

I have tested this implementation using Chrome Version 57.0.2987.110 (64-bit) and Logitech, Inc. Webcam C270. But I think this solution should work in each scenario. Thank You.

Solution 5

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:

enter image description here

Share:
50,234

Related videos on Youtube

homm
Author by

homm

Updated on February 17, 2022

Comments

  • homm
    homm about 2 years

    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 case.

    The problem is looks like there is no way to say "I want a video at maximum resolution". So instead I'm trying to say "I want video not less than very big resolution".

    When I'm trying minWidth: 1600, Chrome returns me 1280×720 video (highest possible for my camera, I think). But what if user has camera with higher resolution? So I'm asking for minWidth: 2048 video, and Chrome returns only 640×480.

    var constraints = {
      video: {
        optional: [
        {minWidth: 2048}
        ]
      }
    };
    

    This is online example: http://jsbin.com/kibeza/1/watch?js,output

    And there is actual problem: Chrome doesn't know math. It think what 1600 is greater than 2048. I can't ask for video "not less than 100500", because in this case I'll get standard low resolution. I cant ask video "not less than some reasonable small resolution", because there can be users with higher resolution and I want to get higher resolution.

    • Martin
      Martin over 9 years
      Have you seen this bug?
    • Michael
      Michael about 8 years
      that's funny, when I request a resolution that is too big I get a "ConstraintNotSatisfiedError" and no video is returned
  • Jiloc
    Jiloc about 9 years
    Still no news about that?
  • jib
    jib about 9 years
    This is the right answer for Chrome, for now. Min/max constraints form ranges of legal values, which the browser is still free to choose any value within, so the only way to influence a direction is with successively narrower or wider ranges. This works because the browser tries to cumulatively satisfy as many ranges as it can, starting with the first, and skipping ones that over-constrain. Chrome will hopefully switch to the standard soon which handles this more intuitively.
  • jib
    jib almost 9 years
    Actually, Firefox is ahead of Chrome here, and supports the spec, so this is a piece of cake: { video: { width: 9999, height: 9999 } } will give you the highest possible resolution. See this related answer
  • Michael
    Michael about 8 years
    this isn't that great if the native width is greater than 2560 or is a not in the above list.
  • navigator
    navigator about 8 years
    Is there any update on this or is this still the best way to get Chrome to use the maximum resolution?
  • Tom
    Tom about 8 years
    @Michael I understand your concern, but take note that it's a videostream, not a photostream. There are no phones or webcams that go any higher than 4K just yet.
  • Skylion
    Skylion almost 8 years
    Yeah, didn't the optional syntax get deprecated anyway so this is not guaranteed to work in the future?
  • sidonaldson
    sidonaldson almost 8 years
    I found this works but kills any device preference when it comes to front or back cameras. I'll add a comment below even though it's not a solution per se
  • deweydb
    deweydb over 6 years
    This seems like a pretty good solution, but I'm getting 1280x900 for Motorola G2 and Motorola G3, and their max video resolution is 1280x720
  • RajibTheKing
    RajibTheKing over 6 years
    Do you really get the video after selecting the resolution by this algorithm. There are two scenario for your problem.... i) you are getting video ii) You are not getting video, after selecting the resolution
  • Ola Berntsson
    Ola Berntsson over 5 years
    This approach is probably the easiest, and you don't even have to use the "ideal" keywords, as this is implied when just specifying width and height.
  • Mick
    Mick over 5 years
    Works like a charm. Couldnt we even set this to 999999 for both?
  • jib
    jib over 4 years
    This answer is outdated. See this answer instead.
  • B''H Bi'ezras -- Boruch Hashem
    B''H Bi'ezras -- Boruch Hashem over 3 years
    is videoConstraints supposed to be constraints or is constraints supposed to contain a videoConstraints object? in other words do we set the deviceID in the video section of the getusermedia constraints, or in the main object?
  • Falk Tandetzky
    Falk Tandetzky over 2 years
    For me setting this to 99999 also worked. This is probably more future save, because resolutions can still get larger than what we have atm. Also note that depending on having your device in landscape or portrait mode the width and height of your camera will be swapped. So a height of e.g. 2160 could already be asking for less then the maximum resolution in some cases.