系列文章总结

【前端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实现摄像头的视频展示等功能,下面为我测试成功了的示例:

提示:以下是本篇文章正文内容,下面案例可供参考


一、vue用到的api介绍

  • 本系统主要采用的是getUserMedia API为用户提供访问硬件设备媒体(摄像头、视频、音频、地理位置等)的接口,基于该接口,开发者可以在不依赖任何浏览器插件的条件下访问硬件媒体设备。
  • getUserMedia API最初是navigator.getUserMedia,目前已被最新Web标准废除,变更为navigator.mediaDevices.getUserMedia()

二、vue实现各部分功能

2.1 vue进行参数配置

系统通过控制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
      }
    },

2.2 vue调用摄像头

  1. 首先获取现存的getUserMedia,并且保持接口一致
  2. 然后再使用navigator.mediaDevices.enumerateDevices()获取本地音频视频输入输出设备,找到要使用的设备id(这个设备id即为要展示的摄像头的标识id)
  3. 然后再通过获取到的设备deviceId填入video的deviceId中,就可以选择要调用的摄像头了
  4. 再通过两个if语句实现按钮的暂停播放切换
 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)
        })
      }

2.3 vue关闭摄像头

关闭摄像头就比较简单了,直接设置一个stop就可以实现

stopNavigator () {
        this.videoState = true
        this.thisVideo.srcObject.getTracks()[0].stop()
      }

2.4 截图拍照功能

  1. 该系统中是通过采用canvas绘图的方式,将采集到的数据帧进行绘图展示。
  2. 随后再将绘制的_this.imgSrc解码得到base64的格式的图片。
  3. 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 = ''
      },
  1. 将图片以base64的格式展示出来如下所示:
	<div>
      {{imgSrc}}
      <img :src="'data:image/jpeg;base64' + imgSrc" alt="" class="img1">
    </div>

2.5 vue中展示本地图片的三种方式

2.5.1 直接引入法

<img src="./image/1.jpg"/>

2.5.2 在data中使用require

<template>
  <img :src="imgUrl">
</template>
<script>
export default {
  data() {
    return {
      imgUrl:require('./image/1.jpg')
    }
  }
}  
</script>

2.5.3 在data里使用import导入

<template>
  <img :src="imgUrl">
</template>
<script>
import img from './image/1.jpg'
export default {
  data() {
    return {
      imgUrl:img
    }
  }
}  
</script>

2.6 将图片下载至本地功能

  1. 必须同源才能下载。
  2. 需要在2.4中对图片进行截图后才能进行保存到本地操作,因为这里的href是取的this.imgSrc,即为展示的图片的索引
 downs() {
        //必须同源才能下载
        var alink = document.createElement("a");
        alink.href = this.imgSrc;
        alink.download = ""; //图片名
        alink.click();
      },

2.7 摄像头开始工作后开始计时,暂停时停止计时

这其实就是一个很容易的计时器的功能,只需要将计时器的启动函数放入摄像头的启动事件中,将计时器的暂停函数放入摄像头的暂停事件中即可


    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()
    }
  

2.8 将base64转换为file格式

不多说直接放代码:


      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 });

      },

2.9 使用vue能够控制摄像头转动等

前面几个功能完成后本以为就已经万事大吉,没想到这个时候导师又来了一个需求,就是需要在能够看到视频的同时能够控制摄像头转动。

这个功能是在使用了萤石云的api的情况下实现摄像头的转动。
在这里插入图片描述

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


三、功能截图展示

3.1 打开摄像头

忽略我的手指头,点击打开摄像头,既可以调用笔记本自带摄像头进行取景拍摄。

在这里插入图片描述

同时计时也会开始启动

在这里插入图片描述


3.2 暂停摄像头

在暂停摄像头的同时,计时也会开始暂停

在这里插入图片描述

同时计时也会开始暂停
在这里插入图片描述


3.3 截图并且保存到本地

  1. 点击拍照识别后,截图会保存到下面的展示中。
  2. 然后再点击下载即可以完成图片到本地的保存。

在这里插入图片描述


码字不易~, 各位看官要是看爽了,可不可以三连走一波,点赞皆有好运!,不点赞也有哈哈哈~~~

Logo

前往低代码交流专区

更多推荐