# FFmpeg threads benchmark

Canonical: https://rendobar.com/blog/ffmpeg-threads-measured/
Author: Abdelrahman Essawy
Published: 2026-08-20
Updated: 2026-08-20

---

## Key takeaways

- Eight threads was 2.99x faster than one, not 8x. Parallel encoding scales sub-linearly and the returns fall off sharply after four.
- Every variant ran five times. With -threads pinned the spread was 1.4% to 8.9%, so these differences are real rather than noise.
- x264's default auto threading swung from 918 to 1,699 ms across five runs of identical work, an 85% spread. Pinning threads is what makes an FFmpeg benchmark reproducible.
- Output size was byte-identical across all five runs of every variant, including auto. Determinism holds; only the clock moves.
- Auto produced a 433.0 KB file where every explicit thread count produced 387.8 KB, 11.8% smaller. We do not have a confident explanation for that.

Adding threads to an encoder feels like it should be linear. Twice the threads,
half the time. It is not, and the gap between expectation and reality is large.

Short version. **Eight threads was 2.99x faster than one, not 8x.** And the more
useful finding: pinning `-threads` is what turns an FFmpeg benchmark from noisy
into reproducible.

## The scaling curve

Five runs per variant, median reported:

| Threads | Median | Speedup vs 1 |
|---|---:|---:|
| 1 | 3,644 ms | — |
| 2 | 2,122 ms | 1.72x |
| 4 | 1,510 ms | 2.41x |
| 8 | 1,220 ms | **2.99x** |

Doubling from one to two threads bought **1.72x**. Doubling again to four bought
another 1.4x. Doubling again to eight bought only 1.24x more.

That is textbook Amdahl behaviour. Video encoding has genuinely serial parts:
rate control decisions depend on previous frames, and the bitstream has to be
assembled in order. Threads speed up the parallel portion and do nothing for the
rest, so the curve flattens.

The practical reading: **four threads gets you most of what eight does.** If you
are sizing a container or a worker, that is the knee in the curve.

## The measurement finding matters more

Look at the range column, not just the median.

| Threads | Range | Spread |
|---|---|---:|
| 1 | 3,590 to 3,657 ms | **1.9%** |
| 2 | 2,108 to 2,181 ms | 3.5% |
| 4 | 1,490 to 1,511 ms | **1.4%** |
| 8 | 1,183 to 1,288 ms | 8.9% |
| auto | 918 to 1,699 ms | **85%** |

With `-threads` pinned, repeated runs of the same command land within a few
percent of each other. With `auto`, the same work took anywhere from 918 to
1,699 ms.

We arrived at this from the other direction. An earlier sweep found one identical
command varying 2.13x across ten runs, which was enough to
[retract a published claim](/blog/measurement-noise-ffmpeg-benchmarks/). Every
one of those runs used default threading.

**x264's default asks the machine how many cores are free and sizes itself
accordingly.** On shared infrastructure that answer moves between runs, so the
encoder does a different amount of parallel work each time. It is not the
measurement that is unreliable. It is the workload, and pinning the thread count
pins the workload.

If you benchmark FFmpeg and your numbers wander, this is almost certainly why.

## Auto was fastest, and produced a different file

Two things about the `auto` row are worth separating.

It was the **fastest** median at 1,033 ms, beating eight explicit threads. That
is expected: the container has more than eight cores available and x264's default
uses roughly 1.5x the core count, so auto is simply using more threads than our
explicit maximum.

It also produced **433.0 KB** where every explicit thread count produced
**387.8 KB**, an 11.8% difference. Every variant's size was byte-identical across
its own five runs, so this is not noise, it is a real behavioural difference
between pinned and default threading.

**We do not have a confident explanation for it.** The usual story is that more
threads means more slices and slightly worse compression, which would predict
auto being larger, and it is. But that story also predicts one thread being
noticeably smaller than eight, and those came out within 0.15% of each other.
Something other than slice count is moving here, and we are not going to invent a
mechanism to cover it.

What it means practically is worth stating even without the explanation:
**pinning threads changes your output, not just your speed.** If you pin threads
in production and benchmark with auto, you are not measuring what you ship.

## What to actually set

For a single encode on a dedicated box, leave it on auto and let x264 use the
machine.

For **anything running concurrently**, pin it. If you run four encodes at once on
an eight-core box and each one grabs twelve threads, they fight, and total
throughput drops. Explicit `-threads 2` on each is usually faster in aggregate
than four jobs all trying to use everything.

For **benchmarking**, always pin it, or your numbers are unrepeatable.

## Where this stops

One 5-second 1280x720 clip, libx264 CRF 23 preset medium, audio stripped, five
runs per variant on shared infrastructure. The scaling shape is a property of the
codec and should travel; the absolute times are specific to this machine and this
clip.

Longer clips parallelise better, because frame-level threading has more frames to
work with and the serial setup is amortised over more work. Treat 2.99x as a
floor for the eight-thread speedup rather than a ceiling.

Threading is one of seven settings measured on this same source. The rest are in [FFmpeg encoding settings compared](/blog/ffmpeg-encoding-settings/).
