From ebcd9a35a759285c5cfe50e0632fb4a3359e3d6f Mon Sep 17 00:00:00 2001 From: Jason Dove <1695733+jasongdove@users.noreply.github.com> Date: Mon, 13 Oct 2025 19:42:01 -0500 Subject: [PATCH] fix scaling image subs with vaapi (#2526) --- CHANGELOG.md | 1 + .../GetPlayoutItemProcessByChannelNumberHandler.cs | 4 ++-- ErsatzTV.FFmpeg/Filter/ScaleSubtitleImageFilter.cs | 14 ++++++++++++++ ErsatzTV.FFmpeg/Pipeline/VaapiPipelineBuilder.cs | 8 ++++---- 4 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 ErsatzTV.FFmpeg/Filter/ScaleSubtitleImageFilter.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index c4d1c1c99..4dfbea537 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -29,6 +29,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Fix intermittent watermark opacity - Improve reliability of live remote streams; they should transcode closer to realtime in most cases - Dramatically improve stream startup time +- VAAPI: fix scaling image-based subtitles (e.g. dvdsub) ### Changed - Do not use graphics engine for single, permanent watermark diff --git a/ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs b/ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs index f1858110f..4d89d58b7 100644 --- a/ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs +++ b/ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs @@ -283,10 +283,10 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< bool isComplete = true; - // if we are working ahead, limit to 45s + // if we are working ahead, limit to 44s (multiple of segment size) if (!request.HlsRealtime) { - TimeSpan limit = TimeSpan.FromSeconds(45); + TimeSpan limit = TimeSpan.FromSeconds(44); if (duration > limit) { diff --git a/ErsatzTV.FFmpeg/Filter/ScaleSubtitleImageFilter.cs b/ErsatzTV.FFmpeg/Filter/ScaleSubtitleImageFilter.cs new file mode 100644 index 000000000..99a33b10a --- /dev/null +++ b/ErsatzTV.FFmpeg/Filter/ScaleSubtitleImageFilter.cs @@ -0,0 +1,14 @@ +namespace ErsatzTV.FFmpeg.Filter; + +public class ScaleSubtitleImageFilter(FrameSize scaledSize) : BaseFilter +{ + public override string Filter => + $"scale={scaledSize.Width}:{scaledSize.Height}:force_original_aspect_ratio=decrease,pad=w={scaledSize.Width}:h={scaledSize.Height}:x=-1:y=-1:color=black@0"; + + public override FrameState NextState(FrameState currentState) => currentState with + { + ScaledSize = scaledSize, + PaddedSize = scaledSize, + FrameDataLocation = FrameDataLocation.Software + }; +} diff --git a/ErsatzTV.FFmpeg/Pipeline/VaapiPipelineBuilder.cs b/ErsatzTV.FFmpeg/Pipeline/VaapiPipelineBuilder.cs index a27997bff..65c97dd6b 100644 --- a/ErsatzTV.FFmpeg/Pipeline/VaapiPipelineBuilder.cs +++ b/ErsatzTV.FFmpeg/Pipeline/VaapiPipelineBuilder.cs @@ -516,16 +516,16 @@ public class VaapiPipelineBuilder : SoftwarePipelineBuilder } else { - var subtitleHardwareUpload = new HardwareUploadVaapiFilter(false); - subtitle.FilterSteps.Add(subtitleHardwareUpload); - // only scale if scaling or padding was used for main video stream if (videoInputFile.FilterSteps.Any(s => s is ScaleFilter or ScaleVaapiFilter or PadFilter)) { - var scaleFilter = new SubtitleScaleVaapiFilter(desiredState.PaddedSize); + var scaleFilter = new ScaleSubtitleImageFilter(desiredState.PaddedSize); subtitle.FilterSteps.Add(scaleFilter); } + var subtitleHardwareUpload = new HardwareUploadVaapiFilter(false); + subtitle.FilterSteps.Add(subtitleHardwareUpload); + var subtitlesFilter = new OverlaySubtitleVaapiFilter(); subtitleOverlayFilterSteps.Add(subtitlesFilter); }