Подтвердить что ты не робот

Получить максимальное разрешение видео с помощью getUserMedia

Я пытаюсь получить максимально возможное видео разрешение через JS navigator.getUserMedia. Я знаю о ограничениях, но не знаю, как правильно выбрать в моем случае.

Проблема заключается в том, что нет способа сказать "Я хочу видео с максимальным разрешением". Поэтому вместо этого я пытаюсь сказать "Я хочу видео не менее, чем очень большое разрешение".

Когда я пытаюсь minWidth: 1600, Chrome возвращает мне 1280 × 720 видео (максимально возможное для моей камеры, я думаю). Но что делать, если у пользователя есть камера с более высоким разрешением? Поэтому я запрашиваю видео minWidth: 2048, а Chrome возвращает только 640 × 480.

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

Это онлайн-пример: http://jsbin.com/kibeza/1/watch?js,output

И есть настоящая проблема: Chrome не знает математику. Он думает, что 1600 больше, чем 2048. Я не могу просить видео "не менее 100500", потому что в этом случае я получу стандартное низкое разрешение. Я не могу спросить видео "не менее разумного малого разрешения", потому что могут быть пользователи с более высоким разрешением, и я хочу получить более высокое разрешение.

4b9b3361

Ответ 1

Я до сих пор не знаю правильного ответа, но я делаю следующее:

video: {
  optional: [
    {minWidth: 320},
    {minWidth: 640},
    {minWidth: 1024},
    {minWidth: 1280},
    {minWidth: 1920},
    {minWidth: 2560},
  ]
}

Пока одно выражение minWidth: 2560 сбрасывает разрешение по умолчанию, серия выражения minWidth делает браузер всегда принимает максимальное разрешение на тестируемом оборудовании.

Ответ 2

Тем не менее, я не нашел никакого хорошего API для получения максимального разрешения видео с помощью getUserMedia.

Но здесь я разделяю идею , чтобы получить максимальное поддерживаемое разрешение видео подключенного устройства с помощью алгоритма двоичного поиска, и он отлично работает.

Вот шаги для выполнения этой задачи,

  • Сохранение некоторых стандартных разрешений в массиве, сохранение по возрастанию порядок.
  • Установите leftIndex= 0 и rightIndex= размер массива разрешений.
  • Отметьте midIndex= (левый + правый)/2 разрешенный или нет, и измените влево и вправо на основе результата.

Здесь я делюсь своей реализацией:

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

Просто вызовите функцию FindMaximum_WidthHeight_ForCamera(). Когда операция будет завершена, максимальное разрешение видео будет сохранено в переменных selectedWidth и selectedHeight. Здесь я также добавляю консольный вывод для своего устройства:

//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

Я протестировал эту реализацию, используя версию Chrome версии 57.0.2987.110 (64-разрядная версия) и Logitech, Inc. Webcam C270. Но я думаю, что это решение должно работать в каждом сценарии. Спасибо.

Ответ 3

Я согласен с 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 = '';
    }
}

В моем случае Opera и Chrome предлагают максимальное разрешение 1280 × 720.

Firefox дает по умолчанию 640 × 480, но вы можете улучшить его разрешение и до 1280 × 720. Вот вы:

enter image description here

Ответ 4

У меня был большой успех с определением размеров 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);
});