文章摘自:https://blog.csdn.net/weixin_43864427/article/details/105771863
webRTC polyfill 的库: https://github.com/webrtcHacks/adapter
第一次启用成功调用前置摄像头,第二次需要调用后置却黑屏或者失败
失败的原因很多,列举两个一开始我遇到的问题
- 前置摄像头调用后,摄像功能需要关闭后才能正常执行第二次调用,否则会报错:设备被占用。解决方法,在每次执行调用方法前,先关闭摄像设备。
1 2 3 4 5
| if (window.stream) { window.stream.getTracks().forEach(track => { track.stop(); }) }
|
- 调用后置API的方法还是无法唤醒后置摄像头,找到另外一个方法,通过查看手机摄像头ID,来直接唤醒后置。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| var deviceInfoId = "", num = 0, carema = [];
window.onload = navigator.mediaDevices.enumerateDevices().then(gotDevices);
function gotDevices(deviceInfos) { for (let i = 0; i < deviceInfos.length; ++i) { if (deviceInfos[i].kind === 'videoinput') { carema.push(deviceInfos[i].deviceId) } } deviceInfoId = carema[后置位置]; }
var constraints = { audio: false, video: { deviceId: deviceInfoId, "permissions": { "audio-capture": { "description": "Required to capture audio using getUserMedia()" }, "video-capture": { "description": "Required to capture video using getUserMedia()" } } } };
navigator.mediaDevices.getUserMedia(constraints).then(function (stream) { var video = document.getElementById('video'); try { window.stream = stream; video.srcObject = stream; } catch (error) { video.src = window.URL.createObjectURL(stream); } this.localMediaStream = stream; }).catch(function (err) { console.log(err.name + ": " + err.message); });
|
如果只是一部手机可以这样,但是测试了多部手机发现摄像头数组毫无规律可循,这个方法慎用。
如果页面上添加选择摄像设备的按钮的话,这个方法还是不错的。查看设备能调用几个摄像头链接如下:
https://webrtc.github.io/samples/src/content/devices/input-output/
部分手机打开摄像头以后是黑屏,但是拍照仍然可以成像
解决方案:做了很多处理都没用,最后发现只要把参数中的分辨率(width,height)删除掉,就解决了黑屏问题
成功调用后用canvas实现成像并适应屏幕大小
我这里的代码是取video的宽高然后复制给canvas,这样可以让canvas和video保持一致,只用给video设置宽度100%,高度调节成合适的值,就实现了适应手机屏幕。
1 2 3 4 5 6 7 8 9 10 11 12 13
| var video = document.getElementById('video'); var canvas = document.getElementById('canvas'), ctx = canvas.getContext('2d'), CHeight = video.clientHeight, CWidth = video.clientWidth; canvas.width = CWidth; canvas.height = CHeight;
if (localMediaStream) { ctx.drawImage(video, 0, 0, CWidth, CHeight); var dataURL = canvas.toDataURL('image/jpeg'); img.src = dataURL; }
|
video 成像镜像问题
API唤醒的前置摄像头是相反的,很不舒服很不舒服。
之后用css处理一下给video添加 transform: rotate(180deg),可以实现反转,但是还是没有达到和手机一样的效果。
这时候可以选择通过设备ID调用前置摄像头,前置摄像头的laval一直都是“default”,也有的是空值,但是也能实现。
配置代码如下:
1 2 3 4 5 6 7
| var constraints = window.constraints = { audio: false, video: { sourceId: 'default', facingMode: { exact: "user" } } };
|
完美调用自己手机的前置摄像头!!!
完整代码如下:
1 2 3 4 5 6 7 8 9 10 11
| <div @click='moveToCameraAVG()' v-cloak> <img v-if="imginfo!==''" :src="imginfo"/> <div class="warm_title2">点击自拍一张头像</div> </div> <video id="video" class="pic_video" playsinline autoplay x5-video-player-type="h5" style='object-fit:fill'></video> <canvas id="canvas" class="canvas_pic" style='margin: 0;padding: 0;'></canvas> <div class="bottom_div"> <div>拍照</div> <img src='images/pic_btn.png' class="capture-btn" @click='captureAvg'/> </div>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| export default { moveToCameraAVG() { var self = this; if (navigator.mediaDevices === undefined) { navigator.mediaDevices = {}; } if (navigator.mediaDevices.getUserMedia === undefined) { navigator.mediaDevices.getUserMedia = function (constraints) { var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia; if (!getUserMedia) { return Promise.reject(new Error('getUserMedia is not implemented in this browser')); } return new Promise(function (resolve, reject) { getUserMedia.call(navigator, constraints, resolve, reject); }); } } if (window.stream) { window.stream.getTracks().forEach(track => { track.stop(); }); } var constraints = window.constraints = { audio: false, video: { sourceId: 'default', facingMode: { exact: "user" } } }; navigator.mediaDevices.getUserMedia(constraints) .then(function (stream) { var video = document.getElementById('video'); try { window.stream = stream; video.srcObject = stream; } catch (error) { video.src = window.URL.createObjectURL(stream); } self.localMediaStream = stream; video.play(); }) .catch(function (err) { alert(err.name + ": " + err.message); }); }, stopCapture: function () { var video = document.getElementById('video'); if (!video.srcObject) return let stream = video.srcObject let tracks = stream.getTracks(); tracks.forEach(track => { track.stop() }) }, captureAvg() { var vm = this; var video = document.getElementById('video'); var canvas = document.getElementById('canvas'), ctx = canvas.getContext('2d'), CHeight = video.clientHeight, CWidth = video.clientWidth; canvas.width = CWidth; canvas.height = CHeight; if (vm.localMediaStream) { ctx.drawImage(video, 0, 0, CWidth, CHeight); var dataURL = canvas.toDataURL('image/jpeg'); vm.imginfo = dataURL; video.pause(); this.stopCapture(); } } }
|