写作背景:
在学习 WebRTC 音视频开发前,我们先来学习了解一下音频、视频等媒体数据的获取与播放。了解一下入门级的 API 的使用。
API 介绍:
MediaDevices:
developer.mozilla.org/zh-CN/docs/…
这个 API 提供了如何访问媒体数据输入的设备,如 PC 电脑的摄像头、麦克风、屏幕共享等。
MediaDevices.getUserMedia():
通过传入不同的约束提条件来获取到不同的媒体数据流,前提的用户授权使用的情况下。使用到摄像头、麦克风时浏览器就会对用户提示并希望得到用户授权。
MediaDevices.getDisplayMedia():
在得到用户授权后可以选择屏幕、窗口、Chrome 标签页进行媒体流的获取。在获取 Mac 屏幕/窗口进行屏幕共享的时候需要在 Mac 的【偏好设置】=>【安全与隐私】=>【隐私】=>【屏幕录制】中勾选允许Chrome。
获取摄像头视频数据流:
- 设置约束条件,允许视频,禁用音频:
const constraints: MediaStreamConstraints = { audio: false, video: true };
复制代码
- 同步调用getUserMedia得到媒体流:
const stream = await navigator.mediaDevices.getUserMedia(constraints);
复制代码
- 通过媒体流得到设备的信息,如设备名称:
const videoTracks = stream.getVideoTracks();
console.log(videoTracks[0].label);
复制代码
- 通过 video 标签播放媒体流,这里不适用 src 属性,要使用 srcObject 属性,这个属性是HTMLMediaElement 类的其中一员,所以我们在 TypeScript 编写代码的时候在泛型约束时指定了它:
const video = ref<HTMLMediaElement>();
const openCamera = async () => {
try {
const constraints: MediaStreamConstraints = { audio: false, video: true };
const stream = await navigator.mediaDevices.getUserMedia(constraints);
const videoTracks = stream.getVideoTracks();
console.log(videoTracks[0].label);
video.value!.srcObject = stream;
} catch (error) {
message.error(`获取用户媒体数据错误:${error}`);
}
};
// video元素定义
<video ref="video" autoplay></video>
复制代码
获取麦克风音频数据流:
与上面获取摄像头媒体数据类似,只是使用不同的约束与不同的播放标签,请看完整代码:
代码语言:javascript复制const audio = ref<HTMLMediaElement>();
const openMicrophone = async () => {
try {
const constraints: MediaStreamConstraints = { audio: true, video: false };
const stream = await navigator.mediaDevices.getUserMedia(constraints);
const audioTracks = stream.getAudioTracks();
console.log(audioTracks[0].label);
audio.value!.srcObject = stream;
} catch (error) {
message.error(`获取用户媒体数据错误:${error}`);
}
};
// audio元素定义
<audio ref="audio" autoplay controls></audio>
复制代码
截取视频流输入到画布:
在进行播放摄像头数据的过程中我们可以截取其中的一个画面输出到画布中,这个案例工作前需要正常得到摄像头返回的媒体数据流:
因为我们要得到 video 标签的一个宽高来设置我们的画布尺寸,所以在泛型约束的时候我们增加一个HTMLVideoElement 类型约束:
代码语言:javascript复制const captureVideo = async () => {
const videoSource = video.value as HTMLVideoElement;
canvas.value!.width = videoSource.videoWidth;
canvas.value!.height = videoSource.videoHeight;
canvas.value
?.getContext("2d")
?.drawImage(videoSource, 0, 0, canvas.value!.width, canvas.value!.height);
};
// canvas元素定义
<canvas ref="canvas"></canvas>
复制代码
通过浏览器共享屏幕:
我们这里有少许的不同,我们需要使用 getDisplayMedia,但是同样将得到的媒体流交由 video 标签播放:
代码语言:javascript复制const shareScreen = async () => {
try {
const stream = await navigator.mediaDevices.getDisplayMedia({
video: true,
});
const videoTracks = stream.getVideoTracks();
console.log(videoTracks[0].label);
video.value!.srcObject = stream;
} catch (error) {
console.log((error as Error).name);
message.error(`获取用户媒体数据错误:${error}`);
}
};
// video元素定义
<video ref="video" autoplay></video>
复制代码
注:我们上面有提到的,屏幕录制的权限,一定要在系统偏好中提前设置,要不你的看到 NotAllowedError: Permission denied by system 的❌错误提示。
结语:
通过上面 4 个场景用例我们熟悉了在浏览器中通过规范的 API 来实现媒体数据的读取与播放,大大节省了音视频在 web 端开发的难度,明天继续学!