はじめに: 数十億回のFFmpeg実行が生み出した独自の課題
Meta(Facebook)は1日に数百億回のFFmpegとffprobeを実行しています。ユーザーがアップロードする動画を、様々な解像度、コーデック、ビットレートでエンコードする必要があるからです。この規模において、FFmpegは単なるツールではなく、コアインフラそのものです。
問題は、FFmpegが元々このような規模を想定して設計されていないことです。個別ファイルのトランスコーディングは優れていますが、数億のアップロードを効率的に処理するには追加機能が必要でした。そこでMetaは長年、独自のFFmpegフォークを維持し、マルチスレッド・マルチレーンエンコーディング、リアルタイム画質測定などの機能を内部で開発してきました。
しかし時間が経つにつれ、内部フォークはアップストリームから乖離し、新しいコーデックのサポートや安定性の改善といったアップストリームの恩恵を受けにくくなりました。これは技術的負債の典型的なケースです。最終的にMetaはフォークを廃止し、すべての機能をアップストリームにコントリビュートすることを決定しました。
この記事では、Metaがどのようなプロセスでこの移行を成功させたのか、そしてその過程で得られた技術的インサイトを共有します。
参考資料: 本内容はMeta Engineeringブログに掲載された FFmpeg at Meta: Media Processing at Scale を基に再構成しています。

主要改善1: マルチレーントランスコーディングの効率化
問題の状況
ユーザーが動画をアップロードすると、MetaはDASH(Dynamic Adaptive Streaming over HTTP)再生のために複数のエンコーディングを生成します。各エンコーディングは解像度、コーデック、フレームレート、画質レベルが異なりますが、すべて同じソースから派生します。
最も単純な方法は各エンコーディングを逐次実行することです。並列実行も可能ですが、各プロセスが同じデコード処理を重複して行うため非効率的です。
解決策: 単一FFmpegコマンドで複数出力を生成
Metaの内部フォークはビデオデコードを一度だけ実行し、デコードされたフレームを各出力のエンコーダインスタンスに送る方式を採用していました。これにより、プロセス起動オーバーヘッドとデコードの重複を大幅に削減しました。
# 単一コマンドで複数解像度のエンコーディングを生成(簡略化例)
ffmpeg -i input.mp4 \
-filter_complex "[0:v]split=3[v1][v2][v3]" \
-map "[v1]" -c:v libx264 -b:v 500k -s 640x360 output_360p.mp4 \
-map "[v2]" -c:v libx264 -b:v 1500k -s 1280x720 output_720p.mp4 \
-map "[v3]" -c:v libx264 -b:v 4000k -s 1920x1080 output_1080p.mp4
さらなる最適化: 並列エンコーディング
以前のFFmpegバージョンでは、複数のエンコーダを使用する際、各エンコーダがフレーム単位で逐次実行されていました。Metaのフォークはすべてのエンコーダインスタンスを並列実行し、全体のスループットを向上させました。
アップストリームへの貢献と現状
FFlabsやVideoLANのFFmpeg開発者がこの設計を参考に、FFmpeg 6.0からより効率的なスレッディングを実装し、8.0で完成させました。これは数十年でFFmpegにおける最も複雑なリファクタリングの1つであり、今ではすべてのFFmpegユーザーが恩恵を受けられるようになりました。
Qiitaコミュニティでの議論を踏まえて: 国内の動画配信サービスでも、同様のマルチレーントランスコーディングは需要が高いテーマです。特にVODアップロードが多いサービスでは、単一コマンドで複数出力を生成する方式を導入することでサーバリソースを節約できます。ただし、filter_complexの記述は複雑になりがちなので、最初はシンプルなsplitから始めることをお勧めします。

主要改善2: リアルタイム画質測定(In-Loop Quality Metrics)
問題の状況
VOD(ビデオ・オン・デマンド)の場合、エンコーディング完了後に別のコマンドでPSNR、SSIM、VMAFなどの画質指標を計算できます。しかしライブストリーミングではリアルタイムで画質をモニタリングする必要があります。
解決策: In-Loopデコード
Metaの内部フォークは、各出力レーンのエンコーダの後ろにビデオデコーダを追加で挿入しました。圧縮適用後のフレームを再びビットマップに復元し、圧縮前のフレームと比較する方式です。
# in-loop quality metrics 計算(概念的な例)
ffmpeg -i input.mp4 \
-filter_complex "[0:v]split=2[ref][enc]; \
[enc]libx264[compressed]; \
[compressed]decode[dec]; \
[ref][dec]libvmaf=model_path=vmaf_v0.6.1.json" \
-f null -
アップストリームへの貢献
FFlabsとVideoLANの開発者がFFmpeg 7.0からin-loopデコードを可能にし、Metaはこの機能によって内部フォークを完全に置き換えることができました。
注意点
in-loopデコードは追加のCPU/GPUリソースを消費します。すべてのエンコーディングに適用するのではなく、サンプリングベースで運用するか、重要なライブストリームにのみ適用する戦略が必要です。Metaの場合、数十億のアップロードのうち一部にのみ適用しても、パイプライン全体の品質をモニタリングできました。
次のステップとしての学習方向: FFmpegのフィルタグラフ(filtergraph)を深く理解したい場合は、FFmpegフィルタドキュメントが参考になります。また、VMAFモデルを独自に学習させ、サービスに特化した画質指標を作成する方法も検討価値があります。

結論: フォーク地獄からの脱出が教えてくれたこと
MetaのFFmpegフォーク廃止の事例は、大規模組織がオープンソースプロジェクトとどう付き合うべきかについて、良い教訓を与えてくれます。
- フォークは最後の手段: 初期には必要に見えても、時間とともに技術的負債が蓄積し、メンテナンスコストが増大します。
- アップストリームファースト戦略: 必要な機能があれば、可能な限りアップストリームにコントリビュートする方が長期的に有利です。MetaはFFlabs、VideoLANと協力し、FFmpeg 6.0、7.0、8.0にわたって必要な機能を追加しました。
- すべての機能をアップストリームする必要はない: MSVP(Meta Scalable Video Processor)のような内部専用ハードウェアのサポートパッチは、むしろアップストリームに混乱をもたらす可能性があるため、内部で維持するのが合理的です。
Metaは現在、すべてのVODおよびライブストリーミングパイプラインで内部フォークの代わりにアップストリームFFmpegを使用しています。25年以上にわたって活発に開発されてきたFFmpegの安定性と新機能を活用しながら、同時に独自の最適化も維持できるようになりました。
合わせて読みたい記事: