226 lines
5.9 KiB
C#
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;
|
|
}
|
|
}
|
|
}
|