ADR-0520: Wire vmaf --no-reference through to the scoring path¶
- Status: Accepted
- Date: 2026-05-18
- Deciders: lusoris, Claude (Opus 4.7)
- Tags: cli, ai, dnn, docs
Context¶
The --no-reference CLI flag has been advertised in vmaf --help and documented in docs/usage/cli.md since the tiny-AI surface landed, but the wiring was incomplete: cli_parse.c parsed the flag into CLISettings::no_reference and then ignored it. The unconditional if (!settings->path_ref) gate at the end of CLI validation rejected every NR invocation with Reference .y4m or .yuv (-r/--reference) is required, contradicting the documented intent that NR-mode runs only need a distorted source plus a no-reference tiny model (.workingdir/bbb_reports/E2E_TEST_MATRIX_v9.md Finding 8).
A real-world NR pipeline (e.g. ingest-side quality monitoring where the original is unavailable) cannot construct a reference YUV at all, so the CLI surface MUST honour the flag or the documented capability is a fiction.
Decision¶
We will wire --no-reference through the CLI end-to-end:
-
cli_parse.c: when--no-referenceis set, replace the "reference required" check with a--tiny-model requiredcheck (the only downstream scorer that can produce a score without a reference is a tiny ONNX model). Also auto-suppress the built-in VMAF SVM default that the parser would otherwise inject (model_cnt == 0 && !no_predictionbranch), because the SVM features (vif,adm,motion) are FR by construction and would fail at the picture-pair gate. -
vmaf.c: whenc.no_referenceis set, do not require a reference path. Open the distorted source twice (twoFILE*+ twovideo_inputhandles backed by the same file) so each frame produces two independent picture-pool entries. Feed them tovmaf_read_pictures(vmaf, pic_dist_a, pic_dist_b, idx); the public API enforces a non-null pair, and an SVM-free, NR-tiny-model-only feature graph emits no FR extractor work, so the second copy is only seen byvmaf_picture_unrefin the cleanup tail.vmaf_ctx_dnn_run_frame(the rank-4 path inlibvmaf.c) already reads picture data exclusively from therefargument, so the distorted frame reaches the NR tensor bridge unchanged. -
Rank-2 feature-vector tiny models (ADR-0518) are intentionally refused in NR mode at parse time — they consume classic VMAF feature columns (
adm2,vif_*,motion2) which require a real reference. -
Skip the
report_pooled_scorespath entirely in NR mode (the classic SVM is not loaded, so there is nothing to pool); the tiny model's per-frame scores still land in the JSON / XML / CSV report via the feature-collector path thatvmaf_ctx_dnn_run_frame_nchwalready writes through.
Alternatives considered¶
| Option | Pros | Cons | Why not chosen |
|---|---|---|---|
Add a public vmaf_read_pictures_nr(vmaf, dist, idx) entry point | Single picture per frame; no double-decode | Touches public API surface; needs ABI-bump, header export, ffmpeg-patch wiring, MCP wiring; out of scope for a bug-fix PR | Deferred to T6-NR-PUBLIC-API follow-up if NR throughput becomes a concern |
| Synthesize a zero-buffer "reference" picture in the CLI | Avoids opening dist twice | Allocates extra memory; semantically misleading; would also need to bypass vmaf_picture_ref (not public) | Worse trade-off than the open-twice approach |
Refuse --no-reference and remove the flag | Cleanest possible code path | Breaks the documented surface; user already depends on it per the task brief | Rejected |
Consequences¶
- Positive:
--no-referencematches the documented behaviour; NR ingest pipelines can score distorted-only sources; the e2e test matrix's Finding 8 closes. - Positive: No public-API change. ffmpeg-patch stack untouched (the filter does not surface NR-mode wiring today).
- Negative: NR mode double-decodes the distorted file because the CLI opens it via two
video_inputhandles. For the typical per-frame inference cost this is in the noise; a public NR entry point can eliminate the redundancy when warranted. - Negative: The picture pool needs one extra slot per worker to accommodate the second dist fetch.
pic_cntis sized as2 * (thread_cnt + 1) + 1and the NR path replaces the ref slot with a second dist slot, so the existing budget already covers it. - Neutral / follow-ups: A future
vmaf_read_pictures_nrAPI would let MCP / Python bindings expose NR scoring without going through the CLI; tracked as T6-NR-PUBLIC-API.
References¶
- Bug report:
.workingdir/bbb_reports/E2E_TEST_MATRIX_v9.mdFinding 8 - Prior tiny-AI work: ADR-0518
- Source:
req(direct user task brief, 2026-05-18, "Fix thevmaf --no-referenceCLI flag which is a documented-but-no-op").