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

Mac及iPhone端Safari浏览器中使用MediaRecorder录制视频的上传格式异常问题

Mac及iPhone端Safari浏览器中使用MediaRecorder录制视频的上传格式异常问题

遇到这种跨浏览器的MediaRecorder兼容问题确实挺挠头的,我来帮你拆解下Safari这里可能的问题点,以及对应的解决思路:

一、最可能的坑:Blob生成时未显式指定MIME类型

从你贴的代码来看,你只保存了录制的chunks,但没展示把chunks合并成Blob并上传的关键部分。这在Safari里是个高频问题:
如果你直接用new Blob(recordedChunks)而不指定type参数,Safari会默认给Blob设置application/octet-stream类型,而非你期望的MP4类型,后端自然会识别为不支持的格式。

解决办法:
合并chunks时必须显式传入正确的MIME类型,上传时还要给文件指定.mp4后缀(部分后端会优先通过扩展名识别文件类型):

// 补充你的上传逻辑
const uploadRecordedVideo = async () => {
  // 显式指定Blob的MIME类型
  const videoBlob = new Blob(recordedChunks, { type: returnVideoMimeType() });
  console.log("生成的Blob类型:", videoBlob.type); // 控制台确认类型是否正确

  const formData = new FormData();
  // 第三个参数指定文件名带.mp4后缀
  formData.append("video", videoBlob, `recording_${Date.now()}.mp4`);

  try {
    const response = await fetch("你的后端上传接口", {
      method: "POST",
      body: formData,
    });
    // 处理上传响应
  } catch (err) {
    console.error("上传失败:", err);
  }
};

二、Safari的MP4封装格式特殊性

Safari的MediaRecorder生成的MP4文件,默认会把moov原子(MP4的元数据块)放在文件末尾,而Chrome等浏览器会把moov放在开头。部分后端的文件解析器对这个位置敏感,会判定格式不合法。

解决办法:
用第三方库mp4box.js调整moov原子的位置到文件开头:

  1. 先安装依赖:npm install mp4box
  2. 编写处理函数:
import MP4Box from "mp4box";

// 修正Safari生成的MP4文件结构
const fixSafariMP4 = async (originalBlob: Blob): Promise<Blob> => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.onload = (e) => {
      const arrayBuffer = e.target?.result as ArrayBuffer;
      const mp4File = MP4Box.createFile();

      mp4File.onError = reject;
      mp4File.onReady = () => {
        // 把moov原子移到文件开头
        const fixedBuffer = MP4Box.write(mp4File, { moovStart: true });
        const fixedBlob = new Blob([fixedBuffer], { type: originalBlob.type });
        resolve(fixedBlob);
      };

      mp4File.appendBuffer(arrayBuffer);
      mp4File.flush();
    };
    reader.readAsArrayBuffer(originalBlob);
  });
};

// 在上传前调用修正函数
const uploadRecordedVideo = async () => {
  let videoBlob = new Blob(recordedChunks, { type: returnVideoMimeType() });
  // 针对Safari做格式修正
  if (/^((?!chrome|android).)*safari/i.test(navigator.userAgent)) {
    videoBlob = await fixSafariMP4(videoBlob);
  }

  const formData = new FormData();
  formData.append("video", videoBlob, `recording_${Date.now()}.mp4`);
  // 后续上传逻辑...
};

三、后端MIME类型校验的细节问题

你的returnVideoMimeType返回的是带codecs参数的完整类型(video/mp4;codecs=avc1.42E01E,mp4a.40.2),但部分后端的校验逻辑可能只识别简化版的video/mp4,会忽略带codecs的类型。

解决办法:
合并Blob时改用简化的MIME类型,或者调整returnVideoMimeType函数返回不带codecs的版本:

// 方式1:生成Blob时用简化类型
const videoBlob = new Blob(recordedChunks, { type: "video/mp4" });

// 方式2:修改returnVideoMimeType函数
export const returnVideoMimeType = () => {
  const mimeTypes = [
    'video/mp4', // 优先用简化版
    'video/mp4;codecs=avc1.42E01E,mp4a.40.2',
    'video/webm;codecs=vp9,opus',
    'video/webm;codecs=vp8,opus',
    'video/webm',
    '',
  ];

  if (MediaRecorder.isTypeSupported) {
    return mimeTypes.find((mimeType) => MediaRecorder.isTypeSupported(mimeType)) || '';
  }

  return 'video/mp4';
};

四、快速排查步骤

  1. 在Safari控制台打印videoBlob.type,确认Blob的实际MIME类型是否为video/mp4相关;
  2. 把生成的Blob下载到本地(用URL.createObjectURL生成下载链接),用QuickTime或ffmpeg查看文件实际格式,确认是否为标准MP4;
  3. 测试直接上传本地MP4文件到后端,看是否能成功,排除后端本身的格式限制。

备注:内容来源于stack exchange,提问作者the preacher

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.14 13:39:51