Browse Source

fix case when cuda hw decode falls back to sw (#2718)

* fix case when cuda hw decode falls back to sw

* use a new filter
pull/2720/head
Jason Dove 3 weeks ago committed by GitHub
parent
commit
09858df654
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 1
      CHANGELOG.md
  2. 9
      ErsatzTV.FFmpeg/Filter/Cuda/CudaSoftwareFallbackUploadFilter.cs
  3. 13
      ErsatzTV.FFmpeg/Filter/Cuda/HardwareUploadCudaFilter.cs
  4. 17
      ErsatzTV.FFmpeg/Filter/HardwareUploadCudaFilter.cs
  5. 2
      ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/CudaHardwareAccelerationOption.cs
  6. 24
      ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs

1
CHANGELOG.md

@ -53,6 +53,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). @@ -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

9
ErsatzTV.FFmpeg/Filter/Cuda/CudaSoftwareFallbackUploadFilter.cs

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
namespace ErsatzTV.FFmpeg.Filter.Cuda;
public class CudaSoftwareFallbackUploadFilter : BaseFilter
{
public override string Filter => "hwupload";
public override FrameState NextState(FrameState currentState) =>
currentState with { FrameDataLocation = FrameDataLocation.Hardware };
}

13
ErsatzTV.FFmpeg/Filter/Cuda/HardwareUploadCudaFilter.cs

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
namespace ErsatzTV.FFmpeg.Filter.Cuda;
public class HardwareUploadCudaFilter(FrameDataLocation frameDataLocation) : BaseFilter
{
public override string Filter => frameDataLocation switch
{
FrameDataLocation.Hardware => string.Empty,
_ => "hwupload_cuda"
};
public override FrameState NextState(FrameState currentState) =>
currentState with { FrameDataLocation = FrameDataLocation.Hardware };
}

17
ErsatzTV.FFmpeg/Filter/HardwareUploadCudaFilter.cs

@ -1,17 +0,0 @@ @@ -1,17 +0,0 @@
namespace ErsatzTV.FFmpeg.Filter;
public class HardwareUploadCudaFilter : BaseFilter
{
private readonly FrameState _currentState;
public HardwareUploadCudaFilter(FrameState currentState) => _currentState = currentState;
public override string Filter => _currentState.FrameDataLocation switch
{
FrameDataLocation.Hardware => string.Empty,
_ => "hwupload_cuda"
};
public override FrameState NextState(FrameState currentState) =>
currentState with { FrameDataLocation = FrameDataLocation.Hardware };
}

2
ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/CudaHardwareAccelerationOption.cs

@ -11,7 +11,7 @@ public class CudaHardwareAccelerationOption(bool isVulkanHdr) : GlobalOption @@ -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"];
}
}
}

24
ErsatzTV.FFmpeg/Pipeline/NvidiaPipelineBuilder.cs

@ -134,6 +134,15 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder @@ -134,6 +134,15 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder
foreach (IDecoder decoder in maybeDecoder)
{
videoInputFile.AddOption(decoder);
// sometimes cuda fails to decode in hardware and falls back to software
// in that case, we need to upload to get the frame in hardware as expected
// this *should* no-op when frames are already in hardware
if (ffmpegState.DecoderHardwareAccelerationMode is HardwareAccelerationMode.Nvenc)
{
videoInputFile.FilterSteps.Add(new CudaSoftwareFallbackUploadFilter());
}
return Some(decoder);
}
@ -266,7 +275,7 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder @@ -266,7 +275,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 +571,7 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder @@ -562,7 +571,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 +621,7 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder @@ -612,7 +621,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 +635,7 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder @@ -626,8 +635,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 +656,7 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder @@ -648,8 +656,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 +707,7 @@ public class NvidiaPipelineBuilder : SoftwarePipelineBuilder @@ -700,8 +707,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);

Loading…
Cancel
Save