From 920eb95e595ffd9676021cfc982e50afa742d078 Mon Sep 17 00:00:00 2001 From: Jason Dove <1695733+jasongdove@users.noreply.github.com> Date: Fri, 12 Dec 2025 12:35:29 -0600 Subject: [PATCH] fix case when cuda hw decode falls back to sw --- CHANGELOG.md | 1 + .../Filter/HardwareUploadCudaFilter.cs | 9 +++----- .../CudaHardwareAccelerationOption.cs | 2 +- .../Pipeline/NvidiaPipelineBuilder.cs | 21 +++++++++++-------- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b7b0778a..ad56c11de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -53,6 +53,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Automatically kill playback troubleshooting ffmpeg process if it hasn't completed after two minutes - Fix playback of certain BT.2020 content - Use playlist item count when using a playlist as filler (instead of a fixed count of 1 for each playlist item) +- NVIDIA: fix stream failure with certain content that should decode in hardware but falls back to software ### Changed - No longer round framerate to nearest integer when normalizing framerate diff --git a/ErsatzTV.FFmpeg/Filter/HardwareUploadCudaFilter.cs b/ErsatzTV.FFmpeg/Filter/HardwareUploadCudaFilter.cs index b15a31466..6f5a4f71a 100644 --- a/ErsatzTV.FFmpeg/Filter/HardwareUploadCudaFilter.cs +++ b/ErsatzTV.FFmpeg/Filter/HardwareUploadCudaFilter.cs @@ -1,14 +1,11 @@ namespace ErsatzTV.FFmpeg.Filter; -public class HardwareUploadCudaFilter : BaseFilter +public class HardwareUploadCudaFilter(FrameDataLocation frameDataLocation) : BaseFilter { - private readonly FrameState _currentState; - - public HardwareUploadCudaFilter(FrameState currentState) => _currentState = currentState; - - public override string Filter => _currentState.FrameDataLocation switch + public override string Filter => frameDataLocation switch { FrameDataLocation.Hardware => string.Empty, + FrameDataLocation.Unknown => "hwupload", _ => "hwupload_cuda" }; diff --git a/ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/CudaHardwareAccelerationOption.cs b/ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/CudaHardwareAccelerationOption.cs index a5f12e2f2..ad7832237 100644 --- a/ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/CudaHardwareAccelerationOption.cs +++ b/ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/CudaHardwareAccelerationOption.cs @@ -11,7 +11,7 @@ public class CudaHardwareAccelerationOption(bool isVulkanHdr) : GlobalOption return ["-init_hw_device", "cuda=nv", "-init_hw_device", "vulkan=vk@nv", "-hwaccel", "vulkan"]; } - return ["-hwaccel", "cuda"]; + return ["-init_hw_device", "cuda", "-hwaccel", "cuda"]; } } } diff --git a/ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs b/ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs index 5aaa1ee83..cfab05adf 100644 --- a/ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs +++ b/ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs @@ -134,6 +134,12 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder foreach (IDecoder decoder in maybeDecoder) { videoInputFile.AddOption(decoder); + + if (ffmpegState.DecoderHardwareAccelerationMode is HardwareAccelerationMode.Nvenc) + { + videoInputFile.FilterSteps.Add(new HardwareUploadCudaFilter(FrameDataLocation.Unknown)); + } + return Some(decoder); } @@ -266,7 +272,7 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder && !context.HasSubtitleText && (context.HasSubtitleOverlay || context.HasWatermark || context.HasGraphicsEngine)) { - var hardwareUpload = new HardwareUploadCudaFilter(currentState); + var hardwareUpload = new HardwareUploadCudaFilter(currentState.FrameDataLocation); currentState = hardwareUpload.NextState(currentState); videoInputFile.FilterSteps.Add(hardwareUpload); } @@ -562,7 +568,7 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder else { watermark.FilterSteps.Add( - new HardwareUploadCudaFilter(currentState with { FrameDataLocation = FrameDataLocation.Software })); + new HardwareUploadCudaFilter(FrameDataLocation.Software)); var watermarkFilter = new OverlayWatermarkCudaFilter( watermark.DesiredState, @@ -612,7 +618,7 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder if (context.HasWatermark || context.HasGraphicsEngine) { - var subtitleHardwareUpload = new HardwareUploadCudaFilter(currentState); + var subtitleHardwareUpload = new HardwareUploadCudaFilter(currentState.FrameDataLocation); currentState = subtitleHardwareUpload.NextState(currentState); videoInputFile.FilterSteps.Add(subtitleHardwareUpload); } @@ -626,8 +632,7 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder { if (_ffmpegCapabilities.HasFilter(FFmpegKnownFilter.ScaleNpp)) { - var subtitleHardwareUpload = new HardwareUploadCudaFilter( - currentState with { FrameDataLocation = FrameDataLocation.Software }); + var subtitleHardwareUpload = new HardwareUploadCudaFilter(FrameDataLocation.Software); subtitle.FilterSteps.Add(subtitleHardwareUpload); // only scale if scaling or padding was used for main video stream @@ -648,8 +653,7 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder subtitle.FilterSteps.Add(scaleFilter); } - var subtitleHardwareUpload = new HardwareUploadCudaFilter( - currentState with { FrameDataLocation = FrameDataLocation.Software }); + var subtitleHardwareUpload = new HardwareUploadCudaFilter(FrameDataLocation.Software); subtitle.FilterSteps.Add(subtitleHardwareUpload); } @@ -700,8 +704,7 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder { graphicsEngine.FilterSteps.Add(new PixelFormatFilter(new PixelFormatYuva420P())); - graphicsEngine.FilterSteps.Add( - new HardwareUploadCudaFilter(currentState with { FrameDataLocation = FrameDataLocation.Software })); + graphicsEngine.FilterSteps.Add(new HardwareUploadCudaFilter(FrameDataLocation.Software)); var graphicsEngineFilter = new OverlayGraphicsEngineCudaFilter(); graphicsEngineOverlayFilterSteps.Add(graphicsEngineFilter);