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

React前端Canvas录制MP4上传Node.js后端后文件异常问题

问题:Canvas录制的MP4无法被Windows识别,需直接生成可用MP4

问题概述

前端通过Canvas的captureStream()结合MediaRecorder生成MP4格式视频,后端用Node.js + express-fileupload接收保存后,文件可在VLC等播放器正常播放,但Windows系统无法正确识别该MP4文件。改用webm格式或经转码工具处理后的MP4则正常,需要实现无需手动转码直接生成Windows兼容的MP4。

前端代码

const canvasResult = document.getElementById("canvasResult") as HTMLCanvasElement;
const createVideo = () => {
  return new Promise((resolve) => {
    const chunks: any[] = []; // 存储录制的媒体片段
    const stream = canvasResult.captureStream(); // 获取Canvas的MediaStream
    const rec = new MediaRecorder(stream); // 初始化录制器

    rec.ondataavailable = (e) => chunks.push(e.data);
    rec.onstop = (e) => {
      setLoadingCanvaGif(100);
      resolve(new Blob(chunks, { type: "video/mp4" }));
    };

    rec.start();
    setTimeout(() => {
      clearInterval(canvaInterval);
      setShowCanva(false);
      rec.stop();
    }, 6000); // 6秒后停止录制
  });
};

const blobvideo = await createVideo();
const fileVideo = new File([blobvideo], "video.mp4", {
  type: blobvideo.type,
});
let formData = new FormData();
formData.append("file", fileVideo); // 修正原代码变量名错误

await axios.post(
  `/uploadFile`,
  formData,
  {
    headers: {
      "Content-Type": "multipart/form-data",
    },
  }
);

后端代码

// 使用express-fileupload
import { UploadedFile } from 'express-fileupload';
import path from 'path';

const file: UploadedFile = req?.files?.file;
const targetPath = path.join(__dirname, `../../uploads`);
const ms = Date.now(); // 示例随机ID
const fileName = path.join(targetPath, `/design_${ms}.mp4`);

await new Promise<void>((resolve, reject) => {
  file.mv(fileName, function (err: any) {
    if (err) {
      throw {
        code: 400,
        message: err,
      };
    }
    resolve();
  });
});

解决方案

1. 指定兼容Windows的MediaRecorder编码格式

浏览器默认的MediaRecorder生成的MP4可能使用了Windows不支持的编码(如VP9视频编码封装进MP4容器),需要明确指定H.264视频+AAC音频的MIME类型,这是Windows原生支持的标准MP4编码组合。

修改前端创建MediaRecorder的代码:

// 检查浏览器是否支持指定的兼容MIME类型
const compatibleMimeType = 'video/mp4; codecs="avc1.42E01E, mp4a.40.2"';
const isSupported = MediaRecorder.isTypeSupported(compatibleMimeType);

// 初始化录制器,优先使用兼容类型,否则降级到webm
const rec = new MediaRecorder(stream, {
  mimeType: isSupported ? compatibleMimeType : 'video/webm'
});

// 同时修改Blob的type为录制器实际使用的MIME类型
rec.onstop = (e) => {
  setLoadingCanvaGif(100);
  resolve(new Blob(chunks, { type: rec.mimeType }));
};
  • avc1.42E01E:基线级别(Baseline Profile)的H.264编码,兼容性覆盖绝大多数设备(包括Windows)
  • mp4a.40.2:AAC音频编码,同样是广泛兼容的音频格式

2. 后端自动转码兜底(可选)

如果部分浏览器不支持H.264的MP4录制,可以在后端集成ffmpeg实现自动转码,确保最终保存的文件是Windows兼容的标准MP4。

示例代码(使用fluent-ffmpeg库):

const ffmpeg = require('fluent-ffmpeg');
const fs = require('fs');

// 保存原始文件后执行转码
ffmpeg(fileName)
  .outputOptions([
    '-c:v libx264', // 指定视频编码为H.264
    '-c:a aac',     // 指定音频编码为AAC
    '-profile:v baseline', // 使用基线级别提升兼容性
    '-level 3.0'
  ])
  .save(path.join(targetPath, `design_${ms}_compatible.mp4`))
  .on('end', () => {
    // 转码完成后,可以删除原始文件,或者用转码后的文件替代
    fs.unlinkSync(fileName);
    console.log('转码完成,已生成兼容MP4');
  })
  .on('error', (err) => {
    console.error('转码失败:', err);
  });

注意:需要先安装fluent-ffmpeg依赖,并确保服务器环境中已安装ffmpeg程序。

3. 修正前端代码变量错误

原前端代码中formData.append("file", file);存在变量名错误,应改为fileVideo,避免上传空文件或错误文件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.12 04:20:35