解析)
remotion/vercel在 Vercel Sandbox 中渲染 Remotion 視頻的完整技術(shù)解析【免費(fèi)下載鏈接】remotion Make videos programmatically with React項(xiàng)目地址: https://gitcode.com/GitHub_Trending/re/remotion本文圍繞 Remotion 倉(cāng)庫(kù)中的remotion/vercel包packages/vercel/README.md展開(kāi)講解如何在 Vercel Sandbox 中創(chuàng)建渲染環(huán)境、上傳項(xiàng)目 Bundle、執(zhí)行視頻/靜幀渲染、跟蹤進(jìn)度并把產(chǎn)物上傳到 Vercel Blob 的完整鏈路所有結(jié)論均基于倉(cāng)庫(kù)內(nèi) packages/vercel/src/index.ts 等源碼。包定位與公開(kāi) APIremotion/vercel的官方定位是“Render Remotion videos on Vercel Sandbox”在 Vercel Sandbox 上渲染 Remotion 視頻當(dāng)前倉(cāng)庫(kù)內(nèi)版本為4.0.521License 為 Remotion License見(jiàn) packages/vercel/package.json。它依賴remotion/renderer與remotion并以vercel/sandbox 1.0.0作為 peer dependency開(kāi)發(fā)中固定使用1.6.0配套vercel/blob2.3.0。從 src/index.ts 的導(dǎo)出清單看該包對(duì)外暴露 6 個(gè)運(yùn)行時(shí) API 和一批類型導(dǎo)出類型作用createSandbox函數(shù)創(chuàng)建一個(gè)安裝好系統(tǒng)依賴、JS 依賴、headless 瀏覽器與渲染腳本的沙箱addBundleToSandbox函數(shù)把本地remotion bundle產(chǎn)物遞歸上傳進(jìn)沙箱renderMediaOnVercel函數(shù)在沙箱內(nèi)渲染視頻支持常規(guī)與 detached 兩種模式renderStillOnVercel函數(shù)在沙箱內(nèi)渲染單幀靜圖getRenderProgress函數(shù)輪詢 detached 渲染任務(wù)的文件式進(jìn)度uploadToVercelBlob函數(shù)把沙箱內(nèi)產(chǎn)物上傳到 Vercel Blob返回 URL類型導(dǎo)出typeVercelSandbox、RenderProgress、VercelBlobUploadOptions、ChromiumOptions、Codec等大部分自 types.ts 與remotion/renderer再導(dǎo)出安裝與版本約束README 給出的安裝方式npm install remotion/vercel --save-exact兩條必須遵守的版本約束來(lái)自 README 與 package.json所有remotion與remotion/*包必須對(duì)齊同一版本需去掉版本號(hào)前的^使用精確版本vercel/sandbox是 peer dependency調(diào)用方需自行安裝1.0.0。另外從沙箱初始化邏輯看包內(nèi)渲染腳本由構(gòu)建產(chǎn)物generated/*-script注入包內(nèi)部通過(guò)remotion/version讀取版本號(hào)在沙箱內(nèi)以精確版本安裝remotion/rendererVERSION與remotion/compositor-linux-x64-gnuVERSION見(jiàn) internals/install-js-dependencies.ts也就是說(shuō)沙箱內(nèi)的渲染器版本永遠(yuǎn)與本地remotion/vercel版本一致這也是“版本必須對(duì)齊”這條約束的底層原因。createSandbox一步準(zhǔn)備一個(gè)可渲染沙箱createSandbox是整個(gè)流程的入口完整實(shí)現(xiàn)在 src/create-sandbox.ts。簽名與默認(rèn)值createSandbox({ onProgress?, // (update: {progress, message}) void | Promisevoid resources {vcpus: 4}, // Vercel Sandbox 的 resources 參數(shù)默認(rèn) 4 vCPU timeoutInMilliseconds 5 * 60 * 1000, // 沙箱創(chuàng)建/初始化超時(shí)默認(rèn) 5 分鐘 } {})它返回VercelSandbox——即Sandbox AsyncDisposable定義見(jiàn) types.ts意味著可以用await using語(yǔ)法自動(dòng)停止沙箱創(chuàng)建時(shí)通過(guò) internals/disposable.ts 給沙箱掛了[Symbol.asyncDispose]dispose 時(shí)調(diào)用sandbox.stop()。沙箱的準(zhǔn)備工作按兩個(gè)加權(quán)階段推進(jìn)onProgress的進(jìn)度權(quán)重系統(tǒng)依賴 75%、下載瀏覽器 25%創(chuàng)建沙箱runtime: node24即 Node 24 運(yùn)行時(shí)安裝系統(tǒng)依賴75%通過(guò)sudo dnf install安裝 headless Chromium 在 Amazon Linux 2023 上運(yùn)行所需的一組庫(kù)nss、atk、at-spi2-atk、cups-libs、libdrm、libXcomposite、libXdamage、libXrandr、mesa-libgbm、alsa-lib、pango、gtk3以及補(bǔ)丁工具鏈patchelf、zstd、binutils見(jiàn) internals/install-system-dependencies.ts。進(jìn)度是通過(guò)統(tǒng)計(jì)命令 stdout 行數(shù)源碼注釋說(shuō)明經(jīng)驗(yàn)值為 272 行線性估算的安裝 JS 依賴在沙箱內(nèi)執(zhí)行pnpm i remotion/renderer remotion/compositor-linux-x64-gnu vercel/blob版本鎖定為當(dāng)前包版本修補(bǔ) compositorVercel Sandbox 的 Amazon Linux 2023 自帶 glibc 2.34而 Remotion 的 compositor 二進(jìn)制要求 glibc 2.35。internals/patch-compositor.ts 會(huì)下載 Ubuntu 22.04 的libc6 2.35deb 包主源為 Launchpad備用源為 remotion.media解壓后用patchelf把remotion二進(jìn)制的動(dòng)態(tài)鏈接指向捆綁的 glibc。源碼注釋明確指出Remotion 并不官方支持 glibc 2.34但可以通過(guò)這種方式打補(bǔ)丁且只有remotion二進(jìn)制需要修補(bǔ)ffmpeg/ffprobe在 glibc 2.34 下工作正常下載 headless 瀏覽器25%寫入并執(zhí)行ensure-browser.mjs以 JSON 日志形式回報(bào)browser-progress百分比見(jiàn) internals/install-browser.ts寫入渲染腳本向沙箱寫入package.json{type: module}以及render-video.mjs、render-still.mjs、upload-blob.mjs三個(gè)腳本后續(xù)渲染命令直接調(diào)用它們。addBundleToSandbox上傳項(xiàng)目 Bundle渲染前需要把npx remotion bundle生成的靜態(tài)產(chǎn)物傳進(jìn)沙箱。src/add-bundle-to-sandbox.ts 的addBundleToSandbox({sandbox, bundleDir})行為如下遞歸讀取bundleDir下所有文件統(tǒng)一轉(zhuǎn)成 POSIX 分隔路徑先在沙箱內(nèi)按祖先目錄逐一mkDir再批量writeFiles上傳所有文件統(tǒng)一放在沙箱內(nèi)的remotion-bundle/目錄下常量REMOTION_SANDBOX_BUNDLE_DIR見(jiàn) internals/add-bundle.ts。渲染時(shí)瀏覽器加載的 URL 因此固定為/vercel/sandbox/remotion-bundle目錄創(chuàng)建或文件上傳失敗時(shí)經(jīng)由 internals/format-sandbox-error.ts 重新拋出帶操作上下文如“upload N bundle file(s)”的錯(cuò)誤便于定位。renderMediaOnVercel渲染視頻完整實(shí)現(xiàn)在 src/render-media-on-vercel.ts。這是一個(gè)通過(guò)重載區(qū)分兩種模式的函數(shù)常規(guī)模式detached缺省或false阻塞等待渲染結(jié)束返回{sandboxFilePath, contentType}產(chǎn)物留在沙箱文件系統(tǒng)中等待后續(xù)uploadToVercelBlobdetached 模式detached: true必須同時(shí)提供vercelBlob: {blobToken, access, blobPath?}立即返回{sandboxId, cmdId, outputFile}由沙箱后臺(tái)繼續(xù)渲染并用getRenderProgress輪詢結(jié)果。完整參數(shù)與默認(rèn)值以下參數(shù)表全部來(lái)自源碼中解構(gòu)默認(rèn)值參數(shù)默認(rèn)值說(shuō)明sandbox必填createSandbox返回的沙箱實(shí)例compositionId必填目標(biāo) Composition 的 idinputProps必填傳給 Composition 的 propsoutputFile/tmp/video.mp4沙箱內(nèi)輸出路徑codech264視頻編碼類型Codec自remotion/renderer再導(dǎo)出crfnull恒定質(zhì)量因子imageFormat/pixelFormatnull幀圖像格式與像素格式envVariables{}注入渲染進(jìn)程的環(huán)境變量frameRangenull只渲染指定幀區(qū)間everyNthFrame1抽幀渲染步長(zhǎng)proResProfilenullProRes 檔位chromiumOptions{}附加 Chromium 啟動(dòng)參數(shù)scale1輸出縮放比例preferLosslessfalse偏好無(wú)損編碼enforceAudioTrackfalse強(qiáng)制包含音軌disallowParallelEncodingfalse禁止并行編碼concurrencynull并發(fā)幀數(shù)metadatanull寫入容器的元數(shù)據(jù)licenseKeynullRemotion 企業(yè)授權(quán)密鑰videoBitrate/audioBitrate/encodingMaxRate/encodingBufferSizenull碼率相關(guān)類型Bitratemutedfalse靜音輸出numberOfGifLoopsnullGIF 循環(huán)次數(shù)x264Preset/gopSizenullH.264 預(yù)設(shè)與 GOP 大小colorSpacedefault色彩空間jpegQuality80JPEG 幀質(zhì)量audioCodecnull音頻編碼logLevelinfo日志級(jí)別timeoutInMilliseconds30000瀏覽器/Composition 打開(kāi)超時(shí)forSeamlessAacConcatenationfalseAAC 無(wú)縫拼接separateAudioTonull單獨(dú)輸出音頻文件路徑hardwareAccelerationdisable硬件加速開(kāi)關(guān)沙箱環(huán)境默認(rèn)關(guān)閉offthreadVideoCacheSizeInBytes/mediaCacheSizeInBytes/offthreadVideoThreadsnull離屏視頻緩存與線程sampleRate48000音頻采樣率detachedfalse是否后臺(tái)渲染detachedSandboxTimeoutInMilliseconds30 * 60 * 1000detached 模式下沙箱超時(shí)延長(zhǎng)時(shí)長(zhǎng)30 分鐘底層執(zhí)行方式函數(shù)把上述參數(shù)組裝成renderConfig其中強(qiáng)制寫死了幾個(gè)與本地渲染不同的字段chromeMode: headless-shell、browserExecutable: null、binariesDirectory: null、repro: 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, });即把整個(gè)渲染配置作為 JSON 傳給沙箱內(nèi)的render-video.mjs腳本腳本內(nèi)部再調(diào)用remotion/renderer完成渲染并以 JSON 行形式把進(jìn)度打到 stdout。常規(guī)模式下客戶端逐行解析stdout日志非 JSON 的行直接忽略把opening-browser、selecting-composition、render-progress三個(gè)階段透?jìng)鹘oonProgress最后wait()等待命令結(jié)束退出碼非 0 時(shí)拋出Render failed: stderr stdout。detached 模式則先sandbox.extendTimeout(detachedSandboxTimeoutInMilliseconds)延長(zhǎng)沙箱壽命然后立即返回{sandboxId, cmdId, outputFile}供后續(xù)輪詢。renderStillOnVercel渲染靜幀實(shí)現(xiàn)在 src/render-still-on-vercel.ts參數(shù)更精簡(jiǎn)參數(shù)默認(rèn)值outputFile/tmp/still.pngframe0imageFormatpng類型StillImageFormatjpegQuality80scale1logLevelinfotimeoutInMilliseconds30000chromiumOptions/envVariables{}/{}offthreadVideoCacheSizeInBytes/mediaCacheSizeInBytes/offthreadVideoThreads/licenseKey均可選執(zhí)行方式與視頻渲染一致node render-still.mjs jsonConfig同樣以 JSON 行協(xié)議回報(bào)opening-browser、selecting-composition、done攜帶size與contentType成功返回{sandboxFilePath, contentType}。getRenderProgress輪詢 detached 任務(wù)detached 模式下的進(jìn)度追蹤實(shí)現(xiàn)在 src/get-render-progress.ts。它不依賴命令句柄而是按“文件 命令狀態(tài)”雙通道讀取Sandbox.get({sandboxId})重新附著沙箱失敗即返回{stage: expired}sandbox.getCommand(cmdId)獲取渲染命令對(duì)象識(shí)別sandbox_stopped一類錯(cuò)誤碼同樣歸為expired讀取沙箱內(nèi)固定路徑/vercel/sandbox/progress.json沙箱內(nèi)渲染腳本把最新進(jìn)度寫在這里文件不存在且命令尚未退出時(shí)返回{stage: starting, overallProgress: 0}文件存在但命令退出碼非 0 時(shí)收集stderr/stdout組裝錯(cuò)誤信息返回error。返回值是聯(lián)合類型RenderProgresstypes.ts覆蓋完整生命周期starting → opening-browser → selecting-composition → render-progress → (detached 時(shí)沙箱內(nèi)自動(dòng)) uploading → done | error | expired其中done攜帶{url, size, contentType, overallProgress}——detached 模式下沙箱內(nèi)的渲染腳本會(huì)使用BLOB_READ_WRITE_TOKEN直接把產(chǎn)物上傳到 Vercel Blob因此done里的url就是可直接下載的產(chǎn)物地址。uploadToVercelBlob上傳產(chǎn)物到 Blob常規(guī)模式渲染完產(chǎn)物只存在于沙箱文件系統(tǒng)中需要顯式上傳。src/upload-to-vercel-blob.ts 的uploadToVercelBlob({sandbox, sandboxFilePath, blobPath?, contentType, blobToken, access})blobPath缺省時(shí)自動(dòng)生成renders/{uuid}{原文件擴(kuò)展名}在沙箱內(nèi)執(zhí)行node upload-blob.mjs jsonConfig沙箱內(nèi)已裝好vercel/blobSDK從 stdout 的type: doneJSON 消息中取回{url, size}access為public | private類型VercelBlobAccess。典型端到端工作流把上述 API 串起來(lái)一個(gè)完整的服務(wù)端渲染流程大致如下基于倉(cāng)庫(kù)內(nèi)各函數(shù)的真實(shí)簽名編寫import { addBundleToSandbox, createSandbox, renderMediaOnVercel, uploadToVercelBlob, } from remotion/vercel; // 1. 創(chuàng)建并初始化沙箱可 await using 自動(dòng)清理 await using sandbox await createSandbox({ onProgress: ({progress, message}) console.log(progress, message), resources: {vcpus: 4}, }); // 2. 上傳 npx remotion bundle 的產(chǎn)物如 out/remotion await addBundleToSandbox({sandbox, bundleDir: out/remotion}); // 3. 渲染視頻常規(guī)模式 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);長(zhǎng)任務(wù)或需要跨進(jìn)程追蹤時(shí)改用 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, }, }); // 在任意時(shí)機(jī)甚至另一個(gè)進(jìn)程中輪詢 const progress await getRenderProgress({sandboxId, cmdId}); // progress.stage: starting | opening-browser | ... | done | expired適用前提與限制綜合源碼可以歸納出該包的使用前提與限制部署前需要確認(rèn)平臺(tái)假設(shè)沙箱初始化腳本圍繞node24運(yùn)行時(shí) Amazon Linux 2023dnf包管理、glibc 2.34 補(bǔ)丁路徑編寫compositor 修補(bǔ)邏輯只處理node_modules/remotion/compositor-linux-x64-gnu即當(dāng)前實(shí)現(xiàn)面向 Linux x64 沙箱環(huán)境瀏覽器固定為 headless-shellrenderConfig中chromeMode被硬編碼為headless-shell且browserExecutable、binariesDirectory恒為null無(wú)法指定自托管 Chromiumdetached 模式強(qiáng)依賴 Vercel Blobdetached: true時(shí)缺少vercelBlob會(huì)直接拋錯(cuò)The vercelBlob option is required when detached is set to true.且沙箱默認(rèn)只自動(dòng)延長(zhǎng) 30 分鐘超時(shí)DEFAULT_DETACHED_SANDBOX_TIMEOUT超長(zhǎng)渲染需自行調(diào)大detachedSandboxTimeoutInMilliseconds版本一致性是硬約束沙箱內(nèi)渲染器版本取自本地remotion/version本地remotion/remotion/*版本不一致會(huì)導(dǎo)致行為不確定因此 README 要求所有包使用--save-exact的同一版本。小結(jié)remotion/vercel把“打包 → 沙箱環(huán)境準(zhǔn)備 → 渲染 → 產(chǎn)物分發(fā)”拆成了 6 個(gè)職責(zé)單一、可組合的 APIcreateSandbox負(fù)責(zé)一個(gè)開(kāi)箱即用的 Node 24 渲染沙箱含系統(tǒng)依賴、glibc 2.35 補(bǔ)丁與 headless-shell 下載addBundleToSandbox負(fù)責(zé) Bundle 分發(fā)renderMediaOnVercel/renderStillOnVercel負(fù)責(zé)以 JSON 配置驅(qū)動(dòng)的無(wú)頭渲染getRenderProgress與uploadToVercelBlob分別覆蓋異步進(jìn)度追蹤與產(chǎn)物上傳。對(duì)于需要在無(wú)狀態(tài)云端按需生成視頻的 Remotion 項(xiàng)目這是一條不依賴長(zhǎng)期 GPU 實(shí)例的輕量渲染路徑實(shí)現(xiàn)細(xì)節(jié)可直接在 packages/vercel/src/ 下按上述文件名查閱?!久赓M(fèi)下載鏈接】remotion Make videos programmatically with React項(xiàng)目地址: https://gitcode.com/GitHub_Trending/re/remotion創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考