最近接到一个少见的需求:在PC端网页调起摄像头并拍照,做完后顺势研究了下mediaDevices这个对象:
(以下内容皆在chrome浏览器中测试)
1.window.navigator.mediaDevices
window对象提供的媒体设备管理对象,供用户调起摄像头,麦克风等设备,还可以实现屏幕共享等功能。在控制台中输入后,打印出的内容为:
2.mediaDevices.enumerateDevices
一个返回Promise对象的函数,fulfilled后返回一个数组,数组内容为当前机器可用的设备数组。
数组子项结构为:
deviceId:设备ID
groupId:设备组ID,同类型的输入设备会被赋予相同的设备组ID,如多个麦克风
kind:设备类型,如videoinput代表摄像头
label:设备名称
这里有一个要提醒的点是:如果某个类型的设备没有得到用户授权的话,其对象依旧会在数组中被返回,但其deviceId和label会为空,所以最好确保得到用户授权后再调用enumerateDevices以获取完整的设备信息。
3.mediaDevices.getUserMedia
一个返回Promise对象的函数,接受一个参数作为配置项,fulfilled后返回一个媒体流mediaStream。
举个例子:
navigator.mediaDevices.getUserMedia({
audio: true,
video:{
width:720,
height:405,
deviceId:'abc'
}
}).then((stream)=>{});
使用这些参数,我们会获得设备ID为abc的摄像头拍摄的宽720高405且带有音频的媒体流,如果获取途中发生错误(如声明了audio但无收音设备),可以用catch获取具体错误对象。
可以指定使用的设备ID在机器拥有多个同类型输入设备时非常有用,通过enumerateDevices获取设备列表和设备ID后,可以使用select标签渲染到页面上供用户切换使用。
4.授权
当我们调用mediaDevices.getUserMedia时,浏览器会先获取当前网站的授权情况,如果没有历史授权且当前配置为“询问”时,浏览器就会弹窗询问用户“是否允许当前页面打开摄像头”,允许后才能获取媒体流。浏览器会记住用户当前选择,下次调用getUserMedia时将遵循历史授权情况执行。
跟很多其他配置一样,这个授权一旦被拒绝,用户必须在浏览器配置中手动打开才能才重新调用getUserMedia。
5.媒体流mediaStream
成功调用getUserMedia后返回的媒体流,可以通过URL.createObjectURL转换成video或audio标签可使用的src属性,部分浏览器可以直接设置为srcObject属性来使用。
6.拍照
video的dom对象能直接被canvas截取,使用drawImage截取当前帧:
const video = document.getElementById('video');
const canvas = document.getElementById('canvas');
const context = canvas.getContext('2d');
context.drawImage(video,0,0,720,405);
let result = canvas.toDataURL('image/png');
通过toDataURL把截取帧转化为base64图片后就可以放到img标签中展示或者供用户下载了。