使用 mediaDevices.getUserMedia 在浏览器录制视频

使用 mediaDevices.getUserMedia 录制视频

MediaDevices 接口提供访问连接媒体输入的设备,如照相机和麦克风,以及屏幕共享等。它可以使你取得任何硬件资源的媒体数据。

使用 mediaDevices.getUserMedia 函数可以调用设备相机和麦克风等设备用于录制视频或视频通话, 具体可以查看 MDN 文档

语法使用说明

mediaDevicesnavigator 下的一个对象, 使用 navigator.mediaDevices.getUserMedia(...) 调用,

该函数接收一个 MediaStreamConstraints 类型参数, 用于指定请求的媒体类型, 返回一个 MediaStream 类型的 Promise 对象

ts 复制代码
// MediaStreamConstraints 类型定义
interface MediaStreamConstraints {
  audio?: boolean | MediaTrackConstraints;
  video?: boolean | MediaTrackConstraints;
}

audiovideo 属性一般接收一个布尔值, 用于指定是否需要录制音频和视频, true 代表需要录制, 默认为 false; 也可以使用一个 MediaTrackConstraints 类型对象, 用于阅读每个功能的精度和范围等, 以及指定使用前置后置摄像头, 这里不详细说明;

注意: audiovideo 属性必须有一个为 true 才能正确调用 getUserMedia 函数

js 复制代码
const mediaStream = await navigator.mediaDevices.getUserMedia({
  audio: true,
  video: true,
});

获取视频示例

页面布局

首先放置一个 video 元素用于呈现录制的视频内容, 放置一个 button 用于开始屏幕录制

界面代码

html 复制代码
<style>
    body {
      padding: 0;
      margin: 0;
      display: flex;
      flex-direction: column;
      height: 100vh;
    }
    video {
      flex: 1;
      border: 1px solid #000;
      margin: 10px;
      border-radius: 4px;
    }
    div {
      height: 40px;
      margin: 10px;
      display: flex;
    }
    button {
      flex: 1;
      margin: 0 10px;
    }
  </style>

<body>
  <video></video>
  <div>
    <button class="start">开始</button>
    <button class="stop">结束</button>
  </div>
</body>

页面效果

上面为 video 元素,作为视频预览;两个操作按钮控制开始录制和结束录制

获取元素,添加按钮事件

接下来获取 video 以及 start 和 stop 等元素, 并添加相应的事件函数

示例代码

js 复制代码
const videoEl = document.querySelector('video');
const startBtnEl = document.querySelector('.start');
const stopBtnEl = document.querySelector('.stop');

/**
 * 在外部声明 mediaScream 对象
 * 因为再 start 中获取后在 stop 函数中需要用到该对象去关闭播放轨道
 */
let mediaScream;

const start = () => {
  ...
}

const stop = () => {
  ...
}

startBtnEl.onclick = start;
stopBtnEl.onclick = stop;

获取媒体设备实现预览效果

在 start 中获取摄像头和麦克风使用并输出到 video 元素中, 再 stop 中关闭播放轨道以及停止 video 播放

逻辑代码

js 复制代码
const start = async () => {
  // 获取 mediaScream 对象, 指定同时获取音频和视频
  mediaScream = await navigator.mediaDevices.getUserMedia({
    video: true,
    audio: true,
  });

  // 将获取到的源赋予给 videoEl
  videoEl.srcObject = mediaScream;
  videoEl.play(); // 开始播放
}

const stop = () => {
  /**
   * mediaScream.getTracks 用于获取改源中的 MediaStreamTrack 列表
   * MediaStreamTrack 一般为音轨和视频
   * 获取后遍历并关闭该轨道
   */
  mediaScream.getTracks().forEach(item => item.stop());
  videoEl.pause(); // 停止播放
  videoEl.srcObject = null;
}

界面效果

现在点击开始按钮,video 元素将会呈现摄像头记录的东西, 点击停止按钮会停止摄像头工作并返回原始状态

记录视频数据并下载

我们可以利用 MediaRecorder 对象,将 mediaStream 数据装换位 MediaRecorder 对象;

再 MediaRecorder 对象加载完成时将加载的数据存到一个 chunks 中;

最后再录制结束时,关闭MediaRecorder 对象并将 chunks 数据转换成 blob 数据,然后下载;

MediaRecorder 可以参考 MDN文档

js 复制代码
/** @type MediaStream */
let mediaScream;
/** @type MediaRecorder */
let mediaRecorder;
let chunks = [];

const start = async () => {
  // 获取 mediaScream 对象, 指定同时获取音频和视频
  mediaScream = await navigator.mediaDevices.getUserMedia({
    video: true,
    audio: true,
  });

  // 将获取到的源赋予给 videoEl
  videoEl.srcObject = mediaScream;
  videoEl.play();

  // 创建一个 mediaRecorder 对象
  mediaRecorder = new MediaRecorder(mediaScream, {
    mimeType : 'video/webm',
  });
  // 在 dataavailable 时间中去记录视频数据到 chunks
  mediaRecorder.ondataavailable = (event) => {
    chunks.push(event.data);
  }
  mediaRecorder.start();
}

// 用于将记录的 chunks 转换并下载
const download = () => {
  const blob = new Blob(chunks);
  const aEl = document.createElement('a');
  aEl.href = URL.createObjectURL(blob);
  aEl.download = 'video.webm';
  aEl.style.display = 'none';
  document.body.appendChild(aEl);
  aEl.click();
  chunks = [];
}

const stop = () => {
  // 在 mediaRecorder 的 stop 时间中执行下载任务
  mediaRecorder.onstop = download;
  mediaRecorder.stop(); // 停止记录
  /**
   * mediaScream.getTracks 用于获取改源中的 MediaStreamTrack 列表
   * MediaStreamTrack 一般为音轨和视频
   * 获取后遍历并关闭该轨道
   */
  mediaScream.getTracks().forEach(item => item.stop());
  videoEl.pause();
  videoEl.srcObject = null;
}

界面效果

视频开始录制后,当点击结束时,便会跳出下载保存窗口

将录制程序制作成一个工具类

可以将上述功能封装成一个工具类 RecordVideo

RecordVideo 代码

js 复制代码
class RecordVideo {
  constructor(videoEl) {
    this.videoEl = videoEl;
    this.mediaScream = null;
    this.mediaRecorder = null;
    this.chunks = [];
  }

  download() {
    const aEl = document.createElement('a');
    aEl.href = URL.createObjectURL(new Blob(this.chunks));
    aEl.download = 'video.webm';
    aEl.style.display = 'none';
    document.body.appendChild(aEl);
    aEl.click();
    this.chunks = [];
  }

  async start() {
    this.mediaScream = await navigator.mediaDevices.getUserMedia({
      video: true,
      audio: true,
    });
    this.videoEl.srcObject = this.mediaScream;
    this.videoEl.play();

    this.mediaRecorder = new MediaRecorder(this.mediaScream, {
      mimeType : 'video/webm',
    });
    this.mediaRecorder.ondataavailable = (event) => {
      this.chunks.push(event.data);
    }
    this.mediaRecorder.start();
  }

  stop() {
    this.mediaRecorder.onstop = () => this.download();
    this.mediaScream.getTracks().forEach(item => item.stop());
    this.videoEl.pause();
    this.videoEl.srcObject = null;
  }
}

使用 RecordVideo 类实现

上述的案例就可以简单的使用 RecordVideo 类来实现了

js 复制代码
const videoEl = document.querySelector('video');
const startBtnEl = document.querySelector('.start');
const stopBtnEl = document.querySelector('.stop');

const recordVideo = new RecordVideo(document.querySelector('video'));
startBtnEl.onclick = () => recordVideo.start();
stopBtnEl.onclick = () => recordVideo.stop();
相关推荐
傻小胖1 分钟前
React 脚手架使用指南
前端·react.js·前端框架
程序员海军14 分钟前
2024 Nuxt3 年度生态总结
前端·nuxt.js
m0_7482567824 分钟前
SpringBoot 依赖之Spring Web
前端·spring boot·spring
web135085886351 小时前
前端node.js
前端·node.js·vim
m0_512744641 小时前
极客大挑战2024-web-wp(详细)
android·前端
若川1 小时前
Taro 源码揭秘:10. Taro 到底是怎样转换成小程序文件的?
前端·javascript·react.js
潜意识起点1 小时前
精通 CSS 阴影效果:从基础到高级应用
前端·css
奋斗吧程序媛1 小时前
删除VSCode上 origin/分支名,但GitLab上实际上不存在的分支
前端·vscode
IT女孩儿2 小时前
JavaScript--WebAPI查缺补漏(二)
开发语言·前端·javascript·html·ecmascript
Say-hai2 小时前
音视频入门知识(二)、图像篇
音视频