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.