A fixed file size does not cap your video's length — it caps its bitrate, and the length is what spends it. At 8,388,608 bytes, a 60-second 720p30 clip has 1,047 kbps of video bitrate to work with; at three minutes it has 306 kbps, which is where a 720p picture visibly softens. At 10,485,760 bytes the same two points are 1,325 kbps and 399 kbps. So the practical answer to "how long can I fit" is about one minute of usable 720p in either budget, not several minutes. There is no hard duration limit in the arithmetic; the bitrate curve is the real constraint.
| Clip length | 8 MB target | 10 MB target |
|---|---|---|
| 15 s | 4,383 kbps | 5,494 kbps |
| 30 s | 2,159 kbps | 2,715 kbps |
| 60 s | 1,047 kbps | 1,325 kbps |
| 180 s | 306 kbps | 399 kbps |
These are planned video rates from floor((target_bytes × 0.994 × 8 ÷ duration_s ÷ 1000) − 64). The 0.994 is a 0.6% reserve for MP4 container bytes; the 64 is a 64 kbps audio allowance used below a 12 MB target. They are formula outputs, not measurements of every possible clip, and they are not a visual-quality benchmark. A clip with no audio track simply does not grow one — the allowance stays unused.
That distinction matters because a target size is a byte budget, not a quality setting. Two clips that both land near 8 MB can look completely different if one is 15 seconds and the other is three minutes.
Three encodes that actually ran
Most writing about target-size compression stops at the formula. Here are three runs through a browser FFmpeg.wasm build, with the byte counts, elapsed times and bitrates that came out of them.
| Target | Input | Pass 1 | Retry | Final output | Elapsed | Measured video bitrate |
|---|---|---|---|---|---|---|
| 10 MB (10,485,760 B) | 15,942,580 B, 1280x720 @ 30 fps, no audio | 8,274 kbps → 10,880,120 B (394,360 B over) | 7,032 kbps → 9,253,520 B (1,232,240 B under) | 9,253,520 B | 140 s | 7,399,220 bps |
| 8 MB (8,388,608 B) | 15,942,580 B, 1280x720 @ 30 fps, no audio | 6,606 kbps → 8,685,880 B (297,272 B over) | 5,615 kbps → 7,345,513 B (1,043,095 B under) | 7,345,513 B | 223 s (117 + 106) | 5,872,840 bps |
| 3 MB (3,145,728 B) | 5,407,489 B, 1920x1080 @ 60 fps, AAC stereo | 2,437 kbps → 3,138,651 B (9,077 B under) | none needed | 3,138,651 B | 150 s | 2,432,889 bps video + 63,940 bps audio |
Every final output landed at or under its target. The third run is the only one with an audio track and the only one that needed a single pass. The first two share the same input file, which makes them a direct comparison: dropping the ceiling from 10 MB to 8 MB lowered the first-attempt video bitrate from 8,274 to 6,606 kbps and the measured output bitrate from 7,399,220 to 5,872,840 bps.
The elapsed times belong to one Windows / Node 22 machine with no GPU. They are a property of that machine, not a promise about yours, and they are included because a two-pass retry is not free: the 8 MB run took 223 seconds for a ten-second clip.
Why one pass is not enough
Two of the three runs overshot on the first attempt. x264 at a high bitrate can spend more than you asked for — 8,274 kbps produced 10,880,120 bytes against a 10,485,760-byte ceiling, and 6,606 kbps produced 8,685,880 bytes against 8,388,608. In both cases the retry tightened the video bitrate by exactly 15% (8,274 → 7,032 and 6,606 → 5,615) and landed under with headroom to spare.
The useful lesson is not "lower the bitrate". It is that a target printed before encoding is a guess. The only thing that tells you the result is measuring the bytes after the encode and retrying once when the miss is outside tolerance. The 8 MB run's second pass came in 1,043,095 bytes under target — 12.4% of the budget left unused — which is the cost of a blunt 15% retry step, not a precision claim.
Notice also that the 8 MB first attempt used 6,606 kbps, which is exactly what the formula gives for a ten-second clip at that target. The published arithmetic and the shipped encoder agree; what the formula cannot predict is how many bytes x264 actually writes.
Where the 0.6% reserve comes from
An MP4 is not only media. It carries headers and a moov index of every frame, and those bytes come out of the budget whether you plan for them or not. Two earlier encodes at 3 MB and 2.8 MB targets landed 0.43% and 0.44% over their target with no reserve in the formula. The same 3 MB run came in 0.22% under once the reserve was added. That is the entire reason the constant exists — it is a measured correction for container overhead, not a fudge factor.
Renaming a file or repackaging its container cannot do this job, because neither changes the byte count. Getting under a fixed ceiling requires re-encoding at a lower bitrate when the source is larger, and a source already below the ceiling should be handed back untouched rather than degraded.
What these three runs do not prove
This is a check on the arithmetic, not a validation suite. All three clips are ten seconds long. Only two distinct input files appear: one 720p30 source without audio, and one 1080p60 source with it. There is no systematic set across durations, resolutions, frame rates, codecs or container conditions, and no independent third-party reproduction. Consistent target-size performance across the range of media people actually upload is not established by this data.
That is worth saying plainly because the numbers above are easy to over-read. A single 3 MB run with an audio track does not characterise how audio behaves at 8 MB. A ten-second clip says nothing about the three-minute row in the first table beyond what the formula computes. And a retry that worked twice is not evidence that it works for every source.
The raw run records, ffprobe output and the script that rebuilds the CSVs are in discord-video-size-data, archived as 10.5281/zenodo.23904987.
Top comments (0)