動画を指定 MB に圧縮する実装メモ:CRF 試行と目標ビットレート
指定の整数 MB 以内に動画を収める必要がある場面は多い。チャンネルのアップロード上限、メール添付上限、社内ストレージの単一ファイル制限など。Discord 無料枠がだいたい 20MB、メールがだいたい 25MB、といった数字は、そうした制約の分かりやすい例にすぎない。
このメモは ffmpeg(H.264 / libx264)で「指定サイズ」を狙うときの手順備忘録。品質優先の CRF と、上限から逆算する目標ビットレートの使い分けを中心に書く。
なぜ「指定 MB」なのか
開発まわりで欲しいのは、だいたい次の三点だ。
- 相手側の上限に収まる
- コードや UI の文字が読める
- 試行回数を減らす
「できるだけ小さく」と「19MB 以下に確実に」は別問題。前者なら CRF で足りることが多い。後者は 体積上限からビットレートを逆算しないと、あと 1MB 足りない/文字が潰れた、の往復になりやすい。
CRF 試行の限界
CRF(Constant Rate Factor)は品質目標に合わせてビットレートを振る。値が小さいほど高品質・ファイルが大きくなりやすい。
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k out.mp4
preset(ultrafast〜veryslow)は速度と圧縮効率の話で、「何 MB になるか」を直接は決めない。
CRF が向かない理由は次のとおり。
- サイズを直接指定できない。同じ CRF でも尺・解像度・画の複雑さで結果が変わる。
- 試行コストが高い。20MB に入れるために CRF を 23→26→28 と何度も回すことになる。
- 読みやすさを落としやすい。確実に小さくしようとして CRF を緩めすぎると、録画内のフォントが潰れる。
品質優先・サイズはだいたいでよい、なら CRF。厳しい上限なら次の節。
目標ビットレート:上限から逆算
ざっくり次の式で総ビットレートを見積もる(コンテナ等の余裕は別途確保)。
目標総ビットレート(kbps) ≈ 目標サイズ(MB) × 8 × 1024 / 尺(秒)
動画ビットレート = 総ビットレート − 音声ビットレート。実務では目標サイズの 90〜95% で計算するか、音声を引いたあとに 0.9 を掛ける。
例:180 秒の画面録画を約 19MB にしたい(Discord ≈20MB の余白)。
総ビットレート ≈ 19 × 8 × 1024 / 180 ≈ 865 kbps
音声 96 kbps → 動画はおよそ 770 kbps
さらに 10% 余白 → 動画 700 kbps から試す
尺の取得:
ffprobe -v error -show_entries format=duration -of default=nw=1:nk=1 input.mp4
1-pass の例:
ffmpeg -i input.mp4 \
-c:v libx264 -b:v 700k -maxrate 700k -bufsize 1400k \
-preset medium -c:a aac -b:a 96k \
out-19mb.mp4
-maxrate / -bufsize で瞬間的な跳ね上がりを抑える。まだ大きいなら -b:v を下げるか、先に解像度を落とす。
2-pass:サイズを寄せやすい
複雑な区間で 1-pass が上振れしやすいときは 2-pass。
# pass 1
ffmpeg -y -i input.mp4 -c:v libx264 -b:v 700k -pass 1 -an -f null /dev/null
# pass 2
ffmpeg -i input.mp4 -c:v libx264 -b:v 700k -pass 2 \
-c:a aac -b:a 96k -movflags +faststart out-19mb.mp4
Windows なら null 出力は NUL。pass 1 のログ(ffmpeg2pass-0.log など)は同じディレクトリで pass 2 が読む。遅いが、目標に近づきやすく「あと 1.5MB」の再エンコードが減る。
メール添付がだいたい 25MB なら、同じ式で目標を 23〜24MB にするだけ。考え方は変えない。
scale と音声ビットレート
まだ入らないときは、ビットレートをさらに絞る前に次を見る。
解像度を下げる
ffmpeg -i input.mp4 -vf "scale=-2:720" \
-c:v libx264 -b:v 700k -c:a aac -b:a 96k out.mp4
1080p のデモ録画でも、技術共有なら 720p で文字が読めることが多い。-2 は偶数幅を保つため。
音声を抑える
画面録画+話声なら AAC 96kbps で十分なことが多い。音楽寄りなら 128kbps。音声を 32kbps 削ると、長い尺では動画側の予算が増える。
おすすめの順番:不要な尺を切る → 必要なら scale → 式で目標ビットレート(できれば 2-pass)→ 最後に品質を大きく落とす。先に尺を短くした方が、同じサイズでも読みやすさが残りやすい。
スクリプトを維持するのが面倒なとき
バッチや CI では自前の ffmpeg が第一選択。たまに 1 本だけ圧縮したい・パラメータを覚えたくない、というときだけ、既存ツールで済ませる選択もある。VideoBee の動画圧縮 は Basic で目標サイズを入れられる。透かしなし・登録なし。クラウド処理で、結果はだいたい 24 時間で削除、AI 学習には使わないと明記。圧縮上限は およそ 10GB。コマンドの代替というより、「メンテしたくない日」の逃げ道程度。

まとめ
| 目的 | 向きやすい手段 |
|---|---|
| 品質優先・サイズは目安 | CRF + preset |
| 必ず ≤ N MB | サイズからビットレート逆算、必要なら 2-pass |
| それでも超える | 尺を切る / scale / 音声と動画ビットレートを再配分 |
指定 MB は「品質の勘」を「ビットレート予算」に置き換える作業。式は単純で、余白を残すのが本番。Discord 20MB やメール 25MB は、その予算に載せる上限の例にすぎない。