HTML5通过navigator.mediaDevices.getUserMedia调用手机摄像头问题
navigator.mediadevices.getusermedia
应项目要求,需要实现移动端app嵌入h5页面完成实人认证的功能。打开getusermedia文档,链接如下:
https://developer.mozilla.org/zh-cn/docs/web/api/mediadevices/getusermedia
看上去很简单,最终却写的怀疑人生。
api环境
问题一:(为什么不管怎么配置都显示前置摄像头)
想正常使用api必须在https环境下进行,否则你会发现不管怎么写,都只能调用默认的摄像头(大部分都是前置,只有少部分是后置)
前端开发者可以将文件上传至"码云"仓库,获取https链接然后在手机上预览
链接:码云仓库入口
问题二:(api在安卓和ios效果一样吗?)
根据官方文档,目前navigator.mediadevices.getusermedia在ios上只支持11版本以上,且只能在safari正常运行。安卓目前没有发现版本限制,需要兼容的代码如下
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); }); } }
问题三:(第一次启用成功调用前置摄像头,第二次需要调用后置却黑屏或者失败)
失败的原因很多,列举两个一开始我遇到的问题
1.前置摄像头调用后,摄像功能需要关闭后才能正常执行第二次调用,否则会报错:设备被占用。解决方法,在每次执行调用方法前,先关闭摄像设备。
if (window.stream) { window.stream.gettracks().foreach(track => { track.stop(); }); }
亲测有用,别的找了很多停止的方法都没有效果。
2.调用后置api的方法还是无法唤醒后置摄像头,于是我找到另外一个方法,通过查看手机摄像头id,来直接唤醒后置。
var deviceinfoid="", //摄像头id num = 0, //摄像头数量 carema = []; //摄像头id数组 //在页面加载完成后获得设备id数组 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, //放在app里面需要下面配置一下 "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; // video.play(); 这个加不加好像没有影响 }) .catch(function (err) { console.log(err.name + ": " + err.message); });
如果只是一部手机可以这样,但是测试了多部手机发现摄像头数组毫无规律可循,这个方法慎用。
如果页面上添加选择摄像设备的按钮的话,这个方法还是不错的。查看设备能调用几个摄像头链接如下:
由于我们的项目页面不希望出现切换按钮,面对后置出现的众多bug,最终选择放弃,使用input调用摄像头。
<input class="card_input" v-on:change="appcapture($event)" type="file" accept="image/*" capture="camera" />
成功调用后用canvas实现成像并适应屏幕大小
我这里的代码是取video的宽高然后复制给canvas,这样可以让canvas和video保持一致,只用给video设置宽度100%,高度调节成合适的值,就实现了适应手机屏幕。
var video = document.getelementbyid('video'); var canvas = document.getelementbyid('canvas'), ctx = canvas.getcontext('2d'), cheight = video.clientheight, //获取屏幕大小让canvas自适应 cwidth = video.clientwidth; canvas.width = cwidth; canvas.height = cheight; //localmediastream 在data里定义一个{} if (localmediastream) { ctx.drawimage(video, 0, 0, cwidth, cheight); var dataurl = canvas.todataurl('image/jpeg'); //dataurl = 'data:image/png;base64,ivborw0kggoaaaansuheugaa' img.src = dataurl;
video成像镜像问题
api唤醒的前置摄像头是相反的,很不舒服很不舒服。
之后用css处理一下给video添加 transform: rotate(180deg),可以实现反转,但是还是没有达到和手机一样的效果。
这时候可以选择通过设备id调用前置摄像头,前置摄像头的laval一直都是“default”,也有的是空值,但是也能实现。
配置代码如下:
var constraints = window.constraints = { audio: false, video: { sourceid: 'default', facingmode: { exact: "user" } } };
完美调用自己手机的前置摄像头!!!
完整代码如下:
页面代码:
<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>
// 头像相机 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, //获取屏幕大小让canvas自适应 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'); //dataurl = 'data:image/png;base64,ivborw0kggoaaaansuheugaa' vm.imginfo = dataurl; // 停止摄像机 video.pause(); this.stopcapture(); } },
到此这篇关于html5通过navigator.mediadevices.getusermedia调用手机摄像头问题的文章就介绍到这了,更多相关html5调用 摄像头内容请搜索以前的文章或继续浏览下面的相关文章,希望大家以后多多支持!