• 记录--h5调用手机摄像头踩坑


    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助

    1. 背景

    一般业务也很少接触摄像头,有也是现成的工具库扫个二维码。难得用一次,记录下踩坑。

    2.调用摄像头的方法

    2.1. input

    1. <input type="file" accept="image/*" capture="camera">
    2. <input type="file" accept="video/*" capture="camcorder">
    3. <input type="file" accept="audio/*" capture="microphone">

    这个就不用多说了,缺点就是没办法自定义界面,它是调用的系统原生相机界面。

    2.2. mediaDevices

    由于我需要自定义界面,就像下面这样:

    所以我选择了这个方案,这个api使用起来其实很简单:

    1. <!-- 创建一个video标签用来播放摄像头的视屏流 -->
    2. <video id="video" autoplay="autoplay" muted width="200px" height="200px"></video>
    3. <button onclick="getMedia()">开启摄像头</button>
    1. async getMedia() {
    2. // 获取设备媒体的设置,通常就video和audio
    3. const constraints = {
    4. // video配置,具体配置可以看看mdn
    5. video: {
    6. height: 200,
    7. wdith: 200,
    8. },
    9. // 关闭音频
    10. audio: false
    11. };
    12. this.video = document.getElementById("video");
    13. // 使用getUserMedia获取媒体流
    14. // 媒体流赋值给srcObject
    15. this.video.srcObject = await window.navigator.mediaDevices.getUserMedia(constraints);
    16. // 直接播放就行了
    17. this.video.play();
    18. }

    可以看到这个效果。

    这个api的配置可以参考MDN

    1. // 截图拍照
    2. takePhoto() {
    3. const video = document.getElementById("video");
    4. // 借助canvas绘制视频的一帧
    5. const canvas = document.getElementById("canvas");
    6. const ctx = canvas.getContext('2d');
    7. ctx.drawImage(this.video, 0, 0, 300, 300);
    8. },
    9. // 停止
    10. stopMedia() {
    11. // 获取媒体流
    12. const stream = this.video.srcObject;
    13. const tracks = stream.getTracks();
    14. // 停止所有轨道
    15. tracks.forEach(function (track) {
    16. track.stop();
    17. })
    18. this.video.srcObject = null;
    19. }

    3.坑

    如果你复制我的代码,在localhost上肯定能运行,但是你想在手机上试试的时候就会发现很多问题。

    3.1. 需要https

    由于浏览器的安全设置,除了localhosthttps连接,你都没办法获取到navigator.mediaDevices,打印出来是undefined。如果要在手机上测试,你要么用内网穿透代理一个https,要么部署在https域名的服务器上测试。

    3.2. 设置前后摄像头

    默认是使用user设备,也就是前摄像头,想要使用后摄像头也是有配置的,

    1. async getMedia() {
    2. // ...
    3. let constraints = {
    4. video: {
    5. height: 200,
    6. wdith: 200,
    7. // environment设备就是后置
    8. facingMode: { exact: "environment" },
    9. },
    10. audio: false
    11. };
    12. // ...
    13. }

    3.3. 设置显示区域大小

    我的需求是铺满整个设备,所以我想当然的直接把video样式宽高设置成容器大小:

    1. #video {
    2. width: 100%;
    3. height: 100%;
    4. }
    5. async getMedia() {
    6. // ....
    7. // 将宽高设置成容器大小
    8. const pageSize = document.querySelector('.page').getBoundingClientRect()
    9. let constraints = {
    10. video: {
    11. height: pageSize.height,
    12. width: pageSize.width,
    13. facingMode: { exact: "environment" },
    14. },
    15. audio: false
    16. };
    17. //....
    18. }

    发现这个视频横着而且没有铺满屏幕。

    通过输出video的信息可以看到,设备返回的视频流宽高是反的:

     所以配置换一下就行了:

    1. let constraints = {
    2. video: {
    3. height: pageSize.width,
    4. width: pageSize.height,
    5. },
    6. };

    本文转载于:

    https://juejin.cn/post/7287965561035210771

    如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。

     

  • 相关阅读:
    JVM面试题总结
    python:Möller–Trumbore射线三角面相交算法
    供给需求双轮驱动安全应急产业高质量发展
    【3D人脸】AI Mesh 数据工程调研
    Git实操图文详解系列教程(4)——IDEA集成GitHub
    思腾云计算
    Java回顾-IO流-节点流/缓冲流/对象流/转换流
    5G网络切片,到底是什么?
    972信息检索 | 第五章 国外综合性信息检索系统
    vue165-main.js-vue中的小提示
  • 原文地址:https://blog.csdn.net/qq_40716795/article/details/133858718