兼容性:
自测如下:
template代码
页面交互根据需求定义
此处为主要功能代码,全部代码需私信
<mt-button class="next_submit" type="default" @click.native="camera" v-if="nextSign">开始人脸识别</mt-button>
<video class="video_rolate"
width="255px"
height="255px"
:src="url" ref="videoRef"
x-webkit-airplay="true"
x5-video-player-fullscreen="true"
x5-video-orientation="h5"
playsinline="true"
autoplay
x5-video-player-type="h5"
webkit-playsinline="true"></video>
//播放录制的视频流
<video ref="videob" controls="" name="media" width="100%" height="400"></video>
js代码
data(){
return {
showVideo: false,
mediaRecorder: null,
MediaStreamTrack: null,
isAlreadyRecord: false,
count: 3,//录制时间 s
startTime:3000,//和count保持一致
countTimer: null,
counts:3,//待开始录制时长 s
recordedBlobs: [],//视频流
randomColor:"#eee",//变色颜色
border:'#fff',//边框颜色
isUpload:false,//上传中状态
faceResult:false
}}
// 调用摄像头 开始录制
async camera () {
//在每次执行前,先关闭设备。
if (window.stream) {
window.stream.getTracks().forEach(track => {
track.stop();
});
}
let constraints = {
audio: false,
video: {
facingMode:{ exact: "user" } // 调前置摄像头
// frameRate: { ideal: 10, max: 15 } //控制视频帧率
}
}
// 旧版本浏览器不支持navigator.mediaDevices,设置一个空的对象
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {};
}
// 部分浏览器部分支持 navigator.mediaDevices,在没有getUserMedia属性的时候添加它。
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function (constraints) {
// 首先,如果有getUserMedia的话,就获得它
var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;
// 部分浏览器不支持- 返回一个error到promise的reject来保持一个统一的接口
if (!getUserMedia) {
this.mediaList=true;
$.showConfirm(
'该浏览器不支持,请使用其他浏览器',
"",
"好的",
"",
() => {
// router.replace({ name: 'home' });
},false);
return Promise.reject(new Error('getUserMedia is not implemented in this browser'));
}
// 否则,为老的navigator.getUserMedia方法包裹一个Promise
return new Promise(function (resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject);
})
}
}
// this.getSystem();
this.mediaList = false;
let times=null;
const delay= (time = 0) => new Promise((res) => { setTimeout(res, time)});
const tapStream = await navigator.mediaDevices.getUserMedia(constraints);
let MediaStreamTracks = typeof tapStream.stop === 'function' ? tapStream : tapStream.getVideoTracks()[0];
if(this.isWeChart() && /(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)){
//ios微信端第一次getUserMedia的stream不能播放
await delay(1000); // 第一次需延迟关闭摄像头
MediaStreamTracks && MediaStreamTracks.stop();
await delay(100);
}
navigator.mediaDevices.getUserMedia(constraints)
.then(async (stream) => {
this.MediaStreamTrack = typeof stream.stop === 'function' ? stream : stream.getVideoTracks()[0];
// 显示录制框
// this.mediaList = false;
this.showVideo = true;
this.isAlreadyRecord = false;
let isUrl = window.URL|| window.webkitURL|| window.mozURL|| window.msURL;
if ('srcObject' in this.$refs.videoRef) {
this.$refs.videoRef.srcObject = stream;
} else {
this.$refs.videoRef.src = isUrl.createObjectURL(stream);
}
if(this.isWeChart() && /(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)){
this.$refs.videoRef.play();
}
//录像容器
this.$refs.videoRef.onloadedmetadata = e => {
// 播放视频
this.$refs.videoRef.play();
}
let options = {
videoBitsPerSecond: 2500000,
// mimeType:'video/webm;codecs=h264'
}
this.mediaRecorder = new MediaRecorder(stream, options);
clearInterval(times);
this.counts=3;
times=setInterval(()=>{
this.counts--;
if(this.counts==1){
clearInterval(times);
this.saveRecord();
}
},1000);
})
.catch((err) => {
this.goStart();
if(err.message == 'Permission denied'){
$.showConfirm(
'摄像头开启失败,请检查摄像头是否授权或是否可用!',
"",
"好的",
"",
() => {
// router.replace({ name: 'home' });
},false);
}else{
$.showConfirm(
'摄像头开启失败,请使用其他浏览器!',
"",
"好的",
"",
() => {
// router.replace({ name: 'home' });
},false);
}
})
},
// 录制倒计时
recordcountDown() {
let timess=null,sjTime=null;
//三秒后自动结束
clearInterval(timess);
clearInterval(sjTime);
sjTime=setInterval(()=>{
this.getsjColor();
},300)
timess=setInterval(()=>{
this.count--;
if(this.count<1){
clearInterval(timess);
clearInterval(sjTime);
this.randomColor='#fff';
this.saveRecord();
}
},1000)
},
// 保存录制视频
saveRecord() {
if (this.isAlreadyRecord) {
this.recordedBlobs=[];
clearTimeout(this.countTimer);
// this.showVideo=false;
this.isUpload=true;
//当录制的数据可用时
this.mediaRecorder.ondataavailable = (e) => {
console.log(e.data)
if (e.data && e.data.size > 0) {
this.recordedBlobs.push(e.data);
}
}
this.mediaRecorder.stop();
setTimeout(() => {
var blob = new Blob(this.recordedBlobs, {type: 'video/mp4'});
//blob转file
var file = new File([blob], Date.now(), {type: 'video/mp4', lastModified: Date.now()});
this.isAlreadyRecord = false;
this.MediaStreamTrack && this.MediaStreamTrack.stop();
var reader = new FileReader();
reader.readAsDataURL(blob, 'utf-8');
reader.onload = () => {
// console.log(reader.result); // base64格式
setTimeout(()=>{
this.faceResult=true;
},2000)
//录制并上传后端
this.$refs.videob.src = reader.result;
}
}, 1000);
} else {
this.count = 3;
this.isAlreadyRecord = true;
this.mediaRecorder.start(3000);
this.recordcountDown();
}
},
//重新录制
again(){
this.MediaStreamTrack && this.MediaStreamTrack.stop();
this.countTimer && clearTimeout(this.countTimer);
this.mediaList=true;
this.faceResult=false;
this.showVideo=false;
this.isUpload=false;
},
isWeChart(){
var userAgent = navigator.userAgent.toLowerCase();
let isW=false;
if(userAgent.match(/MicroMessenger/i) == 'micromessenger' || userAgent.match(/_SQ_/i) == '_sq_'){
isW= true;
}else{
isW= false;
}
return isW;
}
}