From 79496e688b63caa21e49e7db6b1dfd460860bda1 Mon Sep 17 00:00:00 2001 From: Jason Dove <1695733+jasongdove@users.noreply.github.com> Date: Sun, 20 Jul 2025 17:31:21 +0000 Subject: [PATCH] fix video stream selection for remote streams (#2176) --- ...PlayoutItemProcessByChannelNumberHandler.cs | 12 +++++++++++- .../PrepareTroubleshootingPlaybackHandler.cs | 12 +++++++++++- .../OutputFormat/OutputFormatHls.cs | 8 -------- .../Metadata/LocalStatisticsProvider.cs | 18 ++++++++++++++++-- 4 files changed, 38 insertions(+), 12 deletions(-) diff --git a/ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs b/ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs index 5b143832..9312b787 100644 --- a/ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs +++ b/ErsatzTV.Application/Streaming/Queries/GetPlayoutItemProcessByChannelNumberHandler.cs @@ -295,6 +295,16 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< audioPath = string.Empty; } + bool hlsRealtime = request.HlsRealtime; + if (playoutItemWithPath.PlayoutItem.MediaItem is RemoteStream remoteStream) + { + // duration implies live input which we cannot burst + if (remoteStream.Duration.HasValue) + { + hlsRealtime = true; + } + } + bool saveReports = await dbContext.ConfigElements .GetValue(ConfigElementKey.FFmpegSaveReports) .Map(result => result.IfNone(false)); @@ -329,7 +339,7 @@ public class GetPlayoutItemProcessByChannelNumberHandler : FFmpegProcessHandler< channel.FFmpegProfile.VaapiDriver, channel.FFmpegProfile.VaapiDevice, Optional(channel.FFmpegProfile.QsvExtraHardwareFrames), - request.HlsRealtime, + hlsRealtime, playoutItemWithPath.PlayoutItem.FillerKind, inPoint, outPoint, diff --git a/ErsatzTV.Application/Troubleshooting/Commands/PrepareTroubleshootingPlaybackHandler.cs b/ErsatzTV.Application/Troubleshooting/Commands/PrepareTroubleshootingPlaybackHandler.cs index 196f1b05..48306296 100644 --- a/ErsatzTV.Application/Troubleshooting/Commands/PrepareTroubleshootingPlaybackHandler.cs +++ b/ErsatzTV.Application/Troubleshooting/Commands/PrepareTroubleshootingPlaybackHandler.cs @@ -93,6 +93,16 @@ public class PrepareTroubleshootingPlaybackHandler( duration = TimeSpan.FromSeconds(30); } + var hlsRealtime = false; + if (mediaItem is RemoteStream remoteStream) + { + // duration implies live input which we cannot burst + if (remoteStream.Duration.HasValue) + { + hlsRealtime = true; + } + } + Command process = await ffmpegProcessService.ForPlayoutItem( ffmpegPath, ffprobePath, @@ -122,7 +132,7 @@ public class PrepareTroubleshootingPlaybackHandler( ffmpegProfile.VaapiDriver, ffmpegProfile.VaapiDevice, Option.None, - false, + hlsRealtime, FillerKind.None, TimeSpan.Zero, duration, diff --git a/ErsatzTV.FFmpeg/OutputFormat/OutputFormatHls.cs b/ErsatzTV.FFmpeg/OutputFormat/OutputFormatHls.cs index 58c2d82f..5fb28651 100644 --- a/ErsatzTV.FFmpeg/OutputFormat/OutputFormatHls.cs +++ b/ErsatzTV.FFmpeg/OutputFormat/OutputFormatHls.cs @@ -58,14 +58,6 @@ public class OutputFormatHls : IPipelineStep _segmentTemplate ]; - if (_isTroubleshooting) - { - result.AddRange( - [ - "-hls_playlist_type", "vod" - ]); - } - string pdt = _isTroubleshooting ? string.Empty : "program_date_time+omit_endlist+"; if (_isFirstTranscode) diff --git a/ErsatzTV.Infrastructure/Metadata/LocalStatisticsProvider.cs b/ErsatzTV.Infrastructure/Metadata/LocalStatisticsProvider.cs index 544cba5e..608a597e 100644 --- a/ErsatzTV.Infrastructure/Metadata/LocalStatisticsProvider.cs +++ b/ErsatzTV.Infrastructure/Metadata/LocalStatisticsProvider.cs @@ -167,7 +167,7 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider "-i", filePath ]; - //_logger.LogDebug("ffprobe arguments {FFProbeArguments}", arguments); + //_logger.LogDebug("ffprobe arguments {FFProbeArguments}", arguments.ToList()); BufferedCommandResult probe = await Cli.Wrap(ffprobePath) .WithArguments(arguments) @@ -335,7 +335,10 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider version.Streams.Add(stream); } - FFprobeStreamData videoStream = json.streams?.FirstOrDefault(s => s.codec_type == "video"); + FFprobeStreamData videoStream = json.streams? + .Where(s => s.codec_type == "video") + .OrderByDescending(s => ParseBitRate(s.bit_rate)) + .FirstOrDefault(); if (videoStream != null) { version.SampleAspectRatio = string.IsNullOrWhiteSpace(videoStream.sample_aspect_ratio) @@ -494,6 +497,16 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider return Task.FromResult(path); } + private static long ParseBitRate(string bitRate) + { + if (long.TryParse(bitRate, out long result)) + { + return result; + } + + return 0; + } + // ReSharper disable InconsistentNaming public record FFprobe(FFprobeFormat format, List streams, List chapters); @@ -520,6 +533,7 @@ public class LocalStatisticsProvider : ILocalStatisticsProvider string color_primaries, string field_order, string r_frame_rate, + string bit_rate, string bits_per_raw_sample, FFprobeDisposition disposition, FFprobeTags tags);