From 5b100483899869f776a0aa9edae5ca0d2735bd8c Mon Sep 17 00:00:00 2001 From: Jason Dove <1695733+jasongdove@users.noreply.github.com> Date: Thu, 30 Oct 2025 14:11:13 -0500 Subject: [PATCH] fix seeking content with dts audio --- CHANGELOG.md | 1 + ErsatzTV.FFmpeg/Decoder/DecoderDtsCoreOnly.cs | 24 +++++++++++++++++++ ErsatzTV.FFmpeg/Format/AudioFormat.cs | 1 + .../Pipeline/PipelineBuilderBase.cs | 9 +++++++ 4 files changed, 35 insertions(+) create mode 100644 ErsatzTV.FFmpeg/Decoder/DecoderDtsCoreOnly.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index d73b8c608..b1e325cc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - This caused playout build errors like "Unable to locate history for playout item" - Fix crashes due to invalid smart collection searches, e.g. `smart_collection:"this collection does not exist"` - Fix UI crash when editing block playout that has default deco +- Fix playback failure when seeking content with certain DTS audio (e.g. DTS-HD MA) ## [25.8.0] - 2025-10-26 ### Added diff --git a/ErsatzTV.FFmpeg/Decoder/DecoderDtsCoreOnly.cs b/ErsatzTV.FFmpeg/Decoder/DecoderDtsCoreOnly.cs new file mode 100644 index 000000000..1bc18d7f1 --- /dev/null +++ b/ErsatzTV.FFmpeg/Decoder/DecoderDtsCoreOnly.cs @@ -0,0 +1,24 @@ +using ErsatzTV.FFmpeg.Environment; +using ErsatzTV.FFmpeg.InputOption; + +namespace ErsatzTV.FFmpeg.Decoder; + +public class DecoderDtsCoreOnly : IInputOption +{ + public EnvironmentVariable[] EnvironmentVariables => []; + public string[] GlobalOptions => []; + public string[] FilterOptions => []; + public string[] OutputOptions => []; + + public string[] InputOptions(InputFile inputFile) => ["-c:a", "dts", "-core_only", "true"]; + + public FrameState NextState(FrameState currentState) => currentState; + + public bool AppliesTo(AudioInputFile audioInputFile) => true; + + public bool AppliesTo(VideoInputFile videoInputFile) => false; + + public bool AppliesTo(ConcatInputFile concatInputFile) => false; + + public bool AppliesTo(GraphicsEngineInput graphicsEngineInput) => false; +} diff --git a/ErsatzTV.FFmpeg/Format/AudioFormat.cs b/ErsatzTV.FFmpeg/Format/AudioFormat.cs index 79331b9f3..9320ddbd8 100644 --- a/ErsatzTV.FFmpeg/Format/AudioFormat.cs +++ b/ErsatzTV.FFmpeg/Format/AudioFormat.cs @@ -5,6 +5,7 @@ public static class AudioFormat public const string Aac = "aac"; public const string Ac3 = "ac3"; public const string AacLatm = "aac-latm"; + public const string Dts = "dts"; public const string Copy = "copy"; } diff --git a/ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs b/ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs index 79091148b..9f2beeff3 100644 --- a/ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs +++ b/ErsatzTV.FFmpeg/Pipeline/PipelineBuilderBase.cs @@ -454,6 +454,15 @@ public abstract class PipelineBuilderBase : IPipelineBuilder AudioInputFile audioInputFile, List pipelineSteps) { + // workaround for seeking with dts; certain seeks will change format when decoding (e.g. s16p to s32p) + foreach (TimeSpan _ in ffmpegState.Start.Filter(s => s > TimeSpan.Zero)) + { + if (audioInputFile.Streams.OfType() .Any(s => s.Codec == AudioFormat.Dts)) + { + audioInputFile.AddOption(new DecoderDtsCoreOnly()); + } + } + // always need to specify audio codec so ffmpeg doesn't default to a codec we don't want foreach (IEncoder step in AvailableEncoders.ForAudioFormat(ffmpegState, audioInputFile.DesiredState, _logger)) {