前端实现录屏、录音、摄像头

2,047 阅读4分钟

「时光不负,创作不停,本文正在参加2021年终总结征文大赛

仓库地址

gitee地址

主要使用的API

  • navigator.mediaDevices.getDisplayMedia 文档地址

    提示用户去选择和授权捕获展示的内容或部分内容

  • navigator.mediaDevices.getUserMedia 文档地址

    提示用户给予使用媒体输入的许可

  • MediaRecorder 文档地址

    可以捕获由 MediaStreamHTMLMediaElement对象生成的数据,以便进行分析、处理或保存到磁盘。使用它也非常容易。

实现思路

因为第一次搞这个东西,我也没什么头绪,所以我的实现思路很简单,用三个MediaRecorder去控制navigator.mediaDevices.getDisplayMedianavigator.mediaDevices.getUserMedia 返回的MediaStream

  1. 先了解下navigator.mediaDevices.getDisplayMedia | navigator.mediaDevices.getUserMedia返回的stream中用到的一些方法
addTrack          // 将一个新的媒体磁道添加到一组磁道中(我代码没有用过这个方法,我只是在探索的过程中使用过)
getAudioTracks   // 获取音频磁道
getVideoTracks  // 获取视频磁道
getTracks      // 获取音视频磁道,这个取决于constraints参数

举个简单的🌰
// 用await一定要记得async啊, 这里只是举例
// 当你授权之后,浏览器就会弹出窗口让你选择捕获哪个桌面 | 窗口 | 标签卡
const result = await navigator.mediaDevices.getDisplayMedia({
    audio: true, // 设置为true之后,在弹出的窗口中会有共享系统音频的选择框
    video: true
})
result.getTracks() // 你就能获得一个MediaStreamTrack[]类型的数组

MediaStreamTrack`enabled`可以控制轨道是否有效
如果该轨道连接中断,该值还是可以被改变但不会有任何效果了
enabled可以用来对麦克风进行禁音等操作

MediaStreamTrack链接

  1. MediaRecorder的一些用法
  • stream就是getUserMedia | getDisplayMedia返回的数据
  • options 它可以包含下列属性:
    • mimeType: 为新构建的 MediaRecorder 指定录制容器的MIME类型. 在应用中通过调用 MediaRecorder.isTypeSupported()来检查浏览器是否支持此种mimeType .
    • audioBitsPerSecond: 指定音频的比特率.
    • videoBitsPerSecond: 指定视频的比特率.
    • bitsPerSecond: 指定音频和视频的比特率. 此属性可以用来指定上面两个属性. 如果上面两个属性只有其中之一和此属性被指定, 则此属性可以用于设定另外一个属性.

如果视频和/或音频的比特率没有指定, 视频默认采用的比特率是2.5Mbps, 但音频的默认比特率并不固定, 音频的默认比特率根据采样率和轨道数自适应.

创建MediaRecorder并且开启

// 假设我现在关联上面🌰中的stream
const mediaRecorder = new MediaRecorder(result)

mediaRecorder.start() // 开始必须调用,不然状态不会更新

console.log("mediaRecorder => ", mediaRecorder) // 你可以打印查看相关信息
  • MediaRecorder.state返回录制对象MediaRecorder的当前状态(闲置中,录制中或者暂停 ) (inactiverecording, or paused)

停止MediaRecorder并且结束

mediaRecorder.stop() // 停止
// 这个停止,是停止mediaRecorder,并不会结束录屏
// 调用这个方法之后,你会发现浏览器调起的共享并没有结束【下图】。
// 你需要监听stop, 在调用mediaRecorder.stop() 触发该事件, 将track停止
mediaRecorder.addEventListener('stop', event => {
     /**
       * @description 与其停止流本身,不如停止流的轨迹
       */
        result.getTracks().forEach(track => {
            track.stop()
        })
})

// -   媒体流结束时,所有尚未传递到处理程序的媒体数据都将在单个Blob
// 当调用mediaRecorder.stop()时,自记录开始或事件最后一次发生以来已捕获的所有媒体数据都将传递到Blob中
mediaRecorder.addEventListener('dataavailable', ({data}) => {
    // 你可以在这里将data转换成blob url
    const videoAndDownloadUrl = URL.createObjectURL(data)
})

// 如果你点击浏览器的停止共享按钮
// 那么它会执行一个onended事件
监听方法为
result.getVideoTracks.forEach(track => {
    track.addEventListener('ended', (event) => {
       // 停止共享按钮和点击结束按钮一般做的操作是同样的
    })
})

录制过程概述参考链接

MediaRecorder的配置项、方法、事件处理 参考链接

image.png

暂停和继续

// 这两个没什么好扩展的,如果你想监听它们,你可以参考上面的MediaRecorder事件处理链接中的
`MediaRecorder.onpause` 用来处理 `pause` 事件, 该事件在媒体暂停录制时触发
`MediaRecorder.onresume` 用来处理 `resume` 事件, 该事件在暂停后回复录制视频时触发

mediaRecorder.pause() // 暂停
mediaRecorder.resume() // 继续

音频和摄像头的实现同理

// 调用音频,然后使用mediaRecorder进行控制
const result = await navigator.mediaDevices.getUserMedia({
    video: false,
    audio: true
})

const result = await navigator.mediaDevices.getUserMedia({
    video: {
        width: { ideal: 300 },
        height: { ideal: 150 }
    },
    audio: false
})

getUserMedia配置参数

最后

第一次写文章,记录一下这个研究了蛮长时间的几个API!