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

使用MediaRecorder录制时如何按间隔获取可正常播放的分段视频?

MediaRecorder 分段录制上传解决方案

你当前的实现存在的问题是:MediaRecorder 输出的是连续的容器格式流,只有首次触发 ondataavailable 返回的分片携带完整的视频文件头,后续分片仅包含裸音视频帧数据,没有文件头信息,因此无法独立播放;同时每个单独分片没有容器尾标识,所以第一个分片播放时会抛出File ended prematurely的警告。


方案1:分片可独立播放(高容错场景)

适合要求录制中途断开后,已上传的所有分片都能单独正常使用的场景,无需后端拼接。

实现逻辑

每段分片录制完成后停止当前 MediaRecorder 实例,重新实例化新的录制器,每次停止触发的 ondataavailable 拿到的 blob 都是带完整文件头、尾的独立可播放文件。

代码示例

let mediaRecorder = null;
const CHUNK_DURATION = 10000; // 10秒分片
let recordStream = null; // 全局保留录屏流,避免重复申请权限

// 启动录制入口
const handleRecord = function ({stream}) {
  recordStream = stream;
  startNewRecorderInstance();
};

// 启动新的录制器实例
const startNewRecorderInstance = () => {
  // 明确指定编码格式,避免不同浏览器默认值不一致导致兼容性问题
  mediaRecorder = new MediaRecorder(recordStream, {
    mimeType: 'video/webm;codecs=vp8,opus'
  });

  mediaRecorder.ondataavailable = (e) => {
    if (e.data.size > 0) {
      uploadVideoPart(e.data); // 此处拿到的每个分片都是可独立播放的完整文件
    }
  };

  // 当前分片录制结束后,自动启动下一段录制
  mediaRecorder.onstop = () => {
    if (recordStream.active) {
      startNewRecorderInstance();
    }
  };

  mediaRecorder.start();
  // 到分片时长后停止当前录制
  setTimeout(() => {
    if (mediaRecorder.state === 'recording') {
      mediaRecorder.stop();
    }
  }, CHUNK_DURATION);
};

// 停止整个录制流程
const stopFullRecord = () => {
  if (mediaRecorder?.state === 'recording') {
    mediaRecorder.stop();
  }
  recordStream?.getTracks().forEach(track => track.stop());
};

优缺点

  • 优点:每个分片独立完整,任意分片上传失败不影响其他分片,容错性极高
  • 缺点:每次重启录制器会丢失几毫秒的帧数据,对录制连续性要求极高的场景不适用

方案2:分片需后端合并(高连续度场景)

适合要求录制无帧丢失,最终只需要一个完整视频文件的场景。

实现逻辑

无需重建 MediaRecorder 实例,保持原有间隔触发 ondataavailable 的逻辑,给每个分片增加递增序号,后端按序号将所有分片二进制拼接即可得到完整可播放的视频文件。

代码示例

const handleRecord = function ({stream}) {
  // 明确指定编码格式
  const mediaRecorder = new MediaRecorder(stream, {
    mimeType: 'video/webm;codecs=vp8,opus'
  });
  let chunkIndex = 0;

  mediaRecorder.ondataavailable = (e) => {
    if (e.data.size > 0) {
      uploadVideoPart({
        data: e.data,
        index: chunkIndex // 携带序号,后端按顺序拼接
      });
      chunkIndex++;
    }
  };

  // 录制结束时给后端发送结束标记
  mediaRecorder.onstop = () => {
    uploadVideoPart({
      isEnd: true,
      totalChunks: chunkIndex
    });
  };

  mediaRecorder.start(10000);
};

注意事项

  • 第一个分片单独播放出现的提前结束警告是正常现象,拼接完成后警告会消失
  • 必须保证分片按序号顺序拼接,乱序会导致完整文件损坏
  • 这种方案无帧丢失,录制连续性好,但只要有一个分片丢失,整个视频就无法正常播放

内容的提问来源于stack exchange,提问作者fguillen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 04:06:07