From 7869f16573b9f8d29790a830f2bfc7960847170b Mon Sep 17 00:00:00 2001 From: Jason Dove <1695733+jasongdove@users.noreply.github.com> Date: Sun, 3 May 2026 15:43:26 -0500 Subject: [PATCH] feat: use configured scaling behavior with next engine (#2880) * update dependencies * feat: respect desired scaling behavior using next engine --- .../Commands/StartFFmpegNextSessionHandler.cs | 6 +++ .../ErsatzTV.Core.Tests.csproj | 2 +- ErsatzTV.Core/Next/Config/ChannelConfig.cs | 52 +++++++++++++++++++ .../ErsatzTV.FFmpeg.Tests.csproj | 2 +- ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj | 2 +- .../ErsatzTV.Infrastructure.Tests.csproj | 4 +- .../ErsatzTV.Scanner.Tests.csproj | 4 +- ErsatzTV.Tests/ErsatzTV.Tests.csproj | 4 +- ErsatzTV/ErsatzTV.csproj | 2 +- 9 files changed, 68 insertions(+), 10 deletions(-) diff --git a/ErsatzTV.Application/Streaming/Commands/StartFFmpegNextSessionHandler.cs b/ErsatzTV.Application/Streaming/Commands/StartFFmpegNextSessionHandler.cs index 81bb2eaeb..dcc8d3db2 100644 --- a/ErsatzTV.Application/Streaming/Commands/StartFFmpegNextSessionHandler.cs +++ b/ErsatzTV.Application/Streaming/Commands/StartFFmpegNextSessionHandler.cs @@ -348,6 +348,12 @@ public class StartFFmpegNextSessionHandler( Width = ffmpegProfile.Resolution.Width, BitrateKbps = ffmpegProfile.VideoBitrate, BufferKbps = ffmpegProfile.VideoBufferSize, + ScalingMode = ffmpegProfile.ScalingBehavior switch + { + ScalingBehavior.Stretch => ScalingMode.Stretch, + ScalingBehavior.Crop => ScalingMode.Crop, + _ => ScalingMode.ScaleAndPad + }, // TODO: NEXT: more tonemap algorithms TonemapAlgorithm = "linear", VaapiDevice = ffmpegProfile.VaapiDevice, diff --git a/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj b/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj index 20287e7a8..dba59bfc2 100644 --- a/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj +++ b/ErsatzTV.Core.Tests/ErsatzTV.Core.Tests.csproj @@ -16,7 +16,7 @@ - + diff --git a/ErsatzTV.Core/Next/Config/ChannelConfig.cs b/ErsatzTV.Core/Next/Config/ChannelConfig.cs index 7b7eda95f..b9351939d 100644 --- a/ErsatzTV.Core/Next/Config/ChannelConfig.cs +++ b/ErsatzTV.Core/Next/Config/ChannelConfig.cs @@ -119,6 +119,9 @@ namespace ErsatzTV.Core.Next.Config [JsonProperty("height")] public long? Height { get; set; } + [JsonProperty("scaling_mode", NullValueHandling = NullValueHandling.Ignore)] + public ScalingMode? ScalingMode { get; set; } + [JsonProperty("tonemap_algorithm")] public string TonemapAlgorithm { get; set; } @@ -152,6 +155,8 @@ namespace ErsatzTV.Core.Next.Config public enum VideoFormat { H264, Hevc }; + public enum ScalingMode { Crop, ScaleAndPad, Stretch }; + public enum VaapiDriverEnum { I965, Ihd, Radeonsi }; public partial class ChannelConfig @@ -176,6 +181,7 @@ namespace ErsatzTV.Core.Next.Config ModeConverter.Singleton, AccelEnumConverter.Singleton, VideoFormatConverter.Singleton, + ScalingModeConverter.Singleton, VaapiDriverEnumConverter.Singleton, new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal } }, @@ -361,6 +367,52 @@ namespace ErsatzTV.Core.Next.Config public static readonly VideoFormatConverter Singleton = new VideoFormatConverter(); } + internal class ScalingModeConverter : JsonConverter + { + public override bool CanConvert(Type t) => t == typeof(ScalingMode) || t == typeof(ScalingMode?); + + public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer) + { + if (reader.TokenType == JsonToken.Null) return null; + var value = serializer.Deserialize(reader); + switch (value) + { + case "crop": + return ScalingMode.Crop; + case "scale_and_pad": + return ScalingMode.ScaleAndPad; + case "stretch": + return ScalingMode.Stretch; + } + throw new Exception("Cannot unmarshal type ScalingMode"); + } + + public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer) + { + if (untypedValue == null) + { + serializer.Serialize(writer, null); + return; + } + var value = (ScalingMode)untypedValue; + switch (value) + { + case ScalingMode.Crop: + serializer.Serialize(writer, "crop"); + return; + case ScalingMode.ScaleAndPad: + serializer.Serialize(writer, "scale_and_pad"); + return; + case ScalingMode.Stretch: + serializer.Serialize(writer, "stretch"); + return; + } + throw new Exception("Cannot marshal type ScalingMode"); + } + + public static readonly ScalingModeConverter Singleton = new ScalingModeConverter(); + } + internal class VaapiDriverEnumConverter : JsonConverter { public override bool CanConvert(Type t) => t == typeof(VaapiDriverEnum) || t == typeof(VaapiDriverEnum?); diff --git a/ErsatzTV.FFmpeg.Tests/ErsatzTV.FFmpeg.Tests.csproj b/ErsatzTV.FFmpeg.Tests/ErsatzTV.FFmpeg.Tests.csproj index 9c7508d5c..5d7dee790 100644 --- a/ErsatzTV.FFmpeg.Tests/ErsatzTV.FFmpeg.Tests.csproj +++ b/ErsatzTV.FFmpeg.Tests/ErsatzTV.FFmpeg.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj b/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj index 78f7ca0a1..d89318fd2 100644 --- a/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj +++ b/ErsatzTV.FFmpeg/ErsatzTV.FFmpeg.csproj @@ -14,7 +14,7 @@ - + diff --git a/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj b/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj index b77128c8a..6b0f7dc5e 100644 --- a/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj +++ b/ErsatzTV.Infrastructure.Tests/ErsatzTV.Infrastructure.Tests.csproj @@ -11,9 +11,9 @@ - + - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj b/ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj index 9d591d668..8bb380de5 100644 --- a/ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj +++ b/ErsatzTV.Scanner.Tests/ErsatzTV.Scanner.Tests.csproj @@ -12,9 +12,9 @@ - + - + runtime; build; native; contentfiles; analyzers; buildtransitive all diff --git a/ErsatzTV.Tests/ErsatzTV.Tests.csproj b/ErsatzTV.Tests/ErsatzTV.Tests.csproj index 4599a96c9..3d6148f94 100644 --- a/ErsatzTV.Tests/ErsatzTV.Tests.csproj +++ b/ErsatzTV.Tests/ErsatzTV.Tests.csproj @@ -11,8 +11,8 @@ - - + + all runtime; build; native; contentfiles; analyzers; buildtransitive diff --git a/ErsatzTV/ErsatzTV.csproj b/ErsatzTV/ErsatzTV.csproj index 10b7f08e1..20b03f4db 100644 --- a/ErsatzTV/ErsatzTV.csproj +++ b/ErsatzTV/ErsatzTV.csproj @@ -55,7 +55,7 @@ - +