Blog encoding

Target an exact video file size: two-pass encoding

Most encoders target quality, some bitrate, almost none target file size. How two-pass encoding works, when to use it, and the math behind hitting any cap.

If you’ve ever needed a video file under exactly 100 MB, you’ve felt the gap. Most encoders happily let you target a quality level (CRF 23), or a constant bitrate, or a maximum bitrate. Almost none let you say “give me a 100 MB file.” That problem is what two-pass encoding solves.

This post is the practical version: what it is, how the math works, when to use it, and how to do it without writing ffmpeg commands.

TL;DR

Two-pass encoding runs the video twice. The first pass analyzes content complexity; the second pass uses that to spend bits where they matter, producing better quality at a given target bitrate than single-pass.

For “give me a 100 MB file” workflows, two-pass is the only way to hit the target reliably. Video Forge automates both passes; if you want it manual, the ffmpeg pattern is at the end of this post.

The problem two-pass solves

Single-pass encoding makes bitrate decisions one frame at a time, with no knowledge of what’s coming next. If the encoder hits a complex scene late in the file and has already spent its budget on simpler earlier scenes, quality drops. If the file starts complex and gets simple, the encoder wastes bits on the simple back half.

Two-pass solves this by giving the encoder the whole picture before it makes any commits:

  1. Pass 1 runs through the video once, analyzing per-frame complexity, motion, and predictability. Output: a stats file (no actual video).
  2. Pass 2 uses the stats to allocate bitrate intelligently across the timeline. Output: the actual encoded video, hitting the target bitrate on average with much better visual quality than single-pass at the same bitrate.

The result is the encoder spending more bits on the fast-moving sports sequence and fewer on the static interview shot, and ending up at exactly (or very close to) the target file size.

The size-to-bitrate math

Every two-pass workflow starts with this conversion: take a desired file size and a duration, and compute the target average bitrate.

target_video_kbps = (max_size_mb × 1024 × 1024 × 8) / (duration_seconds × 1000)
                    − audio_kbps
                    × 0.95   # safety margin

The × 0.95 is to leave room for container overhead and the natural variance of variable-bitrate output. Without it, you end up about 3 to 5% over the target.

Worked example: target 100 MB, 5-minute video, AAC audio at 192 kbps:

total_kbps  = (100 × 1024 × 1024 × 8) / (300 × 1000)
           = 2796 kbps
video_kbps = 2796 − 192 = 2604 kbps
× 0.95     = ~2473 kbps

So a 5-minute video targeted at 100 MB needs ~2473 kbps of video bitrate. At 1080p with H.264, that’s just-good-enough quality. At 720p, it’s generous. At 4K, it’s going to look soft. Resolution choice is part of the budget.

When two-pass is worth it

Use two-pass when:

Skip two-pass when:

A useful rule of thumb: if you’d be willing to ship the file at “whatever size CRF 23 gives me,” skip two-pass. If you’d be willing to ship at “exactly 50 MB, no more,” do two-pass.

How Video Forge handles it

In Video Forge, two-pass is automatic whenever you pick a destination with a size cap (WhatsApp, Discord, Email) or set Quality Mode to “Target file size” in Manual.

The flow:

  1. You drop in a video; Video Forge reads its duration via ffprobe.
  2. You pick WhatsApp (or set a manual target like “50 MB”).
  3. The app computes the target bitrate using the formula above. The 0.95 safety margin is baked in.
  4. The job runs as two ffmpeg invocations under the hood — pass 1 produces a stats file in a tempdir; pass 2 reads the stats and produces the output.
  5. Both passes report progress to the UI. Pass 1 is mapped to 0-50% of the progress bar; pass 2 is 50-100%.

If you tweak settings after the bitrate has been computed (changing audio codec, resolution, etc.), Video Forge recomputes the target before the job starts. There’s nothing to remember.

Doing it manually with ffmpeg

If you want to drive ffmpeg directly:

# Pass 1: analyze, no output (writes to ffmpeg2pass-0.log)
ffmpeg -y -i input.mov -c:v libx264 -b:v 2473k -pass 1 \
       -an -f mp4 /dev/null

# Pass 2: encode using the stats from pass 1
ffmpeg -i input.mov -c:v libx264 -b:v 2473k -pass 2 \
       -c:a aac -b:a 192k -movflags +faststart \
       output.mp4

Notes:

For H.265 (libx265) — useful when archive size matters more than universal compatibility, see the codec comparison for when to pick H.265 over H.264 — the syntax is slightly different:

ffmpeg -y -i input.mov -c:v libx265 -b:v 1500k \
       -x265-params pass=1 -an -f mp4 /dev/null

ffmpeg -i input.mov -c:v libx265 -b:v 1500k \
       -x265-params pass=2 -c:a aac -b:a 192k output.mp4

x265 takes its pass directive inside -x265-params instead of as a top-level flag.

Common mistakes

A practical comparison

I encoded a 60-second 1080p clip (mixed-content footage, M2 Pro, ffmpeg 7.0) three ways to a 30 MB target:

MethodTimeFinal sizeVisual quality (PSNR)
Single-pass CRF 2314s28.4 MB41.8 dB
Single-pass -b:v 4Mbps12s30.1 MB41.2 dB
Two-pass -b:v 4Mbps23s29.7 MB42.6 dB

The two-pass version hit the target more precisely and gained almost 1 dB of PSNR over single-pass at the same bitrate. CRF was indistinguishable from two-pass on the eye-test but missed the target by 5%. The choice depends on whether “30 MB-ish” or “exactly 30 MB” is what you need.

FAQ

What is two-pass encoding? Two-pass encoding runs the video twice. The first pass analyzes content complexity and writes a stats file. The second pass uses those stats to allocate bitrate intelligently across the timeline, producing better quality at the target bitrate than single-pass.

Is two-pass slower than single-pass? Roughly 1.6 to 1.8× the time of single-pass. The first pass is fast (analysis only, no real output); the second pass is full-rate.

When should I use two-pass encoding? When you need to hit an exact file size or bitrate budget. For CRF-targeted “just make it look good” encodes, single-pass is fine.

Can two-pass encoding hit an exact file size? It usually lands within a few percent of the target. Allow a 5% safety margin, or set the target slightly below the cap.

Does Video Forge do two-pass automatically? Yes, whenever you pick a destination with a size cap (WhatsApp, Discord, Email) or set Quality Mode to “Target file size” in Manual mode.


Video Forge handles two-pass encoding automatically for any destination with a size cap. 10 conversions are free on macOS and Windows; ffmpeg is bundled.