媒体流(MediaStream)
媒体流(MediaStream)是一个重要概念,它代表着音频和视频数据的流。媒体流可以包含一个或多个音频轨道(AudioTrack)和视频轨道(VideoTrack),这些轨道可以同时捕获和播放音频和视频内容。
下面是一些关于媒体流的详解和概念性知识点:
- 媒体轨道(MediaTrack):媒体轨道是媒体流的组成部分,用于表示音频或视频内容。一个媒体流可以包含一个或多个音频轨道和视频轨道。音频轨道捕获和传输音频数据,视频轨道捕获和传输视频数据。
- 媒体流捕获(MediaStream Capture):媒体流捕获是指从设备(如摄像头、麦克风)中获取音频和视频数据,并生成媒体流的过程。通过使用
getUserMedia()
方法,可以请求用户授权访问设备,并获取包含音频和视频轨道的媒体流。 - 媒体流播放(MediaStream Playback):媒体流播放是指将媒体流中的音频和视频数据进行实时播放的过程。可以通过将媒体流关联到HTML5的
<video>
元素的srcObject
属性上,或将媒体流传递给其他WebRTC连接的对等方来实现媒体流的播放。 - 媒体流的控制:媒体流提供了一些方法和属性来控制音频和视频轨道的行为,例如启用/禁用轨道、调整音量、获取当前时间等。通过操作媒体流和轨道,可以实现音频和视频的控制和处理。
- 媒体流的传输:WebRTC使用媒体流来在对等连接之间传输音频和视频数据。通过将媒体流添加到
RTCPeerConnection
对象中的轨道中,并使用WebRTC的信令机制交换媒体流的描述信息(SDP),可以在对等连接之间建立音视频通信。 - 媒体流的事件:媒体流和媒体轨道可以触发各种事件,以便应用程序可以对其进行监听和响应。例如,可以监听媒体流的
onaddtrack
事件以在添加新轨道时执行操作,或者监听轨道的onended
事件以在轨道结束时执行操作。
总之,媒体流是WebRTC中用于捕获、传输和播放音频和视频数据的重要概念。通过使用媒体流,可以实现实时的音视频通信和多媒体应用程序,如视频会议、音视频聊天和实时流媒体等。
在处理媒体流时,以下是一些常用的 Web API:
- MediaDevices API:通过
navigator.mediaDevices
对象可以访问媒体设备,如摄像头和麦克风。它提供了获取媒体流的方法,如getUserMedia()
。 - MediaStream API:
MediaStream
表示一个媒体流,可以通过getUserMedia()
方法获取。它包含音频和/或视频轨道,可以通过操作MediaStream
来控制媒体流的播放和录制。 - MediaRecorder API:
MediaRecorder
允许你在浏览器中录制媒体流(如音频或视频)。它提供了开始、暂停和停止录制的方法,并且可以将录制的内容保存为文件或进行实时传输。 - MediaElement API:
HTMLMediaElement
是媒体元素的 DOM 接口,例如<audio>
和<video>
元素。它提供了控制媒体播放、暂停、音量、播放速度等的方法和属性。 - WebRTC API:WebRTC(Web实时通信)是一组浏览器 API,用于实现实时音视频通信。它包括
RTCPeerConnection
、RTCDataChannel
、RTCRtpSender
等接口,用于建立点对点的音视频连接并进行数据传输。 - Canvas API:
CanvasRenderingContext2D
提供了在<canvas>
元素上绘制和处理图像、视频等的方法和属性。你可以使用它来从视频流中捕捉帧、进行图像处理,或在画布上渲染实时图像。
获取用户的设备(摄像头,麦克风)
使用getUserMedia
这是 navigator.mediaDevices
对象的一个方法,用于请求用户授权访问媒体设备并获取媒体流(MediaStream)对象。通过传递适当的约束条件(constraints),可以指定所需的媒体类型、分辨率、帧率等。
兼容性如下:
这个 API 的基本使用如下:
const isSupportMediaDevicesMedia = () => {
return !!(navigator.getUserMedia || (navigator.mediaDevices && navigator.mediaDevices.getUserMedia));};
if (isSupportMediaDevicesMedia()) {
// 兼容性
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
// 配置
const mediaOption = { audio: true, video: true };
navigator.mediaDevices
.getUserMedia(mediaOption)
.then((stream) => {
console.log([Log] stream-->, stream);
})
.catch((err) => {
console.error([Log] 获取摄像头和麦克风权限失败-->, err);
});
} else {
if (navigator.userAgent.toLowerCase().match(/chrome/) && location.origin.indexOf('https://') < 0) {
console.log('chrome下获取浏览器录音功能,因为安全性问题,需要在localhost或127.0.0.1或https下才能获取权限');
} else {
console.log('无法获取浏览器录音功能,请升级浏览器或使用chrome');
}
}
核心就是 getUserMedia 方法和 mediaOption 这个配置。
mediaOption 配置:
const mediaOption = {
audio: true, // true 标识需要获取音频流
//
video: true, // true 标识需要获取视频流
// 指定视频的宽高和帧率
video: {
width: { min: 980, ideal: 980, max: 1920 },
// min,max 指定一个范围,ideal 表示优先使用的值
height: { min: 560, ideal: 560, max: 1080 },
frameRate: { ideal: 12, max: 15 }, // 指定帧率
deviceId: { exact: '设备id' }, // 多设备的时候,可以通过设备id获取指定的设备
facingMode: 'user', // user:前置摄像头,environment:后置摄像头
},
};
getUserMedia
返回了一个 Promise<MediaStream>
,MediaStream
就是我们需要媒体流,那么拿到了流就可以干我们想干的事情了。
navigator.mediaDevices.getUserMedia({ audio: true, video: true })
.then(function(stream) {
// 在获取媒体流成功后执行操作
})
.catch(function(error) {
// 处理获取媒体流失败的情况
});
```
有几个注意点:
- video 标签的 autoPlay 属性要是 true,这样流才会播放
- 用完一定要记得停止,防止 cpu 占用过高
- 如果想要静音啥的,直接设置 video 标签相关的属性就好了
获取指定设备
一台电脑可以外接多个音视频设备, getUserMedia 默认是拿默认设备,如何获取所有设备以及获取指定设备的流呢?
使用到的是 enumerateDevices 这个 API,返回的是 Promise<MediaDeviceInfo[]>
,
MediaDeviceInfo 有如下属性:
- kind:设备类型,是摄像头还是麦克风,
- label: 设备名称
- deviceId: 设备 ID
有了设备 id 就可以用 getUserMedia 获取指定的设备。
navigator.mediaDevices.enumerateDevices()
.then(function(devices) {
// 处理设备列表
})
.catch(function(error) {
// 处理获取设备列表失败的情况
});
```
录制视频
基本使用
录制视频是使用的 MediaRecorder 这个 API,使用方法也很简单
- 创建一个 MediaRecorder 对象,传入我们获取到的 stream 流,可以使用 mimeType 指定编码类型,默认是
video/webm
- 监听 dataavailable 事件,类似于 change 事件,会吐出录像数据,数据其实就是二进制的 blob 对象,直接 push 到数组里面就好了
- 调用 start 方法开始录制,如果不传时间参数,那 dataavailable 只会在 stop 的时候触发一次,传了时间参数,就每间隔时间触发 dataavailable 事件
- 调用 stop 方法结束录制
编码类型
构造 MediaRecorder 可以传递一个 mimeType 类型,用来指定录制的数据的编码类型,但是我还没弄明白这些类型最终生成的数据有啥区别,建议直接使用 video/webm
,因为不管是啥编码类型,MediaRecorder 最终生成的文件只会是 webm 格式
编码类型可以理解成压缩数据的方式,有一些是无损压缩的,有一些是有损的,无损的压缩文件大小就会非常大,这里就不得不提到一些类型了,因为在项目中踩了很多的坑
在本文中,需要了解的视频格式
- webm: 因为 MediaRecorder 只能录制 webm 格式的数据
- mp4: web 中比较通用的视频格式
在本文中,需要了解的音频格式
- webm: 因为 MediaRecorder 只能录制 webm 格式的数据
- mp3: web 中比较通用的音频格式
- pcm、wav: wav 在 pcm 文件中加入了一些描述信息,其余和 pcm 完全一致,pcm 是一种无损的音频格式,文件十分巨大,webm 可以不是很麻烦的转成 pcm 格式
这些文件格式的转换是十分复杂的,但并不是不能实现,需要将 blob 数据转成最原始的二进制数组,然后使用对应的编码方案,操作这个二进制数组。
注意点
- 浏览器厂商出于对用户安全、隐私等问题的考虑,限制网页在 https 协议下才能正常使用 WebRTC全部功能。为确保使用全部功能,请使用 https 协议访问页面。本地开发可以通过 http://localhost 或者 file:// 协议进行访问。
- 系统默认的设备如果被占用了,获取流的时候可能会失败,比如你在会议里面共享桌面,然后在去获取流就可能会失败。
- 有些笔记本有一个物理开关,能总控摄像头的访问权限,所以有时候一直是黑屏可以检查一下是不是这个原因。