Lambda で FFmpeg が水に合わない理由——Serverless で踏んだ落とし穴
AWS Lambda、Vercel、Cloudflare Workers で FFmpeg を動かそうとして詰まった点——バイナリサイズ、タイムアウト、メモリ、コールドスタートと現実的な代替案。

Serverless は「無限にスケール、運用ゼロ」を謳います。だから動画処理——クリップのトリム、サムネ生成、アップロード変換——が必要になったとき、最初に思い付くのは「Lambda で FFmpeg を動かせばいいじゃん」という発想です。どれくらい大変なんだ、と。
実際にやると、めちゃくちゃ大変でした。この記事では、Serverless で FFmpeg を動かすときに実際に遭遇する問題、よくある回避策とその限界、そしてどこから先は専用 API を使ったほうが良いのかをまとめます。
なぜ Serverless で FFmpeg はつらいのか
1. バイナリサイズ——スタート時点で 70MB 超
主要コーデック(H.264、H.265、VP9、AAC、Opus)入りで静的ビルドした FFmpeg は 70〜100 MB。libass(字幕)や libfdk-aac(高音質 AAC)まで足すと 120 MB 超。
プラットフォーム側の上限がきつい:
| プラットフォーム | デプロイサイズ上限 | 内訳 |
|---|---|---|
| AWS Lambda(zip) | 50 MB(unzip 後 250 MB) | コード + 依存 + バイナリ |
| AWS Lambda(コンテナ) | 10 GB | 余裕あるが cold start が遅い |
| Vercel Serverless Functions | 50 MB | 圧縮後 |
| Cloudflare Workers | 10 MB(有料プラン) | ネイティブバイナリ非対応 |
| Google Cloud Functions | 500 MB(ソース) | 比較的緩い |
AWS Lambda の zip デプロイだと FFmpeg バイナリだけで 50 MB 枠の大半を持っていかれる。アプリ本体のコードが残った隙間で取り合うことになる。
2. 実行時間タイムアウト——最大 15 分
AWS Lambda の最大実行時間は 15 分。他はもっと厳しい:
| プラットフォーム | 最大タイムアウト |
|---|---|
| AWS Lambda | 15 分 |
| Google Cloud Functions | 9 分(2nd gen で 60 分) |
| Vercel Serverless | 5 分(Pro)、60s(Hobby) |
| Cloudflare Workers | 30s(標準)、15 分(Workflows) |
15 分は十分長そうに見える。FFmpeg の現実的な処理時間を見るまでは:
| タスク | 1080p、10 分動画 | 2 vCPU での所要時間 |
|---|---|---|
| サムネイル抽出 | 1 フレーム | < 1 秒 |
| 音声抽出 | ストリームコピー | < 5 秒 |
| H.264 トランスコード | CRF 23、medium | 8〜12 分 |
| H.265 トランスコード | CRF 28、medium | 15〜25 分 |
| 字幕焼き込み | 再エンコード | 10〜15 分 |
| VP9 トランスコード | CRF 30 | 20〜40 分 |
サムネと音声抽出は楽勝。でも数分以上の動画の本格的なトランスコードは、Lambda タイムアウトに引っかかるか、危険なほど近づくかのどちらかです。エンコード時間に効く設定は 動画圧縮のベストプラクティス を参照。
3. メモリ制限——大きいファイルが置けない
動画処理はメモリを食う。FFmpeg は入出力をバッファし、複雑なフィルタは複数フレームを同時に保持します。
| プラットフォーム | 最大メモリ |
|---|---|
| AWS Lambda | 10 GB |
| Google Cloud Functions | 32 GB(2nd gen) |
| Vercel Serverless | 3 GB |
| Cloudflare Workers | 128 MB |
Lambda の 10 GB は良さそうに見える——ただしメモリは直接コストに効きます。Lambda は GB 秒課金。4 GB を 10 分使う関数は、256 MB を 15 秒使う関数より 40 倍 高い。
実測のメモリ使用量:
| タスク | 典型的な使用メモリ |
|---|---|
| サムネイル抽出 | 100〜200 MB |
| 音声抽出 | 50〜150 MB |
| 1080p H.264 トランスコード | 500 MB〜1.5 GB |
| 4K H.264 トランスコード | 2〜4 GB |
| 複雑なフィルタチェーン | 1〜4 GB |
4. GPU が使えない
ハードウェアエンコード(NVENC、QSV、VAML)は H.264/H.265 で 5〜10 倍速い。が、Serverless は GPU を提供しません。
つまり CPU エンコード一択。これは:
- GPU エンコードより 5〜10 倍遅い
- 大規模では動画 1 本あたりのコストが高い
- タイムアウト上限に引っかかりやすい
5. コールドスタートのペナルティ
cold start のたびに FFmpeg バイナリを実行環境にロードする必要があります。70 MB 超のバイナリで、プラットフォーム側の初期化に加えて 1〜3 秒 のコールドスタート遅延が乗ります。
コンテナベース Lambda(大きいバイナリを載せるなら必須)だと cold start が 5〜15 秒 にまで伸びることもある。
6. 一時ストレージの制約
Lambda は /tmp をデフォルト 512 MB(追加課金で 10 GB まで)提供。動画ファイルはでかい——10 分の 1080p 動画は 500 MB〜1 GB。入力と出力の両方を置く場所が要ります:
入力ファイル: 500 MB
出力ファイル: 300 MB
FFmpeg 一時: 200 MB
─────────────────
合計: 1 GB ← デフォルト /tmp を超える
7. 永続プロセスがない
FFmpeg はプロセスを温めて使い回せると効率的(バイナリのウォーム保持、デコードキャッシュ、コネクション再利用)。Serverless はステートレス・短命。呼び出しごとに毎回ゼロから。
よくある回避策
それでも Serverless で FFmpeg を動かすチームはあります。代表的なアプローチ:
Lambda Layers
AWS Lambda Layers を使うと FFmpeg をアプリコードと別パッケージにできる:
# Download a static FFmpeg build
wget https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz
tar xf ffmpeg-release-amd64-static.tar.xz
# Create Lambda layer structure
mkdir -p ffmpeg-layer/bin
cp ffmpeg-*-amd64-static/ffmpeg ffmpeg-layer/bin/
cd ffmpeg-layer && zip -r ../ffmpeg-layer.zip .
Lambda 関数側:
const { execSync } = require('child_process');
exports.handler = async (event) => {
// FFmpeg binary from layer is at /opt/bin/ffmpeg
const result = execSync(
'/opt/bin/ffmpeg -i /tmp/input.mp4 -vf "scale=-2:720" -crf 23 /tmp/output.mp4',
{ timeout: 300000 }
);
return { statusCode: 200 };
};
限界:
- Layer サイズも 250 MB unzip 上限にカウントされる
- 必要なコーデックだけに FFmpeg を絞り込む必要あり
- 自前 FFmpeg ビルドのメンテが恒常的な負担になる
Docker Container Images
Lambda は最大 10 GB のコンテナイメージを許容するので、サイズ的な余裕は出ます:
FROM public.ecr.aws/lambda/nodejs:20
# Install FFmpeg
RUN yum install -y tar xz && \
curl -L https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz | \
tar xJ --strip-components=1 -C /usr/local/bin/ --wildcards '*/ffmpeg' '*/ffprobe'
COPY index.mjs ${LAMBDA_TASK_ROOT}/
CMD ["index.handler"]
限界:
- コールドスタートが目に見えて長くなる(5〜15 秒)
- イメージが大きいぶん ECR ストレージコストが上がる
- 15 分タイムアウトと GPU 非対応は相変わらず
ffmpeg.wasm——ブラウザ/Edge 用 FFmpeg
ffmpeg.wasm は FFmpeg を WebAssembly にコンパイルしたもの。ブラウザや Edge ランタイムで動く:
import { FFmpeg } from '@ffmpeg/ffmpeg';
import { fetchFile } from '@ffmpeg/util';
const ffmpeg = new FFmpeg();
await ffmpeg.load();
await ffmpeg.writeFile('input.mp4', await fetchFile(videoUrl));
await ffmpeg.exec(['-i', 'input.mp4', '-vf', 'scale=-2:720', 'output.mp4']);
const data = await ffmpeg.readFile('output.mp4');
限界:
- ネイティブ FFmpeg より 3〜10 倍遅い
- コーデックサポートが限定的(H.265 不可、フィルタも制限あり)
- ブラウザ環境ではメモリも制限される
- 数百 MB を超えるファイルは扱えない
- ほとんどの環境でシングルスレッド
チャンク分割処理
大きい動画を分割し、並列処理して結合する:
# Split into 2-minute segments
ffmpeg -i input.mp4 -c copy -segment_time 120 -f segment -reset_timestamps 1 chunk_%03d.mp4
// Process chunks in parallel Lambda invocations
const chunks = ['chunk_000.mp4', 'chunk_001.mp4', 'chunk_002.mp4'];
const results = await Promise.all(
chunks.map(chunk => lambda.invoke({
FunctionName: 'process-chunk',
Payload: JSON.stringify({ chunk })
}).promise())
);
// Merge results
// (requires another Lambda invocation)
限界:
- オーケストレーションが複雑化する(Step Functions、SQS など)
- 全操作がチャンク化に向くわけではない(字幕タイミングなど)
- 結合処理がレイテンシを足し、境界にアーティファクトが出る場合がある
- 結局シングルプロセスより総コストが高くなりがち
削ぎ落とした FFmpeg ビルド
必要なコーデックだけでコンパイルしてバイナリを縮める:
./configure \
--disable-everything \
--enable-decoder=h264,aac,mp3 \
--enable-encoder=libx264,aac \
--enable-muxer=mp4,mp3 \
--enable-demuxer=mov,mp4,mp3 \
--enable-protocol=file,pipe \
--enable-filter=scale,overlay \
--enable-gpl --enable-libx264
15〜25 MB まで落とせるが、機能を失う。来月 VP9 が必要になったら?再ビルド。
実測例:Lambda vs 専用サーバー
差を実感してもらうため、5 分の 1080p 動画でのベンチ:
| タスク | Lambda(3 GB、arm64) | EC2 c6g.large(2 vCPU) | EC2 g5.xlarge(GPU) |
|---|---|---|---|
| サムネイル | 0.8s | 0.5s | 0.3s |
| 音声抽出 | 2s | 1.5s | 1.5s |
| H.264 CRF 23 | 4.5 分 | 3.2 分 | 25s |
| H.265 CRF 28 | 9 分 | 7 分 | 35s |
| VP9 CRF 30 | 12 分 | 9 分 | N/A |
1000 本の H.264 トランスコード(5 分・1080p)でのコスト比較:
| 方式 | 1 本あたり時間 | 1 本あたりコスト | 総コスト |
|---|---|---|---|
| Lambda(3 GB) | 4.5 分 | 約 $0.022 | 約 $22 |
| EC2 c6g.large(リザーブド) | 3.2 分 | 約 $0.004 | 約 $4 |
| EC2 g5.xlarge(GPU) | 25s | 約 $0.008 | 約 $8 |
定常ワークロードなら、Lambda はリザーブド EC2 と比べておよそ 5 倍高い。1 時間に数本以上動画が来るならコスト面で勝てません。
Serverless FFmpeg が向くケース
罠だらけと言ってきましたが、ハマるユースケースもあります:
- サムネイル生成——速い、低メモリ、上限に余裕
- ストリームコピーでの音声抽出——ほぼ瞬時、リソース消費も少ない
- 30 秒未満の短尺クリップ——タイムアウトせずに変換できる
- メタデータ抽出——ffprobe はミリ秒で終わる
- 散発的・予測不能なトラフィック——数時間リクエストが来ないこともあるケース
# These tasks work well on Lambda
ffmpeg -i input.mp4 -ss 00:00:05 -frames:v 1 thumbnail.jpg # < 1s
ffmpeg -i input.mp4 -vn -c:a copy audio.aac # < 2s
ffprobe -v quiet -print_format json -show_format -show_streams input.mp4 # < 1s
専用 API を使うべきケース
Serverless だと厳しいのは:
- 2〜3 分を超える動画のトランスコード——タイムアウトリスク
- H.265 や VP9 エンコード——GPU なしでは遅すぎる
- 複雑なフィルタチェーン——字幕、オーバーレイ、マルチ入力合成
- 大規模で予測可能な処理——コストが釣り合わなくなる
- フルコーデックサポート——削ぎ落としビルドだと選択肢が狭い
- GPU アクセラレーション——Serverless にはない
このあたりは専用の動画処理 API でインフラを丸ごと外したほうが楽です。マネージド系を比較するなら FFHub と AWS MediaConvert の比較 もどうぞ。
FFHub:インフラなしの Cloud FFmpeg
FFHub は Serverless が解けない問題に的を絞った Cloud FFmpeg API です。ローカルで叩くのと同じ FFmpeg コマンドを送ると、最適化されたインフラ上で実行されます。
# Instead of wrestling with Lambda layers and timeouts:
curl -X POST https://api.ffhub.io/v1/command \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{
"command": "-i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac output.mp4",
"inputs": ["https://storage.example.com/input.mp4"],
"webhook": "https://your-app.com/callback"
}'
Serverless FFmpeg と比べた利点:
- バイナリ管理不要——フルコーデック、常に最新
- タイムアウトなし——どんな長さの動画でも処理可能
- 最適化されたインフラ——動画処理向けにチューンされた専用ハードウェア
- 同じ FFmpeg シンタックス——新しい API を覚える必要なし
- 従量課金——アイドルインフラのコストなし
特に、本業が動画処理ではないチームには効きます——機能開発に時間を使うべきところで FFmpeg ビルドや Lambda Layer をメンテしている時間はないはずです。
判断フレームワーク
| 観点 | Serverless | 専用 API |
|---|---|---|
| 動画長 | 30 秒未満 | 任意 |
| タスク種別 | サムネ、メタデータ、音声コピー | トランスコード、字幕、フィルタ |
| ボリューム | 50 本/日未満 | 任意 |
| コーデック要件 | H.264 のみ | 任意 |
| GPU 要 | 不要 | 必要(速度面で) |
| チーム体制 | 専任 DevOps あり | マネージド志向 |
まとめ
Serverless で FFmpeg を動かすことは技術的には可能です——ただし苦行です。バイナリサイズ、タイムアウト、メモリコスト、GPU の不在。サムネ生成や音声抽出みたいな簡単なタスク以外には合いません。
本格的なトランスコードを伴うワークロードなら、Lambda の請求書だけでなくカスタム FFmpeg デプロイを構築・維持するエンジニア工数まで含めた総コストで考えてください。多くのチームにとって、専用の動画処理 API のほうが、Serverless を無理やりこの用途に押し込めるより安く・確実です。FFHub という Cloud FFmpeg ソリューション や API でのバッチトランスコード も参照を。
関連記事
- FFHub とは? - インフラ運用なしの Cloud FFmpeg を提供する仕組み
- API での動画バッチトランスコード - シンプルな REST API で何千本もの動画を処理
- FFHub vs AWS MediaConvert - FFHub と AWS のマネージド変換サービスを正直に比較