之前写了 浏览器调用麦克风录制音频 和 调用摄像头拍摄照片 ,这里就继续来调用摄像头拍摄视频。

拍摄视频和录制音频的方法其实是差不多的,使用的也是 MediaRecorder 媒体录制接口,录制音频只需要申请麦克风,录制视频需要同时申请麦克风和摄像头。

下面简单实现显示摄像头画面、拍摄视频、播放视频、导出视频,访问 浏览器录制视频demo 可以查看最终效果。

代码实现

HTML 放几个 button 和 video:

<!--Mr. Ma's Blog www.misterma.com-->
<button type="button" id="start-camera-btn">打开摄像头</button>
<button type="button" id="start-btn">开始录像</button>
<button type="button" id="stop-btn">停止录像</button>
<button type="button" id="play-btn">播放视频</button>
<button type="button" id="export-btn">导出视频</button>
<video width="720" height="360" controls></video>

video 主要用来预览摄像头画面和播放拍摄的视频。

下面的 JavaScript 因为注释比较多,看上去会有点长,但比较容易理解:

const startCameraBtn = document.querySelector('#start-camera-btn');  // 打开摄像头按钮
const startBtn = document.querySelector('#start-btn');  // 开始录像按钮
const stopBtn = document.querySelector('#stop-btn');  // 停止录像按钮
const playBtn = document.querySelector('#play-btn');  // 播放视频按钮
const exportBtn = document.querySelector('#export-btn');  // 导出视频按钮
const videoEl = document.querySelector('video');  // 视频播放元素
let videoData = [];  // 存放视频数据
let  cameraStream = null;  // 存放媒体流
let mediaRecorder = null;  // 存放媒体录制对象

// 打开摄像头按钮点击
startCameraBtn.addEventListener('click', () => {
  // 申请视频和音频的参数
  const constraints = {
    audio: true,
    video: {
      width: 720,
      height: 360
    }
  };
  // 申请摄像头和麦克风权限
  navigator.mediaDevices.getUserMedia(constraints).then(stream => {
    cameraStream = stream;
    // 禁用 video 的控制组件
    videoEl.controls = false;
    // 把媒体流传给 video 的 srcObject
    videoEl.srcObject = cameraStream;
    // 播放画面和声音
    videoEl.play();
  }).catch(info => {
    alert('错误' + info);
  });
});

// 开始录像按钮点击
startBtn.addEventListener('click', () => {
  // 创建媒体录制
  mediaRecorder = new MediaRecorder(cameraStream, {mimeType: 'video/webm'});
  // 开始录制
  mediaRecorder.start();

  // 处理视频数据
  mediaRecorder.addEventListener('dataavailable', ev => {
    videoData.push(ev.data);
  });

  // 录制停止事件
  mediaRecorder.addEventListener('stop', () => {
    videoData = new Blob(videoData);
  });
});

// 停止录像按钮点击
stopBtn.addEventListener('click', () => {
  mediaRecorder.stop();
});

// 播放视频点击
playBtn.addEventListener('click', () => {
  if (videoData === null) return false;
  // 清除 video 的媒体流
  videoEl.srcObject = null;
  // 把视频数据转为 URL 传给 video 的 src
  videoEl.src = URL.createObjectURL(videoData);
  // 播放视频
  videoEl.play();
  // 启用 video 的控制组件
  videoEl.controls = true;
  // 删除媒体流
  cameraStream = null;
});

// 导出视频按钮点击
exportBtn.addEventListener('click', () => {
  if (videoData === null) return false;
  const link = document.createElement('a');
  link.href = URL.createObjectURL(videoData);
  link.download = 'video.webm';
  link.click();
});

上面的代码只是简单演示,没有做重复点击之类的判断。

详细说明

还是分几步写:

  1. 显示摄像头画面
  2. 录制视频
  3. 播放视频
  4. 导出视频

显示摄像头画面

使用 navigator.mediaDevices.getUserMedia 请求媒体输入许可,需要传入一个参数来设置媒体类型,我用的参数如下:

const constraints = {
  audio: true,
  video: {
    width: 720,
    height: 360
  }
};

上面的参数是同时申请视频和音频输入设备,视频使用的尺寸是 720*360。

用户授权完成后会返回一个 Promise,成功 then 会返回一个媒体流,失败 catch 会返回错误信息。

把返回的媒体流传给 video 的 srcObject ,video 就可以显示摄像头画面了,同时也能播放麦克风声音。

录制视频

有了媒体流就可以创建 MediaRecorder 媒体录制接口,第一个参数 MediaStream 是媒体流,可以使用申请设备权限返回的媒体流,第二个参数是录制选项,我的录制选项是 {mimeType: 'video/webm'} ,使用 webm 格式来录制视频。webm 是 Google 的视频格式,Chromium 系的浏览器一般都支持,Firefox 和 Safari 不一定支持,可能需要把 mimeType 设置为 video/mp4 。

使用 MediaRecorder 的 start 方法开始录制,start 方法也可以传入一个 timeslice 参数,timeslice 参数可以设置一个毫秒值来把视频数据分割成多个数据块。

MediaRecorder 的 dataavailable 事件会在停止录制时触发,如果在 start 中设置了 timeslice 的话,每个 timeslice 周期结束也会触发。dataavailable 事件会返回一个 event ,使用 event.data 可以获取视频数据。

MediaRecorder 的 stop 方法可以停止录制,停止录制也会触发 MediaRecorder 的 stop 事件,停止录制后我使用 Blob 把视频数据转为了 Blob 数据。

播放视频

我用来播放视频的 video 元素和显示摄像头画面的是同一个,把 video 的 srcObject 设置为 null 可以停止播放摄像头画面。使用 URL.createObjectURL 把 Blob 视频数据转换为 DataURL 传给 video 的 src ,调用 video 的 play 方法就可以自动播放视频了。

我使用了 video 的 controls 控制组件来控制视频播放,给 video 加入 controls 属性,video 就会包含基本的播放控制功能,不需要手动编写播放控制。在 video 显示摄像头画面的时候我会禁用 controls 组件,在 video 需要播放视频的时候启用 controls 组件。

导出视频

  1. 使用 document.createElement 创建一个链接(不需要插入到页面)
  2. 使用 URL.createObjectURL 把 Blob 视频数据转为 DataURL 传给链接的 href
  3. 通过链接的 download 属性来设置文件名
  4. 调用链接的 click 来触发链接的点击事件

如果需要把视频上传到服务器,可以把视频 Blob 数据添加到 FormData 上传。

之前写录制音频的时候使用的也是 MediaRecorder 媒体录制接口,要查看这里没有使用到的 MediaRecorder 方法和事件说明可以访问 JavaScript 浏览器调用麦克风录音 。

类似文章: