视频录制实战:从摄像头到屏幕的全面捕获
大家好,我是你们的老朋友。今天咱们来聊聊 WebRTC 里最实用的一个场景——视频录制。说实话,我刚开始接触这块时,也被 MediaRecorder 的坑折腾过好几回。但别担心,跟着我一步步来,你很快就能搞定。
核心知识点:MediaRecorder API + MediaStream 的组合使用
14.1 录制摄像头画面
先来个最基础的——录制摄像头。说白了,就是三步走:获取流、创建录制器、处理数据。
// 第一步:获取摄像头流
const stream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true
});
// 第二步:创建 MediaRecorder
const recorder = new MediaRecorder(stream, {
mimeType: 'video/webm;codecs=vp9'
});
// 第三步:收集数据块
const chunks = [];
recorder.ondataavailable = (e) => {
if (e.data.size > 0) chunks.push(e.data);
};
recorder.onstop = () => {
const blob = new Blob(chunks, { type: 'video/webm' });
const url = URL.createObjectURL(blob);
// 这里可以下载或预览
};
// 开始录制
recorder.start(1000); // 每秒触发一次 ondataavailable
我的经验:mimeType 建议先用 'video/webm;codecs=vp9',如果浏览器不支持再降级到 vp8。我在项目中遇到过 Safari 不支持 webm 的情况,那时得用 'video/mp4'。
14.2 录制屏幕(getDisplayMedia)
录制屏幕和录制摄像头其实很像,只是获取流的方式不同。这里用 getDisplayMedia 代替 getUserMedia。
// 获取屏幕流
const screenStream = await navigator.mediaDevices.getDisplayMedia({
video: {
cursor: 'always' // 显示鼠标指针
},
audio: false // 屏幕流通常不带音频
});
// 剩下的录制逻辑和上面一样
const recorder = new MediaRecorder(screenStream);
// ... 后续代码相同
注意:getDisplayMedia 必须由用户手势触发(比如点击按钮),不能自动调用。我曾经在页面加载时直接调用,结果被浏览器无情拒绝。
14.3 同时录制摄像头+屏幕画中画
这个场景比较有意思——你想录制屏幕,同时把自己的人脸也放进去。嗯,这里需要用到 Canvas 来合成两路流。
// 获取两路流
const screenStream = await navigator.mediaDevices.getDisplayMedia({ video: true });
const cameraStream = await navigator.mediaDevices.getUserMedia({ video: true });
// 创建 Canvas 合成
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 1920;
canvas.height = 1080;
// 把两路流画到 canvas 上
const screenVideo = document.createElement('video');
screenVideo.srcObject = screenStream;
await screenVideo.play();
const cameraVideo = document.createElement('video');
cameraVideo.srcObject = cameraStream;
await cameraVideo.play();
// 定时绘制
function draw() {
ctx.drawImage(screenVideo, 0, 0, canvas.width, canvas.height);
// 画中画放在右下角,缩小到 1/4 大小
ctx.drawImage(cameraVideo,
canvas.width - 320, canvas.height - 240,
320, 240
);
requestAnimationFrame(draw);
}
draw();
// 从 canvas 获取合成流
const mixedStream = canvas.captureStream(30); // 30fps
// 录制合成流
const recorder = new MediaRecorder(mixedStream);
// ... 后续录制逻辑
关键点:canvas.captureStream() 是 WebRTC 里非常强大的工具,它能把任何 canvas 动画变成实时视频流。
14.4 录制音频流
有时候你只需要录声音,比如做播客或者语音笔记。这个反而最简单。
// 获取麦克风流
const audioStream = await navigator.mediaDevices.getUserMedia({
audio: {
echoCancellation: true,
noiseSuppression: true,
sampleRate: 44100
},
video: false
});
// 录制纯音频
const recorder = new MediaRecorder(audioStream, {
mimeType: 'audio/webm;codecs=opus'
});
// 或者录制为 WAV 格式(需要额外处理)
// 这里推荐直接用 webm,兼容性好
避坑指南:我曾经在录制音频时忘记设置 echoCancellation,结果录出来的声音有严重的回声。建议默认开启这两个降噪选项。
知识体系总览
下面这张图帮你理清今天讲的所有内容:
常见问题与解决方案
| 问题 | 原因 | 解决方法 |
|---|---|---|
| 录制的视频没有声音 | MediaRecorder 未捕获音频轨道 | 检查 stream.getAudioTracks() 是否为空 |
| 录制文件太大 | 码率设置过高 | 设置 videoBitsPerSecond 参数,比如 2.5Mbps |
| 画中画画面卡顿 | Canvas 绘制频率太高 | 使用 requestAnimationFrame 代替 setInterval |
| 浏览器不支持 webm | Safari 等浏览器限制 | 使用 MediaRecorder.isTypeSupported() 检测 |
总结一下:今天咱们从最基础的摄像头录制,到屏幕录制,再到画中画合成,最后到纯音频录制,把 WebRTC 录制的四种常见场景都过了一遍。核心就是 MediaRecorder + MediaStream 的组合拳。你想想看,掌握了这些,做个视频会议录制功能、在线教育录课工具,是不是心里就有底了?