Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get maximum video resolution with getUserMedia

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.

like image 218
homm Avatar asked Dec 11 '14 10:12

homm


4 Answers

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.

like image 58
Honza Kalfus Avatar answered Nov 20 '22 03:11

Honza Kalfus


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.

like image 35
homm Avatar answered Nov 20 '22 01:11

homm


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);
});
like image 10
sidonaldson Avatar answered Nov 20 '22 03:11

sidonaldson


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.

like image 7
RajibTheKing Avatar answered Nov 20 '22 01:11

RajibTheKing