Remotion LabRemotion Lab
伺服器端渲染使用 SSR API 進行渲染

使用 SSR API 進行渲染

使用 @remotion/renderer 套件的 Node.js API 在伺服器端渲染 Remotion 影片、音訊和圖片序列

使用 SSR API 進行渲染

NPM 套件 @remotion/renderer 提供了在伺服器端渲染 Remotion 影片的 API。這些函數可在 Node.jsBun 中使用。

渲染流程

渲染影片需要三個步驟:

  1. 建立 Bundle(打包 Remotion 專案)
  2. 選擇要渲染的合成並計算其元數據
  3. 渲染影片、音訊、靜態圖片或圖片序列

完整範例

以下是帶有注釋的完整渲染腳本:

import { bundle } from '@remotion/bundler';
import { renderMedia, selectComposition } from '@remotion/renderer';
import path from 'path';
 
// 要渲染的合成 ID
const compositionId = 'HelloWorld';
 
// 您只需建立一次 bundle,可以複用它
// 透過傳入不同的 input props 對多個渲染進行參數化
const bundleLocation = await bundle({
  entryPoint: path.resolve('./src/index.ts'),
  // 如果您在 remotion.config.ts 中有 webpack 覆蓋設定,也在此處傳入
  webpackOverride: (config) => config,
});
 
// 透過傳入 props 對影片進行參數化
const inputProps = {
  title: 'Hello World',
  subtitle: 'Made with Remotion',
};
 
// 獲取要渲染的合成
// 如果您想自訂時長或其他元數據,請傳入 inputProps
const composition = await selectComposition({
  serveUrl: bundleLocation,
  id: compositionId,
  inputProps,
});
 
// 渲染影片
// 如果您的影片使用了資料參數化,再次傳入相同的 inputProps
await renderMedia({
  composition,
  serveUrl: bundleLocation,
  codec: 'h264',
  outputLocation: `out/${compositionId}.mp4`,
  inputProps,
});
 
console.log('渲染完成!');

安裝必要套件

npm install @remotion/renderer @remotion/bundler

核心 API 說明

bundle()

打包您的 Remotion 專案:

import { bundle } from '@remotion/bundler';
 
const bundleLocation = await bundle({
  entryPoint: path.resolve('./src/index.ts'),
  webpackOverride: (config) => config, // 可選的 webpack 覆蓋
  onProgress: (progress) => {
    console.log(`打包進度:${progress}%`);
  },
});

Bundle 可以在多次渲染間複用,只要程式碼沒有變更。

selectComposition()

選擇並獲取合成的元數據:

import { selectComposition } from '@remotion/renderer';
 
const composition = await selectComposition({
  serveUrl: bundleLocation,
  id: 'MyComposition',
  inputProps: { /* 您的 props */ },
  timeoutInMilliseconds: 30000, // 可選,預設 30 秒
});
 
console.log(composition.durationInFrames); // 合成幀數
console.log(composition.fps);              // 幀率
console.log(composition.width);            // 寬度
console.log(composition.height);           // 高度

renderMedia()

渲染影片或音訊:

import { renderMedia } from '@remotion/renderer';
 
await renderMedia({
  composition,
  serveUrl: bundleLocation,
  codec: 'h264',           // 'h264' | 'h265' | 'vp8' | 'vp9' | 'mp3' | 'aac' | 'wav' | 'prores' | 'gif'
  outputLocation: 'out/video.mp4',
  inputProps: { /* 您的 props */ },
  onProgress: ({ progress }) => {
    console.log(`渲染進度:${Math.round(progress * 100)}%`);
  },
  concurrency: 1,          // 並發渲染的瀏覽器頁面數
  timeoutInMilliseconds: 30000,
});

renderStill()

渲染單張靜態圖片:

import { renderStill } from '@remotion/renderer';
 
await renderStill({
  composition,
  serveUrl: bundleLocation,
  frame: 30,               // 要渲染的幀
  output: 'out/still.png',
  inputProps: { /* 您的 props */ },
});

效能調優

並發渲染

await renderMedia({
  composition,
  serveUrl: bundleLocation,
  codec: 'h264',
  outputLocation: 'out/video.mp4',
  concurrency: 4, // 同時使用 4 個瀏覽器頁面
});

複用 Bundle

// 一次打包,多次渲染
const bundleLocation = await bundle({ entryPoint: './src/index.ts' });
 
// 渲染多個影片
await Promise.all([
  renderMedia({ serveUrl: bundleLocation, composition: comp1, /* ... */ }),
  renderMedia({ serveUrl: bundleLocation, composition: comp2, /* ... */ }),
]);

複用瀏覽器實例

import { openBrowser, renderMedia } from '@remotion/renderer';
 
const browser = await openBrowser('chrome');
 
for (const video of videoList) {
  await renderMedia({
    composition: video.composition,
    serveUrl: bundleLocation,
    codec: 'h264',
    outputLocation: video.output,
    browserExecutable: browser,
  });
}
 
await browser.close();

錯誤處理

try {
  await renderMedia({
    composition,
    serveUrl: bundleLocation,
    codec: 'h264',
    outputLocation: 'out/video.mp4',
  });
} catch (err) {
  if (err instanceof Error) {
    console.error('渲染失敗:', err.message);
    // 錯誤訊息包含詳細的堆疊追蹤資訊
  }
}

相關資源