skyscraper8/skyscraper8/Mpeg2/PsiDecoder.cs
feyris-tan ef86554f9a Import
2025-05-12 22:09:16 +02:00

149 lines
4.9 KiB
C#

using System.IO;
using skyscraper5.Dvb;
using skyscraper5.Skyscraper.IO;
namespace skyscraper5.Mpeg2
{
public class PsiDecoder : ITsPacketProcessor, IPayloadUnitDecoder
{
public IPsiProcessor PsiProcessor { get; }
public PsiDecoder(int pid, IPsiProcessor psiProcessor)
{
PsiProcessor = psiProcessor;
this.pid = pid;
}
private int pid;
public void PushPacket(TsPacket packet)
{
if (packet.Payload == null)
return;
if (packet.PID != pid)
return;
bool psiJustStarted = false;
if (psiSection == null)
{
if (packet.PayloadUnitStart)
{
psiSection = new PsiSection();
psiSection.Need = 3;
psiSection.HeaderComplete = false;
psiJustStarted = true;
}
else
{
return;
}
}
MemoryStream payload = new MemoryStream(packet.Payload);
long available = payload.Length - payload.Position;
if (psiJustStarted)
{
long startOffset = packet.PayloadStartOffset;
if (startOffset > 0)
{
startOffset = payload.Position + startOffset;
if (startOffset > payload.Length)
{
OnPsiSectionTooLong?.Invoke(packet, psiJustStarted, psiSection);
PacketLoss();
return;
}
payload.Position += startOffset;
available -= startOffset;
}
}
while (available > 0)
{
if (available > psiSection.Need)
{
//Noch genug im Buffer, um need auf 0 zu bekommen.
byte[] temp1 = new byte[psiSection.Need];
if (payload.Read(temp1, 0, psiSection.Need) != psiSection.Need)
throw new EndOfStreamException("failed to fill psi buffer");
available -= psiSection.Need;
psiSection.Append(temp1);
if (!psiSection.HeaderComplete)
{
psiSection.HeaderComplete = true;
ushort sectionLength = psiSection.SectionLength;
psiSection.Need = sectionLength;
}
else
{
if (psiSection.Valid)
{
lock (this)
{
PsiProcessor.GatherPsi(psiSection, pid);
}
OnValidSection?.Invoke(psiSection, pid, available);
}
else
{
if (!DvbCrc32.ValidatePsi(psiSection))
{
OnCrcError?.Invoke(psiSection, pid,available);
}
}
psiSection = null;
bool newSection = false;
if (available > 0)
{
byte payloadPos = payload.ReadUInt8();
payload.Position--;
if (payloadPos != 0xff)
newSection = true;
}
if (newSection)
{
psiSection = new PsiSection();
psiSection.Need = 3;
psiSection.HeaderComplete = false;
}
else
{
available = 0;
}
}
}
else
{
//Nicht mehr genug da
byte[] filler = payload.ReadBytes(available);
psiSection.Append(filler);
psiSection.Need -= (int)available;
available = 0;
}
}
}
private PsiSection psiSection;
public void PacketLoss()
{
psiSection = null;
}
public bool HeaderComplete => psiSection.HeaderComplete;
public int NeededBytes => psiSection.Need;
public delegate void PsiSectionTooLong(TsPacket packet, bool justStarted, PsiSection section);
public event PsiSectionTooLong OnPsiSectionTooLong;
public delegate void OnSection(PsiSection section, int pid, long available);
public event OnSection OnValidSection;
public event OnSection OnCrcError;
}
}