Measuring what a browser re-encode costs you
Cleaning a video means encoding it again, and encoding it again costs quality. This is what that cost actually is, measured rather than estimated, along with the one-line encoder setting that was quietly making it four times worse.
Why measure instead of tuning by eye
Encoder settings invite guesswork. Raise the bitrate, pick a different codec, ask for hardware acceleration, set a hint that sounds like it means more detail. Each change is one line, each sounds reasonable, and by eye the results all look about the same.
The trouble is that some of those changes do nothing, some do the opposite of what they appear to, and without numbers there is no way to tell which is which. So before touching any of them, it was worth establishing what the pipeline actually produces.
The method
The measurement has to happen in the browser, because that is where the encoder being measured lives. Running the same codec from a command line tells you about that build, not about the one in the tab.
- A page-side script, bundled with esbuild, re-encodes a source clip through the same muxing library the tool uses, once per configuration under test.
- Each resulting blob is posted to a small local Node server, which writes it to disk.
- ffmpeg compares each output against the source for PSNR and SSIM.
Two details matter more than they look. The comparison has to be muxed at the source frame rate, or the frames misalign and every score is meaningless. And timings taken inside an embedded preview pane are not representative: that context reports itself as hidden and runs main-thread work roughly ten times slower than the same code in Node. Use it for correctness, never for performance.
PSNR is measured in decibels on a logarithmic scale, so differences are smaller than they look. Each 3 dB is a halving of mean squared error. Above roughly 40 dB, differences against a source are hard to see without flipping between the two.
What the environment actually offers
The first finding was about the encoder itself. In the browser under test, only Chrome's
software H.264 encoder, OpenH264, was available. A request for
prefer-hardware was rejected, and HEVC was unsupported.
This reframes the whole exercise. A software encoder has a ceiling, and above that ceiling it ignores what you ask for. Most of the settings worth arguing about turn out to be arguing with something that has already decided.
The finding: a content hint that cost four decibels
The engine set contentHint: 'detail' on the encoder configuration. The name
suggests it asks for more detail. What it does on this encoder is select a mode tuned for
screen content, the sort of material that is mostly flat colour and sharp text.
On camera footage that mode stalls rate control. A 12 Mbps request came out at roughly 1 Mbps. Removing the hint, the same request settled somewhere between 4 and 7 Mbps depending on the clip, and the quality difference was substantial:
| Source material | With the hint | Without it | Gain |
|---|---|---|---|
| Veo clip, camera footage | 38.2 dB | 42.3 dB | +4.1 dB |
| NotebookLM export, slides | 36.6 dB | 42.4 dB | +5.8 dB |
The second row is the one that settles the question. NotebookLM exports are slides, which is exactly the screen content the hint is meant to help with, and the hint made them worse by almost six decibels. Whatever the mode is optimising for, it is not fidelity against the source at the bitrate being requested.
The site's export loops now strip that hint. The vendored engine still sets it, which is its own call to make, and the difference is a single destructured property in one function rather than a fork of the engine.
Things that did not help
Equally useful is the list of changes that produced nothing, because each one is a line of tuning not worth writing.
- Raising the bitrate further. Above the encoder's own ceiling the request is ignored. Asking for 20 Mbps from something settling at 5 changes the number in the config and nothing in the file.
- Switching to VP9 or AV1. Neither beat H.264 on this material through this encoder, and both cost compatibility.
- Asking for hardware acceleration. Rejected, so the question of whether it would have helped does not arise.
- A heavier cleanup over the mark region. Several backends were compared, from canvas-level polish to a neural denoiser. Once codec noise is present they all land within about one decibel of each other, and the neural option runs roughly ten times slower for no measurable gain.
That last one is the most useful negative result of the set. It says the residue after cleaning is dominated by compression noise rather than by anything a denoiser is good at, so effort spent on a better cleanup is effort spent on the wrong term.
How the mark region was scored
Whole-frame PSNR tells you about the encode. It says almost nothing about the mark region, which is a few thousand pixels out of a million and vanishes into the average.
So the mark region gets its own procedure, built to have a ground truth. Take clean pixels from beside the mark. Composite the detected alpha map onto them at the detected gain, which produces a synthetic watermark over content you know exactly. Put the result through a JPEG round trip to stand in for codec noise. Clean it. Score the result against the clean pixels you started from.
The point is that the correct answer is known by construction, which is not true of any real watermarked frame.
What the tool does with all this
Three settled conclusions came out of it.
The content hint is gone from the site's export path, which is the single largest quality win available and costs nothing.
The bitrate adapts to the source. A flat 12 Mbps is ample for the clips Gemini produces today, but a source already spending more than a third of that would be re-encoded below its own quality. So the target rises to three times the source rate when the source is heavy, capped at 30 Mbps so a long clip cannot balloon. Three times the source is past the point where a second H.264 pass adds visible loss.
The cleanup stays simple. Canvas-level polish over the mark region, not a neural denoiser, because the measurement says the heavier option buys nothing.
If you want to re-run any of this, the harness is the three steps at the top: a bundled page script that re-encodes under variant configs, a local upload server to catch the blobs, and ffmpeg for the scoring. The cost of a re-encode in general, and what is kept untouched through it, is covered in why cleaning a video means re-encoding it.