同一video标签同时用于录制播放时第三次启动录制MediaStream中断报错
问题排查与修复方案
你遇到的DOMException: Failed to execute 'start' on 'MediaRecorder': There was an error starting the MediaRecorder错误,本质是媒体资源未正确释放、传入MediaRecorder的流处于非活跃状态导致的初始化失败,核心问题点和修复方案如下:
核心问题原因
- 重复创建捕获流:Firefox兼容逻辑中连续两次调用
mozCaptureStream(),生成了两个独立的MediaStream实例,多余的流未被释放会占用媒体资源 - 媒体资源未正确释放:
- 停止录制时仅将
videoElement.srcObject置空,未主动停止摄像头流的所有音视频轨道,设备占用未释放 - 每次播放录制视频时调用
URL.createObjectURL()生成的Blob地址未调用URL.revokeObjectURL()释放,内存持续堆积
- 停止录制时仅将
- 录制器实例未清理:上一次录制的
MediaRecorder实例停止后未解除事件绑定、置空引用,残留资源干扰新实例初始化 - 流状态不一致:第三次启动录制时复用的
this.videoStream可能已经处于非活跃状态,未做有效性校验就直接赋值给video标签
修复代码建议
停止录制逻辑优化
// 先停止录制器,再处理流 this.recorder.stop(); // 清理旧录制器实例 this.recorder.ondataavailable = null; this.recorder.onerror = null; this.recorder = null; // 停止所有摄像头流轨道,释放设备占用 if (this.videoStream) { this.videoStream.getTracks().forEach(track => track.stop()); this.videoStream = null; } this.videoElement.pause(); this.videoElement.srcObject = null; // 释放上一次的Blob URL,避免内存泄漏 if (this.recordedBlobUrl) { URL.revokeObjectURL(this.recordedBlobUrl); } const recordedBlob = new Blob(data); // 存储生成的Blob地址,方便后续释放 this.recordedBlobUrl = URL.createObjectURL(recordedBlob); this.videoElement.src = this.recordedBlobUrl;
启动录制逻辑优化
record(): void { if (this.videoElement.srcObject === null) { this.videoElement.removeAttribute('src'); // 重新启动摄像头获取新的有效流,不要复用旧的videoStream this.startCamera(); // 等待流加载完成后再执行录制,避免流未就绪就捕获 this.videoElement.onloadedmetadata = () => { this.handleCaptureStream(); }; } else { this.handleCaptureStream(); } } private handleCaptureStream(): void { const sUsrAg = navigator.userAgent; let captureStream: MediaStream; if (sUsrAg.indexOf('Firefox') > -1) { // 仅调用一次捕获方法,不要重复生成流 captureStream = this.videoElement.mozCaptureStream(); } else { captureStream = this.videoElement.captureStream(); } this.startRecordingMedia(captureStream); }
启动摄像头逻辑优化
startCamera(): void { // 先清理旧的流,避免设备占用冲突 if (this.videoStream) { this.videoStream.getTracks().forEach(track => track.stop()); } navigator.mediaDevices .getUserMedia({ video: true, audio: { echoCancellation: {exact: true} }, }) .then((stream) => { this.videoStream = stream; this.addStream(); this.videoElement.play(); }) .catch((err) => { console.error('摄像头启动失败:', err); }); }
内容的提问来源于stack exchange,提问作者HYDRA LAZER
相关产品推荐
相关产品推荐

