skyscraper8/skyscraper8/GS/GSE-BFBS/BfbsGseReader.cs
feyris-tan e4d861ef6e
Some checks failed
🚀 Pack skyscraper8 / make-zip (push) Failing after 1m32s
Support for TIM-B in GSE.
2025-11-10 18:18:39 +01:00

226 lines
5.9 KiB
C#

using skyscraper5.Dvb.DataBroadcasting;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.IO;
using skyscraper8.GSE;
using skyscraper8.GSE.GSE;
using skyscraper8.Skyscraper.IO;
using skyscraper8.Skyscraper.Scraper;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.src.InteractionChannel;
namespace skyscraper8.GS.GSE_BFBS
{
internal class BfbsGseReader : IMisHandler
{
private GseLabel lastLabel;
private int frameNo;
public GsContextDto Context { get; set; }
public BfbsGseReader(GsContextDto context)
{
this.Context = context;
}
public void PushFrame(BBHeader bbHeader, ReadOnlySpan<byte> readOnlySpan)
{
frameNo++;
bool validCrc = DvbCrc32.ValidateCrc(readOnlySpan);
if (!validCrc)
return;
if (readOnlySpan[0] == 0 && readOnlySpan[1] == 0 && readOnlySpan[2] == 0 && readOnlySpan[3] == 0)
return;
StreamlikeSpan span = new StreamlikeSpan(readOnlySpan);
while (span.GetAvailableBytes() > 4)
{
byte byteA = span.ReadUInt8();
bool startIndicator = (byteA & 0x80) != 0;
bool endIndicator = (byteA & 0x40) != 0;
int labelTypeIndicator = (byteA & 0x30) >> 4;
if (!startIndicator && !endIndicator && labelTypeIndicator == 0)
{
//padding bits, packet has ended.
return;
}
else
{
GsePacket gsePacket = new GsePacket(startIndicator, endIndicator, labelTypeIndicator);
int gseLength = (byteA & 0x0f) << 8;
gseLength += span.ReadUInt8();
gsePacket.FragmentId = null;
if (!startIndicator || !endIndicator)
{
gsePacket.FragmentId = span.ReadUInt8();
gseLength -= 1;
}
if ((startIndicator) && !endIndicator)
{
gsePacket.TotalLength = span.ReadUInt16BE();
gseLength -= 2;
}
if (startIndicator)
{
gsePacket.ProtocolType = span.ReadUInt16BE();
gseLength -= 2;
if (labelTypeIndicator == 0)
{
gsePacket.Label = new _6byteLabel(span.ReadBytes(6));
gseLength -= 6;
}
else if (labelTypeIndicator == 1)
{
gsePacket.Label = new _3byteLabel(span.ReadBytes(3));
gseLength -= 3;
}
else if (labelTypeIndicator == 2)
{
gsePacket.Label = BroadcastLabel.GetInstance();
}
else if (labelTypeIndicator == 3)
{
gsePacket.Label = lastLabel;
}
lastLabel = gsePacket.Label;
}
if (!startIndicator && endIndicator)
gseLength -= 4;
gsePacket.GseDataBytes = span.ReadBytes(gseLength);
if (!startIndicator && endIndicator)
{
gsePacket.Crc32 = span.ReadUInt32BE();
}
HandleGseFrame(gsePacket);
}
}
}
private GseFragmentation[] fragmentations;
private void HandleGseFrame(GsePacket gsePacket)
{
if (gsePacket.StartIndicator & gsePacket.EndIndicator)
{
HandleAssembledFrame(gsePacket.ProtocolType.Value, gsePacket.GseDataBytes, gsePacket.Label);
return;
}
if (!gsePacket.StartIndicator && gsePacket.EndIndicator)
{
if (fragmentations == null)
{
//This stream had no fragmentations yet, so we cannot reassemble this packet.
return;
}
if (fragmentations[gsePacket.FragmentId.Value] == null)
{
//The previous fragments are missing, so we cannot reassemble this packet.
return;
}
fragmentations[gsePacket.FragmentId.Value].AddFragement(gsePacket);
if (fragmentations[gsePacket.FragmentId.Value].Validate())
{
byte[] gseDataBytes = fragmentations[gsePacket.FragmentId.Value].GetGseDataBytes();
ushort protocolType = fragmentations[gsePacket.FragmentId.Value].ProtocolType;
HandleAssembledFrame(protocolType, gseDataBytes, gsePacket.Label);
fragmentations[gsePacket.FragmentId.Value] = null;
return;
}
else
{
throw new NotImplementedException();
}
}
if (gsePacket.StartIndicator && !gsePacket.EndIndicator)
{
fragmentations = new GseFragmentation[256];
fragmentations[gsePacket.FragmentId.Value] = new GseFragmentation(gsePacket);
return;
}
if (!gsePacket.StartIndicator && !gsePacket.EndIndicator)
{
if (fragmentations == null)
{
//This stream had no fragmentations yet, so we cannot reassemble this packet.
return;
}
if (fragmentations[gsePacket.FragmentId.Value] == null)
{
//The previous fragments are missing, so we cannot reassemble this packet.
return;
}
fragmentations[gsePacket.FragmentId.Value].AddFragement(gsePacket);
return;
}
throw new NotImplementedException(
"A unknown frame type was encountered. Please share a sample of this stream.");
}
private void HandleAssembledFrame(ushort protocolType, byte[] buffer, GseLabel label)
{
switch (protocolType)
{
case 0x0081:
//Network clock reference
HandleNetworkClockReference(buffer);
return;
case 0x0082:
//Lower Layer Signalling, see en_30154502v010401p.pdf, page 49
HandleLowerLayerSignalling(buffer, label);
return;
case 0x0091:
//according to https://www.iana.org/assignments/ule-next-headers/ule-next-headers.xhtml it's private
return;
case 0x0800:
Context.IpOutput.OnIpDatagram(0x010e, buffer);
return;
default:
throw new NotImplementedException(protocolType.ToString());
}
}
private GseL2SHandler rcs2;
private void HandleLowerLayerSignalling(byte[] buffer, GseLabel label)
{
if (rcs2 == null)
{
rcs2 = new GseL2SHandler(Context);
}
rcs2.PushPacket(buffer, label);
}
private void HandleNetworkClockReference(byte[] buffer)
{
MemoryStream binaryReader = new MemoryStream(buffer);
uint pcrA = binaryReader.ReadUInt32BE();
ushort pcrB = binaryReader.ReadUInt16BE();
ulong pcr_base = ((ulong)pcrA << 1) | ((ulong)pcrB >> 15);
ulong pcr_ext = (ulong)pcrB & 0x01ff;
ulong PCR = pcr_base * 300 + pcr_ext;
ulong seconds = PCR / 27000000;
}
}
}