ADR-1562: Every vmaf-tune command returns the lowest-bitrate encode that meets the target¶
- Status: Accepted
- Date: 2026-10-04
- Deciders: maintainer, agent
- Tags: tools, vmaf-tune, python, go, breaking, fork-local
Context¶
vmaf-tune had two pick rules for "the encode that meets a target VMAF". recommend --target-vmaf (Python pick_target_vmaf, Go PickTargetVMAF and SmallestPassingCRF), the ladder's default sampler and the fast objective returned the smallest CRF whose VMAF cleared the target, which is the highest bitrate among the passing rows. compare and the Phase B bisect, benchmark and prefilter returned the lowest bitrate that cleared it. Both were documented as they behaved (state row T-VMAFTUNE-PICK-SEMANTICS-DIVERGE-2026-10-04). The fast objective, |vmaf - target| + 1e-4 * kbps, also did not return a passing encode at all when a CRF just under the target sat closer to it than the cheapest passing one.
Decision¶
Every command returns the lowest-bitrate encode whose VMAF meets the target. One implementation per language holds the rule: Python vmaftune.recommend.lowest_passing_row, Go recommend.lowestPassing. Ties go to the higher VMAF, then to the lower CRF. A row without a usable bitrate_kbps is an error, never skipped or ranked last. When no row meets the target the closest miss is still returned, tagged (UNMET).
recommend(corpus and live mode, with and without--with-uncertainty) and the ladder's default sampler call that implementation. The interval-aware search walks the rows in ascending bitrate order, so its first tight clearing row is the lowest-bitrate one.- The live-mode picker
_smallest_passing_crfis replaced by_lowest_bitrate_passing(Python) andSmallestPassingCRFbyLowestBitratePassing(Go), both thin groupers over the shared rule. - The
fastTPE objective scores a CRF that meets the target by its predicted bitrate and a CRF that misses it by1e9 + shortfall, so the search returns the cheapest CRF that meets the target (objective_value/objectiveValue, pinned value for value in both languages).
This is a breaking change of behaviour (feat!, Migration: footer).
Alternatives considered¶
| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
| Lowest passing bitrate everywhere (chosen) | One rule across recommend, compare, the ladder, fast, the bisect; the answer a user asking for "VMAF at least T" wants | Changes every recommend result and the ladder rungs; assumes the bitrate column is present | Chosen by the maintainer (popup 2026-10-04) |
| Smallest passing CRF everywhere | Matches the old recommend text; best quality that clears the gate | The highest bitrate among passing rows; the bisect and compare already rank the other way; CRF order means nothing across codecs whose quality knob rises with quality | Opposite of what the bisect, compare and prefilter already do |
| Keep both, document the split | No behaviour change | Two rules for one phrase; the divergence stays | The ledger row asked for a decision |
| Closest to the target from above in VMAF | Avoids overshooting quality | Not the cheapest encode; ties between codecs ambiguous | Not what the maintainer asked for |
Consequences¶
- Positive: one rule in two languages, tested per command;
fastnow returns an encode that meets the target when one exists. - Negative:
recommend, the ladder rungs andfastreturn different CRFs than before (a lower-quality, cheaper one). Scripts that read the old pick must rerun. Corpus rows withoutbitrate_kbpsnow failrecommend. - Neutral / follow-ups:
prefilter's objective keeps its own|vmaf - target| + 1e-4 * kbpsform; it is not a pick over rows.