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接口访问连接媒体输入的设备

posted @ 2023-05-11 21:07  码不够的张小墨  阅读(416)  评论(0编辑  收藏  举报