diff --git a/CHANGELOG.md b/CHANGELOG.md index 85f4f06c..f5995e72 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Fix HDR transcoding with NVIDIA accel for: - All NVIDIA docker users - Windows NVIDIA users who have set the `ETV_DISABLE_VULKAN` env var +- Fix audio sync issue with QSV acceleration ## [25.2.0] - 2025-06-24 ### Added diff --git a/ErsatzTV.FFmpeg/Capabilities/HardwareCapabilitiesFactory.cs b/ErsatzTV.FFmpeg/Capabilities/HardwareCapabilitiesFactory.cs index 2bc89f1f..2065033e 100644 --- a/ErsatzTV.FFmpeg/Capabilities/HardwareCapabilitiesFactory.cs +++ b/ErsatzTV.FFmpeg/Capabilities/HardwareCapabilitiesFactory.cs @@ -135,7 +135,7 @@ public class HardwareCapabilitiesFactory : IHardwareCapabilitiesFactory public async Task GetQsvOutput(string ffmpegPath, Option qsvDevice) { - var option = new QsvHardwareAccelerationOption(qsvDevice); + var option = new QsvHardwareAccelerationOption(qsvDevice, FFmpegCapability.Software); var arguments = option.GlobalOptions.ToList(); arguments.AddRange(QsvArguments); diff --git a/ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/QsvHardwareAccelerationOption.cs b/ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/QsvHardwareAccelerationOption.cs index 24b79816..984f2895 100644 --- a/ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/QsvHardwareAccelerationOption.cs +++ b/ErsatzTV.FFmpeg/GlobalOption/HardwareAcceleration/QsvHardwareAccelerationOption.cs @@ -1,11 +1,10 @@ -using ErsatzTV.FFmpeg.Format; +using ErsatzTV.FFmpeg.Capabilities; +using ErsatzTV.FFmpeg.Format; namespace ErsatzTV.FFmpeg.GlobalOption.HardwareAcceleration; -public class QsvHardwareAccelerationOption : GlobalOption +public class QsvHardwareAccelerationOption(Option device, FFmpegCapability decodeCapability) : GlobalOption { - private readonly Option _qsvDevice; - // TODO: read this from ffmpeg output private readonly List _supportedFFmpegFormats = new() { @@ -13,8 +12,6 @@ public class QsvHardwareAccelerationOption : GlobalOption FFmpegFormat.P010LE }; - public QsvHardwareAccelerationOption(Option qsvDevice) => _qsvDevice = qsvDevice; - public override string[] GlobalOptions { get @@ -29,9 +26,14 @@ public class QsvHardwareAccelerationOption : GlobalOption "-hwaccel_output_format", "qsv" }; + if (decodeCapability is not FFmpegCapability.Hardware) + { + result.Clear(); + } + if (OperatingSystem.IsLinux()) { - foreach (string qsvDevice in _qsvDevice) + foreach (string qsvDevice in device) { if (!string.IsNullOrWhiteSpace(qsvDevice)) { diff --git a/ErsatzTV.FFmpeg/Pipeline/QsvPipelineBuilder.cs b/ErsatzTV.FFmpeg/Pipeline/QsvPipelineBuilder.cs index 72055ed6..e2b0bf13 100644 --- a/ErsatzTV.FFmpeg/Pipeline/QsvPipelineBuilder.cs +++ b/ErsatzTV.FFmpeg/Pipeline/QsvPipelineBuilder.cs @@ -74,8 +74,6 @@ public class QsvPipelineBuilder : SoftwarePipelineBuilder encodeCapability = FFmpegCapability.Software; } - pipelineSteps.Add(new QsvHardwareAccelerationOption(ffmpegState.VaapiDevice)); - bool isHevcOrH264 = videoStream.Codec is /*VideoFormat.Hevc or*/ VideoFormat.H264; bool is10Bit = videoStream.PixelFormat.Map(pf => pf.BitDepth).IfNone(8) == 10; @@ -85,6 +83,14 @@ public class QsvPipelineBuilder : SoftwarePipelineBuilder decodeCapability = FFmpegCapability.Software; } + // QSV cannot always decode properly when seeking, so use software + if (decodeCapability == FFmpegCapability.Hardware && ffmpegState.Start.Filter(s => s > TimeSpan.Zero).IsSome) + { + decodeCapability = FFmpegCapability.Software; + } + + pipelineSteps.Add(new QsvHardwareAccelerationOption(ffmpegState.VaapiDevice, decodeCapability)); + // disable hw accel if decoder/encoder isn't supported return ffmpegState with {