如何在 Vercel Sandbox 中用 renderMediaOnVercel 渲染视频并上传到 Vercel Blob?
2026/9/12 16:53:19 网站建设 项目流程

如何在 Vercel Sandbox 中用 renderMediaOnVercel 渲染视频并上传到 Vercel Blob?

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

当你想在 Vercel 上按需渲染 Remotion 视频,又不想自己管理 Lambda 或 AWS 基础设施时,@remotion/vercel包提供了这条路径:在 Vercel Sandbox 里渲染,再把产物上传到 Vercel Blob 得到一个可公开访问的下载 URL。完整流程是四步:createSandbox()创建沙箱 →addBundleToSandbox()拷贝你的 Remotion bundle →renderMediaOnVercel()渲染视频 →uploadToVercelBlob()上传到 Blob 存储。

需要注意的是,@remotion/vercel目前是实验性包(自 v4.0.426 起提供),官方保留在移除警告提示前做破坏性变更的权利;并且它要求@vercel/sandbox作为 peer dependency。

准备条件

创建项目并连接 Blob 存储

使用官方的 Next.js 模板起步:

npx create-video@latest --template vercel

把项目推送到 Vercel,然后在 Vercel 控制台的 "Storage" 下新建一个 Blob store 并连接到项目,重新部署使配置生效。渲染上传依赖环境变量BLOB_READ_WRITE_TOKEN;官方模板的渲染路由在未设置该变量时会直接抛出错误:

BLOB_READ_WRITE_TOKEN is not set. To fix this, go to vercel.com, log in, select Storage, click "Create Database", select "Blob", link it to your project, then add BLOB_READ_WRITE_TOKEN to your .env file.

模板参考实现位于仓库的 template-vercel 渲染路由,可以对照本文步骤逐行理解。

完整渲染与上传流程

以下代码展示了模板中同步渲染路径的核心逻辑(省略了 SSE 进度推送部分),四个 API 均从@remotion/vercel导入:

import { addBundleToSandbox, createSandbox, renderMediaOnVercel, uploadToVercelBlob, } from '@remotion/vercel'; // 1. 创建沙箱:已预装系统库、compositor 和浏览器 const sandbox = await createSandbox({ onProgress: async ({progress, message}) => { console.log(`${message} (${Math.round(progress * 100)}%)`); }, }); // 2. 把 Remotion bundle 拷贝进沙箱 // bundleDir 是相对当前工作目录的路径, // bundle 可以用 npx remotion bundle 命令或 bundle() API 创建 await addBundleToSandbox({ sandbox, bundleDir: '.remotion', }); // 3. 渲染视频,产物留在沙箱内 const {sandboxFilePath, contentType} = await renderMediaOnVercel({ sandbox, compositionId: 'MyComp', inputProps: {title: 'Hello World'}, }); // 4. 上传到 Vercel Blob,得到公开 URL const {url, size} = await uploadToVercelBlob({ sandbox, sandboxFilePath, contentType, blobToken: process.env.BLOB_READ_WRITE_TOKEN!, access: 'public', }); console.log(`Uploaded ${size} bytes to ${url}`); // 5. 用完沙箱后必须 stop,释放资源 await sandbox.stop();

各步骤的判断依据:

  • renderMediaOnVercel()未设置detached时,返回{sandboxFilePath, contentType},其中sandboxFilePath是视频在沙箱内的路径(默认输出路径为/tmp/video.mp4),contentType是 MIME 类型(如"video/mp4")。把这两个值直接传给uploadToVercelBlob()即可,无需手写路径。
  • uploadToVercelBlob()返回{url, size}url是上传文件的公开下载 URL,size是字节数。拿到url即表示渲染产物已可公开访问。
  • access只能是"public""private",默认"private";想让视频可直接播放就显式传access: 'public'blobPath参数可指定 Blob 内的目标路径(如"renders/abc.mp4"),省略时生成随机路径。

沙箱资源与清理

createSandbox()的可选参数:

  • resources:分配给沙箱的资源,类型继承自@vercel/sandboxSDK,每个 vCPU 对应 2048 MB 内存,默认{vcpus: 4}
  • timeoutInMilliseconds(v4.0.452 起):沙箱创建的最大允许时间,默认300000(5 分钟),超时则中止创建。

清理沙箱有两种方式:手动调用sandbox.stop(),或使用await using sandbox = await createSandbox()让沙箱离开作用域时自动 stop。上面的示例代码在上传完成后即调用sandbox.stop()

长渲染:detached 模式 + 进度轮询

Vercel functions 最长可运行 800 秒,而 Sandbox 的超时上限在 Hobby 计划为 45 分钟、Pro/Enterprise 为 5 小时。如果渲染时间可能超过函数时限,用detached: true让启动渲染的路由立即返回,再用getRenderProgress()轮询(两者均自 v4.0.469 起提供):

// app/api/render/start/route.ts import {addBundleToSandbox, createSandbox, renderMediaOnVercel} from '@remotion/vercel'; export async function POST() { const sandbox = await createSandbox(); await addBundleToSandbox({ sandbox, bundleDir: '/path/to/your/bundle', // 替换为你的 bundle 目录 }); const {sandboxId, cmdId} = await renderMediaOnVercel({ sandbox, compositionId: 'MyComp', inputProps: {title: 'Hello World'}, detached: true, vercelBlob: { blobToken: process.env.BLOB_READ_WRITE_TOKEN!, access: 'public', }, }); return Response.json({sandboxId, cmdId}); }
// app/api/render/progress/route.ts import {getRenderProgress} from '@remotion/vercel'; import {Sandbox} from '@vercel/sandbox'; export async function GET(req: Request) { const url = new URL(req.url); const sandboxId = url.searchParams.get('sandboxId'); const cmdId = url.searchParams.get('cmdId'); if (!sandboxId || !cmdId) { return Response.json({error: 'Missing sandboxId or cmdId'}, {status: 400}); } const progress = await getRenderProgress({sandboxId, cmdId}); if (progress.stage === 'done' || progress.stage === 'error') { await Sandbox.get({sandboxId}) .then((sandbox) => sandbox.stop()) .catch(() => undefined); } return Response.json(progress); }

detached 模式的关键约束:

  • 设置detached: true后返回{sandboxId, cmdId, outputFile}vercelBlob参数在该模式下是必需的——因为启动渲染的路由在视频存在之前就已返回,必须由沙箱内自行完成上传;
  • detachedSandboxTimeoutInMilliseconds可延长返回前沙箱的存活时间,默认1800000(30 分钟);
  • getRenderProgress()的终态阶段有done(渲染已上传到 Vercel Blob)、error(渲染失败)、expired(沙箱已不存在)。文档说明:收到doneerror后应删除你应用里保存的渲染句柄,沙箱本身会保持存活到配置的超时时间,以便刷新后的页面仍能读到终态进度。

限制与注意事项

  • 实验性包@remotion/vercel的四个 API 都带有实验性警告,接口可能变化。
  • 性能:Sandbox 渲染发生在单台机器上,而非分布式系统,因此比 Lambda 慢;沙箱内含 Chrome 和 FFmpeg,启动需要几秒。
  • 并发上限:Hobby 计划 10 个同时渲染,Pro/Enterprise 2000 个。
  • 模板不含限流与缓存:官方提示在把应用公开之前自行实现 rate limiting 和 caching,并建议配置 Vercel Spend Management 控制成本。
  • Blob 数据会持久保留:Sandbox 快照、渲染视频和其他 Vercel Blob 数据会一直存在,不再需要时应删除。
  • 渲染参数renderMediaOnVercel()还支持codec(默认"h264")、frameRangeconcurrencytimeoutInMilliseconds等与@remotion/renderer一致的编码参数,详见 renderMediaOnVercel() 文档 的参数列表。

相关文档入口:Rendering with Vercel Sandbox、@remotion/vercel API 索引、createSandbox()、addBundleToSandbox()、uploadToVercelBlob()、getRenderProgress()。

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

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询