【前端vue——系列1】vue的路由
【前端vue——系列2】vue中的data是函数而不是对象与computed的实现原理
【前端vue——系列3】vue框架的优缺点;vue实现双向绑定
【前端vue——系列4】vuex和angular
【前端vue——系列5】生命周期详讲(vue的生命周期、页面的生命周期)
【前端vue——系列6】vue连接摄像头并实现摄像头暂停,计时,截图到本地等功能
前不久做了一个qt的展示摄象头拍摄的视频的,然后管理系统是用vue做的,最后集成的话可能会有些麻烦,所以我就想能不能用vue实现摄像头的视频展示等功能,下面为我测试成功了的示例:
提示:以下是本篇文章正文内容,下面案例可供参考
getUserMedia API
为用户提供访问硬件设备媒体(摄像头、视频、音频、地理位置等)的接口,基于该接口,开发者可以在不依赖任何浏览器插件的条件下访问硬件媒体设备。getUserMedia API
最初是navigator.getUserMedia
,目前已被最新Web标准废除,变更为navigator.mediaDevices.getUserMedia()
系统通过控制
thisvideo
的状态控制摄像头的(暂停、开始播放、结束)等操作,flag
参数是在后续的过程中实现点击暂停,再点击又开始播放的判断标志位。
data () {
return {
videoWidth: 500,
videoHeight: 300,
number:0,
hours: 0,
minutes: 0,
seconds: 0,
run:false,
imgSrc: '',
flag:true,
thisCancas: null,
thisContext: null,
thisVideo: null,
userInfo: {
imgStr:""
},
videoState: true
}
},
getUserMedia
,并且保持接口一致navigator.mediaDevices.enumerateDevices()
获取本地音频视频输入输出设备,找到要使用的设备id(这个设备id即为要展示的摄像头的标识id)deviceId
填入video的deviceId
中,就可以选择要调用的摄像头了 getCompetence () {
this.videoState = false
var _this = this
this.thisCancas = document.getElementById('canvasCamera')
this.thisContext = this.thisCancas.getContext('2d')
this.thisVideo = document.getElementById('videoCamera')
// 旧版本浏览器可能根本不支持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
// 有些浏览器不支持,会返回错误信息
// 保持接口一致
console.log('viedo',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)
})
}
}
//使用此方式获取本地音频视频输入输出设备,找到要使用的设备id,方式见下图
var enumeratorPromise = navigator.mediaDevices.enumerateDevices()
console.log(enumeratorPromise)
//把上面获取到的设备deviceId填入下面video的deviceId中,就可以选择要调用的摄像头了
var constraints = { audio: false, video: { deviceId: 'becf7e45fe56e42bcb4ec3f78b1b6b0fcffd6c6ccd890d30fffc2430a92c99bb', width: this.videoWidth, height: this.videoHeight } }
navigator.mediaDevices.getUserMedia(constraints).then(function (stream) {
// 旧的浏览器可能没有srcObject
if ('srcObject' in _this.thisVideo) {
_this.thisVideo.srcObject = stream
} else {
// 避免在新的浏览器中使用它,因为它正在被弃用。
_this.thisVideo.src = window.URL.createObjectURL(stream)
}
_this.thisVideo.onloadedmetadata = function (e) {
if (_this.flag==true){
_this.thisVideo.play();
_this.flag=false;
}
else {
_this.thisVideo.pause()
_this.flag=true;
}
}
}).catch(err => {
console.log(err)
})
}
关闭摄像头就比较简单了,直接设置一个stop就可以实现
stopNavigator () {
this.videoState = true
this.thisVideo.srcObject.getTracks()[0].stop()
}
canvas
绘图的方式,将采集到的数据帧进行绘图展示。_this.imgSrc
解码得到base64
的格式的图片。clearImgSrc
是再图片进行展示后再次绘图时将上一次的图片清除掉setImage () {
var _this = this
_this.imgSrc='';
// 点击,canvas画图
_this.thisContext.drawImage(_this.thisVideo, 0, 0, _this.videoWidth, _this.videoHeight)
// 获取图片base64链接
_this.imgSrc = this.thisCancas.toDataURL('image/png')//_this.imgSrc为解码得到的base64编码格式的图片
console.log('picture',_this.imgSrc)
// this.$emit('setImgSrc', _this.imgSrc)
console.log('转换',this.dataURLtoFile(_this.imgSrc, 'file'))
},
clearImgSrc () {
this.imgSrc = ''
},
<div>
{{imgSrc}}
<img :src="'data:image/jpeg;base64' + imgSrc" alt="" class="img1">
</div>
<img src="./image/1.jpg"/>
<template>
<img :src="imgUrl">
</template>
<script>
export default {
data() {
return {
imgUrl:require('./image/1.jpg')
}
}
}
</script>
<template>
<img :src="imgUrl">
</template>
<script>
import img from './image/1.jpg'
export default {
data() {
return {
imgUrl:img
}
}
}
</script>
href
是取的this.imgSrc
,即为展示的图片的索引 downs() {
//必须同源才能下载
var alink = document.createElement("a");
alink.href = this.imgSrc;
alink.download = ""; //图片名
alink.click();
},
这其实就是一个很容易的计时器的功能,只需要将计时器的启动函数放入摄像头的启动事件中,将计时器的暂停函数放入摄像头的暂停事件中即可
methods: {
num (n) {
return n < 10 ? '0' + n : '' + n
},
cutTimeDown () {
var that = this
var timer = window.setInterval(function () {
if (that.run){
if (that.seconds === 59 ){
that.minutes += 1
that.seconds = 0
}
if (that.minutes === 59 ) {
that.hours += 1
that.minutes = 0
}
// window.clearInterval(timer)
else {
that.seconds += 1
}
}
}, 1000)
},
start(){
this.run=true;
},
stop(){
this.run=false;
},
},
watch: {
second: {
handler (newVal) {
this.num(newVal)
}
},
minute: {
handler (newVal) {
this.num(newVal)
}
},
hour: {
handler (newVal) {
this.num(newVal)
}
}
},
computed: {
second: function () {
return this.num(this.seconds)
},
minute: function () {
return this.num(this.minutes)
},
hour: function () {
return this.num(this.hours)
}
},
mounted () {
this.cutTimeDown()
}
不多说直接放代码:
base64转文件
dataURLtoFile (urlData, fileName) {
let arr = urlData.split(',');
let mime = arr[0].match(/:(.*?);/)[1];
let bytes = atob(arr[1]); // 解码base64
let n = bytes.length
let ia = new Uint8Array(n);
while (n--) {
ia[n] = bytes.charCodeAt(n);
}
console.log('转换成功');
return new File([ia], fileName, { type: mime });
},
前面几个功能完成后本以为就已经万事大吉,没想到这个时候导师又来了一个需求,就是需要在能够看到视频的同时能够控制摄像头转动。
directionControl(num) {
this.$http({
url:'https://open.ys7.com/api/lapp/token/get',
method: 'post',
params: {appKey: 'c11a991793ef6eebe7279fea9c98a55718fdbc88227a65736f3af85de40e7708', appSecret:'c11a991793ef6eebe7279fea9c98a55718fdbc88227a65736f3af85de40e7708'}, //传入摄像头的appkey和appsecrect
timeout:2000
}).then(res=>{
// this.accessToken = res.accessToken;
console.log('666',res);
this.$http({
url:'https://open.ys7.com/api/lapp/device/ptz/start',
method: 'post',
params: {
accessToken: this.accessToken, //accesstoken码,一般一周过期
speed:2, //旋转速度
direction:num, //方向,传入数字,对应数字在api文档有
channelNo:1, // 通道号
deviceSerial:'12132123' //序列号
},
timeout: 2000
}).then(res=>{
// console.log(res.data)
if(res.data.code == '60000' ){
this.$message(res.data.msg)
}
})
})
},
stopTurn(){
this.$http({
url:'https://open.ys7.com/api/lapp/device/ptz/stop',
method: 'post',
params: {
accessToken: this.accessToken,
// direction:num,
channelNo:1, // 通道号
deviceSerial:'c11a991793ef6eebe7279fea9c98a55718fdbc88227a65736f3af85de40e7708' //序列号
},
timeout: 2000
}).then(res=> {
console.log('5555555',res.data);
if(res.data.code == '60000' ){
this.$message(res.data.msg)
}
})
},
这里另外下了个插件axios的,过程如下:
cnpm install vue-axios --save
然后再到main.js中:
import axios from 'axios'
Vue.prototype.$http = axios
忽略我的手指头,点击打开摄像头,既可以调用笔记本自带摄像头进行取景拍摄。
同时计时也会开始启动
在暂停摄像头的同时,计时也会开始暂停
码字不易~, 各位看官要是看爽了,可不可以三连走一波,点赞皆有好运!,不点赞也有哈哈哈~~~