首页
/ 用 Mediabunny 读取视频时长:在 Remotion 中跨浏览器、Node.js 与 Bun 获取视频长度的统一方案

用 Mediabunny 读取视频时长:在 Remotion 中跨浏览器、Node.js 与 Bun 获取视频长度的统一方案

2026-09-08 19:27:08作者:盛欣凯Ernestine

Mediabunny 是 Remotion 官方技能(remotion-multimedia)中推荐的浏览器端多媒体处理库,可安全、跨环境地解析音频与视频元数据。本文以技能文档 get-video-duration.md 为骨架,讲解如何用 Mediabunny 的 Input + computeDuration() 获取视频时长(单位:秒),覆盖远程 URL、Remotion public/ 目录静态资源以及 Node.js / Bun 本地文件三类场景,并结合仓库内真实用法给出源码级佐证。读完即可写出一个可在浏览器、服务端通用复用的 getVideoDuration 工具函数。

Mediabunny 的能力定位与本技能文档在仓库中的位置

Mediabunny 是一个处理浏览器中音视频的多媒体库。Remotion 仓库将其作为官方建议的底层能力接入自身多个包(例如 packages/mediapackages/media-parserpackages/studio 等都在 package.json 中声明了 mediabunny 依赖),并以一套"技能(Skill)"文档对 Agent / LLM 给出规范用法。这些技能存放在 packages/skills/skills/remotion-multimedia/ 目录下,入口 SKILL.md 将其描述为 "Interacting with Mediabunny",并按能力拆成三份子文档:

三者共享同一套 API 风格(构造 Input、选择 source、再调用解析方法),掌握了视频时长的读取方式,其他元数据读取几乎可以举一反三。

关于 Mediabunny 的跨环境能力,技能文档明确表述为:It works in browser, Node.js, and Bun environments(在浏览器、Node.js 与 Bun 环境中均可运行)。这也是它被选为 Remotion 统一媒体解析方案的重要原因——media-parser 的 parse-media.ts 中甚至留下了 @deprecated Use Mediabunny instead 的迁移提示,说明该项目正在把元数据解析能力收敛到 Mediabunny 上。

远程 URL 视频:从构造 Input 到 computeDuration()

读取视频时长的核心思路是:把视频源封装进 Mediabunny 的 Input,再用 computeDuration() 异步计算秒数。技能文档给出了可直接落地的实现:

import { Input, ALL_FORMATS, UrlSource } from "mediabunny";

export const getVideoDuration = async (src: string) => {
  const input = new Input({
    formats: ALL_FORMATS,
    source: new UrlSource(src),
  });

  const durationInSeconds = await input.computeDuration();
  return durationInSeconds;
};

这段代码中每个要素都有明确职责:

  • Input:Mediabunny 的统一解析入口,它持有"解析哪些格式"与"数据从哪来"两项配置;
  • formats: ALL_FORMATS:告诉解析器允许匹配全部封装/容器格式。由于 Input 需要自行探测媒体容器类型,传入 ALL_FORMATS 可免去预先判断视频是 MP4、WebM 还是其他容器的工作;
  • UrlSource:以远程 URL 字符串作为数据源。只要字符串指向一个可访问的视频地址即可;
  • await input.computeDuration():返回视频时长,单位为秒,且为浮点数(如 10.5 表示 10.5 秒)。

computeDuration() 是异步方法,因此在组件、事件回调或服务端函数中调用时记得使用 await

调用示例

const duration = await getVideoDuration("https://remotion.media/video.mp4");
console.log(duration); // e.g. 10.5 (seconds)

返回结果可直接用于 Remotion 的时间轴、进度条渲染或素材校验等场景——例如判断某段远程视频是否超出合成(composition)时长,再决定是否截断或提示用户。

Remotion 组件中调用:处理好异步生命周期

由于该函数返回 Promise<number>,若在 Remotion 组件内部使用,建议在数据就绪前先返回一个占位 UI(或配合 useEffect 缓存结果),避免"渲染时 await"导致的竞态。技能文档的示例函数是无状态的纯异步工具,天然适合放在 Remotion Studio 的 Props 编辑面板、媒体检查器或渲染前校验逻辑中复用。

读取 public/ 目录内的视频:务必包一层 staticFile()

在 Remotion 项目中,放在 public/ 目录中的视频不能直接把文件系统路径传给 getVideoDuration,必须先用 Remotion 的 staticFile() 把文件名解析成可访问的静态资源 URL。技能文档明确强调这一点:

import { staticFile } from "remotion";

const duration = await getVideoDuration(staticFile("video.mp4"));

这里 staticFile("video.mp4") 会解析为类似 /video.mp4 的路径(在配置了 staticBase 的浏览器环境中还会自动带上该前缀),从而让 UrlSource 能正常加载它。注意 staticFile() 接收的应当是 public/ 目录内文件的名称,而不是裸路径。

static-file.ts 的实现可以佐证其设计约束:它会对传入值做严格校验并抛出 TypeError,包括——

  • 传入 http://https:// 开头的远程 URL(应直接传 URL,不要包 staticFile);
  • 传入 .././ 开头的相对路径,或 /Users/homeC: 等绝对路径;
  • 传入带 public/ 前缀的路径;
  • 传入 null / undefined

同时 staticFile() 自 Remotion 4.0 起会自己完成按路径片段的 URL 编码(encodeBySplitting 逐段调用 encodeURIComponent),所以调用方无需(也不应)再手动包一层 encodeURIComponent()。这正是技能文档要求"把 public 目录中的文件路径交给 staticFile() 包裹"的底层原因——它保证 URL 编码、静态基址前缀都得到正确处理,避免本地播放正常、换到浏览器后 404 的隐患。

Node.js 与 Bun 环境:改用 FileSource

当视频不在远程、而是来自本地文件系统时,需把数据源从 UrlSource 换成 FileSource,其余 API 保持一致:

import { Input, ALL_FORMATS, FileSource } from "mediabunny";

const input = new Input({
  formats: ALL_FORMATS,
  source: new FileSource(file), // File object from input or drag-drop
});

const durationInSeconds = await input.computeDuration();

其中 file 通常来自浏览器中的文件选择(<input type="file">)或拖拽(drag-and-drop)得到的 File 对象;在 Node.js / Bun 这类服务端运行时中,则可基于本地文件构造对应的文件句柄传入 FileSource。这使同一套 Input 抽象得以在浏览器与 SSR、脚本执行场景间无缝切换——浏览器端用 UrlSource/FileSource(File),Node.js 与 Bun 中用 FileSource 指向本地文件。

仓库源码佐证:为什么"元数据优先、computeDuration 兜底"是推荐姿势

computeDuration() 并非唯一的时长来源。在仓库的 packages/media/src/get-duration-or-compute.ts 中,Remotion 自己给出了更高效的组合策略:

import type {Input} from 'mediabunny';

export const getDurationOrCompute = async (input: Input) => {
	return (
		(await input.getDurationFromMetadata(undefined, {
			skipLiveWait: true,
		})) ?? input.computeDuration(undefined, {skipLiveWait: true})
	);
};

这段源码揭示了两个要点:

  1. Mediabunny 的 Input 还提供 getDurationFromMetadata(),它优先从容器/轨道的元数据中直接读取时长(通常无需完整解码、速度更快);
  2. 元数据读取可能拿不到结果(返回空值,例如流式录制、时长信息未写在文件头部的视频),因此用 ?? 回退到 computeDuration() 做完整解析,保证最终一定能得到数值。

技能文档直接使用 computeDuration(),胜在逻辑最简单、一调即得;在追求性能且格式可控的场景,可参考上述源码按"先元数据、再全量计算"的顺序优化。另需留意的是,文档页 get-video-metadata.mdx 提醒:旧版 @remotion/media-utilsgetVideoMetadata() 不支持 Linux 上的 H.265 视频并对部分格式解析失败,且其返回的 durationInSeconds 可能为 Infinity(时长未写在文件开头时,例如边录边编码的摄像头视频)。使用 Mediabunny 是官方文档给出的替代方案;同时,若你的视频确实存在"时长写在文件末尾"的录制型格式,仍建议对用户上传素材做边界处理或先用 FFmpeg 重编码将时长信息前置。

安装与版本前提

Mediabunny 是独立发布的 npm 包。在本仓库中,它通过依赖目录表(catalog)在多个包中被引用(如 packages/media/package.jsonpackages/media-parser/package.json 中的 "mediabunny": "catalog:"),而模板类项目(如 packages/template-three/package.json)直接锁定了 mediabunny 版本号。在读者自己的 Remotion 项目中,若尚未安装,只需执行包管理器安装 mediabunny,即可在浏览器端、Node.js 或 Bun 中导入本文所用的 InputALL_FORMATSUrlSourceFileSource

与其他媒体技能文档的衔接

Mediabunny 读取媒体元数据的 API 高度统一,本文的模式可以平移到仓库内另两份技能文档:

  • 读取音频时长:把 UrlSource 指向音频地址并调用同样的 computeDuration(),详见 get-audio-duration.md(内部同样覆盖 staticFile() 包裹与 FileSource 两种场景);
  • 读取视频宽高:改用 input.getPrimaryVideoTrack() 后读取 displayWidth / displayHeight,详见 get-video-dimensions.md

小结

本文围绕 Remotion 技能文档 get-video-duration.md 给出的方案,总结了用 Mediabunny 获取视频时长的完整实践路径:

场景 数据源类型 关键代码
远程 URL new UrlSource(src) new Input({formats: ALL_FORMATS, source}) + computeDuration()
Remotion public/ 目录 new UrlSource(staticFile("video.mp4")) 先用 staticFile() 解析,再走 URL 分支
浏览器本地文件 / Node.js / Bun new FileSource(file) 同一 Input,仅更换 source 类型

三个可以记住的要点:

  1. computeDuration() 返回的是以秒为单位的浮点数,调用是异步的;
  2. Remotion 项目里凡是 public/ 目录的文件,一律先用 staticFile() 包裹后再作为 URL 传入;
  3. 跨浏览器 / Node.js / Bun 的本质差异只在于 source 的构造方式UrlSource 还是 FileSource),Input 与解析调用完全一致。

掌握了这套 API 之后,把示例扩展成"读取后自动校验时长并写入 Remotion Props""批量生成媒体资源清单"等能力,也就顺理成章了。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
docsdocs
暂无描述
Markdown
899
5.83 K
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.14 K
2.76 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
860
1.35 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
925
1.85 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.84 K
1.02 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
533
601
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.37 K
1.46 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
548
395
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.04 K
525