使用 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();
相关推荐
清灵xmf11 分钟前
TypeScript 类型进阶指南
javascript·typescript·泛型·t·infer
小白学大数据18 分钟前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫
qq_3901617726 分钟前
防抖函数--应用场景及示例
前端·javascript
334554321 小时前
element动态表头合并表格
开发语言·javascript·ecmascript
John.liu_Test1 小时前
js下载excel示例demo
前端·javascript·excel
Yaml41 小时前
智能化健身房管理:Spring Boot与Vue的创新解决方案
前端·spring boot·后端·mysql·vue·健身房管理
PleaSure乐事1 小时前
【React.js】AntDesignPro左侧菜单栏栏目名称不显示的解决方案
前端·javascript·react.js·前端框架·webstorm·antdesignpro
哟哟耶耶1 小时前
js-将JavaScript对象或值转换为JSON字符串 JSON.stringify(this.SelectDataListCourse)
前端·javascript·json
getaxiosluo1 小时前
react jsx基本语法,脚手架,父子传参,refs等详解
前端·vue.js·react.js·前端框架·hook·jsx
理想不理想v1 小时前
vue种ref跟reactive的区别?
前端·javascript·vue.js·webpack·前端框架·node.js·ecmascript