fix(505): gate the OpenCL tonemap on the ACTUAL frame location, not an enumeration

UseOpenClTonemap excluded the two known ways frames reach a hardware surface
before the tonemap (the QSV decoder, deinterlace_qsv). That is only correct for
as long as the enumeration stays complete -- and the failure mode if it ever
stops being complete is a second hwupload stacked on frames that are already on
a surface.

Check currentState.FrameDataLocation directly instead. The route begins with
hwupload, so "frames are in software" is the actual precondition; the specific
exclusions stay as documentation of the known cases, but the state check is what
makes it safe. A future filter landing ahead of the tonemap now degrades to the
software tonemap rather than emitting a broken graph.
This commit is contained in:
2026-07-26 20:59:54 +02:00
parent 41e2870113
commit 7c075ffa70
+16 -2
View File
@@ -222,7 +222,7 @@ public class QsvPipelineBuilder : SoftwarePipelineBuilder
// the plan the downscale has to happen in scale_vaapi rather than vpp_qsv, because a QSV
// surface can be mapped neither to OpenCL nor back to VA-API. Decided once, up front, so
// the scale and tonemap steps cannot disagree about which device the frames are on.
bool useOpenClTonemap = UseOpenClTonemap(videoStream, context, ffmpegState);
bool useOpenClTonemap = UseOpenClTonemap(videoStream, context, ffmpegState, currentState);
// _logger.LogDebug("After decode: {PixelFormat}", currentState.PixelFormat);
currentState = SetDeinterlace(videoInputFile, context, ffmpegState, currentState);
@@ -671,13 +671,27 @@ public class QsvPipelineBuilder : SoftwarePipelineBuilder
// The QSV pipeline can only reach tonemap_opencl through the VA-API device that its own QSV
// device is derived from, so every condition here is about that device existing and being
// reachable with software frames in hand.
private bool UseOpenClTonemap(VideoStream videoStream, PipelineContext context, FFmpegState ffmpegState)
private bool UseOpenClTonemap(
VideoStream videoStream,
PipelineContext context,
FFmpegState ffmpegState,
FrameState currentState)
{
if (!videoStream.ColorParams.IsHdr)
{
return false;
}
// The backstop for every case below, and for any future filter that lands ahead of the
// tonemap: the route starts with hwupload, so the frames have to actually be in software.
// Checked against the state rather than inferred from the enumeration, so a later change
// that puts frames on a surface earlier degrades to the software tonemap instead of
// emitting a second upload on top of an existing one.
if (currentState.FrameDataLocation == FrameDataLocation.Hardware)
{
return false;
}
// ffmpeg has no vaapi on Windows, so there is no device to derive OpenCL from
if (OperatingSystem.IsWindows())
{