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

这篇文章主要介绍了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正常运行。安卓目前没有发现版本限制,需要兼容的代码如下

1

2

3

4

5

6

7

8

9

10

11

12

13

14

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.前置摄像头调用后,摄像功能需要关闭后才能正常执行第二次调用,否则会报错:设备被占用。解决方法,在每次执行调用方法前,先关闭摄像设备。

1

2

3

4

5

if (window.stream) {

    window.stream.getTracks().forEach(track => {

          track.stop();

    });

}

亲测有用,别的找了很多停止的方法都没有效果。
2.调用后置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

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);

                });

如果只是一部手机可以这样,但是测试了多部手机发现摄像头数组毫无规律可循,这个方法慎用。
如果页面上添加选择摄像设备的按钮的话,这个方法还是不错的。查看设备能调用几个摄像头链接如下:Select audio and video sources
由于我们的项目页面不希望出现切换按钮,面对后置出现的众多BUG,最终选择放弃,使用input调用摄像头。

1

<input class="card_input" v-on:change="appCapture($event)" type="file" accept="image/*" capture="camera" />

成功调用后用canvas实现成像并适应屏幕大小

我这里的代码是取video的宽高然后复制给canvas,这样可以让canvas和video保持一致,只用给video设置宽度100%,高度调节成合适的值,就实现了适应手机屏幕。

1

2

3

4

5

6

7

8

9

10

11

12

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”,也有的是空值,但是也能实现。
配置代码如下:

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

<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

// 头像相机

       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();

           }

       },

转载地址:https://www.jb51.net/html5/722394.html

前端实践之调用手机摄像头相关推荐

  1. 前端调用手机摄像头权限进行扫码解析

    前端调用手机摄像头权限进行扫码解析(demo含Vue及原生) 前端调用手机摄像头权限进行扫码解析(demo含Vue及原生js写法) 引子 实践 此时已经可以成功调用摄像头,接下来集成进Vue工程中 最 ...

  2. 原生html调手机拍照,如何让HTML5调用手机摄像头拍照——实践就是一切

    原文:如何让HTML5调用手机摄像头拍照--实践就是一切 NanShan 小编将思路提供给了大家,学编程最重要的是实践,我这虽然有完善的代码,但是希望大家都可以自己写出属于自己的代码 HTML5 Th ...

  3. 使用HTML5+调用手机摄像头和相册

    前言: 前端时间使用HTML5做了一个WEB端APP,其中用到了H5页面调用手机摄像头的功能,当时也是花了不少时间去研究.最终是采用了HTML5plus(HTML5+)的方式完成了该功能,现将具体方法 ...

  4. html调起苹果手机摄像头_使用HTML5+调用手机摄像头和相册

    前言: 前端时间使用HTML5作了一个WEB端APP,其中用到了H5页面调用手机摄像头的功能,当时也是花了很多时间去研究.最终是采用了HTML5plus(HTML5+)的方式完成了该功能,现将具体方法 ...

  5. uniapp调用手机摄像头_HTML5通过navigator.mediaDevices.getUserMedia调用手机摄像头问题...

    navigator.mediaDevices.getUserMedia 应项目要求,需要实现移动端app嵌入H5页面完成实人认证的功能.打开getUserMedia文档,链接如下: https://d ...

  6. MediaDevices html5,HTML5如何通过navigator.mediaDevices.getUserMedia调用手机摄像头

    HTML5如何通过navigator.mediaDevices.getUserMedia调用手机摄像头 发布时间:2021-05-23 15:03:11 来源:亿速云 阅读:76 作者:小新 这篇文章 ...

  7. python+opencv用电脑调用手机摄像头或其他网路摄像头

    python+opencv用电脑调用手机摄像头或其他网路摄像头 文章目录: 1 获取手机摄像头或网络摄像头的ip 1.1 获取手机摄像头的ip 1.2 获取网络摄像头的IP 1.3 关于RTSP协议 ...

  8. html5调用手机摄像头,实现拍照上传功能

    http://www.glve.net/html5-calls-cell-phone-cameras-to-achieve-photo-upload-feature.html 今天做手机网站,想实现手 ...

  9. H5调用手机摄像头拍照,如何压缩后上传

    H5调用手机摄像头拍照后,怎样压缩再上传? 实际的压缩功能,就是利用canvas画布功能,将图片进行裁剪后保存图片的base64数据流,然后上传. 案例全部代码,示下: <!DOCTYPE ht ...

最新文章

  1. IO流 带行号的缓冲区
  2. Lesson 6.1 身份证识别: 提取字段
  3. Go的sync.RWMutex(六)
  4. 如何优化代码和RAM大小
  5. (转)解决Google Adsense广告只显示英文的问题
  6. python安装sqlalchemy-Python流行ORM框架sqlalchemy安装与使用教程
  7. [Errno 256] No more mirrors to try.
  8. DTCC技术大会来了
  9. 复旦大学2015--2016学年第二学期高等代数II期末考试情况分析
  10. python中24≤2825是否合法_在下列Python语句中非法的是() (2.0分)_学小易找答案
  11. Windows Subsystem for Linux (WSL2) - WSL 的基本命令
  12. 安装与使用 supervisor(可管理Tomcat进程)
  13. 数据赋能:Uber的数据治理实践分享
  14. Android-第九节网络编程
  15. ClickHouse副本表ReplicatedMergeTree实操
  16. Rosbag提取特定话题、改变话题名称及改变话题的Frame_id
  17. 浅谈德州扑克AI核心算法:CFR
  18. python---A*搜索算法解决八数码问题
  19. 阻止click点击事件
  20. JDBC连接MySQL数据库,访问数据库信息完成登录功能——保姆级详细教程(附所有java和jsp源代码)

热门文章

  1. Time Machine
  2. Oracle创建索引bitmap,Oracle编程高手箴言:位图索引(Bitmap Index)的故事
  3. java 魔法值_Java代码中的魔法值
  4. Git Pull failed: Failed to start Git process…\JetBrains\IntelliJIdea2021.1\tmp\intelliji-git-askpass
  5. 【python设置临时环境变量】export PYTHONPATH=$(pwd):${PYTHONPATH}
  6. c语言教学理念和思路,基于CDIO理念的《C语言程序设计》教学改革探索
  7. 绝地求生服务器维护6.17,绝地求生最新更新维护到几点 6月17日绝地求生停机维护多久...
  8. 最新北交所发行上市业务规则解读
  9. springboot自定义logbackAppender
  10. 计算机科学技术知识体系--转载