使用 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();
相关推荐
梦帮科技3 分钟前
AI 音乐产品的发布工程:验证门、数据发布、回滚与生产运维纪律
数据结构·数据库·架构·node.js·音视频·动态规划·推荐算法
泯泷6 分钟前
那段文字是谁删的?Yjs 14 正式版之前,一套删除归属方案的实现与边界
前端·javascript·算法
hold?fish:palm14 分钟前
34 合并K个升序链表
javascript·算法·链表
揽秀亭长18 分钟前
视频转文字有哪些方法?在线AI、剪辑软件、本地对比
人工智能·音视频
野槐3 小时前
前端项目优化(有了我,会发生...)
前端
幸运小圣3 小时前
PointerEvent 常用属性与事件整理【JavaScript】
开发语言·javascript·ecmascript
aa小小3 小时前
【无标题】
前端
计算机魔术师4 小时前
还在单线程跟 AI 聊天?Claude Code 并行多会话让你一个人干三个人的活
前端
志尊宝4 小时前
Vue3 零基础每日笔记(038):亲手封装 useDebounceFn 与 useThrottleFn——高频事件的流量阀
前端·javascript·vue·html·vue3
JavaGuide4 小时前
对标 MinIO!全新一代分布式文件系统正式发布
前端·后端