Vue 使用 navigator.mediaDevices.getUserMedia 调用本地摄像头实现录像以及拍照功能

前言

最近在做开源实例: Vue.js 实战系列之实现视频类WebApp的项目(仿抖音App)【感兴趣的小伙伴可以看一下】,其中就有一个功能是视频的拍摄发布(摄像头调用,视频录制等功能),所以特意整理一个Vue如何使用该API调用本地摄像头实现录像拍照功能。

本文主要包括前端调用本地摄像头实现拍照、录像的使用实例、应用技巧、基本知识点总结和一些需要注意的事项,在项目开发中具有一定的参考价值,需要的朋友可以参考一下。

Vue 调用本地摄像头实现拍照功能,由于调用摄像头有使用权限,只能在本地运行,线上需用 https 域名才可以使用。


API

MediaDevices.getUserMedia()

该 API 会提示用户给予使用媒体输入的许可,媒体输入会产生一个MediaStream,里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道(来自硬件或者虚拟视频源,比如相机、视频采集设备和屏幕共享服务等等)、一个音频轨道(同样来自硬件或虚拟音频源,比如麦克风、A/D转换器等等),也可能是其它轨道类型。

它返回一个 Promise 对象,成功后会 resolve 回调一个 MediaStream 对象。若用户拒绝了使用权限,或者需要的媒体源不可用,Promisereject 回调一个 PermissionDeniedError 或者 NotFoundError

注意:返回的 Promise 对象可能既不会 resolve 也不会 reject,因为用户不是必须选择允许或拒绝。

使用:我们可以使用 navigator.mediaDevices 来获取 MediaDevices

navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
  /* 使用这个stream stream */
})
.catch(function(err) {
  /* 处理error */
});

constraints 参数介绍:

指定了请求的媒体类型和相对应的参数。

参数包含了 videoaudio 两个成员的 MediaStreamConstraints 对象,用于说明请求的媒体类型。必须至少一个类型或者两个同时可以被指定。

关于该API其他具体使用细节,请移步 getUserMedia - MDN 查看。


拍照功能实例

完整代码

<template>
  <div class="publish">
    <video ref="video"></video>
    <canvas style="display: none" id="canvasCamera"></canvas>
    <div v-if="imgSrc" class="img_bg_camera">
      <img :src="imgSrc" class="tx_img" />
    </div>
    <button @click="OpenCamera">打开摄像头</button>
    <button @click="CloseCamera">关闭摄像头</button>
    <button @click="setImage">拍照</button>
  </div>
</template>

<script>
export default {
  data() {
    return {
      mediaStreamTrack: {},
      video_stream: '', // 视频stream
      imgSrc: '', // 拍照图片
      canvas: null,
      context: null,
    };
  },
  mounted() {
    // 进入页面 自动调用摄像头
    this.getCamera();
  },
  methods: {
    // 调用打开摄像头功能
    getCamera() {
      // 获取 canvas 画布
      this.canvas = document.getElementById('canvasCamera');
      this.context = this.canvas.getContext('2d');
      // 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
      if (navigator.mediaDevices === undefined) {
        navigator.mediaDevices = {};
      }
      // 正常支持版本
      navigator.mediaDevices
        .getUserMedia({
          video: true,
        })
          .then((stream) => {
          // 摄像头开启成功
          this.mediaStreamTrack = typeof stream.stop === 'function' ? stream : stream.getTracks()[0];
          this.video_stream = stream;
          this.$refs.video.srcObject = stream;
          this.$refs.video.play();
        })
        .catch(err => {
          console.log(err);
        });
    },
    // 拍照 绘制图片
    setImage() {
      console.log('拍照');
      // 点击canvas画图
      this.context.drawImage(
        this.$refs.video,
        0,
        0,
        200,
        100,
      );
      // 获取图片base64链接
      const image = this.cancas.toDataURL('image/png');
      this.imgSrc = image;
      this.$emit('refreshDataList', this.imgSrc);
    },
    // 打开摄像头
    OpenCamera() {
      console.log('打开摄像头');
      this.getCamera();
    },
    // 关闭摄像头
    CloseCamera() {
      console.log('关闭摄像头');
      this.$refs.video.srcObject.getTracks()[0].stop();
    },
  },
};
</script>

<style lang="less" scoped>
video {
  width: 100%;
  height: 300px;
}
canvas {
  width: 100%;
  height: 300px;
}
button {
  width: 100px;
  height: 40px;
  position: relative;
  bottom: 0;
  left: 0;
  background-color: rgb(22, 204, 195);
}
.img_bg_camera {
  img {
    width: 300px;
    height: 200px;
  }
}
</style>

实现效果

打开摄像头:
在这里插入图片描述

拍照:
在这里插入图片描述

关闭摄像头:
在这里插入图片描述


录像功能实例

完整代码

<template>
  <div class="publish">
  	<!-- 下载按钮 -->
    <a id="downLoadLink" style="display: none;"></a>
    <video ref="video"></video>
    <!-- 视频录制或暂停 -->
    <div @click="recordOrStop">视频录制</div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      mediaStreamTrack: {}, // 退出时关闭摄像头
      video_stream: '', // 视频stream
      recordedBlobs: [], // 视频音频 blobs
      isRecord: false, // 视频是否正在录制
    };
  },
  mounted() {
    // 进入页面 调用摄像头
    this.getCamera();
  },
  methods: {
    // 调用打开摄像头功能
    getCamera() {
      // 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
      if (navigator.mediaDevices === undefined) {
        navigator.mediaDevices = {};
      }
      navigator.mediaDevices
        .getUserMedia({
          video: true,
        })
          .then((stream) => {
          // 摄像头开启成功
          this.mediaStreamTrack = typeof stream.stop === 'function' ? stream : stream.getTracks()[0];
          this.video_stream = stream;
          this.$refs.video.srcObject = stream;
          this.$refs.video.play();
        })
        .catch(err => {
          console.log(err);
        });
    },
    // 录制或暂停
    recordOrStop() {
      if (this.isRecord) {
        this.stop();
      } else {
        this.record();
      }
    },
    // 视频录制
    record() {
      console.log('record');
      this.isRecord = !this.isRecord;
      let mediaRecorder;
      let options;
      this.recordedBlobs = [];
      if (typeof MediaRecorder.isTypeSupported === 'function') {
        // 根据浏览器来设置编码参数
        if (MediaRecorder.isTypeSupported('video/webm;codecs=vp9')) {
          options = {
            MimeType: 'video/webm;codecs=h264',
          };
        } else if (MediaRecorder.isTypeSupported('video/webm;codecs=h264')) {
          options = {
            MimeType: 'video/webm;codecs=h264',
          };
        } else if (MediaRecorder.isTypeSupported('video/webm;codecs=vp8')) {
          options = {
            MimeType: 'video/webm;codecs=vp8',
          };
        }
        mediaRecorder = new MediaRecorder(this.video_stream, options);
      } else {
        // console.log('isTypeSupported is not supported, using default codecs for browser');
        console.log('当前不支持isTypeSupported,使用浏览器的默认编解码器');
        mediaRecorder = new MediaRecorder(this.video_stream);
      }
      mediaRecorder.start();
      // 视频录制监听事件
      mediaRecorder.ondataavailable = e => {
        console.log(e);
        // 录制的视频数据有效
        if (e.data && e.data.size > 0) {
          this.recordedBlobs.push(e.data);
        }
      };
      // 停止录像后增加下载视频功能,将视频流转为mp4格式
      mediaRecorder.onstop = () => {
        const blob = new Blob(this.recordedBlobs, { type: 'video/mp4' });
        this.recordedBlobs = [];
        // 将视频链接转换完可以用于在浏览器上预览的本地视频
        const videoUrl = window.URL.createObjectURL(blob);
        // 设置下载链接
        document.getElementById('downLoadLink').href = videoUrl;
        // 设置下载mp4格式视频
        document.getElementById('downLoadLink').download = 'media.mp4';
        document.getElementById('downLoadLink').innerHTML = 'DownLoad video file';
        // 生成随机数字
        const rand = Math.floor((Math.random() * 1000000));
        // 生成视频名
        const name = `video${rand}.mp4`;
        
        // setAttribute() 方法添加指定的属性,并为其赋指定的值
        document.getElementById('downLoadLink').setAttribute('download', name);
        document.getElementById('downLoadLink').setAttribute('name', name);
		
		// 0.5s后自动下载视频
        setTimeout(() => {
          document.getElementById('downLoadLink').click();
        }, 500);
      };
    },
    // 停止录制
    stop() {
      this.isRecord = !this.isRecord;
      if (!this.$refs.video.srcObject) return;
      const stream = this.$refs.video.srcObject;
      const tracks = stream.getTracks();
      // 关闭摄像头和音频
      tracks.forEach(track => {
        track.stop();
      });
    },
  },
};
</script>

<style lang="less" scoped>
.publish {
  color: #fff;
  video {
    width: 100%;
    height: 100vh;
  }
  div {
    position: absolute;
    left: calc(50% - 80px);
    bottom: 0;
    height: 40px;
    width: 160px;
    font-size: 14px;
    border-radius: 10px;
    line-height: 40px;
    background-color: rgb(25, 179, 179);
    text-align: center;
  }
}
</style>

实现效果

在这里插入图片描述


总结

通过以上两段代码,可以分别实现调用本地摄像头实现录像或者拍照的功能,并且支持视频下载到本地。

以上代码可以拿来直接使用,欢迎小伙伴踊跃尝试,有什么问题欢迎留言讨论。

如果觉得有用,别忘了一键三连哦,感觉各位的支持。

  • 69
    点赞
  • 168
    收藏
    觉得还不错? 一键收藏
  • 44
    评论
要在 Vue调用本地摄像头,可以使用 WebRTC 技术实现。WebRTC 是一个开放的项目,提供了一些 JavaScript API,可以在浏览器中实现实时通信,包括视频和音频通信。以下是基本的步骤: 1. 在 Vue 项目中引入 WebRTC 相关的 JavaScript 库,例如 webrtc-adapter 或 simplewebrtc。 2. 在 Vue 组件中创建一个 video 标签,用于展示摄像头捕捉的画面。 3. 使用 getUserMedia API 获取本地摄像头的权限,并将视频流绑定到 video 标签上。 4. 可以在 Vue 组件中添加一些控制按钮,例如开始、暂停、停止等,实现摄像头的控制。 下面是一个简单的示例代码: ``` <template> <div> <video ref="video" autoplay></video> <button @click="start">开始</button> <button @click="pause">暂停</button> <button @click="stop">停止</button> </div> </template> <script> export default { data() { return { stream: null, video: null, } }, mounted() { this.video = this.$refs.video }, methods: { async start() { try { this.stream = await navigator.mediaDevices.getUserMedia({ video: true }) this.video.srcObject = this.stream this.video.play() } catch (error) { console.log('获取摄像头权限失败:', error) } }, pause() { this.video.pause() }, stop() { this.video.pause() this.video.srcObject = null this.stream.getTracks()[0].stop() }, }, } </script> ``` 需要注意的是,getUserMedia API 可能会在不同的浏览器中有不同的兼容性问题,需要做好兼容性处理。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值