Skip to content

feat(grain): grain_sigma/grain_flat metadata — the tune=auto detection enabler (ADR-0142)#43

Merged
lusoris merged 1 commit into
masterfrom
feat/tune-auto-grain-metadata
Jun 27, 2026
Merged

feat(grain): grain_sigma/grain_flat metadata — the tune=auto detection enabler (ADR-0142)#43
lusoris merged 1 commit into
masterfrom
feat/tune-auto-grain-metadata

Conversation

@lusoris

@lusoris lusoris commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

What

The foundational first step of tune=auto (the content-adaptive pre-encode router): vf_pelorus_grain_estimate_vulkan now emits lavfi.pelorus.grain_sigma and lavfi.pelorus.grain_flat as per-frame metadata, so the router can detect grainy content. ADR-0142 records the full design.

Why (the law this session established)

With the real tooling (vmaf v1.0.16 + v0.6.1-NEG, x265-enabled ffmpeg, on-hardware NVENC): NVENC is genuinely worse than x265, but the pre-encode gain that closes it is REDUCTIVE and CONTENT-DEPENDENT.

  • Additive pre-sharpen → wash on VMAF-NEG (you can't add past the deadzone).
  • Reductive (denoise) → real but scales with removable impairment (−34% heavy grain, ~5–7% moderate, ~0 clean).
  • Source-side RC (QP map / per-shot CRF) → loses structurally.
  • And it's mostly tuning — the default denoise over-smoothed (false negative); retuned temporal-dominant it recovers the gain.

→ There is no single best filter, there's a tuned reductive boost per content class + a router. That router needs detection metadata that didn't exist (only analyze emitted any).

The enabler

grain_estimate already computes per-band RMS residual over edge-gated locally-flat pixels (structure excluded by construction → what survives is grain stddev) but trapped it in the PEL_SEC_FILMGRAIN side-data. This emits the peak as grain_sigma + the flat fraction as grain_flat (confidence), via the ADR-0136 av_dict_set pattern — no interop ABI change, no shader change, the value was already computed; the side-data path is untouched. Verified discriminating: heavy-grain clip 0.019 vs clean-ish Bluray 0.012.

ADR-0142 (Proposed) records the full design

The 8-class routing table (grainy→denoise, anime→dehalo+aa+deband, textured→spatial-denoise, re-encode→demosquito, dark→dark-masked-denoise, screen→deblock, sports→denoise+mc-warp, clean→no-op), the validation priority (grainy scaling first — the proven lever; every leg iso-bitrate-proven + held-out-confirmed before it enters the router), the constraints (analyze.texture is derived; motion needs upstream mc), and the encoder-integration patch parallel track (NVENC/QSV/AMF features FFmpeg underuses).

Deliverables

Filter (metadata only) + ADR-0142 + README index + grain_estimate.md metadata section + changelog + regenerated patch 0006. No ABI/shader/surface-behavior change beyond the additive metadata.

🤖 Generated with Claude Code

…ection enabler (ADR-0142)

The session's measurement campaign established the law: NVENC is genuinely
worse than x265, but the pre-encode gain that closes it is REDUCTIVE and
CONTENT-DEPENDENT (additive pre-sharpen washes; denoise scales with removable
grain; clean content gains ~0), and mostly a matter of TUNING. So there is no
single best filter -- there is a tuned reductive boost per content class and a
router (tune=auto) that detects the class from analyze.* metadata and applies it.

The router needs content detection that did not exist: grain_estimate computes
per-band RMS residual but emitted zero frame metadata (trapped in the
PEL_SEC_FILMGRAIN side-data). This ships the first and highest-leverage enabler:
grain_estimate now emits lavfi.pelorus.grain_sigma (peak per-band RMS over the
edge-gated flat bands -- structure excluded by construction, so what survives is
grain stddev) and lavfi.pelorus.grain_flat (the flat fraction = confidence), via
the ADR-0136 av_dict_set pattern. No interop ABI change, no shader change, the
value was already computed; the side-data path is untouched. Verified
discriminating (heavy-grain 0.019 vs clean-ish Bluray 0.012) and unblocks the
proven -34% grainy denoise route.

ADR-0142 records the full tune=auto design (8-class routing table + validation
priority + the encoder-integration patch parallel track). Follow-ups: the
remaining detection enablers (noise_sigma, dark_frac), the per-leg validations,
the router itself, and the encoder-patch track.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@lusoris
lusoris merged commit fbca672 into master Jun 27, 2026
3 checks passed
@lusoris
lusoris deleted the feat/tune-auto-grain-metadata branch June 27, 2026 19:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant