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

250 lines
7.0 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.IO;
namespace skyscraper5.Docsis
{
internal class DocsisPacketProcessor : ITsPacketProcessor, IPayloadUnitDecoder, IDisposable
{
public DocsisPacketProcessor(IDocsisEventHandler eventHandler)
{
this.eventHandler = eventHandler;
this.docsisEnvironment = new DocsisEnvironment(eventHandler);
}
private IDocsisEventHandler eventHandler;
private bool currentPayloadUnitPresent;
private MemoryStream currentPayloadBuffer;
private byte? FC;
public int? FC_TYPE
{
get
{
if (!FC.HasValue)
return null;
int i = (FC.Value & 0xc0) >> 6;
return i;
}
}
public int? FC_PARM
{
get
{
if (!FC.HasValue)
return null;
int i = (FC.Value & 0x3e) >> 1;
return i;
}
}
public bool? EHDR_ON
{
get
{
if (!FC.HasValue)
return null;
bool i = (FC.Value & 0x01) != 0;
return i;
}
}
private byte? MAC_PARM;
private byte? LEN_L, LEN_R;
private int? LEN
{
get
{
if (!LEN_L.HasValue || !LEN_R.HasValue)
return null;
int result = LEN_L.Value;
result <<= 8;
result += LEN_R.Value;
return result;
}
}
private byte[] EHDR;
private bool EHDR_done;
private int EHDR_ptr;
private int neededBytes;
private byte? HCS_L, HCS_R;
private bool packetDone;
public void PushPacket(TsPacket packet)
{
if (packet.AdaptionFieldControl != 1)
{
PacketLoss();
return;
}
bool packetPayloadUnitStart = packet.PayloadUnitStart;
MemoryStream ms = new MemoryStream(packet.Payload, false);
if (!currentPayloadUnitPresent && !packetPayloadUnitStart)
return;
if (!currentPayloadUnitPresent && packetPayloadUnitStart)
{
ms.Position = packet.PayloadStartOffset;
currentPayloadUnitPresent = true;
currentPayloadBuffer = new MemoryStream();
}
while (ms.GetAvailableBytes() > 0)
{
if (!FC.HasValue)
{
FC = ms.ReadUInt8();
currentPayloadBuffer.WriteByte(FC.Value);
continue;
}
if (!MAC_PARM.HasValue)
{
MAC_PARM = ms.ReadUInt8();
currentPayloadBuffer.WriteByte(MAC_PARM.Value);
continue;
}
if (!LEN_L.HasValue)
{
LEN_L = ms.ReadUInt8();
currentPayloadBuffer.WriteByte(LEN_L.Value);
continue;
}
if (!LEN_R.HasValue)
{
LEN_R = ms.ReadUInt8();
currentPayloadBuffer.WriteByte(LEN_R.Value);
if (EHDR_ON.Value)
{
EHDR = new byte[MAC_PARM.Value];
neededBytes = MAC_PARM.Value;
EHDR_done = false;
}
continue;
}
if (!EHDR_done && EHDR_ON.Value)
{
int ehdrAvailable = (int)Math.Min(neededBytes, ms.GetAvailableBytes());
int ehdrWasRead = ms.Read(EHDR, EHDR_ptr, ehdrAvailable);
neededBytes -= ehdrWasRead;
EHDR_ptr += ehdrWasRead;
if (neededBytes == 0)
{
currentPayloadBuffer.Write(EHDR, 0, EHDR.Length);
EHDR_done = true;
}
continue;
}
if (!HCS_L.HasValue)
{
HCS_L = ms.ReadUInt8();
currentPayloadBuffer.WriteByte(HCS_L.Value);
continue;
}
if (!HCS_R.HasValue)
{
HCS_R = ms.ReadUInt8();
currentPayloadBuffer.WriteByte(HCS_R.Value);
packetDone = false;
neededBytes = LEN.Value;
if (EHDR_ON.Value)
neededBytes -= EHDR.Length;
continue;
}
if (!packetDone)
{
int toRead = (int)Math.Min(neededBytes, ms.GetAvailableBytes());
if (toRead < 0)
{
PacketLoss();
return;
}
byte[] tmp = new byte[toRead];
int readAmount = ms.Read(tmp, 0, toRead);
currentPayloadBuffer.Write(tmp, 0, readAmount);
neededBytes -= readAmount;
if (neededBytes == 0)
packetDone = true;
continue;
}
HandlePacket();
while (ms.GetAvailableBytes() > 0)
{
byte stuffing = ms.ReadUInt8();
if (stuffing != 0xff)
{
ms.Position--;
currentPayloadUnitPresent = true;
currentPayloadBuffer = new MemoryStream();
break;
}
}
}
}
public void PacketLoss()
{
Reset();
}
private void Reset()
{
currentPayloadUnitPresent = false;
currentPayloadBuffer = null;
FC = null;
MAC_PARM = null;
LEN_L = null;
LEN_R = null;
EHDR = null;
EHDR_done = false;
EHDR_ptr = 0;
neededBytes = 0;
HCS_L = null;
HCS_R = null;
packetDone = false;
}
private ulong processedPackets = 0;
private DocsisEnvironment docsisEnvironment;
private void HandlePacket()
{
currentPayloadBuffer.Position = 0;
docsisEnvironment.PushPacket(currentPayloadBuffer);
Reset();
}
public void Dispose()
{
docsisEnvironment?.Dispose();
}
public DocsisEnvironment DocsisEnvironment => docsisEnvironment;
}
}