# How to compress video to a target size

Canonical: https://rendobar.com/blog/compress-video-target-size/
Author: Abdelrahman Essawy
Published: 2026-08-20
Updated: 2026-08-20

---

## Key takeaways

- The two-pass bitrate formula hits a size target but not a quality one. It spends exactly the bitrate you allocated whether the content needed it or not.
- Across 120 real compression jobs the search ran 667 probe encodes, a median of 6 per job and a maximum of 10, to land on a setting.
- 20 of those 120 jobs returned passthrough: the search found no encode that beat the original and handed the source back untouched.
- Median achieved quality was VMAF 86.0, with a floor of 30.7 on jobs forced under a hard byte ceiling and a ceiling of 96.3.
- Median compression ratio was only 1.41x, because most sources were already efficient. The 90th percentile was 6.48x and the maximum 825.7x.

## Short version

There are two different questions hiding in "compress to a target size" and the command you want depends on which one you are actually asking.

**If the size is a hard requirement**, use two-pass with a computed bitrate. It hits the number.

```bash
# 10 MB target, 60 second video, 128k audio
# (10 * 8192) / 60 - 128  =  1237 kbit/s video
ffmpeg -y -i input.mp4 -c:v libx264 -b:v 1237k -pass 1 -an -f null /dev/null
ffmpeg -i input.mp4 -c:v libx264 -b:v 1237k -pass 2 -c:a aac -b:a 128k output.mp4
```

**If you actually want it small and still good**, use CRF and stop specifying a size.

```bash
ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k output.mp4
```

The formula is the part people search for. The trap is what it costs you, and that is measurable.

## The formula, and what it does not know

Target size in kilobits divided by duration, minus audio, gives you a video bitrate. Two-pass then spends exactly that budget.

The word "exactly" is the problem. Two-pass distributes bits across the timeline intelligently, but the total is fixed by you rather than by the content. A static screencast and a handheld shot of falling leaves get the same budget for the same duration. One of them is wasting most of it and the other cannot possibly look acceptable.

A bitrate target answers "how big" and refuses to answer "how does it look". CRF answers "how does it look" and refuses to answer "how big". **Neither one answers both**, which is why hitting a size target with predictable quality takes more than one encode.

## What it takes to hit both

We ran the search that does answer both, and recorded it. **120 completed compression jobs, 667 probe encodes**, a **median of 6 probes per job** and a maximum of **10**.

Each probe is a real encode of a sample of the source at a candidate quality level, scored against the original. The search moves the quality level based on what it measured rather than what it predicted, and stops when the result is inside the target. **58 of the jobs scored with VMAF and 50 with SSIMULACRA2**, with the metric chosen by media type, and 12 were dry runs that predicted without encoding.

Six encodes to place one setting sounds expensive until you compare it to the alternative, which is a human encoding, looking, adjusting and repeating. The median job cost **$0.0128** with a 90th percentile of **$0.0431**.

## Most files compress far less than you expect

The measured compression ratios are the number most likely to change how you think about this.

| Percentile | Compression ratio |
|---|---|
| 50th | **1.41x** |
| 90th | 6.48x |
| max | 825.7x |

**The median was 1.41x.** Not 10x, not 5x. Slightly less than half again smaller.

That is not the compressor underperforming. It is what happens when the input is already an H.264 file that some other encoder already optimised. The large ratios in the tail came from sources that were genuinely wasteful, and the 825.7x outlier was an image rather than video.

If your mental model is "compression makes videos much smaller", it was built on unoptimised sources. On anything already encoded sensibly, the honest expectation is tens of percent, not multiples.

## Sometimes the right answer is not to encode

**20 of 120 jobs returned `passthrough`**, meaning the search evaluated candidates, found that none of them beat the original at acceptable quality, and handed back the source file untouched.

That is one in six. Re-encoding an already-efficient file usually makes it **larger**, because you are paying a fresh generation of lossy encoding on top of an existing one and adding container overhead. A compressor that always produces output will happily hand you a bigger file and call it success.

Worth building into your own pipeline whether or not you use a service for it: **compare the output to the input, and keep the smaller one.** It is three lines and it prevents an entire class of silent regression. We wrote about the behaviour separately in [the compressor that refuses to compress](/blog/compressor-that-refuses/).

## What quality actually landed

Median achieved score was **VMAF 86.0**. The range ran from **30.7 to 96.3**.

Roughly, above 93 reads as visually lossless, above 80 as good, and below 60 as visibly degraded. A median of 86 is the honest middle: clearly compressed if you compare side by side, fine in normal viewing.

The 30.7 floor is instructive. Those were jobs given a hard byte ceiling well below what the content needed. When a size is non-negotiable, quality is what pays for it, and there is no setting that avoids the trade. The value of measuring is that you find out **before** shipping rather than after.

What that trade looks like, on the same five seconds, at 8x the difference in bytes:

_The same source at two quality levels, showing what an aggressive byte target costs in the picture._

Play both. At normal size and normal attention the difference is smaller than the 8x byte gap suggests, which is exactly why picking a target by eye on a still frame goes wrong in both directions.

## Letting the codec be chosen for you

Across the 120 jobs the search picked **h264 47 times, avif 41, opus 9, av1 7, jxl 5, hevc 3**, plus a handful of others.

That spread is entirely driven by input type, and it is the reason a fixed codec choice underperforms across mixed media. AV1 is the strongest video codec in the set and it was chosen 7 times, because it is slow and most of these jobs did not need it. AVIF dominated the image inputs. Picking one codec for everything means being wrong on most of it.

## Doing it over HTTP

The whole search runs as a single job, and the response includes the probe count, the metric used, the achieved score and the verdict, so the decision is auditable rather than opaque.

const rb = createClient({ apiKey: process.env.RENDOBAR_API_KEY });

const job = await rb.jobs.run({
  type: "compress.target",
  inputs: { source: "https://cdn.rendobar.com/assets/examples/sample.mp4" },
  // A named posture, a 1-100 number, or { maxBytes } when size is fixed.
  params: { target: "balanced", for: "web" },
});

const d = job.output.data;

// The search reports itself. "passthrough" means nothing beat the original.
console.log(d.verdict, d.codec, d.probes, d.achievedScore);`}
  curl={`curl -X POST https://api.rendobar.com/jobs \
  -H "Authorization: Bearer $RENDOBAR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "compress.target",
    "inputs": { "source": "https://cdn.rendobar.com/assets/examples/sample.mp4" },
    "params": { "target": "balanced", "for": "web" }
  }'`}
/>

`target` takes a named posture, a quality number from 1 to 100, or an object such as `{ "maxBytes": 153600 }` when the size really is fixed. Setting `dryRun: true` returns the predicted size, quality and cost without encoding, which is how the 12 dry-run jobs in this sample were measured.

## Where this stops

120 jobs is a decent sample for verdict distribution and a thin one for per-codec conclusions. The 3 HEVC and 5 JXL jobs are anecdotes, not measurements, and nothing here should be read as ranking codecs against each other. [Video codec comparison](/blog/video-codec-comparison/) does that properly on matched inputs.

The compression ratios describe **our** sources, which skew short, small and already encoded. A library of camera-original footage would show much larger ratios and a very different median.

Two metrics are mixed in the quality figures, VMAF for video and SSIMULACRA2 for images, and they are not on the same scale. The median of 86.0 spans both, so treat it as a summary of this workload rather than a VMAF result.

Nothing here measures perceptual quality with human viewers. Every quality claim is a metric score, and metrics disagree with eyes often enough that we have published a case where they ranked the visibly worse option higher.

For per-setting size numbers, see [FFmpeg encoding settings measured](/blog/ffmpeg-encoding-settings/). For what these jobs cost against other services, see [FFmpeg API pricing compared](/blog/ffmpeg-api-pricing-compared/).
