feat(tools): vmaf-tune — HDR-aware encoding + HDR-VMAF scoring#379
Merged
feat(tools): vmaf-tune — HDR-aware encoding + HDR-VMAF scoring#379
Conversation
9e4b582 to
581f961
Compare
…#9, ADR-0261) Closes Bucket #9 of the PR #354 vmaf-tune capability audit. Adds ffprobe-driven HDR detection, codec-specific HDR encode flag dispatch, and HDR-VMAF model resolution to the Phase A corpus driver. New module ``tools/vmaf-tune/src/vmaftune/hdr.py``: - ``detect_hdr(path)`` — runs ``ffprobe -show_streams -of json``, classifies the first video stream as PQ / HLG / SDR. Strict BT.2020-primaries gate so malformed signaling falls back to SDR. - ``hdr_codec_args(encoder, info)`` — per-encoder dispatch table covering libx264 (container ``-color_*``), libx265 (``-x265-params`` with master-display + max-cll + hdr10-opt), libsvtav1 (AV1 enums via ``-svtav1-params``), hevc_nvenc (``-pix_fmt p010le -profile:v main10``), libvvenc. - ``select_hdr_vmaf_model()`` — globs ``model/vmaf_hdr_*.json``; returns ``None`` when none shipped (current state — fork hasn't ported Netflix's HDR model yet). Corpus driver wiring: - ``CorpusOptions.hdr_mode`` ∈ {``auto``, ``force-sdr``, ``force-hdr-pq``, ``force-hdr-hlg``}; CLI flags ``--auto-hdr`` / ``--force-sdr`` / ``--force-hdr-pq`` / ``--force-hdr-hlg`` (mutually exclusive). Auto is the default. - New schema-v2 row keys ``hdr_transfer`` / ``hdr_primaries`` / ``hdr_forced``; ``SCHEMA_VERSION`` bumped 1 → 2. Phase B / C loaders treat missing keys as SDR (additive change, v1 rows remain readable). - ``score._model_arg`` now passes pre-formatted ``path=`` / ``version=`` strings through unchanged so the HDR model path can be injected via ``vmaf --model``. - HDR detected but no HDR model shipped → log warning, fall back to SDR model with notice that scores trend low. Tests (``tools/vmaf-tune/tests/test_hdr.py``, 21 cases): - detection: SDR / PQ / HLG / mismatched-primaries / missing-file / ffprobe-failure / invalid-JSON - codec dispatch: shape per encoder (x264, x265 PQ + HLG, SVT-AV1 PQ + HLG, NVENC HEVC, unknown encoder) - model resolution: empty dir / shipped / multi-version pick-latest / missing dir - corpus integration: end-to-end ``force-hdr-pq`` (verify HDR fields in row + ``-color_*`` in encode argv) and ``force-sdr`` ADR-0261 (Accepted, encode-side; HDR-VMAF scoring deferred until fork-local model port). Research-0054 digest, rebase-notes 0261, AGENTS.md invariant note, docs/usage/vmaf-tune.md HDR section, changelog fragment all included.
581f961 to
b8664af
Compare
…5→0300, 0261→0300, 0071→0072)
There was a problem hiding this comment.
Pull request overview
Adds HDR-aware scaffolding to tools/vmaf-tune so corpus runs can detect PQ/HLG sources, attach encoder HDR metadata, and record HDR provenance in emitted rows while keeping SDR-model fallback for scoring until an HDR model is shipped.
Changes:
- Added new
vmaftune.hdrmodule for ffprobe-based HDR classification, encoder-specific HDR flag generation, and HDR-model discovery. - Wired HDR mode selection through corpus generation/CLI, bumped the corpus schema to v2, and allowed explicit
path=/version=VMAF model arguments. - Added HDR-focused tests and accompanying ADR/research/changelog/docs updates.
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
tools/vmaf-tune/tests/test_hdr.py |
New HDR unit/integration-style mocked tests for detection, dispatch, model lookup, and corpus wiring. |
tools/vmaf-tune/tests/test_corpus.py |
Updated schema contract assertions for v2 HDR row fields. |
tools/vmaf-tune/src/vmaftune/score.py |
Lets --model accept preformatted key=value strings. |
tools/vmaf-tune/src/vmaftune/hdr.py |
New HDR detection, metadata extraction, encoder flag dispatch, and HDR model resolution logic. |
tools/vmaf-tune/src/vmaftune/corpus.py |
Integrates HDR detection/model selection into corpus row generation and schema output. |
tools/vmaf-tune/src/vmaftune/cli.py |
Adds ffprobe override and mutually exclusive HDR mode flags. |
tools/vmaf-tune/src/vmaftune/__init__.py |
Bumps schema version and adds HDR row keys. |
tools/vmaf-tune/AGENTS.md |
Documents HDR invariants and fallback behavior for future contributors. |
docs/usage/vmaf-tune.md |
Documents new HDR CLI options and schema fields. |
docs/research/0071-vmaf-tune-hdr-aware.md |
Adds research digest for HDR-aware tuning. |
docs/rebase-notes.md |
Adds a rebase note for the fork-local HDR tooling changes. |
docs/adr/0295-vmaf-tune-hdr-aware.md |
Adds the ADR describing the HDR-aware design/decision. |
docs/adr/_index_fragments/0261-vmaf-tune-hdr-aware.md |
Adds ADR index fragment entry for the new ADR. |
docs/adr/_index_fragments/_order.txt |
Appends the ADR slug to the generated index order manifest. |
changelog.d/added/T-VMAF-TUNE-hdr-aware.md |
Adds changelog fragment for the HDR-aware tooling feature. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+385
to
+388
| candidates = sorted(base.glob("vmaf_hdr_*.json")) | ||
| if not candidates: | ||
| return None | ||
| return candidates[-1] |
Comment on lines
+241
to
+248
| try: | ||
| return int(round((float(num) / float(den)) * scale)) | ||
| except (ValueError, ZeroDivisionError): | ||
| return 0 | ||
| try: | ||
| return int(round(float(text) * scale)) | ||
| except ValueError: | ||
| return 0 |
Comment on lines
+256
to
+265
| Returns ``(hdr_info, forced)``. ``forced`` is true iff the user | ||
| overrode the probe via ``--force-hdr-*`` / ``--force-sdr``. | ||
| """ | ||
| mode = opts.hdr_mode | ||
| if mode == "force-sdr": | ||
| return None, True | ||
| if mode == "force-hdr-pq": | ||
| return _synthetic_hdr_info("pq"), True | ||
| if mode == "force-hdr-hlg": | ||
| return _synthetic_hdr_info("hlg"), True |
Comment on lines
+307
to
+312
| def _hdr_args_x265(info: HdrInfo) -> tuple[str, ...]: | ||
| """x265: in-stream SEI via ``-x265-params``.""" | ||
| parts = [ | ||
| "colorprim=bt2020", | ||
| f"transfer={'smpte2084' if info.transfer == 'pq' else 'arib-std-b67'}", | ||
| "colormatrix=bt2020nc", |
Comment on lines
87
to
+89
|
|
||
| def _model_arg(model: str) -> str: | ||
| """Format the ``--model`` argument for the libvmaf CLI. |
Comment on lines
+331
to
+336
| tc = 16 if info.transfer == "pq" else 18 | ||
| parts = [ | ||
| "color-primaries=9", | ||
| f"transfer-characteristics={tc}", | ||
| "matrix-coefficients=9", | ||
| "color-range=0" if info.color_range != "pc" else "color-range=1", |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes Bucket #9 of the PR #354
vmaf-tunecapability audit — HDR-aware encoding + HDR-VMAF scoring scaffolding.vmaftune.hdrmodule:detect_hdr(ffprobe-driven PQ / HLG classification with strict BT.2020-primaries gate),hdr_codec_args(per-encoder dispatch table forlibx264,libx265,libsvtav1,hevc_nvenc,libvvenc),select_hdr_vmaf_model(returnsmodel/vmaf_hdr_*.jsonif shipped).--auto-hdr(default) /--force-sdr/--force-hdr-pq/--force-hdr-hlgmutually-exclusive CLI modes and three new schema-v2 row keys (hdr_transfer,hdr_primaries,hdr_forced);SCHEMA_VERSIONbumped 1 → 2.vmaf_hdr_v0.6.1.json. Until then, HDR sources are scored against the SDR model with a one-shot warning.Type
feat— new capability insidetools/vmaf-tune/Checklist
Bug-status hygiene
Netflix golden-data gate
assertAlmostEqualscore.Deep-dive deliverables (ADR-0108)
docs/research/0072-vmaf-tune-hdr-aware.md.AGENTS.mdinvariant note — added totools/vmaf-tune/AGENTS.md(HDR fail-safe-to-SDR, codec dispatch contract, model fallback).changelog.d/added/T-VMAF-TUNE-hdr-aware.md.docs/rebase-notes.md(entry 0261).Reproducer
Expected:
34 passed; help output shows--auto-hdr,--force-sdr,--force-hdr-pq,--force-hdr-hlg.HDR detection accuracy on test fixtures
bt709/bt709)smpte2084/bt2020nc+ master-display SEI)arib-std-b67/bt2020)smpte2084/bt709)Codec dispatch coverage
libx264-color_*only (x264 has no in-stream HDR SEI)libx265-x265-paramsw/ master-display + max-cll + hdr10-opt (PQ only)libsvtav1-svtav1-paramsAV1 enums (prim=9, transfer=16/18, matrix=9)hevc_nvenc-pix_fmt p010le -profile:v main10+ global-color_*libvvenc-color_*Out of scope
vmaf_hdr_v0.6.1.jsonmodel port (license + provenance review). Filed as backlog follow-up; see ADR-0261 Consequences § Neutral / follow-ups.