You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

同一video标签同时用于录制播放时第三次启动录制MediaStream中断报错

问题排查与修复方案

你遇到的DOMException: Failed to execute 'start' on 'MediaRecorder': There was an error starting the MediaRecorder错误,本质是媒体资源未正确释放、传入MediaRecorder的流处于非活跃状态导致的初始化失败,核心问题点和修复方案如下:

核心问题原因

  • 重复创建捕获流:Firefox兼容逻辑中连续两次调用mozCaptureStream(),生成了两个独立的MediaStream实例,多余的流未被释放会占用媒体资源
  • 媒体资源未正确释放:
    1. 停止录制时仅将videoElement.srcObject置空,未主动停止摄像头流的所有音视频轨道,设备占用未释放
    2. 每次播放录制视频时调用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.01 13:54:06