GIFはフレームごとに待ち時間を保存します

GIF89aのGraphic Control Extensionは、0以外の遅延を1/100秒単位で保存します。1単位は10msです。Moyoutilは各フレームの1000/FPS msを同梱のgifenc 1.0.3へ渡し、エンコーダーは10で割って丸めます。15FPSの約66.667msは7単位、70msになります。選択したFPSはフレーム抽出の設定であり、そのままGIFに保存されるFPS値ではありません。

5・10・15FPSの1秒の仮想フレームで保存された遅延合計1000・1000・1050msの比較
独自制作の遅延合計図。棒の長さは保存フィールドの合計に比例します。画面上の実再生時間を測定したグラフではありません。

GIF89a §23: Graphic Control Extension

1秒を選択したときの保存合計を再現する

同じGIFワーカーコードとエンコーダーで1×1pxの仮想フレームを生成し、遅延フィールドを読みました。1秒・5FPSは5フレーム×200ms=1000ms、10FPSは10×100ms=1000ms、15FPSは15×70ms=1050msでした。これはテストGIFの保存値です。実際の動画変換やプレーヤーの再生時間測定ではありません。以下の計算コードは同じ数値を再現します。

for (const fps of [5, 10, 15]) {
  const frames = Math.ceil(1 * fps);
  const delayMs = Math.round(1000 / fps / 10) * 10;
  console.log(fps, frames, delayMs, frames * delayMs);
}
// 5 5 200 1000
// 10 10 100 1000
// 15 15 70 1050

フレーム数はceil(長さ×FPS)です。0.1秒・15FPSは2フレームとなり、保存遅延の合計は140msです。現在のGIF画面は5・10・15FPSを提供し、最大10秒・150フレームです。タイミングが重要なら、出力ファイルを使用予定のプレーヤーで確認してください。この計算だけで全プレーヤーの再生時間や変換処理時間は予測できません。

gifenc: writeFrame / delayTime

よくある質問

15FPSを選ぶと1秒は必ず1.05秒で再生されますか?

いいえ。1050msはこの1秒・15フレームの例の保存遅延合計です。実際の表示タイミングは別途検証が必要で、この記事ではプレーヤー別の再生時間を測定していません。