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

如何将HTML Canvas与ffmpeg.wasm绑定生成视频(无需服务器)

将Canvas物理模拟帧编码为视频(基于ffmpeg.wasm)

完全可以通过ffmpeg.wasm实现将Canvas渲染的物理模拟帧转换为视频,核心流程是按固定帧率生成模拟帧 → 捕获Canvas帧数据写入ffmpeg虚拟文件系统 → 调用ffmpeg命令编码为视频。以下是具体实现方案,适配你提供的物理模拟器代码:

1. 初始化ffmpeg.wasm

先完成ffmpeg.wasm的基础加载(可通过npm或CDN引入):

import { createFFmpeg } from '@ffmpeg/ffmpeg';

// 初始化ffmpeg实例,开启日志便于调试
const ffmpeg = createFFmpeg({ log: true });
await ffmpeg.load();

2. 改造物理模拟器为离线帧生成模式

实时渲染的requestAnimationFrame依赖屏幕刷新率,无法保证视频帧率稳定,需要改成固定时间步进的离线渲染模式,按目标视频帧率生成每帧:

// 视频参数配置
const VIDEO_FPS = 30;
const FRAME_TIME_MS = 1000 / VIDEO_FPS; // 单帧时长(毫秒)
const TOTAL_FRAMES = 180; // 生成6秒视频(30fps × 6s)

// 重置模拟器状态
let simulationTime = 0;
const canvas = document.getElementById('your-canvas');
const ctx = canvas.getContext('2d');
let physicsObjects = [/* 你的物理对象实例数组 */];

// 生成单帧并写入ffmpeg虚拟文件
async function renderAndSaveFrame(frameIndex) {
  // 计算当前帧的时间增量
  const dt = FRAME_TIME_MS / 1000;
  
  // 清空画布并更新渲染物理对象
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  for (const obj of physicsObjects) {
    obj.update(dt);
    obj.render(canvas, ctx);
  }
  
  // 将Canvas内容转为Uint8Array格式
  const dataUrl = canvas.toDataURL('image/png');
  const rawData = atob(dataUrl.split(',')[1]);
  const uint8Frame = Uint8Array.from(rawData, char => char.charCodeAt(0));
  
  // 写入ffmpeg虚拟文件系统,命名格式适配ffmpeg序列帧解析
  ffmpeg.FS('writeFile', `frame_${String(frameIndex).padStart(3, '0')}.png`, uint8Frame);
  
  simulationTime += FRAME_TIME_MS;
}

// 批量生成所有帧
async function generateAllFrames() {
  for (let i = 0; i < TOTAL_FRAMES; i++) {
    await renderAndSaveFrame(i);
  }
}

3. 调用ffmpeg编码视频

帧生成完成后,执行ffmpeg命令将序列帧编码为MP4(或其他格式):

await generateAllFrames();

// 执行ffmpeg编码命令:序列帧转MP4,指定帧率、编码器
await ffmpeg.run(
  '-framerate', String(VIDEO_FPS),
  '-i', 'frame_%03d.png', // 匹配之前的帧命名格式
  '-c:v', 'libx264', // H.264编码器
  '-pix_fmt', 'yuv420p', // 兼容大部分播放器的像素格式
  'physics_sim.mp4'
);

// 导出并下载视频
const videoData = ffmpeg.FS('readFile', 'physics_sim.mp4');
const downloadUrl = URL.createObjectURL(new Blob([videoData.buffer], { type: 'video/mp4' }));
const downloadLink = document.createElement('a');
downloadLink.href = downloadUrl;
downloadLink.download = 'physics_simulation.mp4';
downloadLink.click();

// 清理ffmpeg虚拟文件系统
for (let i = 0; i < TOTAL_FRAMES; i++) {
  ffmpeg.FS('unlink', `frame_${String(i).padStart(3, '0')}.png`);
}
ffmpeg.FS('unlink', 'physics_sim.mp4');

关键优化与注意事项

  • 帧率一致性:必须用固定dt计算物理更新,避免实时渲染的帧率波动导致视频速度异常。
  • 性能优化:如果生成大量帧,建议用BMP格式替代PNG(canvas.toDataURL('image/bmp')),编码速度更快且内存占用更低。
  • 分辨率适配:Canvas的width和height决定视频分辨率,建议设置为标准尺寸(如1280×720),避免后期拉伸。
  • ffmpeg内核配置:若出现编码错误,确保加载的ffmpeg内核包含所需编码器(如libx264),可在createFFmpeg时指定corePath指向对应内核文件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 16:05:30