Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
Re-pinned the vendored Pelorus interop ABI mirror from `pelorus@835e097`
(ABI 1.0) to `pelorus@818d844` (ABI 1.3, ADR-1120) and taught perceptual
weighting to consume the new per-frame `PEL_SEC_COMPLEXITY` section. The mirror
gains three vendored files (`pelorus/denoise.h`, `pelorus_denoise_params.c`,
`pelorus_qp_report_csv.c`); the minor-3 conformance fixture
(`test_pelorus_interop`, now 14 vectors) links the x265 CSV QP-report reader.
Perceptual weighting (`--lavfi libvmaf=perceptual_weight=1`, C-API
`vmaf_set_perceptual_*`) now attenuates the banding salience by
`(1 − 0.5·complexity)` (floored at 0.25): banding is up-weighted on flat/simple
frames and masked on busy/textured frames. The modulation is opt-in and
golden-isolated — an absent complexity section means an exact `1.0` factor, so
the Netflix golden 576×324 pair still scores `76.667831`. Also fixes the
`scripts/sync-pelorus-interop.sh --update` bug that re-vendored the six manifest
files but not the conformance-fixture body. See `docs/api/pelorus-interop.md`
and `docs/api/perceptual-weight.md`.
43 changes: 21 additions & 22 deletions core/include/libvmaf/pelorus/deband.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
*/

/*
* VENDORED FROM VMAFx/pelorus@835e097 — DO NOT EDIT. Append-only ABI; single
* VENDORED FROM VMAFx/pelorus@818d844 — DO NOT EDIT. Append-only ABI; single
* source of truth is pelorus. Re-sync via scripts/sync-pelorus-interop.sh.
* See docs/adr/1113-vendor-pelorus-interop-abi.md.
*
Expand Down Expand Up @@ -53,9 +53,9 @@ extern "C" {
#endif

enum pel_deband_sample_mode {
PEL_DEBAND_SAMPLE_COLUMN = 1, /* 2 vertical taps */
PEL_DEBAND_SAMPLE_SQUARE = 2, /* 4 rotated taps (== vf_deband; DEFAULT) */
PEL_DEBAND_SAMPLE_ROW = 3, /* 2 horizontal taps */
PEL_DEBAND_SAMPLE_COLUMN = 1, /* 2 vertical taps */
PEL_DEBAND_SAMPLE_SQUARE = 2, /* 4 rotated taps (== vf_deband; DEFAULT) */
PEL_DEBAND_SAMPLE_ROW = 3, /* 2 horizontal taps */
PEL_DEBAND_SAMPLE_SQUARE_ROT = 4 /* 4 taps + per-frame ring rotation */
};

Expand All @@ -66,15 +66,15 @@ enum pel_deband_blur_mode {

enum pel_deband_dither_mode {
PEL_DEBAND_DITHER_NONE = 0,
PEL_DEBAND_DITHER_BAYER8 = 1, /* ordered 8x8 Bayer */
PEL_DEBAND_DITHER_BLUENOISE = 2 /* hashed TPDF (DEFAULT) */
PEL_DEBAND_DITHER_BAYER8 = 1, /* ordered 8x8 Bayer */
PEL_DEBAND_DITHER_BLUENOISE = 2 /* hashed TPDF (DEFAULT) */
};

/* Flag bits, mirrored 1:1 into the shader push-constant `flags` word. */
enum pel_deband_flags {
PEL_DEBAND_FLAG_DYNAMIC_GRAIN = 1u << 0, /* re-seed grain each frame */
PEL_DEBAND_FLAG_PROTECT_DETAIL = 1u << 1,/* gate off textured regions */
PEL_DEBAND_FLAG_COUPLING = 1u << 2 /* all planes must agree (4:4:4) */
PEL_DEBAND_FLAG_DYNAMIC_GRAIN = 1u << 0, /* re-seed grain each frame */
PEL_DEBAND_FLAG_PROTECT_DETAIL = 1u << 1, /* gate off textured regions */
PEL_DEBAND_FLAG_COUPLING = 1u << 2 /* all planes must agree (4:4:4) */
};

/*
Expand All @@ -83,17 +83,17 @@ enum pel_deband_flags {
* 16-bit internal domain). Per-plane order is {Y, Cb, Cr, A}.
*/
typedef struct PelorusDebandParams {
int32_t range; /* reference-sampling radius in pixels (1..31) */
float thr[4]; /* per-plane normalized threshold */
float grain[4]; /* per-plane normalized grain amplitude */
float softness; /* blend transition width (0 = hard vf_deband) */
float detail_thr; /* detail-mask activity threshold (normalized) */
int32_t sample_mode; /* enum pel_deband_sample_mode */
int32_t blur_mode; /* enum pel_deband_blur_mode */
int32_t dither_mode; /* enum pel_deband_dither_mode */
uint32_t planes; /* bitmask of planes to process (default 0xF) */
uint32_t flags; /* enum pel_deband_flags */
int32_t out_depth; /* output bit depth (8/10/12/16; 0 = same as input) */
int32_t range; /* reference-sampling radius in pixels (1..31) */
float thr[4]; /* per-plane normalized threshold */
float grain[4]; /* per-plane normalized grain amplitude */
float softness; /* blend transition width (0 = hard vf_deband) */
float detail_thr; /* detail-mask activity threshold (normalized) */
int32_t sample_mode; /* enum pel_deband_sample_mode */
int32_t blur_mode; /* enum pel_deband_blur_mode */
int32_t dither_mode; /* enum pel_deband_dither_mode */
uint32_t planes; /* bitmask of planes to process (default 0xF) */
uint32_t flags; /* enum pel_deband_flags */
int32_t out_depth; /* output bit depth (8/10/12/16; 0 = same as input) */
} PelorusDebandParams;

/* Fill p with the dark-scene pre-encode defaults (range=15, square sampling,
Expand All @@ -102,8 +102,7 @@ void pel_deband_params_default(PelorusDebandParams *p);

/* Validate p against documented ranges. Returns PEL_OK or PEL_ERR_RANGE; on
* error and if `what` is non-NULL, *what points at a static field name. */
pel_result pel_deband_params_validate(const PelorusDebandParams *p,
const char **what);
pel_result pel_deband_params_validate(const PelorusDebandParams *p, const char **what);

#ifdef __cplusplus
}
Expand Down
112 changes: 112 additions & 0 deletions core/include/libvmaf/pelorus/denoise.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/**
*
* Copyright 2026 Lusoris
*
* Licensed under the BSD+Patent License (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://opensource.org/licenses/BSDplusPatent
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/

/*
* VENDORED FROM VMAFx/pelorus@818d844 — DO NOT EDIT. Append-only ABI; single
* source of truth is pelorus. Re-sync via scripts/sync-pelorus-interop.sh.
* See docs/adr/1113-vendor-pelorus-interop-abi.md.
*
* Local edit vs the pelorus original: the intra-pelorus #include below is
* rewritten from "pelorus/pelorus.h" to "libvmaf/pelorus/pelorus.h" so it resolves
* under core/include/. Nothing else is changed.
*/

/*
* denoise.h — parameter contract for the Pelorus temporal denoise filter.
*
* Shared by the FFmpeg vf_pelorus_denoise_vulkan filter (which mirrors these
* fields into its compute-shader push constants) and the vmafx autotune loop
* (which sweeps `sigma` against encoded-VMAF-at-bitrate as the oracle, ADR-0106).
* The wire form of the push constants lives in shaders/pelorus_denoise.comp;
* this struct is the host-side, AVOption-addressable view of the same params.
*
* Algorithm (PEL_DENOISER_BILATERAL_TEMPORAL): an edge-preserving
* spatio-temporal denoiser in a single Vulkan compute pass over a CAUSAL window
* [cur, prev_1 .. prev_n]. The spatial term is an NLM-lite joint bilateral whose
* range weight is a small-patch SSD (a real edge has high patch SSD, driving the
* weight to zero, so it refuses to average across edges). The temporal term
* averages the same-coordinate sample of each previous frame, gated per pixel by
* a similarity threshold (a delta above `temporal_cut` breaks the walk so motion
* / scene-cuts cannot ghost) and decayed by `temporal_decay` per frame. The two
* are blended (`blend`) and applied dry/wet (`strength`). No motion compensation
* in v0.x — same-coordinate taps only; MC is a later filter (PEL_DENOISE_FLAG_
* MOTION_COMP is reserved, off). Thresholds are NORMALIZED in [0,1], independent
* of bit depth (the shader works in a normalized domain). Per-plane order is
* {Y, Cb, Cr, A}. With meta=1 the filter emits PEL_SEC_DENOISE residual stats.
* See docs/metrics/denoise.md and ADR-0111 (benchmark methodology proving it).
*/
#ifndef PELORUS_DENOISE_H
#define PELORUS_DENOISE_H

#include <stdint.h>

#include "libvmaf/pelorus/pelorus.h"

#ifdef __cplusplus
extern "C" {
#endif

/* Which Pelorus denoiser ran — echoed into PelorusDenoiseSection.denoiser_id. */
enum pel_denoiser_id {
PEL_DENOISER_NONE = 0,
PEL_DENOISER_BILATERAL_TEMPORAL = 1 /* edge-preserving spatio-temporal NLM-lite */
};

/* Flag bits, mirrored 1:1 into the shader push-constant `flags` word. */
enum pel_denoise_flags {
PEL_DENOISE_FLAG_TEMPORAL = 1u << 0, /* use the temporal term */
PEL_DENOISE_FLAG_MOTION_COMP = 1u << 1, /* reserved (MC is a later filter)*/
PEL_DENOISE_FLAG_PROTECT_DETAIL = 1u << 2, /* damp strength on texture/edges */
PEL_DENOISE_FLAG_AUTO_SIGMA = 1u << 3 /* reserved (variance-fed sigma) */
};

/*
* Denoise parameters. Sigmas/cuts are NORMALIZED in [0,1] relative to full
* range, independent of bit depth. Per-plane arrays are {Y, Cb, Cr, A}.
* Defaults are the conservative param-contract preset (so the vmafx autotune
* loop sweeps strength/sigma UP from a safe floor); see pel_denoise_params_default.
*/
typedef struct PelorusDenoiseParams {
float sigma_s[4]; /* per-plane spatial range sigma (edge sensitivity) */
float sigma_t[4]; /* per-plane temporal gate bandwidth */
float strength[4]; /* per-plane dry/wet mix: out = mix(in, filtered, s) */
float blend; /* spatial<->temporal blend (0 = spatial, 1 = temporal)*/
float temporal_decay; /* per-frame trust falloff (older frames weigh less) */
float temporal_cut; /* per-pixel scene-cut/fast-motion clamp (normalized) */
int32_t patch_radius; /* spatial window radius in pixels (0 = temporal-only)*/
int32_t n_prev; /* temporal depth — previous frames held in VRAM */
int32_t denoiser_id; /* enum pel_denoiser_id */
uint32_t planes; /* bitmask of planes to process (default 0xF) */
uint32_t flags; /* enum pel_denoise_flags */
} PelorusDenoiseParams;

/* Maximum temporal depth the filter holds (cur + PEL_DENOISE_MAX_PREV prev). */
#define PEL_DENOISE_MAX_PREV 4

/* Fill p with the conservative pre-encode defaults (sigma 0.03/0.04, strength
* 0.30/0.20, 3-frame causal temporal window, detail protection on). */
void pel_denoise_params_default(PelorusDenoiseParams *p);

/* Validate p against documented ranges. Returns PEL_OK or PEL_ERR_RANGE; on
* error and if `what` is non-NULL, *what points at a static field name. */
pel_result pel_denoise_params_validate(const PelorusDenoiseParams *p, const char **what);

#ifdef __cplusplus
}
#endif
#endif /* PELORUS_DENOISE_H */
Loading
Loading