Vue-13-人脸录像

157 阅读4分钟

一、概述

各个银行app都有人脸识别功能,就是一个圆形的录像界面。这一章节主要学习如何使用vedio标签,以及将录像形状调整为圆形。 实现效果如下:

image.png

二、知识点

2.1 vedio标签的使用

其核心代码如下,在开始录制视频的时候,通过MediaRecorder收集视频的字节,并在录制结束的时候转换为Blob对象,再通过FileReader转换为base64格式的数据。

startRecording() {
      console.log('开始录制视频');
      navigator.mediaDevices.getUserMedia({ video: true, audio: true })
        .then(stream => {
          this.video.srcObject = stream;
          this.video.play();
          this.mediaRecorder = new MediaRecorder(stream);
          this.recordedChunks = [];
          this.isRecording = true;
          this.mediaRecorder.ondataavailable = (event) => {
            if (event.data && event.data.size > 0) {
              this.recordedChunks.push(event.data);
            }
          };
          this.mediaRecorder.start(100); // 每 100 毫秒收集一次数据
        });
    }
    stopRecording() {
      // 在停止录制视频时,首先打印日志信息
      console.log('停止录制视频');
      // 检查是否存在mediaRecorder实例
      if (this.mediaRecorder) {
        // 停止录制
        this.mediaRecorder.stop();
        // 重置mediaRecorder实例
        this.mediaRecorder = null;
        this.isRecording = false;
        // 将录制的Chunk数据块组合成一个Blob对象
        const blob = new Blob(this.recordedChunks, { type: 'video/webm' });
        // 将Blob对象转换为Base64字符串
        const fileReader = new FileReader();
        fileReader.onload = (e) => {
          this.recordedBase64Data = e.target.result;
        };
        fileReader.readAsDataURL(blob);
        // 将Blob对象转换为URL,便于在网页中使用
        this.recordedBlobUrl = URL.createObjectURL(blob);
        // 重置录制的Chunk数据块数组
        this.recordedChunks = [];
      }
    }

2.2 vedio的样式

圆形的录制界面,是通过样式来调整的,如下:

/**
 * .video-container 类的样式定义
 * 该类用于创建一个相对定位的容器,容器为一个圆形,用于展示视频
 * 容器的宽高为200px,有圆角和隐藏溢出内容的属性,顶部有20px的外边距
 */
.video-container {
  position: relative;
  width: 200px;
  height: 200px;
  border-radius: 50%;
  overflow: hidden;
  margin-top: 20px;
}

/**
 * .video-container 类下的 video 元素的样式定义
 * 该类用于绝对定位容器中的视频元素,并且使视频元素的中心点与容器的中心点对齐
 * 视频元素的宽高设置为100%,确保视频能够填满容器,并且保持宽高比正确缩放
 */
.video-container video {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100%;
  height: 100%;
  object-fit: cover;
}

三、实现

完整实现如下:

<template>
  <div class="recording-container">
    <div class="video-container recording">
      <video ref="video" width="200" height="200" autoplay muted playsinline></video>
    </div>
    <button @click="startRecording" class="custom-camera-button">开始录像</button>
    <button @click="stopRecording" class="custom-camera-button">停止录像</button>
    <div v-if="recordedBlobUrl" class="video-container">
      <h2>已录制的视频</h2>
      <video :src="recordedBlobUrl" controls width="640" height="480"></video>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      video: null,
      mediaRecorder: null,
      recordedChunks: [],
      recordedBlobUrl: null,
      recordedBase64Data: null,
      isRecording: false
    };
  },
  methods: {
    /**
     * 开始录像
     * 
     * 此方法用于创建 MediaRecorder 对象并开始录制视频
     */
    startRecording() {
      console.log('开始录制视频');
      navigator.mediaDevices.getUserMedia({ video: true, audio: true })
        .then(stream => {
          this.video.srcObject = stream;
          this.video.play();
          this.mediaRecorder = new MediaRecorder(stream);
          this.recordedChunks = [];
          this.isRecording = true;
          this.mediaRecorder.ondataavailable = (event) => {
            if (event.data && event.data.size > 0) {
              this.recordedChunks.push(event.data);
            }
          };
          this.mediaRecorder.start(100); // 每 100 毫秒收集一次数据
        });
    },
    /**
     * 停止录像
     * 
     * 此方法用于停止录制视频并将录制的数据转换为 Blob URL
     */
    stopRecording() {
      // 在停止录制视频时,首先打印日志信息
      console.log('停止录制视频');
      // 检查是否存在mediaRecorder实例
      if (this.mediaRecorder) {
        // 停止录制
        this.mediaRecorder.stop();
        // 重置mediaRecorder实例
        this.mediaRecorder = null;
        this.isRecording = false;
        // 将录制的Chunk数据块组合成一个Blob对象
        const blob = new Blob(this.recordedChunks, { type: 'video/webm' });
        // 将Blob对象转换为Base64字符串
        const fileReader = new FileReader();
        fileReader.onload = (e) => {
          this.recordedBase64Data = e.target.result;
        };
        fileReader.readAsDataURL(blob);
        // 将Blob对象转换为URL,便于在网页中使用
        this.recordedBlobUrl = URL.createObjectURL(blob);
        // 重置录制的Chunk数据块数组
        this.recordedChunks = [];
      }
    }
  },
  mounted() {
    this.video = this.$refs.video;
  }
};
</script>

<style scoped>
#app {
  font-family: 'Avenir', Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-align: center;
  color: #2c3e50;
  margin-top: 60px;
}

/* 自定义相机控制按钮 */
.custom-camera-button {
  background-color: #1890ff;
  /* 蓝色背景 */
  color: white;
  /* 白色文字 */
  border: none;
  padding: 10px 20px;
  cursor: pointer;
  font-size: 16px;
  border-radius: 4px;
  outline: none;
  margin: 10px;
}

.custom-camera-button:hover {
  background-color: #1377db;
  /* 鼠标悬停时更深的蓝色 */
}

.recording-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  margin: 20px;
}

/**
 * .video-container 类的样式定义
 * 该类用于创建一个相对定位的容器,容器为一个圆形,用于展示视频
 * 容器的宽高为200px,有圆角和隐藏溢出内容的属性,顶部有20px的外边距
 */
.video-container {
  position: relative;
  width: 200px;
  height: 200px;
  border-radius: 50%;
  overflow: hidden;
  margin-top: 20px;
}

/**
 * .video-container 类下的 video 元素的样式定义
 * 该类用于绝对定位容器中的视频元素,并且使视频元素的中心点与容器的中心点对齐
 * 视频元素的宽高设置为100%,确保视频能够填满容器,并且保持宽高比正确缩放
 */
.video-container video {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 100%;
  height: 100%;
  object-fit: cover;
}
</style>

四、总结

工具用得好,学习也就快,借助AI做的,自己主要负责提问。