DEV Community

MartinDelophy
MartinDelophy

Posted on

浏览器视频编辑器如何兼容 MKV?LibAV.js、WebCodecs 与 FFmpeg.wasm 实践

前言

我们正在开发一款运行在浏览器中的 AI 视频编辑器,支持素材导入、时间线剪辑、字幕、AI 配音、音频处理和视频导出。

早期版本主要支持浏览器原生兼容较好的 MP4 和 WebM。但在真实使用中,用户还会上传 MKV、MOV 等文件,其中可能包含 H.264、H.265、AAC、AC3 等不同编码。它们能在桌面播放器中正常打开,却不一定能被浏览器直接播放。

为此,我们重新设计了媒体导入和导出链路。

一、格式兼容不只是扩展名

MP4、MKV、MOV 和 WebM 是容器,H.264、VP9、AAC 和 AC3 才是音视频编码。

同样是 MKV,内部可能是 H.264 + AAC,也可能是 H.265 + AC3。因此不能只根据文件名判断素材是否可用。导入时需要识别容器、视频编码、音频编码、时长、分辨率和轨道信息。

用户导入文件
    ↓
识别文件签名和容器
    ↓
探测音视频轨道
    ↓
检测浏览器解码能力
    ↓
选择成本最低的处理路径
Enter fullscreen mode Exit fullscreen mode

二、为什么不把所有文件都交给 FFmpeg.wasm?

最直接的方案,是先把所有输入转成 MP4。它兼容性强,但在浏览器中也有明显成本:

  • WebAssembly 运行时较大;
  • 初始化和完整转码需要时间;
  • 原文件、中间数据与输出文件会同时占用内存;
  • 即使原视频已经是 H.264,也可能被重复编码。

因此,我们没有移除 FFmpeg.wasm,而是把它从默认入口调整为兼容回退方案。

三、混合媒体处理架构

目前编辑器采用三层处理方式:

浏览器原生能力
      ↓
LibAV.js + WebCodecs
      ↓
FFmpeg.wasm 兼容回退
Enter fullscreen mode Exit fullscreen mode

浏览器原生路径

对于标准 MP4、WebM 等浏览器可以直接播放的素材,继续使用 video 元素和 Web Audio API。这条路径启动快、内存成本低,适合大多数用户。

LibAV.js + WebCodecs 路径

对于 MKV、MOV 等浏览器不能直接识别的容器,使用 LibAV.js 探测并解封装轨道,再把兼容的视频数据交给 WebCodecs。

例如,一个 MKV 中包含 H.264 视频和 AC3 音频时,可以分别处理:

H.264 视频 → 解封装 → WebCodecs 解码
AC3 音频  → LibAV.js 解码 → PCM/WAV
Enter fullscreen mode Exit fullscreen mode

这样不必为了一个不兼容的音频轨道而重新编码整段视频。

FFmpeg.wasm 回退路径

如果遇到浏览器和 WebCodecs 都无法处理的编码、异常时间戳或特殊像素格式,再通过 FFmpeg.wasm 转码。

核心原则是:能原生处理就不转码,能解封装就不重新编码,只有必要时才走完整转码。

四、性能优化

为了避免扩展格式支持拖慢普通 MP4,我们做了几项调整。

延迟加载

LibAV.js 和 FFmpeg.wasm 不随首屏一起初始化。只有检测到需要兼容处理的文件时才动态加载。

使用 Web Worker

媒体探测、解封装和音频解码会消耗较多 CPU。把这些任务放进 Worker,可以避免阻塞时间线拖动和预览交互。

缓存探测结果

同一个素材的容器、编码、时长和轨道信息只探测一次,缩略图、预览和导出尽量复用结果。

支持任务取消

用户删除素材或关闭项目后,后台探测和解码任务会立即终止,避免继续消耗 CPU 与内存。

五、统一内部媒体模型

支持更多格式后,不能让时间线持续感知 MP4、MKV 和 MOV 的差异。

无论输入是什么格式,最终都会转换成统一的媒体描述,包含素材 ID、容器、时长、视频编码、分辨率、帧率、音频采样率和声道数。格式兼容层负责处理差异,时间线只面对统一的媒体源和时间范围。

这样后续增加新格式时,不需要重写剪辑、字幕与导出模块。

六、简化导出选项

底层能力增加后,我们曾在导出面板中提供编码器、分辨率、帧率、质量等级、关键帧间隔和多种预设。但对大多数用户来说,参数过多反而增加使用成本。

最终主要保留四种组合:

  • MP4 · H.264 + AAC:默认选项,兼容性最好;
  • MOV · H.264 + AAC:方便导入 Final Cut、Premiere 和 DaVinci;
  • WebM · VP9 + Opus:适合网页和较高压缩率;
  • WebM · VP8 + Opus:兼容较旧的 WebM 工作流。

高级参数主要保留视频码率和音频码率。底层能力可以复杂,但产品界面应该简单。

七、修复 5 秒视频导出成 17 秒的问题

改造过程中,我们遇到一个典型问题:浏览器中的时间线只有 5 秒,导出的文件却长达 17 秒。

原因是旧逻辑把“根据脚本文字估算的配音时长”也用于计算导出范围。即使真实时间线只有 5 秒,只要脚本估算为 17 秒,导出器就会继续生成空白帧。

修复后,导出时长只取时间线中真实存在的视觉、字幕、配音、音乐和贴纸轨道终点。

const frameCount = Math.ceil(duration * frameRate);
Enter fullscreen mode Exit fullscreen mode

5 秒、30 fps 的项目应当导出 150 帧,而不是依赖播放状态或脚本预测值。

八、确定性离线渲染

高质量导出采用逐帧离线渲染:

时间线时间戳
    ↓
渲染当前画面
    ↓
WebCodecs 视频编码
    ↓
OfflineAudioContext 混音
    ↓
封装为 MP4、MOV 或 WebM
Enter fullscreen mode Exit fullscreen mode

每一帧都由准确时间戳驱动,因此页面卡顿、后台标签页限速或预览掉帧不会改变最终文件的帧数和时长。MediaRecorder 仍然保留,但主要作为浏览器能力不足时的兼容方案。

九、验证真正的导出结果

导出成功不能只看是否生成了 Blob。自动化测试还会重新读取产物并验证:

  • 容器和编码格式;
  • 视频与音频轨道;
  • 分辨率和总时长;
  • 视频帧数;
  • 字幕与透明贴纸是否出现在画面中;
  • 音频轨道是否真实存在。

相比只判断界面是否显示“导出完成”,重新解析和解码产物更可靠。

总结

浏览器视频编辑器兼容 MKV 和 MOV,并不是简单增加两个扩展名,而是要解决容器探测、编解码能力判断、解封装、音频处理、时间戳和导出验证等一整套问题。

我们的最终选择是:优先浏览器原生处理,必要时使用 LibAV.js + WebCodecs,最后由 FFmpeg.wasm 兼容回退。

这样既保留了普通 MP4 的快速体验,也让 MKV、MOV 等素材有机会直接进入浏览器编辑流程。对于用户来说,最终体验仍然应该简单:上传素材、完成编辑、选择格式并导出。复杂性应该尽可能留在系统内部。

项目地址

Top comments (0)