DEV Community

NullPointerZen
NullPointerZen

Posted on

HandBrake two-pass vs hand-written FFmpeg two-pass: which lands closer to a 10 MB target?


I am not a video person. I came into tech from a content-ops job, so I use whatever tool gets a clip under a size limit without making me read a manual. When the limit is a hard number, say 10 MB for an upload form, I had two options on my machine: HandBrake with its two-pass setting, or a two-pass command I type into FFmpeg myself. I wanted to know which one actually lands closer to the number, so I ran both on the same clip with the same bitrate.

Everything below is one run per setting, on an M4 Mac with HandBrake 1.11.2 and FFmpeg 7.1. Clip A is 60 seconds of 1080p, 30 fps street-performance footage by Isak Zvegelj (CC BY 3.0, Wikimedia Commons), re-encoded to a phone-level bitrate first, so it is not a phone original. Clip B is a screen recording I generated myself, so it is quieter and cleaner than a real one. Treat the numbers as "these two clips", not as a rule.

Both got the same bitrate

The video bitrate I fed both tools is target size × 8 ÷ 60 seconds, minus 128 kbps for the audio track. That is 1205 kbps for 10 MB and 3205 kbps for 25 MB. Audio is AAC 128 kbps in both. HandBrake's own log shows it encoded at 1205 and 3205 kbps, the same numbers I gave FFmpeg.

Here is the one difference I did not remove. FFmpeg ran x264 with -preset medium. HandBrake ran its built-in "Fast 1080p30" preset, which brings its own x264 settings. So this is "the tool as most people would click it" against "the command as I wrote it", not a controlled x264 experiment.

ffmpeg -i A.mp4 -c:v libx264 -preset medium -b:v 1205k -pass 1 -an -f null /dev/null
ffmpeg -i A.mp4 -c:v libx264 -preset medium -b:v 1205k -pass 2 -c:a aac -b:a 128k out.mp4
HandBrakeCLI -i A.mp4 -o out.mp4 --preset "Fast 1080p30" -b 1205 --multi-pass -B 128
Enter fullscreen mode Exit fullscreen mode

On the action clip both land within 2 percent

MB here means 1,000,000 bytes. If your limit is written in MiB (1,048,576 bytes per MB), a "10 MiB" cap is 10,485,760 bytes and you have about 4.9% more room, so check which one your form means.

Clip A Target Output (bytes) Over target Time
HandBrake Fast 1080p30, two-pass 10 MB 10,120,027 +1.20% 30.7 s
FFmpeg x264 medium, two-pass 10 MB 10,174,131 +1.74% 25.8 s
HandBrake Fast 1080p30, two-pass 25 MB 25,019,191 +0.08% 34.5 s
FFmpeg x264 medium, two-pass 25 MB 25,069,942 +0.28% 34.2 s

HandBrake finished closer both times, by about half a percentage point at 10 MB and 0.2 at 25 MB. My reading, and it is a reading, not something I tested: the delivered video bitrates were 1216 and 1218 kbps, so the two encoders produced almost the same video, and the gap is small enough that I would not pick a tool because of it. What I would take from the table is the sign. All four files came out over the target, even after I took the audio off the budget. If your limit is strict, aim a couple of percent low.

The built-in 25 MB preset plays it safe

HandBrake also ships a "Social 25 MB" preset. On the same clip it gave 23,596,928 bytes, which is 5.6% under 25 MB, at 1280×720. That is the opposite trade: it will not bust your limit, it leaves some size on the table, and it quietly drops the resolution. For an upload form that rejects oversize files, that is a reasonable default. For a clip that needs to stay 1080p, the manual bitrate was the one that kept it.

The screen recording is where both tools slip

The same two-pass setup on clip B at 10 MB: HandBrake gave 11,053,279 bytes (+10.5%), FFmpeg gave 11,195,510 bytes (+12.0%). Both overshot by a lot more than on the action clip. My guess is that a mostly static screen recording gives the encoder very uneven demands from second to second. That is an inference. The data only shows the overshoot.

Deviation from target size for single-pass, two-pass and CRF on both clips, x264 medium and AAC 128 kbps

What to look at in this chart (it shows the FFmpeg runs, not HandBrake): the two-pass bars on the action clip sit just above the target line, and the two-pass bar on the screen recording at 10 MB is the tall one. Clip A credit: Isak Zvegelj, CC BY 3.0. Clip B is synthetic.

Where a no-install tool fits

If you only want a free compressor and do not want either command line, ImgIng (https://imging.ai/) runs in a desktop browser, and its video page says processing happens locally. I saw no upload requests across 11 tasks. It does not work on phones. It also has no "compress to N MB" box. On clip A its smallest-size preset gave 10,487,546 bytes at 1080×608 and 24 fps, and its high-quality preset with the longest edge set to 1280 gave 25,938,497 bytes. Those are presets landing near a number, not a setting aimed at it, so for a hard cap I still pick bitrate by hand. Free-tier limits of online tools change, so read their pages on the day you use them.

What I would do now

For a hard cap, I would take the bitrate formula, subtract 128 kbps for audio, run HandBrake or FFmpeg two-pass, and then check the file size before uploading. If it is over, lower the bitrate by roughly the overage and run again. For a static screen recording I would start about 12 percent lower, since that is how far the synthetic one overshot. Both come from two clips, so run your own file once before you trust them.

Top comments (0)