前言
最近接手一个需求,页面上调用设备摄像头将拍摄的内容实时展示,用户可以随时截图上传,描述起来觉得挺简单,实际做了不少工作,特此记录。
getUserMedia使用环境
目前获取摄像头流推荐的API是navigator.mediaDevices.getUserMedia,很多刚接触的小伙伴可能会发现自己的navigator找不到mediaDevices这个对象,如果你出现这种情况有两种方式可以解决,使用localhost或者https协议(推荐),我本人开发过程中使用Vue+webpack,对于https有很便捷的支持,只需要在webpack配置文件devServer选项中添加https: true 参考链接。
注:如果你遇到程序出现req.handle.writev is not a function, 这种情况一般会发生在iphone请求https时候,我的解决方法是给node降级,没搜到什么好方法,参考自https://github.com/nodejs/node/issues/21665,都是泪...
给getUserMedia做个备胎
并不是所有的用户浏览器都是支持getUserMedia,我们又不知道究竟各个浏览器哪个版本是支持的,为了兼容性我们给getUserMedia做个垫片,代码从MDN上copy而来。
// Older browsers might not implement mediaDevices at all, so we set an empty object first
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
// Some browsers partially implement mediaDevices. We can't just assign an object
// with getUserMedia as it would overwrite existing properties.
// Here, we will just add the getUserMedia property if it's missing.
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function(constraints) {
// First get ahold of the legacy getUserMedia, if present
var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
// Some browsers just don't implement it - return a rejected promise with an error
// to keep a consistent interface
if (!getUserMedia) {
return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
}
// Otherwise, wrap the call to the old navigator.getUserMedia with a Promise
return new Promise(function(resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject);
});
}
}
调用getUserMedia
所有的准备工作都已经做好了,那下一部分就是开始使用getUserMedia来获取视频流了,不出意外你就可以打开摄像头并且在video中播放实时画面了。
navigator.mediaDevices.getUserMedia({ audio: true, video: true })
.then(function(stream) {
var video = document.querySelector('video');
// Older browsers may not have srcObject
if ("srcObject" in video) {
video.srcObject = stream;
} else {
// Avoid using this in new browsers, as it is going away.
video.src = window.URL.createObjectURL(stream);
}
video.onloadedmetadata = function(e) {
video.play();
};
})
.catch(function(err) {
console.log(err.name + ": " + err.message);
});
iphone运行有问题
如果上几步你都跟着做了,你应该发现在PC网页端可以完美运行,如果你尝试在移动端运行,运气好你先拿起了一部安卓手机,完美运行,你又拿起了一部iphone,what?为什么只有第一帧就卡住了(PS:iphone微信打开无法运行,我也没有解决,只能用Safari打开),找不到那篇说明文档了,大致说一下意思就是苹果对于网页端媒体开发进行了限制,会限制视频的自动播放,需要用户主动去触发授权。比如可以在onclick事件中调用,我看文档上写着还可以设置viedo无声(muted属性)也可以自动播放,我尝试并没有效果,结果就是加了一个按钮,让用户主动去调用video.play()。OK,那就好了吗?你会发现苹果会自己把video全屏,那有些时候这可能不是你想要的效果,解决方法,Safari在10版本前后有些差异,webkit-playsinline、playsinline作用相同,只不过为了更全面的兼容性。
<video muted webkit-playsinline='true' playsinline='true'></video>