What You Will Learn

Tested version: FFmpeg 6.1 (ubuntu-latest / CI-validated)
Target OS: Windows / macOS / Linux


CRF Mode vs. Two-Pass Bitrate Mode

FFmpeg’s libx264 and libx265 encoders offer two main quality/bitrate control modes:

ModeOptionUse When
CRF (Constant Rate Factor)-crf 18–28You want consistent quality, file size varies
Two-pass bitrate-b:v N -pass 1/2You need to hit a specific file size or bitrate

CRF is simpler and often preferred for archiving or streaming. Two-pass is the right choice when you must deliver a file that fits within a specific size budget (e.g., email attachment limits, disc capacity).


How Two-Pass Works

Pass 1 (Analysis): FFmpeg encodes the video quickly, writing a log file that records the complexity of each frame. No output video is produced — only the log file matters.

Pass 2 (Encoding): FFmpeg reads the log file to understand which scenes need more bits and which need fewer, then encodes the final output with the bitrate distributed according to the analysis.

The log file is named ffmpeg2pass-0.log (and ffmpeg2pass-0.log.mbtree for H.264) in the working directory.


Basic Two-Pass H.264 Example

Pass 1 — Analysis only, no output:

ffmpeg -i input.mp4 -c:v libx264 -b:v 1M -pass 1 -an -f null /dev/null

Pass 2 — Actual encode with analysis data:

ffmpeg -i input.mp4 -c:v libx264 -b:v 1M -pass 2 -c:a aac -b:a 128k output.mp4

Run both commands in the same directory — FFmpeg looks for ffmpeg2pass-0.log in the current working directory.


Targeting a Specific File Size

To calculate the bitrate for a target file size:

total_bitrate_kbps = (target_size_MB × 8192) ÷ duration_seconds
video_bitrate_kbps = total_bitrate_kbps − audio_bitrate_kbps

Example: Target 50 MB for a 4-minute (240-second) video with 128 kbps audio:

total = (50 × 8192) ÷ 240 ≈ 1707 kbps
video = 1707 − 128 = 1579 kbps ≈ 1.5M

Pass 1:

ffmpeg -i input.mp4 -c:v libx264 -b:v 1500k -pass 1 -an -f null /dev/null

Pass 2:

ffmpeg -i input.mp4 -c:v libx264 -b:v 1500k -pass 2 -c:a aac -b:a 128k output.mp4

Custom Log File Location

By default, FFmpeg writes the log to ./ffmpeg2pass-0.log. Use -passlogfile to specify a different path (useful in scripts or when encoding multiple files in parallel):

ffmpeg -i input.mp4 -c:v libx264 -b:v 1M -pass 1 -passlogfile /tmp/mylog -an -f null /dev/null
ffmpeg -i input.mp4 -c:v libx264 -b:v 1M -pass 2 -passlogfile /tmp/mylog -c:a aac output.mp4

Two-Pass H.265 (libx265)

Two-pass encoding with H.265 follows the same structure:

ffmpeg -i input.mp4 -c:v libx265 -b:v 800k -x265-params pass=1 -an -f null /dev/null
ffmpeg -i input.mp4 -c:v libx265 -b:v 800k -x265-params pass=2 -c:a aac output.mp4

Note: libx265 uses -x265-params pass=1 instead of -pass 1. The behavior is otherwise identical.


Adding Encoder Presets

You can combine two-pass with encoder presets. A slower preset gives the encoder more time to find efficient coding decisions:

ffmpeg -i input.mp4 -c:v libx264 -preset slow -b:v 1M -pass 1 -an -f null /dev/null
ffmpeg -i input.mp4 -c:v libx264 -preset slow -b:v 1M -pass 2 -c:a aac -b:a 128k output.mp4

Use the same preset in both passes to ensure the log file and pass 2 analysis are consistent.


When to Use Two-Pass

ScenarioRecommendation
Archiving with consistent visual qualityUse CRF mode (-crf 23)
File must fit a specific size limitUse two-pass bitrate mode
Streaming delivery with guaranteed bitrateTwo-pass (or constrained bitrate with -maxrate)
Quick transcodes or previewsCRF mode (single pass)

Common Pitfalls

Log File Not Found in Pass 2

If pass 2 runs in a different directory than pass 1, it cannot find ffmpeg2pass-0.log. Either run both in the same directory, or use -passlogfile /path/to/log in both passes.

Audio in Pass 1

Pass 1 with -an skips audio encoding, which is correct — the log only needs video complexity data. Including audio in pass 1 wastes time without benefit.

Same -b:v in Both Passes

Always use the same -b:v value in both passes. Using different values means the log from pass 1 targets a different bitrate than pass 2, producing unreliable results.



Tested with: ffmpeg 6.1.1 / Ubuntu 24.04 (GitHub Actions runner)
Primary sources: trac.ffmpeg.org/wiki/Encode/H.264 / ffmpeg.org/ffmpeg.html