web调用PC摄像头进行视频录制
在项目中 我们很多时候都会遇到使用浏览器调用电脑设备的需求,记录一下实现思路及方法,共享一下技术点,同时也方便日后查看和整理
web浏览器在设计的时候为我们提供了很多的API接口实现功能,我们这次使用web调用PC摄像头和录音设备,主要思路是:获取到设备的媒体流,再将媒体流进行转存。
首先看一下目录结构
在components目录下定义一个提供视频录制功能的子组件,在Page目录下创建一个调用子组件的页面父组件。
接下来介绍一下子组件的功能方法:
调用摄像头
先定义一个模板
<template> <div class="camera_outer"> <video id="videoCamera" :width="videoWidth" :height="videoHeight" autoplay ></video> <!-- 放置图片 --> <canvas style="display: none" id="canvasCamera" :width="videoWidth" :height="videoHeight" ></canvas> <!-- 放置视频 --> <canvas style="display: none" id="canvasCameraTwo" :width="videoWidth" :height="videoHeight" ></canvas> <!-- <img src="/assets/logo.png" alt="" class="bg_r_img"> --> <div v-if="imgSrc" class="img_bg_camera" v-show="isShow"> <img :src="imgSrc" alt="" class="tx_img" /> </div> </div> </template>
<script> export default { data() { return { videoWidth: 540, videoHeight: 410, imgSrc: "", thisCancas: null, thisContext: null, thisVideo: null, thisCancasTwo: null, thisContextTwo: null, timer: null, isShow: true, mediaRecorder: null, recordedBlobs: [], }; }, computed: {}, methods: { /* *@author *@function 绘制图片 */ setImage() { var _this = this; if (!_this.thisVideo) { alert("请先开启摄像头"); return; } _this.isShow = true; //点击,canvas画图 _this.thisContext.drawImage( _this.thisVideo, 0, 0, _this.videoWidth, _this.videoHeight ); // 获取图片base64链接 var image = this.thisCancas.toDataURL("image/png"); //打印一下图片的base64码 console.log("图片base64码:" + image); _this.imgSrc = image; this.$emit("refreshDataList", this.imgSrc); //将base64值传到后台 }, //加载本地摄像头 changePhoto(){ var that =this; /*得到所有的摄像头 */ navigator.mediaDevices.enumerateDevices() .then(function(devices){ console.log(devices); that.videoArr= []; devices.forEach((device) => { if (device.kind=='videoinput') { that.videoArr.push({ 'label':device.label, 'id':device.deviceId }) console.log('label:'+device.label+', id:'+device.deviceId); } }); that.$emit('videoArr',that.videoArr); }) .catch(function(err){ console.log('ERROR:'+err.name+':'+err.message) }) }, //切换下拉 changeSel(val){ const videoConstraints={}; if (val === '') { videoConstraints.facingMode = 'environment'; }else{ videoConstraints.deviceId = { exact: val }; } var constraints ={ video: videoConstraints, }; //调用选中的摄像头 this.getOneUserMedia(constraints); }, //调用单个摄像头 getOneUserMedia(constrains){ var that =this; if (navigator.mediaDevices.getUserMedia) { navigator.mediaDevices.getUserMedia(constrains).then(success=>{ //开启摄像头 that.thisVideo.srcObject=success; that.thisVideo.play(); }) } }, //开启一个摄像头 getOneCompetence() { var _this = this; this.thisCancas = document.getElementById("canvasCamera"); this.thisContext = this.thisCancas.getContext("2d"); this.thisVideo = document.getElementById("videoCamera"); //设置视频放置数据 this.thisCancasTwo = document.getElementById("canvasCameraTwo"); this.thisContextTwo = this.thisCancasTwo.getContext("2d"); // 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象 if (navigator.mediaDevices === undefined) { navigator.mediaDevices = {}; } // 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象 // 使用getUserMedia,因为它会覆盖现有的属性 // 这里,如果缺少getUserMedia属性,就添加它 if (navigator.mediaDevices.getUserMedia == undefined) { navigator.mediaDevices.getUserMedia = function (constraints) { // 首先获取现存的getUserMedia(如果存在) var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.getUserMedia; // 有些浏览器不支持,会返回错误信息 // 保持接口一致 if (!getUserMedia) { return Promise.reject( new Error("getUserMedia is not implemented in this browser") ); } //否则,使用promise将调用包装到旧的navigator.getUserMedia return new Promise(function (resolve, reject) { getUserMedia.call(navigator, constraints, resolve, reject); }); }; } //设置摄像头和麦克风是否启用 var constraints = { audio: true, video: { width: this.videoWidth, height: this.videoHeight, transform: "scaleX(-1)", frameRate: 60, }, }; navigator.mediaDevices .getUserMedia(constraints) .then(function (stream) { window.stream = stream; //旧的浏览器可能没有srcObject if ("srcObject" in _this.thisVideo) { _this.thisVideo.srcObject = stream; } else { // 避免在新的浏览器中使用它,因为它正在被弃用。 _this.thisVideo.src = window.URL.createObjectURL(stream); } //在视频的原数据加载后执行的方法 _this.thisVideo.onloadedmetadata = function (e) { _this.thisVideo.play(); }; }) .catch((err) => { console.log(err); }); }, /* *@author *@function 绘制视频 */ drawVideoAtCanvas() { var that=this; that.recordedBlobs = []; var options = { audioBitsPerSecond : 128000,videoBitsPerSecond : 100000,mimeType: 'video/webm;codecs=opus,vp8' }; try { that.mediaRecorder = new MediaRecorder(window.stream, options); } catch (e) { return; } that.mediaRecorder.blobs = []; that.mediaRecorder.ondataavailable = function (e) { var blob = new Blob([e.data], { type: "video/mp4" }); const blobUrl = window.URL.createObjectURL(blob); const a = document.createElement("a"); a.style.display = "none"; a.download = "vvvvvv"; a.href = blobUrl; a.click(); }; that.mediaRecorder.start(); }, //停止录制 stopDrawVideoAtCanvas() { this.mediaRecorder.stop(); }, //关闭摄像头 stopNavigator() { if (this.timer) { alert("请先停止录制~"); return; } let tracks= this.thisVideo.srcObject.getTracks(); tracks.forEach(track=>{ track.stop(); }) this.isShow = false; this.thisVideo = null; }, }, mounted() { // this.getCompetence(); }, beforeDestroy() { if (this.timer) { clearInterval(this.timer); this.timer = null; } this.stopNavigator(); }, }; </script>
我们通过MediaDevices接口访问连接媒体输入的设备。方法:
getOneCompetence()
通过getUserMedia()方法提示用户给我们摄像机的权限
我们通过MediaDevices接口访问连接媒体输入的设备