news 2026/9/8 19:43:21

@remotion/vercel:在 Vercel Sandbox 中渲染 Remotion 视频的完整技术解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
@remotion/vercel:在 Vercel Sandbox 中渲染 Remotion 视频的完整技术解析

@remotion/vercel:在 Vercel Sandbox 中渲染 Remotion 视频的完整技术解析

【免费下载链接】remotion🎥 Make videos programmatically with React项目地址: https://gitcode.com/GitHub_Trending/re/remotion

本文围绕 Remotion 仓库中的@remotion/vercel包(packages/vercel/README.md)展开,讲解如何在 Vercel Sandbox 中创建渲染环境、上传项目 Bundle、执行视频/静帧渲染、跟踪进度并把产物上传到 Vercel Blob 的完整链路,所有结论均基于仓库内 packages/vercel/src/index.ts 等源码。

包定位与公开 API

@remotion/vercel的官方定位是“Render Remotion videos on Vercel Sandbox”(在 Vercel Sandbox 上渲染 Remotion 视频),当前仓库内版本为4.0.521,License 为 Remotion License(见 packages/vercel/package.json)。它依赖@remotion/rendererremotion,并以@vercel/sandbox >= 1.0.0作为 peer dependency(开发中固定使用1.6.0,配套@vercel/blob2.3.0)。

从 src/index.ts 的导出清单看,该包对外暴露 6 个运行时 API 和一批类型:

导出类型作用
createSandbox函数创建一个安装好系统依赖、JS 依赖、headless 浏览器与渲染脚本的沙箱
addBundleToSandbox函数把本地remotion bundle产物递归上传进沙箱
renderMediaOnVercel函数在沙箱内渲染视频(支持常规与 detached 两种模式)
renderStillOnVercel函数在沙箱内渲染单帧静图
getRenderProgress函数轮询 detached 渲染任务的文件式进度
uploadToVercelBlob函数把沙箱内产物上传到 Vercel Blob,返回 URL
类型导出typeVercelSandboxRenderProgressVercelBlobUploadOptionsChromiumOptionsCodec等(大部分自 types.ts 与@remotion/renderer再导出)

安装与版本约束

README 给出的安装方式:

npm install @remotion/vercel --save-exact

两条必须遵守的版本约束(来自 README 与 package.json):

  1. 所有remotion@remotion/*包必须对齐同一版本,需去掉版本号前的^使用精确版本;
  2. @vercel/sandbox是 peer dependency,调用方需自行安装(>=1.0.0)。

另外从沙箱初始化逻辑看,包内渲染脚本由构建产物(generated/*-script)注入,包内部通过remotion/version读取版本号,在沙箱内以精确版本安装@remotion/renderer@<VERSION>@remotion/compositor-linux-x64-gnu@<VERSION>(见 internals/install-js-dependencies.ts),也就是说沙箱内的渲染器版本永远与本地@remotion/vercel版本一致,这也是“版本必须对齐”这条约束的底层原因。

createSandbox:一步准备一个可渲染沙箱

createSandbox是整个流程的入口,完整实现在 src/create-sandbox.ts。签名与默认值:

createSandbox({ onProgress?, // (update: {progress, message}) => void | Promise<void> resources = {vcpus: 4}, // Vercel Sandbox 的 resources 参数,默认 4 vCPU timeoutInMilliseconds = 5 * 60 * 1000, // 沙箱创建/初始化超时,默认 5 分钟 } = {})

它返回VercelSandbox——即Sandbox & AsyncDisposable(定义见 types.ts),意味着可以用await using语法自动停止沙箱:创建时通过 internals/disposable.ts 给沙箱挂了[Symbol.asyncDispose],dispose 时调用sandbox.stop()

沙箱的准备工作按两个加权阶段推进(onProgress的进度权重:系统依赖 75%、下载浏览器 25%):

  1. 创建沙箱runtime: 'node24',即 Node 24 运行时;
  2. 安装系统依赖(75%):通过sudo dnf install安装 headless Chromium 在 Amazon Linux 2023 上运行所需的一组库:nssatkat-spi2-atkcups-libslibdrmlibXcompositelibXdamagelibXrandrmesa-libgbmalsa-libpangogtk3,以及补丁工具链patchelfzstdbinutils(见 internals/install-system-dependencies.ts)。进度是通过统计命令 stdout 行数(源码注释说明经验值为 272 行)线性估算的;
  3. 安装 JS 依赖:在沙箱内执行pnpm i @remotion/renderer @remotion/compositor-linux-x64-gnu @vercel/blob,版本锁定为当前包版本;
  4. 修补 compositor:Vercel Sandbox 的 Amazon Linux 2023 自带 glibc 2.34,而 Remotion 的 compositor 二进制要求 glibc 2.35。internals/patch-compositor.ts 会下载 Ubuntu 22.04 的libc6 2.35deb 包(主源为 Launchpad,备用源为 remotion.media),解压后用patchelfremotion二进制的动态链接指向捆绑的 glibc。源码注释明确指出:Remotion 并不官方支持 glibc 2.34,但可以通过这种方式打补丁;且只有remotion二进制需要修补,ffmpeg/ffprobe在 glibc 2.34 下工作正常;
  5. 下载 headless 浏览器(25%):写入并执行ensure-browser.mjs,以 JSON 日志形式回报browser-progress百分比(见 internals/install-browser.ts);
  6. 写入渲染脚本:向沙箱写入package.json{"type": "module"})以及render-video.mjsrender-still.mjsupload-blob.mjs三个脚本,后续渲染命令直接调用它们。

addBundleToSandbox:上传项目 Bundle

渲染前需要把npx remotion bundle生成的静态产物传进沙箱。src/add-bundle-to-sandbox.ts 的addBundleToSandbox({sandbox, bundleDir})行为如下:

  • 递归读取bundleDir下所有文件,统一转成 POSIX 分隔路径;
  • 先在沙箱内按祖先目录逐一mkDir,再批量writeFiles上传;
  • 所有文件统一放在沙箱内的remotion-bundle/目录下(常量REMOTION_SANDBOX_BUNDLE_DIR,见 internals/add-bundle.ts)。渲染时浏览器加载的 URL 因此固定为/vercel/sandbox/remotion-bundle
  • 目录创建或文件上传失败时,经由 internals/format-sandbox-error.ts 重新抛出带操作上下文(如“upload N bundle file(s)”)的错误,便于定位。

renderMediaOnVercel:渲染视频

完整实现在 src/render-media-on-vercel.ts。这是一个通过重载区分两种模式的函数:

  • 常规模式detached缺省或false):阻塞等待渲染结束,返回{sandboxFilePath, contentType},产物留在沙箱文件系统中,等待后续uploadToVercelBlob
  • detached 模式detached: true):必须同时提供vercelBlob: {blobToken, access, blobPath?},立即返回{sandboxId, cmdId, outputFile},由沙箱后台继续渲染,并用getRenderProgress轮询结果。

完整参数与默认值

以下参数表全部来自源码中解构默认值:

参数默认值说明
sandbox必填createSandbox返回的沙箱实例
compositionId必填目标 Composition 的 id
inputProps必填传给 Composition 的 props
outputFile/tmp/video.mp4沙箱内输出路径
codech264视频编码(类型Codec@remotion/renderer再导出)
crfnull恒定质量因子
imageFormat/pixelFormatnull帧图像格式与像素格式
envVariables{}注入渲染进程的环境变量
frameRangenull只渲染指定帧区间
everyNthFrame1抽帧渲染步长
proResProfilenullProRes 档位
chromiumOptions{}附加 Chromium 启动参数
scale1输出缩放比例
preferLosslessfalse偏好无损编码
enforceAudioTrackfalse强制包含音轨
disallowParallelEncodingfalse禁止并行编码
concurrencynull并发帧数
metadatanull写入容器的元数据
licenseKeynullRemotion 企业授权密钥
videoBitrate/audioBitrate/encodingMaxRate/encodingBufferSizenull码率相关(类型Bitrate
mutedfalse静音输出
numberOfGifLoopsnullGIF 循环次数
x264Preset/gopSizenullH.264 预设与 GOP 大小
colorSpacedefault色彩空间
jpegQuality80JPEG 帧质量
audioCodecnull音频编码
logLevelinfo日志级别
timeoutInMilliseconds30000浏览器/Composition 打开超时
forSeamlessAacConcatenationfalseAAC 无缝拼接
separateAudioTonull单独输出音频文件路径
hardwareAccelerationdisable硬件加速开关(沙箱环境默认关闭)
offthreadVideoCacheSizeInBytes/mediaCacheSizeInBytes/offthreadVideoThreadsnull离屏视频缓存与线程
sampleRate48000音频采样率
detachedfalse是否后台渲染
detachedSandboxTimeoutInMilliseconds30 * 60 * 1000detached 模式下沙箱超时延长时长(30 分钟)

底层执行方式

函数把上述参数组装成renderConfig,其中强制写死了几个与本地渲染不同的字段:chromeMode: 'headless-shell'browserExecutable: nullbinariesDirectory: nullrepro: false,以及serveUrl: '/vercel/sandbox/remotion-bundle'。随后:

const renderCmd = await sandbox.runCommand({ cmd: 'node', args: ['render-video.mjs', JSON.stringify(renderConfig)], detached: true, env: vercelBlob ? {BLOB_READ_WRITE_TOKEN: vercelBlob.blobToken} : undefined, });

即:把整个渲染配置作为 JSON 传给沙箱内的render-video.mjs脚本,脚本内部再调用@remotion/renderer完成渲染,并以 JSON 行形式把进度打到 stdout。常规模式下,客户端逐行解析stdout日志(非 JSON 的行直接忽略),把opening-browserselecting-compositionrender-progress三个阶段透传给onProgress,最后wait()等待命令结束;退出码非 0 时抛出Render failed: <stderr> <stdout>。detached 模式则先sandbox.extendTimeout(detachedSandboxTimeoutInMilliseconds)延长沙箱寿命,然后立即返回{sandboxId, cmdId, outputFile},供后续轮询。

renderStillOnVercel:渲染静帧

实现在 src/render-still-on-vercel.ts,参数更精简:

参数默认值
outputFile/tmp/still.png
frame0
imageFormatpng(类型StillImageFormat
jpegQuality80
scale1
logLevelinfo
timeoutInMilliseconds30000
chromiumOptions/envVariables{}/{}
offthreadVideoCacheSizeInBytes/mediaCacheSizeInBytes/offthreadVideoThreads/licenseKey均可选

执行方式与视频渲染一致:node render-still.mjs <jsonConfig>,同样以 JSON 行协议回报opening-browserselecting-compositiondone(携带sizecontentType),成功返回{sandboxFilePath, contentType}

getRenderProgress:轮询 detached 任务

detached 模式下的进度追踪实现在 src/get-render-progress.ts。它不依赖命令句柄,而是按“文件 + 命令状态”双通道读取:

  1. Sandbox.get({sandboxId})重新附着沙箱,失败即返回{stage: 'expired'}
  2. sandbox.getCommand(cmdId)获取渲染命令对象,识别sandbox_stopped一类错误码同样归为expired
  3. 读取沙箱内固定路径/vercel/sandbox/progress.json(沙箱内渲染脚本把最新进度写在这里);文件不存在且命令尚未退出时返回{stage: 'starting', overallProgress: 0}
  4. 文件存在但命令退出码非 0 时,收集stderr/stdout组装错误信息返回error

返回值是联合类型RenderProgress(types.ts),覆盖完整生命周期:

starting → opening-browser → selecting-composition → render-progress → (detached 时沙箱内自动) uploading → done | error | expired

其中done携带{url, size, contentType, overallProgress}——detached 模式下沙箱内的渲染脚本会使用BLOB_READ_WRITE_TOKEN直接把产物上传到 Vercel Blob,因此done里的url就是可直接下载的产物地址。

uploadToVercelBlob:上传产物到 Blob

常规模式渲染完产物只存在于沙箱文件系统中,需要显式上传。src/upload-to-vercel-blob.ts 的uploadToVercelBlob({sandbox, sandboxFilePath, blobPath?, contentType, blobToken, access})

  • blobPath缺省时自动生成renders/{uuid}{原文件扩展名}
  • 在沙箱内执行node upload-blob.mjs <jsonConfig>(沙箱内已装好@vercel/blobSDK),从 stdout 的type: 'done'JSON 消息中取回{url, size}
  • access'public' | 'private'(类型VercelBlobAccess)。

典型端到端工作流

把上述 API 串起来,一个完整的服务端渲染流程大致如下(基于仓库内各函数的真实签名编写):

import { addBundleToSandbox, createSandbox, renderMediaOnVercel, uploadToVercelBlob, } from '@remotion/vercel'; // 1. 创建并初始化沙箱(可 await using 自动清理) await using sandbox = await createSandbox({ onProgress: ({progress, message}) => console.log(progress, message), resources: {vcpus: 4}, }); // 2. 上传 `npx remotion bundle` 的产物(如 out/remotion) await addBundleToSandbox({sandbox, bundleDir: 'out/remotion'}); // 3. 渲染视频(常规模式) const {sandboxFilePath, contentType} = await renderMediaOnVercel({ sandbox, compositionId: 'MyComp', inputProps: {title: 'Hello'}, codec: 'h264', scale: 1, onProgress: ({stage, overallProgress}) => console.log(stage, overallProgress), }); // 4. 上传到 Vercel Blob 并拿到 URL const {url, size} = await uploadToVercelBlob({ sandbox, sandboxFilePath, contentType, blobToken: process.env.BLOB_READ_WRITE_TOKEN!, access: 'public', }); console.log(url, size);

长任务或需要跨进程追踪时改用 detached 模式:

const {sandboxId, cmdId, outputFile} = await renderMediaOnVercel({ sandbox, compositionId: 'MyComp', inputProps: {title: 'Hello'}, detached: true, vercelBlob: { blobToken: process.env.BLOB_READ_WRITE_TOKEN!, access: 'public', blobPath: 'renders/hello.mp4', }, }); // 在任意时机(甚至另一个进程中)轮询 const progress = await getRenderProgress({sandboxId, cmdId}); // progress.stage: 'starting' | 'opening-browser' | ... | 'done' | 'expired'

适用前提与限制

综合源码可以归纳出该包的使用前提与限制,部署前需要确认:

  1. 平台假设:沙箱初始化脚本围绕node24运行时 + Amazon Linux 2023(dnf包管理、glibc 2.34 补丁路径)编写,compositor 修补逻辑只处理node_modules/@remotion/compositor-linux-x64-gnu,即当前实现面向 Linux x64 沙箱环境;
  2. 浏览器固定为 headless-shellrenderConfigchromeMode被硬编码为headless-shell,且browserExecutablebinariesDirectory恒为null,无法指定自托管 Chromium;
  3. detached 模式强依赖 Vercel Blobdetached: true时缺少vercelBlob会直接抛错(The vercelBlob option is required when detached is set to true.),且沙箱默认只自动延长 30 分钟超时(DEFAULT_DETACHED_SANDBOX_TIMEOUT),超长渲染需自行调大detachedSandboxTimeoutInMilliseconds
  4. 版本一致性是硬约束:沙箱内渲染器版本取自本地remotion/version,本地remotion/@remotion/*版本不一致会导致行为不确定,因此 README 要求所有包使用--save-exact的同一版本。

小结

@remotion/vercel把“打包 → 沙箱环境准备 → 渲染 → 产物分发”拆成了 6 个职责单一、可组合的 API:createSandbox负责一个开箱即用的 Node 24 渲染沙箱(含系统依赖、glibc 2.35 补丁与 headless-shell 下载),addBundleToSandbox负责 Bundle 分发,renderMediaOnVercel/renderStillOnVercel负责以 JSON 配置驱动的无头渲染,getRenderProgressuploadToVercelBlob分别覆盖异步进度追踪与产物上传。对于需要在无状态云端按需生成视频的 Remotion 项目,这是一条不依赖长期 GPU 实例的轻量渲染路径;实现细节可直接在 packages/vercel/src/ 下按上述文件名查阅。

【免费下载链接】remotion🎥 Make videos programmatically with React项目地址: https://gitcode.com/GitHub_Trending/re/remotion

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 19:42:27

从生成内容到生成交互:界面世界模型如何重构前端范式

1. 项目的完整技术拆解&#xff1a;Solaris到底做了什么过去两年里&#xff0c;AI生成领域的主流叙事一直是“生成内容”&#xff1a;文生图、文生视频、文生代码。你输入一句提示词&#xff0c;模型吐出一张图、一段视频、一个函数。这套范式下的产品形态无论怎么变&#xff0…

作者头像 李华
网站建设 2026/9/8 19:42:16

云克隆 Luminex 多因子检测试剂盒(IL10,IL13,IL17,MCP1,MIP1a,TGFb1,TNF-α)Th2-Th17 免疫轴标志物检测方案上市

近些年来&#xff0c;过敏性疾病、银屑病、类风湿关节炎、多发性硬化等一系列自身免疫与慢性炎症疾病的发病率在全球范围内持续走高&#xff0c;给临床诊疗、新药研发以及基础免疫学探索带来了巨大挑战。大量前沿免疫学研究证实&#xff0c;Th2、Th17 免疫通路失衡是介导慢性炎…

作者头像 李华
网站建设 2026/9/8 19:40:01

深入探索:ROS中rosparam参数服务器的完整使用指南与面试策略

在机器人开发领域,ROS(Robot Operating System)作为开源框架广泛用于构建复杂系统。其中,参数服务器是ROS的核心组件之一,它允许开发者动态存储和检索配置参数,提升模块间解耦能力。本文聚焦于rosparam参数服务器的深度应用,涵盖从基础到高级技巧的全过程,旨在为机器人…

作者头像 李华
网站建设 2026/9/8 19:39:58

res-downloader 视频号下载完整教程:从配置代理到批量下载

res-downloader 视频号下载完整教程&#xff1a;从配置代理到批量下载 【免费下载链接】res-downloader 视频号、小程序、抖音、快手、小红书、直播流、m3u8、酷狗、QQ音乐等常见网络资源下载! 项目地址: https://gitcode.com/GitHub_Trending/re/res-downloader 想把某…

作者头像 李华
网站建设 2026/9/8 19:39:48

Gazebo详解: 基于ROS的机器人动态仿真核心技术实践

在机器人系统开发领域,仿真工具已成为不可或缺的技术支撑。作为ROS生态中的核心技术支柱,Gazebo凭借其强大的物理仿真能力,为开发者构建了安全高效的虚拟验证平台。本文将深入剖析Gazebo的核心技术架构与实践应用,结合典型开发案例揭示其在机器人软件开发全生命周期中的战略…

作者头像 李华
网站建设 2026/9/8 19:39:04

2026广州军队文职报班避坑:纯线上、本地班、进京集训怎么选?

结论先行&#xff1a;广州考生怎么选军队文职的培训机构&#xff1f; 广州是华南教育重镇&#xff0c;高校密集、考编氛围浓厚&#xff0c;广东也是军队文职报考的热门省份。但细看本地市场&#xff0c;专门深耕军队文职的线下培训机构并不多&#xff0c;主流供给以线上课程和综…

作者头像 李华