Retain selectable audio languages and DVB subtitles through live continuity
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Jellyfin.Plugin.Enigma2;
|
||||
|
||||
/// <summary>Keep DVB page/region/object versions distinct across independently muxed status and live clips.</summary>
|
||||
public sealed class DvbSubtitleVersions
|
||||
{
|
||||
private readonly HashSet<int> pids;
|
||||
private readonly Dictionary<(int Pid, int Type, int Id), int> versions = new();
|
||||
private readonly Dictionary<long, List<(int Position, byte Value)>> plans = new();
|
||||
public DvbSubtitleVersions(BroadcastTracks tracks) => pids = tracks.Output.Select((s, i) => (s.Codec, Pid: 256 + i)).Where(s => s.Codec == "DVBSUB").Select(s => s.Pid).ToHashSet();
|
||||
public void Apply(byte[] transport, long sequence)
|
||||
{
|
||||
if (pids.Count == 0) return;
|
||||
if (plans.TryGetValue(sequence, out var known)) { foreach (var edit in known) transport[edit.Position] = edit.Value; return; }
|
||||
var edits = new List<(int, byte)>();
|
||||
var packets = new Dictionary<int, List<int>>();
|
||||
void Flush(int pid, List<int> positions)
|
||||
{
|
||||
if (positions.Count < 14) return;
|
||||
byte At(int index) => transport[positions[index]];
|
||||
if (At(0) != 0 || At(1) != 0 || At(2) != 1 || At(3) != 189) return;
|
||||
var length = (At(4) << 8) | At(5);
|
||||
var end = length > 0 ? Math.Min(positions.Count, length + 6) : positions.Count;
|
||||
var p = 9 + At(8);
|
||||
if (p + 2 > end || At(p) != 32) return; p += 2;
|
||||
while (p + 6 <= end && At(p) == 15)
|
||||
{
|
||||
var type = At(p + 1); var size = (At(p + 4) << 8) | At(p + 5); var data = p + 6;
|
||||
if (data + size > end) break;
|
||||
var field = type switch { 16 => 1, 17 => 1, 18 => 1, 19 => 2, 20 => 0, _ => -1 };
|
||||
if (field >= 0 && size > field)
|
||||
{
|
||||
var id = type switch { 17 or 18 => At(data), 19 => (At(data) << 8) | At(data + 1), _ => 0 };
|
||||
var key = (pid, (int)type, id);
|
||||
if (!versions.ContainsKey(key) && versions.Count >= 4096) throw new InvalidDataException("Too many DVB subtitle objects");
|
||||
versions.TryGetValue(key, out var next); versions[key] = next + 1;
|
||||
var index = positions[data + field]; var value = (byte)((transport[index] & 15) | ((next & 15) << 4));
|
||||
transport[index] = value; edits.Add((index, value));
|
||||
}
|
||||
p = data + size;
|
||||
}
|
||||
}
|
||||
for (var start = 0; start + 188 <= transport.Length; start += 188)
|
||||
{
|
||||
var pid = ((transport[start + 1] & 31) << 8) | transport[start + 2]; if (!pids.Contains(pid)) continue;
|
||||
if ((transport[start + 3] & 16) == 0) continue;
|
||||
var payload = start + 4 + ((transport[start + 3] & 32) != 0 ? transport[start + 4] + 1 : 0);
|
||||
if (payload >= start + 188) continue;
|
||||
if ((transport[start + 1] & 64) != 0)
|
||||
{
|
||||
if (packets.TryGetValue(pid, out var previous)) Flush(pid, previous);
|
||||
packets[pid] = new();
|
||||
}
|
||||
if (!packets.TryGetValue(pid, out var positions)) continue;
|
||||
if (positions.Count + 188 > 512 * 1024) throw new InvalidDataException("Oversized DVB subtitle PES");
|
||||
for (var p = payload; p < start + 188; p++) positions.Add(p);
|
||||
}
|
||||
foreach (var packet in packets) Flush(packet.Key, packet.Value);
|
||||
plans[sequence] = edits;
|
||||
foreach (var old in plans.Keys.Order().Take(Math.Max(0, plans.Count - 8)).ToArray()) plans.Remove(old);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user