<template>
  <div style="height: 100vh;background: #000;">
    <video ref="video" autoplay muted playsinline></video>
    <div class="video_btn">
      <van-button round @click="start" type="info">{{ isRecording ?  `录制倒计时${timernum}秒后停止录制` : '开始录制' }}</van-button>
      <van-button round @click="switchCamera" :disabled="isRecording">切换摄像头</van-button>
    </div>
    <video v-if="recordedVideoUrl" :src="recordedVideoUrl" controls></video>
  </div>
</template>

<script>
export default {
  data() {
    return {
      mediaStream: null, // 摄像头视频流
      mediaRecorder: null, // 媒体录制器
      recordedChunks: [], // 录制的数据块
      recordedVideoUrl: null, // 录制后的视频 URL
      isRecording: false, // 是否正在录制
      currentDeviceId: null, // 当前摄像头设备 ID
      currentText: "front", // front前 after后
      devices: [], // 设备列表
      timer: null, // 计时器,用于限制录制时间
      timernum: 30, // 计时器,用于限制录制时间
      maxFileSize: 100 * 1024 * 1024, // 100MB
    };
  },
  mounted() {
    this.startCamera();
  },
  methods: {
    async startCamera() {
      try {
        // 获取设备列表
        const devices = await navigator.mediaDevices.enumerateDevices();
        this.devices = devices.filter(device => device.kind === "videoinput");

        if (this.devices.length === 0) {
          throw new Error("没有找到摄像头设备");
        }

        // 默认选择第一个设备 首次前置
        this.currentDeviceId = this.devices[0].deviceId;

        // 获取视频流并绑定
        this.mediaStream = await navigator.mediaDevices.getUserMedia({
          video: { deviceId: this.currentDeviceId }
        });

        const videoElement = this.$refs.video;
        videoElement.srcObject = this.mediaStream;
      } catch (error) {
        console.error("无法访问摄像头:", error);
      }
    },
    // 开始录制或停止录制
    start() {
      if (this.isRecording) {
        this.stopRecording();
      } else {
        this.startRecording();
      }
    },
    startRecording() {
      if (this.mediaStream) {
        this.mediaRecorder = new MediaRecorder(this.mediaStream);
        this.recordedChunks = [];
        this.mediaRecorder.ondataavailable = (event) => {
          if (event.data.size > 0) {
            this.recordedChunks.push(event.data);
            // 检查文件大小是否超过 95MB
            const totalSize = this.recordedChunks.reduce((acc, chunk) => acc + chunk.size, 0);

            // this.$toast(`大小:`+ (totalSize/1024/1024))
            if (totalSize > this.maxFileSize) {
              this.stopRecording();
            }
          }
        };
        this.mediaRecorder.onstop = () => {
          const blob = new Blob(this.recordedChunks, { type: "video/webm" });
          this.recordedVideoUrl = URL.createObjectURL(blob);
        };
        this.timer = setInterval(() => {
          this.settime()
        }, 1000); // 60秒后停止录制
        this.mediaRecorder.start();
        this.isRecording = true;
      }
    },
    settime() { 
      if (this.timernum < 1) {
        this.stopRecording()
        clearInterval(this.timer)
        return
      } else { 
        this.timernum--
      }
    },
    stopRecording() {
      if (this.mediaRecorder) {
        this.mediaRecorder.stop();
        clearInterval(this.timer); // 停止定时器
        this.isRecording = false;
      }
      this.timernum = 30
    },
    async switchCamera() {
      try {
        // 停止当前的媒体流
        this.stopStream();
        // 切换到下一个摄像头设备(前后切换)
        if (this.currentText === "front") {
          this.currentDeviceId = this.devices[3].deviceId;
          this.currentText = "after";
        } else {
          this.currentDeviceId = this.devices[0].deviceId;
          this.currentText = "front";
        }
        // 获取新的摄像头流
        this.mediaStream = await navigator.mediaDevices.getUserMedia({
          video: { deviceId: this.currentDeviceId }
        });

        const videoElement = this.$refs.video;
        videoElement.srcObject = this.mediaStream;
      } catch (error) {
        console.error("无法切换摄像头:", error);
      }
    },
    stopStream() {
      if (this.mediaStream) {
        const tracks = this.mediaStream.getTracks();
        tracks.forEach(track => track.stop());
      }
    }
  }
};
</script>

<style>
.video_btn {
  position: fixed;
  bottom: 30px;
  z-index: 99;
  display: flex;
  justify-content: space-around;
  align-items: center;
  width: 100%;
  max-width: 640px;
  margin: 0 auto;
}

video {
  width: 100%;
  height: 80vh;
  max-width: 640px;
  margin: 0 auto;
}
</style>

vue视频录制 限制大小,限制时长-LMLPHP

01-01 10:19