週次Remotion動画出力量をワークフロー別に試算する
執筆: RenderComp チーム 編集方針
Remotionはビデオをフレーム番号の関数として扱う。useCurrentFrame() が返す値と inputProps の組み合わせが同じであれば、コンポーネントは常に同じピクセルを出力する。
週次出力本数を決める要素は2つある。1本あたりのレンダリング実時間と、同時に走らせられるレンダラーの数である。ローカルシングルプロセスからLambda並列化、キュー自動化へと進むにつれ、この2つの値は異なる制約に支配される。
ローカルrenderMediaワークフロー
@remotion/renderer の renderMedia をNode.jsスクリプトから呼ぶ構成がローカルワークフローの基本形である。concurrency オプションを省略すると os.cpus().length が使われ、Puppeteerインスタンスが論理CPUコア数だけ並列に起動してフレームを描画する。
import { bundle } from "@remotion/bundler";
import { renderMedia, selectComposition } from "@remotion/renderer";
const serveUrl = await bundle({ entryPoint: "./src/index.ts" });
async function renderOne(
id: string,
inputProps: Record<string, unknown>
): Promise<void> {
const composition = await selectComposition({ serveUrl, id, inputProps });
await renderMedia({
composition,
serveUrl,
codec: "h264",
outputLocation: `out/${id}-${Date.now()}.mp4`,
// concurrency: os.cpus().length がデフォルト
// 論理コア数を超える並列化はこのオプションでは実現しない
});
}
ループで複数本を順に処理するスクリプトを書くと、週次出力本数は「週の稼働時間 ÷ 1本あたりの実時間」という計算になる。スループット改善の手段はマシンスペックの向上か複数台への分散である。
Remotion Lambda 単発ワークフロー
renderMediaOnLambda を使うと、1本の動画のフレームをN個のLambda関数に分割して並列レンダリングできる。並列数の上限はRemotionのドキュメントで 200 と明記されており、200を超えると収穫逓減になるため制限されている。
並列数を設定する concurrency パラメーターには2つのフレーム数制約がかかる。concurrency の値は framesPerLambda が4以上になるように設定しなければならず、加えて動画がどれだけ短くても Lambda 1つあたり最低 20フレーム がレンダリングされる。
この「最低20フレーム」が短い動画の実効並列数を制限する。concurrency=200 を有効に使うには 200 × 20 = 4,000フレーム 以上の動画長が必要になる。
import {
renderMediaOnLambda,
getRenderProgress,
} from "@remotion/lambda/client";
// 900フレームの動画に対する2つのconcurrency設定:
// concurrency=45 → framesPerLambda = 900 / 45 = 20(最低値)
// concurrency=200 → framesPerLambda = ceil(900 / 200) = 5(>= 4 を満たす)
const { renderId, bucketName } = await renderMediaOnLambda({
region: "ap-northeast-1",
functionName: "remotion-render-4-0-272",
serveUrl,
composition: "MyComposition",
inputProps: { text: "Hello" },
codec: "h264",
concurrency: 45,
});
while (true) {
const progress = await getRenderProgress({
renderId,
bucketName,
region: "ap-northeast-1",
functionName: "remotion-render-4-0-272",
});
if (progress.done) break;
if (progress.fatalErrorEncountered) {
throw new Error(progress.errors[0].message);
}
await new Promise((r) => setTimeout(r, 1000));
}
Lambda 1回の最大実行時間は 15分、使用できるメモリは最大 10,240MB まで指定できる。高解像度のコンポジションや計算コストの高いエフェクトを使う動画では、memorySizeInMb の設定が1フレームあたりの処理時間に直結する。
Lambda + キュー自動化ワークフロー
Lambda単発ワークフローをキューで自動化すると、複数の動画を継続的に処理できる。このときスループットの上限を決めるのはAWS Lambdaのデフォルト同時実行数制限 1,000 である。
Remotionの1レンダーが最大200のLambda関数を消費するため、同時に走れるレンダー数の理論的上限は floor(1000 / 200) = 5 本になる。Lambda実行環境インスタンス1つが処理できる同期呼び出しは秒間最大 10リクエスト である。
import { renderMediaOnLambda } from "@remotion/lambda/client";
type RenderJob = {
composition: string;
inputProps: Record<string, unknown>;
};
// AWSデフォルト同時実行数1,000 / Remotion上限200 = 同時5本
const MAX_CONCURRENT_RENDERS = 5;
async function processQueue(jobs: RenderJob[]): Promise<void> {
for (let i = 0; i < jobs.length; i += MAX_CONCURRENT_RENDERS) {
const batch = jobs.slice(i, i + MAX_CONCURRENT_RENDERS);
await Promise.all(
batch.map((job) =>
renderMediaOnLambda({
region: "ap-northeast-1",
functionName: "remotion-render-4-0-272",
serveUrl,
composition: job.composition,
inputProps: job.inputProps,
codec: "h264",
concurrency: 200,
})
)
);
}
}
週次出力本数の見積もりは、代表的な動画1本のレンダリング実時間を測定してから行う。実時間をT分とすると、デフォルト構成での1時間あたり最大処理本数は 5 × (60 / T) になり、これに週の稼働時間を掛けた値が週次上限になる。AWSコンソールでクォータを引き上げれば MAX_CONCURRENT_RENDERS の上限も変わるが、動画が4,000フレーム未満であれば concurrency=200 を設定しても有効Lambda数はそれ以下に抑えられる。クォータを増やす前に、framesPerLambdaの計算が先決である。