Preserve native broadcast video and add patient shared stream startup
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using MediaBrowser.Model.Entities;
|
||||
|
||||
namespace Jellyfin.Plugin.Enigma2;
|
||||
|
||||
/// <summary>Only the status picture is encoded. Unsupported programs stay entirely in stream-copy mode.</summary>
|
||||
public sealed class LosslessSlateProfile
|
||||
{
|
||||
public int Width { get; private init; }
|
||||
public int Height { get; private init; }
|
||||
public double Rate { get; private init; }
|
||||
public string RateArgument { get; private init; }
|
||||
public string Aspect { get; private init; }
|
||||
public string Profile { get; private init; }
|
||||
public int Gop { get; private init; }
|
||||
public double SegmentSeconds => Gop / Rate;
|
||||
public static LosslessSlateProfile Create(BroadcastTracks tracks)
|
||||
{
|
||||
var video = tracks.Input[0];
|
||||
// A guessed codec/layout is unsafe during cold-start outages. Never convert the channel to fit a slate.
|
||||
if (video.Codec != "h264" || video.PixelFormat != "yuv420p" || video.IsInterlaced
|
||||
|| video.Width is not (> 0 and <= 16384) || video.Height is not (> 0 and <= 16384)
|
||||
|| video.Width % 2 != 0 || video.Height % 2 != 0
|
||||
|| video.ColorTransfer is "smpte2084" or "arib-std-b67"
|
||||
|| tracks.AudioCount == 0 || tracks.AudioCount > 8
|
||||
|| tracks.Input.Where(s => s.Type == MediaStreamType.Audio).Any(s => s.Codec != "aac" || s.Profile != "LC" || s.Channels != 2 || s.SampleRate != 48000)) return null;
|
||||
var profile = video.Profile switch { "Constrained Baseline" or "Baseline" => "baseline", "Main" => "main", "High" => "high", _ => null };
|
||||
var rate = (double)(video.AverageFrameRate ?? video.RealFrameRate ?? 0);
|
||||
var aspect = (video as BroadcastMediaStream)?.SampleAspectRatio;
|
||||
if (profile == null || !double.IsFinite(rate) || rate <= 0 || rate > 240
|
||||
|| aspect == null || !Regex.IsMatch(aspect, @"^[1-9][0-9]{0,5}:[1-9][0-9]{0,5}$")) return null;
|
||||
var rational = (video as BroadcastMediaStream)?.FrameRateRational;
|
||||
if (rational == null || !Regex.IsMatch(rational, @"^[1-9][0-9]{0,8}/[1-9][0-9]{0,8}$"))
|
||||
rational = rate.ToString("0.########", CultureInfo.InvariantCulture);
|
||||
// Repeating a cached clip must end on complete video AND AAC frames.
|
||||
// If that needs a long clip (e.g. 23.976/59.94), retain the original
|
||||
// broadcast without a status clip rather than rounding its cadence.
|
||||
var gop = Enumerable.Range(Math.Max(1, (int)(rate * 1.5)), Math.Max(1, (int)(rate * 1.5) + 2))
|
||||
.Where(n => Math.Abs(n / rate * 48000 / 1024 - Math.Round(n / rate * 48000 / 1024)) < 0.00001)
|
||||
.OrderBy(n => Math.Abs(n / rate - ContinuityTimeline.SegmentSeconds)).FirstOrDefault();
|
||||
if (gop == 0) return null;
|
||||
return new() { Width = video.Width.Value, Height = video.Height.Value, Rate = rate,
|
||||
RateArgument = rational, Aspect = aspect.Replace(':', '/'), Profile = profile, Gop = gop };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user