ADR-0705: vmafx-tune Go port — Stage 1 (compare subcommand)¶
- Status: Accepted
- Date: 2026-05-28
- Deciders: lusoris
- Tags:
go,vmafx-tune,language-modernization,cli,phase4,fork-local
Context¶
The Phase 4 language-modernization initiative (ADR-0702) establishes Go as the target language for VMAFX CLI tooling. tools/vmaf-tune/ is a 4,000+ line Python CLI with multiple subcommands (compare, tune-per-shot, ladder, fast, corpus, report, …). A full port in one PR would be unreviably large and would block the Python binary during migration.
The user directed a staged approach: Stage 1 ports the single most commonly invoked subcommand (compare) to a Go binary installed as vmafx-tune-go alongside the existing Python binary, with all other subcommands as stubs that redirect to vmaf-tune. Stage 2+ will port the remaining subcommands one milestone at a time.
The compare subcommand runs a rate-quality sweep: for each (codec, VMAF target) pair it bisects the CRF axis to find the highest CRF whose measured VMAF still meets the target, then reports bitrate and score. This is the most commonly invoked subcommand and the most self-contained (no per-shot state, no ladder state machine).
Decision¶
We ship cmd/vmafx-tune/ as the Stage-1 Go binary under the name vmafx-tune-go. The binary is wired via the existing go.mod at github.com/VMAFx/vmafx (Phase 4 foundation). The three new Go packages are:
pkg/encoder/—Encoderinterface +LibX264Encoder/LibX265Encoder(subprocess ffmpeg, no libavcodec cgo). Hardware encoders are Stage-2.pkg/bisect/— statelessRun(src, enc, scoreFunc, params)VMAF-target bisect mirroring the Python Phase B algorithm inbisect.py.pkg/report/—EmitJSON/EmitMarkdownrenderers whose JSON schema matches the Pythoncompare.pyschema-v1 / schema-v2 so the existingreport.pyrenderer can ingest Go output without modification.
The Python tools/vmaf-tune/ is unchanged. The Go binary installs as vmafx-tune-go (not vmaf-tune) to avoid a naming collision during the migration. Stage 3 (swap) will rename when feature parity is reached.
Alternatives considered¶
| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
| Full port in one PR | Single migration event | 40,000+ LOC diff, unreviable, blocks Python users if bugs slip through | Too risky; staged approach is required by project policy (ADR-0108) |
Port tune-per-shot first | Complex subcommand tests completeness | Harder to test in isolation; depends on per-shot state machine | compare is simpler and most commonly invoked |
| Use cgo for libavcodec | No ffmpeg subprocess overhead | Adds C build complexity, breaks static binary goal | Phase 1 goal is correctness and portability; subprocess is fine for rate-quality work |
Ship under vmaf-tune name (replace) | Simpler UX | Any missing feature breaks existing users immediately | Migration strategy requires parallel coexistence until parity |
Consequences¶
vmafx-tune-go compareis immediately usable for libx264/libx265 rate-quality sweeps. Hardware encoders require Stage-2.- The JSON output schema is compatible with the Python
report.pyrenderer and all existing tooling that readsvmaf-tuneJSON. go.modaddsgithub.com/spf13/cobraandgithub.com/spf13/pflagas dependencies.- The bisect in
pkg/bisect/is the test seam: unit tests inject a mock encoder and mock score function so tests run without ffmpeg or vmaf on PATH.
References¶
- req: "Begin the Go port of vmaf-tune — Stage 1: minimum viable Go CLI" (user directive 2026-05-28)
- ADR-0702: vmafx Phase 4 language-modernization umbrella
tools/vmaf-tune/src/vmaftune/bisect.pyPhase B algorithmtools/vmaf-tune/src/vmaftune/compare.pyschema-v1/v2 JSON shape