Vue调用摄像头录制视频和音频并上传给后端或下载到本地

下载插件

npm install --save webm-duration-fix

代码及作用

调用摄像头


callCamera () {
        let _this = this;
        MediaUtils.getUserMedia(true, true, function (err, stream) {
          if (err) {
            throw err;
          } else {
            // 通过 MediaRecorder 记录获取到的媒体流
            const mimeType = 'video/webm;codecs=vp8,opus';
            mediaRecorder = new MediaRecorder(stream, {
              // mimeType: "video/webm;codecs=vp9",
              mimeType: mimeType,
            });
            mediaStream = stream;
            var chunks = []
            var video = _this.$refs.videos;
            video["srcObject"] = stream;
            video.play();// 播放实时画面
            mediaRecorder.ondataavailable = function (e) {
              mediaRecorder.blobs.push(e.data);
              chunks.push(e.data);
            };
            mediaRecorder.blobs = [];

            mediaRecorder.onstop = async () => {
              recorderFile = await fixWebmDuration(new Blob(chunks, { type: mimeType }));
              console.log(recorderFile);
              var url = URL.createObjectURL(recorderFile)
              var videosreplay = _this.$refs.videosreplay;
              videosreplay.setAttribute("src", url);
              console.log('url', url)
              chunks = [];
              if (null != stopRecordCallback) {
                stopRecordCallback();
              }
            };
            _this.record()
          }
        });
      },

开始结束录制

record () {
        if (this.recordtype == "ING") {
          this.stopRecord(() => {
            console.log("结束录制");
            this.toggleReplayVideo()
          });
        }
        else if (this.recordtype == "BEGIN") {
          console.log("开始录制");
          this.startAudio();
          mediaRecorder.start();
          startTime = Date.now();
          this.recordtype = "ING";
        }
      },

对录像时长进行记录


      startAudio () {
        this.timer = setInterval(() => {
          this.recordtime += 1000;
          if (this.recordtime == 1000000) {
            this.stopRecord();
          }
          this.second++;
          if (this.second >= 60) {
            this.second = 0;
            this.minute = this.minute + 1;
          }

          if (this.minute >= 60) {
            this.minute = 0;
            this.hour = this.hour + 1;
          }
          console.log(this.recordtime)
        }, 1000);
      },

停止录像时终止录制器,关闭媒体流并清除时长记录定时器

      stopRecord (callback) {
        this.recordtype = "END";
        this.showReplay = true;
        stopRecordCallback = callback;
        clearInterval(this.timer);
        // 终止录制器
        mediaRecorder.stop();
        // 关闭媒体流
        MediaUtils.closeStream(mediaStream);
        var videosreplay = this.$refs.videosreplay;
        videosreplay.onended = () => {
          this.playtime = 0;
          this.replayVideo = false;
          clearInterval(this.playtimer);
        };
        videosreplay.onclick = () => {
          this.showReplay = !this.showReplay;
        };
      },

回放

      toggleReplayVideo () {
        console.log('播放中...')
        this.replayVideo = !this.replayVideo;
        this.showReplay = false;
        var videosreplay = this.$refs.videosreplay;
        if (this.replayVideo) {
          videosreplay.play().catch(err => {
            this.$message.error(err.message);
            console.log(err);
          });
          this.playtimer = setInterval(() => {
            this.playtime += 1000;
          }, 1000);
        } else {
          videosreplay.pause();
          clearInterval(this.playtimer);
        }
      },

下载视频

指定且只能指定,下载后的默认文件名字和文件后缀。注意,可以不指定后缀名,浏览器会根据数据类型自动为其匹配后缀名,但是最好指定后缀。

<a href="base64..." download="after">SAVE</a>

下载后的文件名为after.jpg
download属性不能指定下载路径;
当 download 属性值为空时,下载的文件的名字和扩展名与源文件一致;当href为base64编码的图像数据时,则下载后文件名也是那么离谱得长。

<a href="base64..." download>SAVE</a>

下载后的文件名为data_image_jpeg;base64,… .jpg

      download () {
        var url = URL.createObjectURL(recorderFile)
        console.log("URLLLLLL", url)
        const a = document.createElement("a");
        document.body.appendChild(a);
        a.style.display = "none";
        a.href = url;
        if (this.fileName) {
          a.download = this.fileName + ".mp4";
        } else {
          a.download = new Date() + ".mp4";
        }
        a.click();
        window.URL.revokeObjectURL(url);
      },

下载或上传给后端

      submit () {
        let that = this;
        console.log(recorderFile)
        // 下载
        this.download()
        let file = new File(
          [recorderFile],
          "msr-" + new Date().toISOString().replace(/:|\./g, "-") + ".mp4",
          {
            type: "video/mp4",
          }
        );
        let config = {
          headers: { "Content-Type": "multipart/form-data" }
        }
        console.log('file', file)
        const formdata = new FormData()
        formdata.append("file", file);
        // 传给后端
        // axios.post('/video', formdata, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } },) //请求头要为表单
        //   .then(response => {
        //     console.log('video', response.data);
        //     this.yy_score = parseInt(response.data.data + 0.5)
        //     that.progress = response.data.data * 1.0 / 23 * 100
        //   })
        //   .catch(function (error) {
        //     that.$message({
        //       message: error,
        //       type: 'error'
        //     });
        //     console.log(error);
        //   })
      },
var MediaUtils = {
    /**
     * 获取用户媒体设备(处理兼容的问题)
     * @param videoEnable {boolean} - 是否启用摄像头
     * @param audioEnable {boolean} - 是否启用麦克风
     * @param callback {Function} - 处理回调
     */
    getUserMedia: function (videoEnable, audioEnable, callback) {
      navigator.getUserMedia =
        navigator.getUserMedia ||
        navigator.webkitGetUserMedia ||
        navigator.mozGetUserMedia ||
        navigator.msGetUserMedia ||
        window.getUserMedia;
      var constraints = { video: videoEnable, audio: audioEnable };
      if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
        navigator.mediaDevices
          .getUserMedia(constraints)
          .then(function (stream) {
            callback(false, stream);
          })
        ["catch"](function (err) {
          callback(err);
        });
      } else if (navigator.getUserMedia) {
        navigator.getUserMedia(
          constraints,
          function (stream) {
            callback(false, stream);
          },
          function (err) {
            callback(err);
          }
        );
      } else {
        callback(new Error("Not support userMedia"));
      }
    },

    /**
     * 关闭媒体流
     * @param stream {MediaStream} - 需要关闭的流
     */
    closeStream: function (stream) {
      if (typeof stream.stop === "function") {
        stream.stop();
      } else {
        let trackList = [stream.getAudioTracks(), stream.getVideoTracks()];

        for (let i = 0; i < trackList.length; i++) {
          let tracks = trackList[i];
          if (tracks && tracks.length > 0) {
            for (let j = 0; j < tracks.length; j++) {
              let track = tracks[j];
              if (typeof track.stop === "function") {
                track.stop();
              }
            }
          }
        }
      }
    },
  };
  var startTime, mediaRecorder, mediaStream, stopRecordCallback, recorderFile;

页面完整代码

<template>
  <div>
    <video id="video" autoplay ref="videos" style="width: 400px;height: 400px;" muted></video>
    <video style="width: 400px;height: 400px;" id="videosreplay" src="" ref="videosreplay"></video>
    <button @click="callCamera()">开始录制</button>
    <button @click="record()">结束录制</button>
    <button @click="submit()">下载或上传</button>
  </div>
</template>
<script>
  import axios from 'axios'
  import fixWebmDuration from 'webm-duration-fix'

  export default {
    name: "Test",
    data () {
      return {
        progress: 0,
        replayVideo: false,
        recordtype: "BEGIN",
        showReplay: true,
        timer: 0,
        recordtime: 0,
        second: 0,
        minute: 0,
        hour: 0,
        playtime: 0,
        playtimer: 0,
        yy_score: 0,
        cnt_sum: 0,
        ansMaxTime: 0,
        ansBeginTime: 0,
        ansMaxBeginTime: 0,

      }
    },
    methods: {
      // 调用摄像头
      callCamera () {
        let _this = this;
        MediaUtils.getUserMedia(true, true, function (err, stream) {
          if (err) {
            throw err;
          } else {
            // 通过 MediaRecorder 记录获取到的媒体流
            const mimeType = 'video/webm;codecs=vp8,opus';
            mediaRecorder = new MediaRecorder(stream, {
              // mimeType: "video/webm;codecs=vp9",
              mimeType: mimeType,
            });
            mediaStream = stream;
            var chunks = []
            var video = _this.$refs.videos;
            video["srcObject"] = stream;
            video.play();// 播放实时画面
            mediaRecorder.ondataavailable = function (e) {
              mediaRecorder.blobs.push(e.data);
              chunks.push(e.data);
            };
            mediaRecorder.blobs = [];

            mediaRecorder.onstop = async () => {
              recorderFile = await fixWebmDuration(new Blob(chunks, { type: mimeType }));
              console.log(recorderFile);
              var url = URL.createObjectURL(recorderFile)
              var videosreplay = _this.$refs.videosreplay;
              videosreplay.setAttribute("src", url);
              console.log('url', url)
              chunks = [];
              if (null != stopRecordCallback) {
                stopRecordCallback();
              }
            };
            _this.record()
          }
        });
      },
      record () {
        if (this.recordtype == "ING") {
          this.stopRecord(() => {
            console.log("结束录制");
            this.toggleReplayVideo()
          });
        }
        else if (this.recordtype == "BEGIN") {
          console.log("开始录制");
          this.startAudio();
          mediaRecorder.start();
          startTime = Date.now();
          this.recordtype = "ING";
        }
      },

      // 对录像时长进行记录
      startAudio () {
        this.timer = setInterval(() => {
          this.recordtime += 1000;
          if (this.recordtime == 1000000) {
            this.stopRecord();
          }
          this.second++;
          if (this.second >= 60) {
            this.second = 0;
            this.minute = this.minute + 1;
          }

          if (this.minute >= 60) {
            this.minute = 0;
            this.hour = this.hour + 1;
          }
          console.log(this.recordtime)
        }, 1000);
      },

      // 停止录像时终止录制器,关闭媒体流并清除时长记录定时器
      stopRecord (callback) {
        this.recordtype = "END";
        this.showReplay = true;
        stopRecordCallback = callback;
        clearInterval(this.timer);
        // 终止录制器
        mediaRecorder.stop();
        // 关闭媒体流
        MediaUtils.closeStream(mediaStream);
        var videosreplay = this.$refs.videosreplay;
        videosreplay.onended = () => {
          this.playtime = 0;
          this.replayVideo = false;
          clearInterval(this.playtimer);
        };
        videosreplay.onclick = () => {
          this.showReplay = !this.showReplay;
        };
      },
      // 回放
      toggleReplayVideo () {
        console.log('播放中...')
        this.replayVideo = !this.replayVideo;
        this.showReplay = false;
        var videosreplay = this.$refs.videosreplay;
        if (this.replayVideo) {
          videosreplay.play().catch(err => {
            this.$message.error(err.message);
            console.log(err);
          });
          this.playtimer = setInterval(() => {
            this.playtime += 1000;
          }, 1000);
        } else {
          videosreplay.pause();
          clearInterval(this.playtimer);
        }
      },
      // 下载视频
      download () {
        var url = URL.createObjectURL(recorderFile)
        console.log("URLLLLLL", url)
        const a = document.createElement("a");
        document.body.appendChild(a);
        a.style.display = "none";
        a.href = url;
        if (this.fileName) {
          a.download = this.fileName + ".mp4";
        } else {
          a.download = new Date() + ".mp4";
        }
        a.click();
        window.URL.revokeObjectURL(url);
      },
      // 下载或上传
      submit () {
        let that = this;
        console.log(recorderFile)
        // 下载
        this.download()
        let file = new File(
          [recorderFile],
          "msr-" + new Date().toISOString().replace(/:|\./g, "-") + ".mp4",
          {
            type: "video/mp4",
          }
        );
        let config = {
          headers: { "Content-Type": "multipart/form-data" }
        }
        console.log('file', file)
        const formdata = new FormData()
        formdata.append("file", file);
        // 传给后端
        // axios.post('/video', formdata, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } },) //请求头要为表单
        //   .then(response => {
        //     console.log('video', response.data);
        //     this.yy_score = parseInt(response.data.data + 0.5)
        //     that.progress = response.data.data * 1.0 / 23 * 100
        //   })
        //   .catch(function (error) {
        //     that.$message({
        //       message: error,
        //       type: 'error'
        //     });
        //     console.log(error);
        //   })
      },
    }
  }
  var MediaUtils = {
    /**
     * 获取用户媒体设备(处理兼容的问题)
     * @param videoEnable {boolean} - 是否启用摄像头
     * @param audioEnable {boolean} - 是否启用麦克风
     * @param callback {Function} - 处理回调
     */
    getUserMedia: function (videoEnable, audioEnable, callback) {
      navigator.getUserMedia =
        navigator.getUserMedia ||
        navigator.webkitGetUserMedia ||
        navigator.mozGetUserMedia ||
        navigator.msGetUserMedia ||
        window.getUserMedia;
      var constraints = { video: videoEnable, audio: audioEnable };
      if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
        navigator.mediaDevices
          .getUserMedia(constraints)
          .then(function (stream) {
            callback(false, stream);
          })
        ["catch"](function (err) {
          callback(err);
        });
      } else if (navigator.getUserMedia) {
        navigator.getUserMedia(
          constraints,
          function (stream) {
            callback(false, stream);
          },
          function (err) {
            callback(err);
          }
        );
      } else {
        callback(new Error("Not support userMedia"));
      }
    },

    /**
     * 关闭媒体流
     * @param stream {MediaStream} - 需要关闭的流
     */
    closeStream: function (stream) {
      if (typeof stream.stop === "function") {
        stream.stop();
      } else {
        let trackList = [stream.getAudioTracks(), stream.getVideoTracks()];

        for (let i = 0; i < trackList.length; i++) {
          let tracks = trackList[i];
          if (tracks && tracks.length > 0) {
            for (let j = 0; j < tracks.length; j++) {
              let track = tracks[j];
              if (typeof track.stop === "function") {
                track.stop();
              }
            }
          }
        }
      }
    },
  };
  var startTime, mediaRecorder, mediaStream, stopRecordCallback, recorderFile;
</script>

结果

录制

在这里插入图片描述

播放

在这里插入图片描述

下载

在这里插入图片描述

项目代码

https://gitee.com/yuan-hongting/video

  • 7
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
系统功能1、管理员管理:根据不同角色设置不同的管理权限;2、小区管理,管理多个小区资料,新增、修改、删除、摄像头管理等功能;3、小区摄像头管理:摄像头的新增、修改及删除功能;4、居民管理:居民资料新增,修改,删除,Excel批量导入,导出,居民人脸采集;5、访客登记:访客的新增,修改,删除,进入登记,离开登记,查询等功能;6、人脸识别:居民出入小区人脸识别功能的实现,使用腾讯AI人脸识别技术实现;7、出入记录:居民出入小区的人脸识别记录查询;8、小区地图:所有小区在地图的分布情况,使用百度地图实现;9、使用Echarts技术实现小区人员分类统计(柱状)图表;10、菜单管理:新增、修改、删除菜单功能(包括目录,菜单,按钮)11、角色管理:新增、修改、删除角色(系统角色、普通角色)12、系统日志:记录了系统中所有操作的日志,方便发现问题,查找原因;运行环境:  1、JDK1.8及以上版本  2、Tomcat 8.5及以上版本  3、MySql 5.7及以上版本  4、Redis开发工具:  1、前端开发工具:Visual Studio Code  2、后端开发工具:Intellij IDEA使用技术:  1、Vue2.x+ElementUI(前端)  2、Springboot+MyBatisPlus+Redis+Shiro+Swagger(后端)  3、人脸识别技术(腾讯AI)  4、MySql数据库技术  5、Redis缓存技术  6、百度地图  7、Echarts图表技术  8、POI Excel导入导出技术  9、Shiro权限控制:菜单管理,角色管理,权限管理(按钮及用户级别权限)  10、 Swagger接口配置管理,接口文档管理技术  11、Token单点技术(一个用户不能同时在多个设备登录使用)  12、前后端分离跨域设置等技术
以下是使用Vue调用摄像头录制视频的示例代码: ```html <template> <div> <video ref="video" autoplay></video> <button @click="startRecording">开始录制</button> <button @click="stopRecording">停止录制</button> </div> </template> <script> export default { data() { return { mediaRecorder: null, chunks: [], }; }, mounted() { navigator.mediaDevices.getUserMedia({ video: true }) .then((stream) => { this.$refs.video.srcObject = stream; this.mediaRecorder = new MediaRecorder(stream); this.mediaRecorder.ondataavailable = (e) => { this.chunks.push(e.data); }; this.mediaRecorder.onstop = () => { const blob = new Blob(this.chunks, { type: 'video/webm' }); const videoUrl = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = videoUrl; a.download = 'recorded_video.webm'; a.click(); URL.revokeObjectURL(videoUrl); this.chunks = []; }; }) .catch((error) => { console.error('Error accessing camera:', error); }); }, methods: { startRecording() { this.mediaRecorder.start(); }, stopRecording() { this.mediaRecorder.stop(); }, }, }; </script> ``` 这段代码使用了Vue框架来调用摄像头录制视频。在模板中,我们使用`<video>`元素来显示摄像头视频流,并添加了两个按钮来控制录制的开始和停止。在脚本部分,我们使用`navigator.mediaDevices.getUserMedia()`方法来获取摄像头视频流,并将其赋值给`<video>`元素的`srcObject`属性。然后,我们创建了一个`MediaRecorder`对象来录制视频,并设置了`ondataavailable`事件来处理录制的数据块。当点击停止录制按钮时,我们将录制的数据块合并为一个`Blob`对象,并通过创建一个下载链接来保存录制视频文件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值