Browser calls camera getUserMedia

Keywords: Firefox Android

Browser calls camera getUserMedia

The news of QQ browser launching in 2018 will boot the camera is full of buzz.
Some time ago, the company asked to study the browser to enable the camera function, hoping to achieve the browser web page scanning two-dimensional code function. Now write it down and record it.
Browser-enabled cameras are implemented using getUserMedia api, which prompts the user to grant permission to use media input. Media input generates a Media Stream, which contains the track of the requested media type. This stream may contain a video track (from hardware or virtual video sources, such as cameras, video capture devices, screen sharing services, etc.), an audio track (also from hardware or virtual audio sources, such as microphones, A/D converters, etc.), or other track types.
With this api, it is possible for browsers to call cameras. But the compatibility is poor.

I tested Huawei's own browser and Android Wechat's browser. The figure shows that UC supported in version 12.0.8.988 has been tested and found to support this getUserMedia method. It also successfully callback but can not image. However, the test of millet browser found that it can not open the camera. It should be that millet browser has security detection and browser does not allow the camera to be invoked.
No more nonsense, code it:
html

<select id="select"></select>
<input type="button" title="open Camera" value="Turn on the camera" "getMedia();" />
<div>
        <video id="video" style="background:#000;" width="400" height="400"></video>
        <canvas id='canvas' style="display: none;" width='400' height='400'></canvas>
</div>

js

var video = document.getElementById('video'),       //Camera
    canvas = document.getElementById('canvas'),     //Intercept images
    select = document.getElementById("select"),     //Switching Camera
    exArray = [];                                   //Storage device source ID

//Getting the device source ID navigator.getUserMedia needs
if (typeof MediaStreamTrack != 'undefined' && typeof MediaStreamTrack.getSources != 'undefined') {
    MediaStreamTrack.getSources(function (sourceInfos) {
        for (var i = 0; i != sourceInfos.length; ++i) {
            var sourceInfo = sourceInfos[i];
            //It traverses audio and video, so distinguish between them.  
            if (sourceInfo.kind === 'video') {
                exArray.push(sourceInfo.id);
            }
        }
    });
}

function getMedia() {
    if(window.stream) {
        window.stream.getTracks().forEach(function(track) {
            track.stop();
        });
    }
    if (typeof navigator.mediaDevices == 'undefined' && typeof navigator.mediaDevices.getUserMedia == 'undefined') {
        navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
        if (typeof navigator.getUserMedia == 'undefined') {
            return errorFunc({name: "ERROR", message: "navigator.getUserMedia is undefined!"});            
        }
        for(var i = 0; i < exArray.length; i++) {
            var option = document.createElement('option');
            option.text = 'camera ' + (i + 1);
            option.value = exArray[i];
            select.appendChild(option);
        }
        var val = select.value;        
        navigator.getUserMedia({
            'video': {
                'optional': [{
                        'sourceId': val ? val : exArray[0]//0 is the front camera and 1 is the rear camera.  
                    }]
            },
//            'video': true,
            'audio': false
        }, successFunc, errorFunc)
    } 
    else {
        navigator.mediaDevices.enumerateDevices().then(getDevice).catch(errorFunc);
        var val = select.value;
        var constraints = {
            audio: false,
            video: {deviceId: val ? {exact: val} : undefined}
//            Video: {facing mode: {exact:'environment'}// ineffective
//            video: true
        }
        navigator.mediaDevices.getUserMedia(constraints)
            .then(function (stream) {
                successFunc(stream);
                return navigator.mediaDevices.enumerateDevices();
            }).then(getDevice)
            .catch(function (err) {
                errorFunc(err);
            });
    }
}
function getDevice(deviceInfos) {
    var val = select.value;
    while(select.firstChild) {
        select.removeChild(select.firstChild);
    }
    for(var i = 0; i !== deviceInfos.length; ++i) {
        var deviceInfo = deviceInfos[i];
        var option = document.createElement('option');
        option.value = deviceInfo.deviceId;
         if (deviceInfo.kind === 'videoinput') {
            option.text = deviceInfo.label || 'camera ' + (select.length + 1);
            select.appendChild(option);
         }
    }
    if(select.value && select.value !== "") {
        select.value = val;
    }
    
}
//Turn on the camera and call back successfully
function successFunc(stream) {
    window.stream = stream;
    if ("srcObject" in video) {
        video.srcObject = stream;
    } else if (video.mozSrcObject !== undefined) {
//In Firefox, video.mozSrcObject was originally null, not undefined, and we can rely on this to detect Firefox support.  
        video.mozSrcObject = stream;
    } else {
        window.URL = window.URL || window.webkitURL || window.mozURL || window.msURL;
        video.src = window.URL && window.URL.createObjectURL(stream) || stream;
    }
    video.onloadedmetadata = function (e) {
        video.play();
    };
}
//Turn on camera error callback
function errorFunc(e) {
    alert(e.name + ": " + e.message);
}

//Intercept images
function screenShot() {
    canvas.getContext('2d').drawImage(video, 0, 0, 400, 400);
    var imgData = canvas.toDataURL("image/png", 0.8);
}

This is done by using getUserMedia to call the camera and image it in canvas, then scan and identify the image with canvas mapping.
summary
The above code has compatible processing, can image but not zoom in, and can not focus, browser support rate is not high.

Posted by MrPixel on Thu, 16 May 2019 04:54:40 -0700