• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    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);
                    });

    如果只是一部手机可以这样,但是测试了多部手机发现摄像头数组毫无规律可循,这个方法慎用。
    如果页面上添加选择摄像设备的按钮的话,这个方法还是不错的。查看设备能调用几个摄像头链接如下:https://webrtc.github.io/samples/src/content/devices/input-output/
    由于我们的项目页面不希望出现切换按钮,面对后置出现的众多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调用 摄像头内容请搜索脚本之家以前的文章或继续浏览下面的相关文章,希望大家以后多多支持脚本之家!

    上一篇:遮罩层 + Iframe实现界面自动显示的示例代码
    下一篇:HTML5中的网络存储实现方式
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

    HTML5通过navigator.mediaDevices.getUserMedia调用手机摄像头问题 HTML5,通过,navigator.mediaDevices.getUserMedia,