简体   繁体   English

使用 getUserMedia 获得最大视频分辨率

[英]Get maximum video resolution with getUserMedia

I'm trying to get highest video resolution as possible through JS navigator.getUserMedia .我正在尝试通过 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).当我尝试minWidth: 1600时,Chrome 会返回 1280×720 视频(我认为是我相机的最高可能)。 But what if user has camera with higher resolution?但是如果用户有更高分辨率的相机呢? So I'm asking for minWidth: 2048 video, and Chrome returns only 640×480.所以我要求minWidth: 2048视频,Chrome 只返回 640×480。

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

This is online example: http://jsbin.com/kibeza/1/watch?js,output这是在线示例: http://jsbin.com/kibeza/1/watch?js,output

And there is actual problem: Chrome doesn't know math.并且存在实际问题:Chrome 不懂数学。 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.它认为 1600 大于 2048。我不能要求视频“不小于 100500”,因为在这种情况下我将获得标准的低分辨率。 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.我不能要求视频“不少于一些合理的小分辨率”,因为可以有更高分辨率的用户,我想获得更高的分辨率。

Use:用:

var constraints = { 
    video: {
        width: { ideal: 4096 },
        height: { ideal: 2160 } 
    } 
};

This will make the browser use the maximum resolution available, up to 4K.这将使浏览器使用可用的最大分辨率,最高可达 4K。 Works in Chrome 63, Edge 41 and Firefox 58.适用于 Chrome 63、Edge 41 和 Firefox 58。

Citing MDN regarding the use of ideal :引用MDN关于理想的使用:

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.理想值在使用时具有重力,这意味着浏览器将尝试找到与给定理想值的最小适应距离的设置(和相机,如果您有多个)。

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.当单个minWidth: 2560表达式将分辨率重置为默认值时,一系列minWidth表达式使浏览器在测试硬件上始终采用最大分辨率。

I had varied success with defining ideal dimensions and trying to force the 'back' camera.我在定义ideal尺寸并尝试强制使用“后置”相机方面取得了不同的成功。

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

Still I haven't found any good API to get maximum video resolution with getUserMedia .我仍然没有找到任何好的 API 来使用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 .在 Array 中存储一些标准分辨率,保持升序。
  • Set leftIndex = 0 and rightIndex = size of resolution array.设置leftIndex = 0 和rightIndex = 分辨率数组的大小。
  • Check midIndex = (left+right)/2 resolution supported or not, and modify left and right based on the result.检查midIndex = (left+right)/2分辨率是否支持,根据结果修改左右。

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() .只需调用函数 FindMaximum_WidthHeight_ForCamera() When operation will be completed then maximum video resolution will be stored in selectedWidth and selectedHeight variables.操作完成后,最大视频分辨率将存储在selectedWidthselectedHeight变量中。 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 .我已经使用Chrome 版本 57.0.2987.110(64 位)Logitech, Inc. Webcam C270测试了这个实现。 But I think this solution should work in each scenario.但我认为这个解决方案应该适用于每种情况。 Thank You.谢谢你。

I agree with homm, his approach works fine: https://jsfiddle.net/evpozdniakov/c84ksucw/我同意 homm,他的方法效果很好: 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.就我而言,Opera 和 Chrome 提供的最大分辨率为 1280×720。

Firefox gives 640×480 by default, but you can improve his resolution as well up to 1280×720. Firefox 默认提供 640×480,但您也可以将其分辨率提高到 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/ https://webrtchacks.github.io/WebRTC-Camera-Resolution/

It is useful for troubleshooting purposes.它可用于故障排除目的。

Hope you find it interesting!希望你觉得它很有趣!

APIs and standards have changed since these answers were posted so I will post my current solution to the max-res GUM problem.自发布这些答案以来,API 和标准发生了变化,因此我将发布我当前针对最大分辨率 GUM 问题的解决方案。 I've tried the "scanning" solutions, even binary search etc., all have resulted in a crashing webpage on mobile devices (eg iPhone iPad) while desktop browsers showed more resilience.我尝试过“扫描”解决方案,甚至二进制搜索等,都导致网页在移动设备(例如 iPhone iPad)上崩溃,而桌面浏览器则表现出更强的弹性。

This is what I currently do to get max resolution (use advanced: [ and multiple width: { exact: s):这是我目前为获得最大分辨率所做的事情(使用advanced: [和 multiple width: { exact: s):

 const video = $("#video")[0] const constraints = { audio: false, video: { advanced: [ { width: { exact: 2560 } }, { width: { exact: 1920 } }, { width: { exact: 1280 } }, { width: { exact: 1024 } }, { width: { exact: 900 } }, { width: { exact: 800 } }, { width: { exact: 640 } }, { width: { exact: 320 } } ] } }; $(document).ready(() => { navigator.mediaDevices.getUserMedia(constraints).then((mediaStream) => { window.stream = mediaStream; video.srcObject = mediaStream; }).then(() => { return new Promise((resolve) => { video.onloadedmetadata = resolve; }); }).then(async () => { console.log('Ready to work'); }) });
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script> <video id="video" autoplay muted playsinline />

You can always use applyConstraints() combined with getCapabilities() on the track.您始终可以在轨道上结合使用applyConstraints()getCapabilities() Honza Kalfus' answer claims chrome now handles the ideal prop right for resolution. Honza Kalfus 的回答声称 chrome 现在可以处理解决问题的ideal道具。 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.我没有测试过,但 Chrome 83 仍然搞砸了理想的帧率值,如果超出范围,就不会启动视频......所以我希望这对某人有所帮助。

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).如果这是最大值(Chrome83),这会给我 30hz。

see also the MDN docs另请参阅MDN 文档

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM