Complete Rewrite of the PsiDecoder.
Some checks failed
🚀 Pack skyscraper8 / make-zip (push) Failing after 1m40s
Some checks failed
🚀 Pack skyscraper8 / make-zip (push) Failing after 1m40s
This commit is contained in:
parent
c740e3c6bb
commit
ca9ed0f11a
@ -69,7 +69,7 @@ namespace skyscraper5.Dvb.DataBroadcasting
|
||||
//Undocumented, manufacterer specific data.
|
||||
break;
|
||||
default:
|
||||
logger.Warn(String.Format("Unknown DSM-CC Sectino type: 0x{0:X2}", dataCopy[0]));
|
||||
//logger.Warn(String.Format("Unknown DSM-CC Section type: 0x{0:X2}", dataCopy[0]));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,159 +1,158 @@
|
||||
using System.IO;
|
||||
using log4net;
|
||||
using log4net.Repository.Hierarchy;
|
||||
using skyscraper5.Dvb;
|
||||
using skyscraper5.Skyscraper.IO;
|
||||
using System.IO;
|
||||
|
||||
namespace skyscraper5.Mpeg2
|
||||
{
|
||||
public class PsiDecoder : ITsPacketProcessor, IPayloadUnitDecoder
|
||||
{
|
||||
public IPsiProcessor PsiProcessor { get; }
|
||||
private int pid;
|
||||
private int state;
|
||||
private byte headerA, headerB, headerC;
|
||||
private byte[] psiPayload;
|
||||
private int psiPayloadNeeded;
|
||||
private int psiPayloadOffset;
|
||||
private int copyOps;
|
||||
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
|
||||
|
||||
public PsiDecoder(int pid, IPsiProcessor psiProcessor)
|
||||
public PsiDecoder(int pid, IPsiProcessor psiProcessor)
|
||||
{
|
||||
PsiProcessor = psiProcessor;
|
||||
this.pid = pid;
|
||||
}
|
||||
|
||||
private int pid;
|
||||
|
||||
public void PushPacket(TsPacket packet)
|
||||
{
|
||||
if (packet.GetPayload() == null)
|
||||
return;
|
||||
if (packet.PID != pid)
|
||||
return;
|
||||
Span<byte> span = packet.GetPayload();
|
||||
int automataIterations = 0;
|
||||
|
||||
if (packet.PID == 0x0881)
|
||||
;
|
||||
|
||||
bool psiJustStarted = false;
|
||||
if (psiSection == null)
|
||||
while(span.Length > 0)
|
||||
{
|
||||
if (packet.PayloadUnitStart)
|
||||
switch(state)
|
||||
{
|
||||
psiSection = new PsiSection();
|
||||
psiSection.Need = 3;
|
||||
psiSection.HeaderComplete = false;
|
||||
psiJustStarted = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
MemoryStream payload = new MemoryStream(packet.GetPayload().ToArray(), false);
|
||||
long available = payload.Length - payload.Position;
|
||||
if (psiJustStarted)
|
||||
{
|
||||
payload.Position = 0;
|
||||
byte payloadUnitStartOffset = payload.ReadUInt8();
|
||||
available--;
|
||||
payload.Position += payloadUnitStartOffset;
|
||||
available -= payloadUnitStartOffset;
|
||||
|
||||
long startOffset = 0;
|
||||
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)
|
||||
case 0:
|
||||
//Noch keine PSI am zusammenbauen.
|
||||
if (!packet.PayloadUnitStart)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
PsiProcessor.GatherPsi(psiSection, pid);
|
||||
}
|
||||
OnValidSection?.Invoke(psiSection, pid, available);
|
||||
//im TS Paket beginnt keine neue, also wegwerfen.
|
||||
return;
|
||||
}
|
||||
else
|
||||
byte startOffset = span[0];
|
||||
span = span.Slice(1);
|
||||
span = span.Slice(startOffset);
|
||||
state = 1;
|
||||
break;
|
||||
case 1:
|
||||
//Section Header Byte 1 extrahieren;
|
||||
if (span.Length == 0)
|
||||
return;
|
||||
if (automataIterations == 0)
|
||||
{
|
||||
if (packet.PayloadUnitStart)
|
||||
span = span.Slice(1);
|
||||
}
|
||||
if (span[0] == 0xff)
|
||||
{
|
||||
if (!DvbCrc32.ValidatePsi(psiSection))
|
||||
{
|
||||
OnCrcError?.Invoke(psiSection, pid,available);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
psiSection = null;
|
||||
|
||||
bool newSection = false;
|
||||
if (available > 0)
|
||||
headerA = span[0];
|
||||
span = span.Slice(1);
|
||||
state = 2;
|
||||
break;
|
||||
case 2:
|
||||
//Section Header Byte 2 extrahieren;
|
||||
headerB = span[0];
|
||||
span = span.Slice(1);
|
||||
state = 3;
|
||||
break;
|
||||
case 3:
|
||||
//Section Header Byte 3 extrahieren;
|
||||
headerC = span[0];
|
||||
span = span.Slice(1);
|
||||
state = 4;
|
||||
psiPayloadNeeded = headerB;
|
||||
psiPayloadNeeded <<= 8;
|
||||
psiPayloadNeeded += headerC;
|
||||
psiPayloadNeeded &= 0x0fff;
|
||||
psiPayload = new byte[psiPayloadNeeded];
|
||||
break;
|
||||
case 4:
|
||||
if (automataIterations == 0)
|
||||
{
|
||||
byte payloadPos = payload.ReadUInt8();
|
||||
payload.Position--;
|
||||
if (payloadPos != 0xff)
|
||||
newSection = true;
|
||||
if (payload.Position == 0)
|
||||
{
|
||||
payload.Position++;
|
||||
available--;
|
||||
}
|
||||
if (packet.PayloadUnitStart)
|
||||
span = span.Slice(1);
|
||||
}
|
||||
|
||||
if (newSection)
|
||||
int copyable = Math.Min(psiPayloadNeeded, span.Length);
|
||||
Copy(span, 0, psiPayload, psiPayloadOffset, copyable);
|
||||
psiPayloadNeeded -= copyable;
|
||||
psiPayloadOffset += copyable;
|
||||
span = span.Slice(copyable);
|
||||
if (psiPayloadNeeded == 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
AssemblePsiPayload(headerA, headerB, headerC, psiPayload);
|
||||
headerA = 0;
|
||||
headerB = 0;
|
||||
headerC = 0;
|
||||
psiPayload = null;
|
||||
psiPayloadNeeded = 0;
|
||||
psiPayloadOffset = 0;
|
||||
copyOps = 0;
|
||||
state = 1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException(String.Format("PSI Decoder finite automata state {0}", state));
|
||||
}
|
||||
automataIterations++;
|
||||
}
|
||||
}
|
||||
|
||||
private PsiSection psiSection;
|
||||
public void PacketLoss()
|
||||
private void AssemblePsiPayload(byte headerA, byte headerB, byte headerC, byte[] psiPayload)
|
||||
{
|
||||
PsiSection section = new PsiSection();
|
||||
section.Append(new byte[] { headerA, headerB, headerC });
|
||||
section.HeaderComplete = true;
|
||||
section.Append(psiPayload);
|
||||
if (!section.Valid)
|
||||
{
|
||||
//logger.ErrorFormat("Invalid MPEG-2 section");
|
||||
OnCrcError?.Invoke(section, pid, section.SectionLength);
|
||||
return;
|
||||
}
|
||||
PsiProcessor.GatherPsi(section, pid);
|
||||
OnValidSection?.Invoke(section, pid, section.SectionLength);
|
||||
}
|
||||
|
||||
public void PacketLoss()
|
||||
{
|
||||
psiSection = null;
|
||||
state = 0;
|
||||
headerA = 0;
|
||||
headerB = 0;
|
||||
headerC = 0;
|
||||
psiPayload = null;
|
||||
psiPayloadNeeded = 0;
|
||||
psiPayloadOffset = 0;
|
||||
copyOps = 0;
|
||||
}
|
||||
|
||||
public bool HeaderComplete => psiSection.HeaderComplete;
|
||||
public int NeededBytes => psiSection.Need;
|
||||
private void Copy(Span<byte> input, int inputOffset, byte[] output, int outputOffset, int length)
|
||||
{
|
||||
for (int i = 0; i < length; i++)
|
||||
{
|
||||
output[outputOffset + i] = input[inputOffset + i];
|
||||
}
|
||||
copyOps++;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
public delegate void OnSection(PsiSection section, int pid, long available);
|
||||
public event OnSection OnValidSection;
|
||||
public event OnSection OnCrcError;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user