注册
web

h5调用手机摄像头踩坑

1. 背景


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


2.调用摄像头的方法


2.1. input


<!-- 调用相机 -->
<input type="file" accept="image/*" capture="camera">
<!-- 调用摄像机 -->
<input type="file" accept="video/*" capture="camcorder">
<!-- 调用录音机 -->
<input type="file" accept="audio/*" capture="microphone">

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


2.2. mediaDevices


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


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


<!-- 创建一个video标签用来播放摄像头的视屏流 -->
<video id="video" autoplay="autoplay" muted width="200px" height="200px"></video>
<button onclick="getMedia()">开启摄像头</button>

async getMedia() {
// 获取设备媒体的设置,通常就video和audio
const constraints = {
// video配置,具体配置可以看看mdn
video: {
height: 200,
wdith: 200,
},
// 关闭音频
audio: false
};
this.video = document.getElementById("video");
// 使用getUserMedia获取媒体流
// 媒体流赋值给srcObject
this.video.srcObject = await window.navigator.mediaDevices.getUserMedia(constraints);
// 直接播放就行了
this.video.play();
}

image.png
可以看到这个效果。


这个api的配置可以参考MDN


// 截图拍照
takePhoto() {
const video = document.getElementById("video");
// 借助canvas绘制视频的一帧
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext('2d');
ctx.drawImage(this.video, 0, 0, 300, 300);
},
// 停止
stopMedia() {
// 获取媒体流
const stream = this.video.srcObject;
const tracks = stream.getTracks();
// 停止所有轨道
tracks.forEach(function (track) {
track.stop();
})
this.video.srcObject = null;
}

3.坑


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


3.1. 需要https


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


3.2. 设置前后摄像头


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


async getMedia() {
// ...
let constraints = {
video: {
height: 200,
wdith: 200,
// environment设备就是后置
facingMode: { exact: "environment" },
},
audio: false
};
// ...
}

3.3. 设置显示区域大小


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


#video {
width: 100%;
height: 100%;
}

async getMedia() {
// ....
// 将宽高设置成容器大小
const pageSize = document.querySelector('.page').getBoundingClientRect()
let constraints = {
video: {
height: pageSize.height,
width: pageSize.width,
facingMode: { exact: "environment" },
},
audio: false
};
//....
}

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


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


image.png


所以配置换一下就行了:


    let constraints = {  
video: {
height: pageSize.width,
width: pageSize.height,
},
};

作者:头上有煎饺
来源:juejin.cn/post/7287965561035210771

0 个评论

要回复文章请先登录注册