记录--h5调用手机摄像头踩坑
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助
1. 背景
一般业务也很少接触摄像头,有也是现成的工具库扫个二维码。难得用一次,记录下踩坑。
2.调用摄像头的方法
2.1. input
1 2 3 4 5 6 | <!-- 调用相机 --> <input type= "file" accept= "image/*" capture= "camera" > <!-- 调用摄像机 --> <input type= "file" accept= "video/*" capture= "camcorder" > <!-- 调用录音机 --> <input type= "file" accept= "audio/*" capture= "microphone" > |
这个就不用多说了,缺点就是没办法自定义界面,它是调用的系统原生相机界面。
2.2. mediaDevices
由于我需要自定义界面,就像下面这样:
所以我选择了这个方案,这个api
使用起来其实很简单:
1 2 3 | <!-- 创建一个video标签用来播放摄像头的视屏流 --> <video id= "video" autoplay= "autoplay" muted width= "200px" height= "200px" ></video> <button onclick= "getMedia()" >开启摄像头</button> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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(); } |
可以看到这个效果。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // 截图拍照 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
由于浏览器的安全设置,除了localhost
和https
连接,你都没办法获取到navigator.mediaDevices
,打印出来是undefined
。如果要在手机上测试,你要么用内网穿透代理一个https
,要么部署在https
域名的服务器上测试。
3.2. 设置前后摄像头
默认是使用user
设备,也就是前摄像头,想要使用后摄像头也是有配置的,
1 2 3 4 5 6 7 8 9 10 11 12 13 | async getMedia() { // ... let constraints = { video: { height: 200, wdith: 200, // environment设备就是后置 facingMode: { exact: "environment" }, }, audio: false }; // ... } |
3.3. 设置显示区域大小
我的需求是铺满整个设备,所以我想当然的直接把video
样式宽高设置成容器大小:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | #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 }; //.... } |
发现这个视频横着而且没有铺满屏幕。
通过输出video
的信息可以看到,设备返回的视频流宽高是反的:
所以配置换一下就行了:
1 2 3 4 5 6 | let constraints = { video: { height: pageSize.width, width: pageSize.height, }, }; |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2022-10-12 记录--uni-app adb安卓wifi无线调试