feat(stream): enable GPU libplacebo in prod image + gate to real GPU
Make libplacebo actually reachable in the shipped agent image, and refuse it where it would be a regression. Dockerfile (so a Vulkan-capable host can use the GPU tonemap path): - install libvulkan1 (the Vulkan loader libplacebo links at runtime; ~150 KB) - add 'graphics' to NVIDIA_DRIVER_CAPABILITIES so the nvidia container runtime mounts the Vulkan ICD (nvidia_icd.json + GLX libs) under --gpus all Both are inert without a working Vulkan GPU — the functional probe gates use. hls.go: gate libplacebo on a real HW encoder (HWAccel != none). A software-only host with mesa would expose lavapipe (CPU Vulkan); the functional probe accepts it but its tonemap is SLOWER than the zscale CPU chain, so libplacebo there is a regression. No HW encoder -> stay on zscale. Verified on the GPU dev box: nvenc session still picks libplacebo (-c:v h264_nvenc -vf ...,libplacebo=...:tonemapping=bt.2390); new unit test locks the software-encoder path onto zscale.
This commit is contained in:
parent
cfaedb7f3b
commit
5e5a719f27
3 changed files with 47 additions and 9 deletions
|
|
@ -1359,7 +1359,14 @@ func buildHLSFFmpegArgsAt(cfg HLSSessionConfig, probe *StreamProbe, tmpDir strin
|
|||
// CPU chain; else play untonemapped (desaturated, last resort). Skip
|
||||
// libplacebo on VAAPI: its Vulkan surface flow doesn't compose with our
|
||||
// nv12+hwupload path, so VAAPI keeps the zscale-or-none behaviour.
|
||||
useLibplacebo := probe.HDR != "" && cfg.Transcode.HasLibplacebo && codec != "h264_vaapi"
|
||||
//
|
||||
// Gate on a real HW encoder (HWAccel != none): only then is the Vulkan
|
||||
// device a genuine GPU. A software-only host with mesa would expose lavapipe
|
||||
// (CPU Vulkan), which the functional probe accepts but whose tonemap is
|
||||
// SLOWER than the zscale CPU chain — so on those hosts libplacebo would be a
|
||||
// regression. No HW encoder ⇒ stay on zscale.
|
||||
useLibplacebo := probe.HDR != "" && cfg.Transcode.HasLibplacebo &&
|
||||
codec != "h264_vaapi" && cfg.Transcode.HWAccel != HWAccelNone
|
||||
tonemap := ""
|
||||
if probe.HDR != "" && cfg.Transcode.TonemapHDR && !useLibplacebo {
|
||||
tonemap = hdrTonemapChain
|
||||
|
|
|
|||
|
|
@ -68,13 +68,15 @@ func TestTonemap_AppliedInNoDownscaleBranch(t *testing.T) {
|
|||
}
|
||||
|
||||
func TestTonemap_LibplaceboPreferredOverZscale(t *testing.T) {
|
||||
// HDR source + an ffmpeg with libplacebo → the single GPU filter replaces
|
||||
// the whole CPU zscale chain (and the trailing format=/setparams it folds in).
|
||||
// HDR source + an ffmpeg with libplacebo on a REAL HW encoder (NVENC) → the
|
||||
// single GPU filter replaces the whole CPU zscale chain (and the trailing
|
||||
// format=/setparams it folds in). NVENC (not None) because libplacebo is
|
||||
// gated on a real GPU — a software encoder stays on zscale.
|
||||
cfg := HLSSessionConfig{
|
||||
SessionID: "test",
|
||||
SourcePath: "/movies/x.mkv",
|
||||
Quality: "720p",
|
||||
Transcode: TranscodeRuntime{FFmpegPath: "/usr/bin/ffmpeg", HWAccel: HWAccelNone, TonemapHDR: true, HasLibplacebo: true},
|
||||
Transcode: TranscodeRuntime{FFmpegPath: "/usr/bin/ffmpeg", HWAccel: HWAccelNVENC, TonemapHDR: true, HasLibplacebo: true},
|
||||
}
|
||||
probe := &StreamProbe{Width: 3840, Height: 2160, BitDepth: 10, HDR: "HDR10", DurationSec: 100}
|
||||
vf := vfChain(strings.Join(buildHLSFFmpegArgsAt(cfg, probe, "/tmp/t", 0, 0), " "))
|
||||
|
|
@ -86,6 +88,26 @@ func TestTonemap_LibplaceboPreferredOverZscale(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTonemap_LibplaceboSkippedOnSoftwareEncoder(t *testing.T) {
|
||||
// libplacebo present but no HW encoder (software libx264) → must NOT use
|
||||
// libplacebo: a software host's only Vulkan would be lavapipe (CPU), slower
|
||||
// than zscale. Falls back to the zscale chain.
|
||||
cfg := HLSSessionConfig{
|
||||
SessionID: "test",
|
||||
SourcePath: "/movies/x.mkv",
|
||||
Quality: "720p",
|
||||
Transcode: TranscodeRuntime{FFmpegPath: "/usr/bin/ffmpeg", HWAccel: HWAccelNone, TonemapHDR: true, HasLibplacebo: true},
|
||||
}
|
||||
probe := &StreamProbe{Width: 3840, Height: 2160, BitDepth: 10, HDR: "HDR10", DurationSec: 100}
|
||||
vf := vfChain(strings.Join(buildHLSFFmpegArgsAt(cfg, probe, "/tmp/t", 0, 0), " "))
|
||||
if strings.Contains(vf, "libplacebo") {
|
||||
t.Errorf("software encoder must not use libplacebo (lavapipe trap), got %q", vf)
|
||||
}
|
||||
if !strings.Contains(vf, "zscale=t=linear") {
|
||||
t.Errorf("software encoder with HDR + zscale should fall back to the zscale chain, got %q", vf)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTonemap_SkippedWhenFFmpegLacksZscale(t *testing.T) {
|
||||
vf := vfChain(hlsArgsFor("HDR10", false, HWAccelNone))
|
||||
if strings.Contains(vf, "zscale") || strings.Contains(vf, "tonemap") {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue