Preparations for BFBS Navy TV.
Some checks failed
🚀 Pack skyscraper8 / make-zip (push) Failing after 2m18s

This commit is contained in:
feyris-tan 2025-11-08 21:16:43 +01:00
parent 124bf9eb49
commit 8f2c31f10d
24 changed files with 410 additions and 88 deletions

View File

@ -7,12 +7,13 @@ the following Signalling applies:
|Stream Type|Interpretation | |Stream Type|Interpretation |
|-----------|-----------------------------------| |-----------|-----------------------------------|
|0x80 |TBS 6903-X GSE Packets | |0x80 |STiD135 GS/GSE Packets |
|0x81 |AC-3 Audio | |0x81 |AC-3 Audio |
|0x82 |PID only used for PCR | |0x82 |PID only used for PCR |
|0x83 |AC-3 True HD Audio | |0x83 |AC-3 True HD Audio |
|0x84 |AC-3+ Audio | |0x84 |AC-3+ Audio |
|0x85 |ULE (RFC 4326) | |0x85 |DTS Audio |
|0x91 |ULE (RFC 4326) |
## Descriptors: ## Descriptors:

View File

@ -13,8 +13,8 @@
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fe1ab690537c44e02a014076312b886b7b2e200_003F4f_003F7bfc5050_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003AThrowHelper_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Fe1ab690537c44e02a014076312b886b7b2e200_003F4f_003F7bfc5050_003FThrowHelper_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATuple_00602_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F57d616db882b441b8c50720b4477e03db2e200_003F9f_003F0d16f921_003FTuple_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String> <s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATuple_00602_002Ecs_002Fl_003A_002E_002E_003F_002E_002E_003F_002Econfig_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F57d616db882b441b8c50720b4477e03db2e200_003F9f_003F0d16f921_003FTuple_00602_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
<s:String x:Key="/Default/Environment/Highlighting/HighlightingSourceSnapshotLocation/@EntryValue">/home/schiemas/.cache/JetBrains/Rider2025.1/resharper-host/temp/Rider/vAny/CoverageData/_skyscraper8.1808907683/Snapshot/snapshot.utdcvr</s:String> <s:String x:Key="/Default/Environment/Highlighting/HighlightingSourceSnapshotLocation/@EntryValue">/home/schiemas/.cache/JetBrains/Rider2025.1/resharper-host/temp/Rider/vAny/CoverageData/_skyscraper8.1808907683/Snapshot/snapshot.utdcvr</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=94eea68c_002Dcaa0_002D4657_002Da521_002D7b96c8ead0ec/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from &amp;lt;skyscraper8.Tests&amp;gt;" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt; <s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=94eea68c_002Dcaa0_002D4657_002Da521_002D7b96c8ead0ec/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from &amp;lt;skyscraper8.Tests&amp;gt;" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;&#xD;
&lt;Project Location="/home/schiemas/RiderProjects/skyscraper8/skyscraper8.Tests" Presentation="&amp;lt;skyscraper8.Tests&amp;gt;" /&gt; &lt;Project Location="\home\schiemas\RiderProjects\skyscraper8\skyscraper8.Tests" Presentation="&amp;lt;skyscraper8.Tests&amp;gt;" /&gt;&#xD;
&lt;/SessionState&gt;</s:String> &lt;/SessionState&gt;</s:String>

View File

@ -1,19 +1,18 @@
using log4net; using log4net;
using skyscraper5.Dvb.DataBroadcasting; using skyscraper5.Dvb.DataBroadcasting;
using skyscraper8.GS;
using skyscraper8.Skyscraper.Scraper; using skyscraper8.Skyscraper.Scraper;
namespace skyscraper8.GSE; namespace skyscraper8.GSE;
public class BbframeDeencapsulator3 : IBbframeDeencapsulator class BbframeDeencapsulator3 : IBbframeDeencapsulator
{ {
public BbframeDeencapsulator3(IMultiprotocolEncapsulationEventHandler mpeEventHandler, ISubTsHandler subTsHandler) public BbframeDeencapsulator3(GsContextDto context)
{ {
_mpeEventHandler = mpeEventHandler; this.context = context;
_subTsHandler = subTsHandler;
} }
private readonly ISubTsHandler _subTsHandler; private readonly GsContextDto context;
private readonly IMultiprotocolEncapsulationEventHandler _mpeEventHandler;
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
private long numPushed; private long numPushed;
public void PushPacket(byte[] bbframe) public void PushPacket(byte[] bbframe)
@ -38,11 +37,7 @@ public class BbframeDeencapsulator3 : IBbframeDeencapsulator
if (mis[bbHeader.Matype2] == null) if (mis[bbHeader.Matype2] == null)
{ {
logger.InfoFormat("Found a stream on MIS {0}",bbHeader.Matype2); logger.InfoFormat("Found a stream on MIS {0}",bbHeader.Matype2);
mis[bbHeader.Matype2] = new GsTypeDetector(bbHeader.Matype2) mis[bbHeader.Matype2] = new GsTypeDetector(context.MisClone(bbHeader.Matype2));
{
mpeEventHandler = this._mpeEventHandler,
subTsHandler = this._subTsHandler
};
} }
mis[bbHeader.Matype2].PushFrame(bbHeader, new ReadOnlySpan<byte>(bbframe, 11, bbframe.Length - 11)); mis[bbHeader.Matype2].PushFrame(bbHeader, new ReadOnlySpan<byte>(bbframe, 11, bbframe.Length - 11));

View File

@ -1,30 +1,31 @@
using System; using skyscraper5.Dvb.DataBroadcasting;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Mpeg2; using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.IO;
using skyscraper8.GSE; using skyscraper8.GSE;
using skyscraper8.GSE.GSE; using skyscraper8.GSE.GSE;
using skyscraper8.Skyscraper.IO; using skyscraper8.Skyscraper.IO;
using skyscraper8.Skyscraper.Scraper; 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 namespace skyscraper8.GS.GSE_BFBS
{ {
internal class BfbsGseReader : IMisHandler internal class BfbsGseReader : IMisHandler
{ {
private readonly byte _misId;
private readonly ISubTsHandler _subTsHandler;
private GseLabel lastLabel; private GseLabel lastLabel;
private int frameNo; private int frameNo;
public GsContextDto Context { get; set; }
public BfbsGseReader(byte misId, ISubTsHandler subTsHandler) public BfbsGseReader(GsContextDto context)
{ {
_misId = misId; this.Context = context;
_subTsHandler = subTsHandler;
} }
public void PushFrame(BBHeader bbHeader, ReadOnlySpan<byte> readOnlySpan) public void PushFrame(BBHeader bbHeader, ReadOnlySpan<byte> readOnlySpan)
{ {
frameNo++; frameNo++;
@ -51,68 +52,171 @@ namespace skyscraper8.GS.GSE_BFBS
} }
else else
{ {
GsePacket gsePacket = new GsePacket(startIndicator, endIndicator, labelTypeIndicator);
int gseLength = (byteA & 0x0f) << 8; int gseLength = (byteA & 0x0f) << 8;
gseLength += span.ReadUInt8(); gseLength += span.ReadUInt8();
byte? fragId = null; gsePacket.FragmentId = null;
if (!startIndicator || !endIndicator) if (!startIndicator || !endIndicator)
{ {
fragId = span.ReadUInt8(); gsePacket.FragmentId = span.ReadUInt8();
gseLength -= 1; gseLength -= 1;
} }
ushort? totalLength = null;
if ((startIndicator) && !endIndicator) if ((startIndicator) && !endIndicator)
{ {
totalLength = span.ReadUInt16BE(); gsePacket.TotalLength = span.ReadUInt16BE();
gseLength -= 2; gseLength -= 2;
} }
GseLabel label = null;
ushort? protocolType = null;
if (startIndicator) if (startIndicator)
{ {
protocolType = span.ReadUInt16BE(); gsePacket.ProtocolType = span.ReadUInt16BE();
gseLength -= 2; gseLength -= 2;
if (labelTypeIndicator == 0) if (labelTypeIndicator == 0)
{ {
label = new _6byteLabel(span.ReadBytes(6)); gsePacket.Label = new _6byteLabel(span.ReadBytes(6));
gseLength -= 6; gseLength -= 6;
} }
else if (labelTypeIndicator == 1) else if (labelTypeIndicator == 1)
{ {
label = new _3byteLabel(span.ReadBytes(3)); gsePacket.Label = new _3byteLabel(span.ReadBytes(3));
gseLength -= 3; gseLength -= 3;
} }
else if (labelTypeIndicator == 2) else if (labelTypeIndicator == 2)
{ {
label = BroadcastLabel.GetInstance(); gsePacket.Label = BroadcastLabel.GetInstance();
} }
else if (labelTypeIndicator == 3) else if (labelTypeIndicator == 3)
{ {
label = lastLabel; gsePacket.Label = lastLabel;
} }
lastLabel = gsePacket.Label;
} }
if (!startIndicator && endIndicator) if (!startIndicator && endIndicator)
gseLength -= 4; gseLength -= 4;
ReadOnlySpan<byte> gseDataBytes = span.ReadBytes(gseLength); gsePacket.GseDataBytes = span.ReadBytes(gseLength);
uint? crc32 = null;
if (!startIndicator && endIndicator) if (!startIndicator && endIndicator)
{ {
crc32 = span.ReadUInt32BE(); gsePacket.Crc32 = span.ReadUInt32BE();
} }
HandleGseFrame(startIndicator, endIndicator, fragId, totalLength, label, protocolType, gseDataBytes, crc32); HandleGseFrame(gsePacket);
} }
} }
} }
private void HandleGseFrame(bool startIndicator, bool endIndicator, byte? fragId, ushort? totalLength, GseLabel label, ushort? protocolType, ReadOnlySpan<byte> gseDataBytes, uint? crc32) private GseFragmentation[] fragmentations;
private void HandleGseFrame(GsePacket gsePacket)
{ {
//throw new NotImplementedException(); if (gsePacket.StartIndicator & gsePacket.EndIndicator)
{
HandleAssembledFrame(gsePacket.ProtocolType.Value, gsePacket.GseDataBytes);
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);
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;
}
throw new NotImplementedException("Frames without start and end indicators are not supported yet. Please consider submitting a sample.");
}
throw new NotImplementedException();
}
private void HandleAssembledFrame(ushort protocolType, byte[] buffer)
{
switch (protocolType)
{
case 0x0081:
//Network clock reference
HandleNetworkClockReference(buffer);
return;
case 0x0082:
//Lower Layer Signalling, see en_30154502v010401p.pdf, page 49
HandleLowerLayerSignalling(buffer);
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)
{
if (rcs2 == null)
{
rcs2 = new GseL2SHandler(Context);
}
rcs2.PushPacket(buffer);
}
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;
} }
} }
} }

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper8.InteractionChannel;
namespace skyscraper8.GS.GSE_BFBS
{
internal class GseL2SHandler
{
public GsContextDto Context { get; }
public GseL2SHandler(GsContextDto context)
{
Context = context;
}
public void PushPacket(byte[] buffer)
{
GseTableStructure gseTableStructure = new GseTableStructure(buffer);
switch (gseTableStructure.TableId)
{
default:
throw new NotImplementedException(String.Format(
"Unknown DVB-RCS2 Table Id: 0x{0:X2}\nIf this is reproducible on this stream, please consider submitting me a sample.",
gseTableStructure.TableId));
}
}
}
}

View File

@ -1,24 +1,26 @@
using log4net; using log4net;
using skyscraper5.Dvb.DataBroadcasting; using skyscraper5.Dvb.DataBroadcasting;
using skyscraper5.Skyscraper.IO; using skyscraper5.Skyscraper.IO;
using skyscraper8.GS;
using skyscraper8.GSE.GSE; using skyscraper8.GSE.GSE;
namespace skyscraper8.GSE.GSE_HEM; namespace skyscraper8.GSE.GSE_HEM;
public class GseHemReader : IMisHandler class GseHemReader : IMisHandler
{ {
public GseHemReader(IMultiprotocolEncapsulationEventHandler mpeEventHandler) public GseHemReader(GsContextDto context)
{ {
rayBuffer = new RayBuffer(); rayBuffer = new RayBuffer();
this.mpeEventHandler = mpeEventHandler; this.Context = context;
} }
private IMultiprotocolEncapsulationEventHandler mpeEventHandler;
private GseLabel lastLabel; private GseLabel lastLabel;
private RayBuffer rayBuffer; private RayBuffer rayBuffer;
private const int BUFFER_THRESHOLD = 65536 * 2; //Twice the maximum PDU size of GSE. That way we can guarantee we have one full PDU in buffer. private const int BUFFER_THRESHOLD = 65536 * 2; //Twice the maximum PDU size of GSE. That way we can guarantee we have one full PDU in buffer.
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
public GsContextDto Context { get; set; }
public void PushFrame(BBHeader bbHeader, ReadOnlySpan<byte> readOnlySpan) public void PushFrame(BBHeader bbHeader, ReadOnlySpan<byte> readOnlySpan)
{ {
MemoryStream ms = new MemoryStream(readOnlySpan.ToArray()); MemoryStream ms = new MemoryStream(readOnlySpan.ToArray());
@ -101,7 +103,7 @@ public class GseHemReader : IMisHandler
switch (packet.ProtocolType) switch (packet.ProtocolType)
{ {
case 0x0800: case 0x0800:
mpeEventHandler.OnIpDatagram(0x010e,packet.GseDataBytes); Context.IpOutput.OnIpDatagram(0x010e,packet.GseDataBytes);
return; return;
default: default:
logger.WarnFormat("This GSE-HEM stream contains traffic other than IP. IP is type 0x0800, but we got 0x{0:X4} here.", packet.ProtocolType); logger.WarnFormat("This GSE-HEM stream contains traffic other than IP. IP is type 0x0800, but we got 0x{0:X4} here.", packet.ProtocolType);

View File

@ -7,10 +7,22 @@ public class GseFragmentation
this.ProtocolType = child.ProtocolType.Value; this.ProtocolType = child.ProtocolType.Value;
this.Label = child.Label; this.Label = child.Label;
AddFragement(child); AddFragement(child);
this.TotalLength = child.TotalLength.Value;
this.Crc32 = child.Crc32;
} }
public uint Crc32 { get; set; }
public ushort TotalLength { get; set; }
private List<byte[]> fragments; private List<byte[]> fragments;
public bool Validate()
{
//TODO: Implement proper CRC-32 checking here
return true;
}
public void AddFragement(GsePacket packet) public void AddFragement(GsePacket packet)
{ {
if (fragments == null) if (fragments == null)
@ -23,12 +35,11 @@ public class GseFragmentation
public ushort ProtocolType { get; private set; } public ushort ProtocolType { get; private set; }
public bool Validate()
{
//To be implemented...
return true;
}
/// <summary>
/// Assembles the payload
/// </summary>
/// <returns>The concatenated GSE Data Bytes of each packet.</returns>
public byte[] GetGseDataBytes() public byte[] GetGseDataBytes()
{ {
int totalLength = fragments.Select(x => x.Length).Sum(); int totalLength = fragments.Select(x => x.Length).Sum();

View File

@ -6,6 +6,8 @@ public abstract class GseLabel
{ {
public abstract int Length { get; } public abstract int Length { get; }
public abstract string ToString(); public abstract string ToString();
public abstract int LabelTypeIndicator { get; }
} }
public class _6byteLabel : GseLabel public class _6byteLabel : GseLabel
@ -23,6 +25,7 @@ public class _6byteLabel : GseLabel
} }
public override int Length => 6; public override int Length => 6;
public override int LabelTypeIndicator => 0;
} }
public class _3byteLabel : GseLabel public class _3byteLabel : GseLabel
@ -53,6 +56,8 @@ public class _3byteLabel : GseLabel
} }
override public int Length => 3; override public int Length => 3;
public override int LabelTypeIndicator => 1;
} }
public class BroadcastLabel : GseLabel public class BroadcastLabel : GseLabel
@ -75,4 +80,6 @@ public class BroadcastLabel : GseLabel
} }
return _instance; return _instance;
} }
public override int LabelTypeIndicator => 2;
} }

View File

@ -1,14 +1,17 @@
using log4net; using log4net;
using skyscraper5.Dvb.DataBroadcasting; using skyscraper5.Dvb.DataBroadcasting;
using skyscraper5.Skyscraper.IO; using skyscraper5.Skyscraper.IO;
using skyscraper8.GS;
namespace skyscraper8.GSE.GSE; namespace skyscraper8.GSE.GSE;
internal class GseReader : IMisHandler internal class GseReader : IMisHandler
{ {
private GseLabel lastLabel; private GseLabel lastLabel;
public IMultiprotocolEncapsulationEventHandler mpeEventHandler { get; set; }
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
public GsContextDto Context { get; set; }
public void PushFrame(BBHeader bbHeader, ReadOnlySpan<byte> readOnlySpan) public void PushFrame(BBHeader bbHeader, ReadOnlySpan<byte> readOnlySpan)
{ {
MemoryStream ms = new MemoryStream(readOnlySpan.ToArray()); MemoryStream ms = new MemoryStream(readOnlySpan.ToArray());
@ -115,7 +118,7 @@ internal class GseReader : IMisHandler
currentFragmentation.AddFragement(child); currentFragmentation.AddFragement(child);
if (currentFragmentation.Validate()) if (currentFragmentation.Validate())
{ {
mpeEventHandler.OnIpDatagram(0x010e,currentFragmentation.GetGseDataBytes()); Context.IpOutput.OnIpDatagram(0x010e,currentFragmentation.GetGseDataBytes());
} }
fragmentations[child.FragmentId.Value] = null; fragmentations[child.FragmentId.Value] = null;
@ -150,7 +153,7 @@ internal class GseReader : IMisHandler
switch (child.ProtocolType) switch (child.ProtocolType)
{ {
case 0x0800: case 0x0800:
mpeEventHandler.OnIpDatagram(0x010e, child.GseDataBytes); Context.IpOutput.OnIpDatagram(0x010e, child.GseDataBytes);
break; break;
default: default:
if (warnedEthertypes == null) if (warnedEthertypes == null)

View File

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Dvb.DataBroadcasting;
using skyscraper5.src.InteractionChannel;
using skyscraper8.Skyscraper.Scraper;
namespace skyscraper8.GS
{
internal class GsContextDto
{
public GsContextMisDto MisClone(byte mis)
{
GsContextMisDto misClone = new GsContextMisDto(mis);
Type type = this.GetType();
PropertyInfo[] propertyInfos = type.GetProperties();
foreach (PropertyInfo propertyInfo in propertyInfos)
{
object? value = propertyInfo.GetValue(this);
propertyInfo.SetValue(misClone, value);
}
return misClone;
}
public byte GetMisId()
{
GsContextMisDto misDto = this as GsContextMisDto;
if (misDto == null)
return 0;
return misDto.Mis;
}
public ISubTsHandler TsOutput { get; set; }
public IMultiprotocolEncapsulationEventHandler IpOutput { get; set; }
public InteractionChannelHandler Rcs2Output { get; set; }
}
internal class GsContextMisDto : GsContextDto
{
public byte Mis { get; }
public GsContextMisDto(byte mis)
{
Mis = mis;
}
}
}

View File

@ -0,0 +1,23 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.GS
{
public class GsException : Exception
{
public GsException()
{
}
public GsException(string message) : base(message)
{
}
public GsException(string message, Exception inner) : base(message, inner)
{
}
}
}

View File

@ -1,5 +1,6 @@
using log4net; using log4net;
using skyscraper5.Dvb.DataBroadcasting; using skyscraper5.Dvb.DataBroadcasting;
using skyscraper8.GS;
using skyscraper8.GS.GSE_BFBS; using skyscraper8.GS.GSE_BFBS;
using skyscraper8.GS.SiminnRadiomidun; using skyscraper8.GS.SiminnRadiomidun;
using skyscraper8.GSE.GSE_HEM; using skyscraper8.GSE.GSE_HEM;
@ -8,17 +9,16 @@ using skyscraper8.Skyscraper.Scraper;
namespace skyscraper8.GSE; namespace skyscraper8.GSE;
public class GsTypeDetector : IMisHandler class GsTypeDetector : IMisHandler
{ {
public IMultiprotocolEncapsulationEventHandler mpeEventHandler { get; set; } public GsContextDto Context { get; set; }
private readonly byte _misId; private readonly ILog logger;
private readonly ILog logger;
private HashSet<Tuple<int, byte>> _postedStreamTypes; private HashSet<Tuple<int, byte>> _postedStreamTypes;
public ISubTsHandler subTsHandler;
public GsTypeDetector(byte misId) public GsTypeDetector(GsContextMisDto context)
{ {
_misId = misId; this.logger = LogManager.GetLogger(String.Format("{0} MIS {1}",System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name,context.Mis));
logger = LogManager.GetLogger(String.Format("{0} MIS {1}",System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name,misId)); this.Context = context;
} }
private GseReader gseReader; private GseReader gseReader;
@ -41,7 +41,7 @@ public class GsTypeDetector : IMisHandler
if (gseReader == null) if (gseReader == null)
{ {
gseReader = new GseReader(); gseReader = new GseReader();
gseReader.mpeEventHandler = mpeEventHandler; gseReader.Context = Context;
} }
gseReader.PushFrame(bbHeader, readOnlySpan); gseReader.PushFrame(bbHeader, readOnlySpan);
@ -53,7 +53,7 @@ public class GsTypeDetector : IMisHandler
//Looks like GSE-HEM //Looks like GSE-HEM
if (gseHemReader == null) if (gseHemReader == null)
{ {
gseHemReader = new GseHemReader(mpeEventHandler); gseHemReader = new GseHemReader(Context);
} }
gseHemReader.PushFrame(bbHeader, readOnlySpan); gseHemReader.PushFrame(bbHeader, readOnlySpan);
return; return;
@ -68,7 +68,7 @@ public class GsTypeDetector : IMisHandler
if (siminnRadiomidunReader == null) if (siminnRadiomidunReader == null)
{ {
//These behave similar to T2-MI. Interesting. //These behave similar to T2-MI. Interesting.
siminnRadiomidunReader = new SiminnRadiomidunReader(_misId,subTsHandler); siminnRadiomidunReader = new SiminnRadiomidunReader(Context);
} }
siminnRadiomidunReader.PushFrame(bbHeader, readOnlySpan); siminnRadiomidunReader.PushFrame(bbHeader, readOnlySpan);
@ -89,7 +89,7 @@ public class GsTypeDetector : IMisHandler
{ {
if (bfbsGseReader == null) if (bfbsGseReader == null)
{ {
bfbsGseReader = new BfbsGseReader(_misId, subTsHandler); bfbsGseReader = new BfbsGseReader(Context);
} }
bfbsGseReader.PushFrame(bbHeader, readOnlySpan); bfbsGseReader.PushFrame(bbHeader, readOnlySpan);

View File

@ -1,6 +1,10 @@
using skyscraper8.GS;
namespace skyscraper8.GSE; namespace skyscraper8.GSE;
public interface IMisHandler interface IMisHandler
{ {
public GsContextDto Context { get; set; }
void PushFrame(BBHeader bbHeader, ReadOnlySpan<byte> readOnlySpan); void PushFrame(BBHeader bbHeader, ReadOnlySpan<byte> readOnlySpan);
} }

View File

@ -44,7 +44,7 @@ public class Pts2Bbf
FileStream fileStream = file.OpenRead(); FileStream fileStream = file.OpenRead();
TsContext mpeg2 = new TsContext(); TsContext mpeg2 = new TsContext();
mpeg2.RegisterPacketProcessor(0x010e, new Stid135BbFrameReader(null, null, dumper)); mpeg2.RegisterPacketProcessor(0x010e, new Stid135BbFrameReader(null, dumper));
DataStorage dataStorage = new InMemoryScraperStorage(); DataStorage dataStorage = new InMemoryScraperStorage();
ObjectStorage objectStorage = new NullObjectStorage(); ObjectStorage objectStorage = new NullObjectStorage();
SkyscraperContext skyscraper = new SkyscraperContext(mpeg2, dataStorage, objectStorage); SkyscraperContext skyscraper = new SkyscraperContext(mpeg2, dataStorage, objectStorage);

View File

@ -25,7 +25,7 @@ public class Pts2Bbf2 : IBbframeDeencapsulator
public void Run() public void Run()
{ {
TsContext mpeg2 = new TsContext(); TsContext mpeg2 = new TsContext();
Stid135BbFrameReader bbFrameReader = new Stid135BbFrameReader(null, null, this); Stid135BbFrameReader bbFrameReader = new Stid135BbFrameReader(null, this);
mpeg2.RegisterPacketProcessor(0x010e, bbFrameReader); mpeg2.RegisterPacketProcessor(0x010e, bbFrameReader);
SkyscraperContext context = new SkyscraperContext(mpeg2, new InMemoryScraperStorage(), new NullObjectStorage()); SkyscraperContext context = new SkyscraperContext(mpeg2, new InMemoryScraperStorage(), new NullObjectStorage());

View File

@ -3,6 +3,7 @@ using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.Scraper; using skyscraper5.Skyscraper.Scraper;
using skyscraper5.Skyscraper.Scraper.Storage.Filesystem; using skyscraper5.Skyscraper.Scraper.Storage.Filesystem;
using skyscraper5.Skyscraper.Scraper.Storage.InMemory; using skyscraper5.Skyscraper.Scraper.Storage.InMemory;
using skyscraper8.GS;
using skyscraper8.Skyscraper.Scraper.Storage; using skyscraper8.Skyscraper.Scraper.Storage;
namespace skyscraper8.GSE; namespace skyscraper8.GSE;
@ -19,7 +20,8 @@ public class Stid135Test
ObjectStorage objectStorage = new FilesystemStorage(new DirectoryInfo("nip")); ObjectStorage objectStorage = new FilesystemStorage(new DirectoryInfo("nip"));
SkyscraperContext skyscraper = new SkyscraperContext(mpeg2, dataStorage, objectStorage); SkyscraperContext skyscraper = new SkyscraperContext(mpeg2, dataStorage, objectStorage);
mpeg2.RegisterPacketProcessor(0x010e, new Stid135BbFrameReader(skyscraper,skyscraper)); GsContextDto context = new GsContextDto();
mpeg2.RegisterPacketProcessor(0x010e, new Stid135BbFrameReader(context));
skyscraper.InitalizeFilterChain(); skyscraper.InitalizeFilterChain();
skyscraper.IngestFromStream(fileStream); skyscraper.IngestFromStream(fileStream);

View File

@ -13,19 +13,18 @@ namespace skyscraper8.GS.SiminnRadiomidun
{ {
internal class SiminnRadiomidunReader : IMisHandler internal class SiminnRadiomidunReader : IMisHandler
{ {
public SiminnRadiomidunReader(byte mis, ISubTsHandler tsOutput) public SiminnRadiomidunReader(GsContextDto context)
{ {
this.packetQueue = new Queue<Tuple<BBHeader,MemoryStream>>(); this.packetQueue = new Queue<Tuple<BBHeader,MemoryStream>>();
this.isInSync = false; this.isInSync = false;
this.subTsKey = new SiminnRadiomidunSubTsIdentifier(mis); this.subTsKey = new SiminnRadiomidunSubTsIdentifier(context.GetMisId());
this.tsOutput = tsOutput; this.Context = context;
} }
private bool isInSync; private bool isInSync;
private Queue<Tuple<BBHeader, MemoryStream>> packetQueue; private Queue<Tuple<BBHeader, MemoryStream>> packetQueue;
private MemoryStream currentItem; private MemoryStream currentItem;
private SiminnRadiomidunSubTsIdentifier subTsKey; private SiminnRadiomidunSubTsIdentifier subTsKey;
private ISubTsHandler tsOutput;
public long PacketQueueSize public long PacketQueueSize
{ {
@ -37,6 +36,9 @@ namespace skyscraper8.GS.SiminnRadiomidun
return packetQueue.Select(x => x.Item2.Length).Sum(); return packetQueue.Select(x => x.Item2.Length).Sum();
} }
} }
public GsContextDto Context { get; set; }
public void PushFrame(BBHeader bbHeader, ReadOnlySpan<byte> readOnlySpan) public void PushFrame(BBHeader bbHeader, ReadOnlySpan<byte> readOnlySpan)
{ {
if (packetQueue == null) if (packetQueue == null)
@ -87,7 +89,7 @@ namespace skyscraper8.GS.SiminnRadiomidun
private void OutputPacket(byte[] buffer) private void OutputPacket(byte[] buffer)
{ {
buffer[0] = 0x47; buffer[0] = 0x47;
tsOutput.OnSubTsPacket(subTsKey, buffer); Context.TsOutput.OnSubTsPacket(subTsKey, buffer);
} }
} }
} }

View File

@ -7,6 +7,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using skyscraper5.Dvb.DataBroadcasting; using skyscraper5.Dvb.DataBroadcasting;
using skyscraper8.GS;
using skyscraper8.Skyscraper.Scraper; using skyscraper8.Skyscraper.Scraper;
namespace skyscraper8.GSE namespace skyscraper8.GSE
@ -15,10 +16,10 @@ namespace skyscraper8.GSE
{ {
private IBbframeDeencapsulator deencapsulator; private IBbframeDeencapsulator deencapsulator;
public Stid135BbFrameReader(IMultiprotocolEncapsulationEventHandler mpeEventHandler, ISubTsHandler subTsHandler, IBbframeDeencapsulator deencapsulator = null) public Stid135BbFrameReader(GsContextDto context, IBbframeDeencapsulator deencapsulator = null)
{ {
if (deencapsulator == null) if (deencapsulator == null)
deencapsulator = new BbframeDeencapsulator3(mpeEventHandler, subTsHandler); deencapsulator = new BbframeDeencapsulator3(context);
this.deencapsulator = deencapsulator; this.deencapsulator = deencapsulator;
} }

View File

@ -0,0 +1,38 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Skyscraper.IO;
namespace skyscraper8.InteractionChannel
{
/// <summary>
/// Represents the structure in ETSI EN 301 545-2 V1.4.1, clause 6.4.3.1.1
/// </summary>
internal class GseTableStructure
{
public GseTableStructure(byte[] buffer)
{
MemoryStream ms = new MemoryStream(buffer, false);
TableId = ms.ReadUInt8();
InteractiveNetworkId = ms.ReadUInt16BE();
byte byteA = ms.ReadUInt8();
VersionNumber = (byteA & 0x3e) >> 1;
CurrentNextIndicator = (byteA & 0x01) != 0;
TableContent = ms.ReadBytes(ms.GetAvailableBytes());
}
public byte[] TableContent { get; private set; }
public bool CurrentNextIndicator { get; private set; }
public int VersionNumber { get; private set; }
public ushort InteractiveNetworkId { get; private set; }
public byte TableId { get; private set; }
}
}

View File

@ -62,7 +62,12 @@ namespace skyscraper5.src.InteractionChannel
switch (buffer[0]) switch (buffer[0])
{ {
case 0x40: //NIT case 0x40: //NIT
//see ETSI EN 301 545-2 InteractionChannelSiSectionHeader nitHeader = new InteractionChannelSiSectionHeader(ms);
if (!nitHeader.Valid)
{
_handler.OnInteractionChannelError(InteractionChannelErrorState.HeaderInvalid);
return;
}
throw new NotImplementedException("NIT"); throw new NotImplementedException("NIT");
case 0x41: //RMT case 0x41: //RMT
Rmt rmt = new Rmt(ms); Rmt rmt = new Rmt(ms);

View File

@ -100,5 +100,12 @@ namespace skyscraper5.Mpeg2
} }
public int BytesContained => receivedBytes; public int BytesContained => receivedBytes;
internal static PsiSection FromByteArray(byte[] alreadyGathered)
{
PsiSection child = new PsiSection();
child.data = new MemoryStream(alreadyGathered, false);
return child;
}
} }
} }

View File

@ -2,7 +2,7 @@
"profiles": { "profiles": {
"skyscraper8": { "skyscraper8": {
"commandName": "Project", "commandName": "Project",
"commandLineArgs": "E:\\638951188146456482.ts", "commandLineArgs": "\"E:\\638951188146456482.ts\"",
"remoteDebugEnabled": false "remoteDebugEnabled": false
}, },
"Container (Dockerfile)": { "Container (Dockerfile)": {

View File

@ -119,6 +119,11 @@ public class MpeEject : ISkyscraperMpePlugin
byte[] packetBuffer = new byte[188]; byte[] packetBuffer = new byte[188];
for (int i = 0; i < userDatagram.Payload.Length; i += 188) for (int i = 0; i < userDatagram.Payload.Length; i += 188)
{ {
if (!session.PrintedNotice)
{
logger.InfoFormat("Found a Transport Stream in IP packets: {0} -> {1}", sourceEndpoint, targetEndpoint);
session.PrintedNotice = true;
}
Array.Copy(userDatagram.Payload, i, packetBuffer, 0, 188); Array.Copy(userDatagram.Payload, i, packetBuffer, 0, 188);
subTsHandler.OnSubTsPacket(session, packetBuffer); subTsHandler.OnSubTsPacket(session, packetBuffer);
lastOutputSucessful = true; lastOutputSucessful = true;
@ -134,6 +139,8 @@ public class MpeEject : ISkyscraperMpePlugin
{ {
return lastOutputSucessful; return lastOutputSucessful;
} }
} }
public class MpeEjectSession public class MpeEjectSession
@ -155,4 +162,5 @@ public class MpeEjectSession
} }
public int ValidDatagrams { get; set; } public int ValidDatagrams { get; set; }
public bool PrintedNotice { get; set; }
} }

View File

@ -74,12 +74,14 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Net; using System.Net;
using System.Net.NetworkInformation; using System.Net.NetworkInformation;
using System.Reflection;
using System.Security.Policy; using System.Security.Policy;
using System.Text; using System.Text;
using skyscraper5.src.InteractionChannel.Model2; using skyscraper5.src.InteractionChannel.Model2;
using skyscraper8.Abertis; using skyscraper8.Abertis;
using skyscraper8.Experimentals.NdsSsu; using skyscraper8.Experimentals.NdsSsu;
using skyscraper8.Experimentals.OtvSsu; using skyscraper8.Experimentals.OtvSsu;
using skyscraper8.GS;
using skyscraper8.GSE; using skyscraper8.GSE;
using skyscraper8.Ieee802_1AB; using skyscraper8.Ieee802_1AB;
using skyscraper8.InteractionChannel.Model2; using skyscraper8.InteractionChannel.Model2;
@ -306,7 +308,7 @@ namespace skyscraper5.Skyscraper.Scraper
{ {
if (!DvbContext.IsPidProcessorPresent(0x010e)) if (!DvbContext.IsPidProcessorPresent(0x010e))
{ {
DvbContext.RegisterPacketProcessor(0x010e, new Stid135BbFrameReader(this, this)); DvbContext.RegisterPacketProcessor(0x010e, new Stid135BbFrameReader(CreateGsContext()));
UiJunction?.SetGseMode(); UiJunction?.SetGseMode();
LogEvent(SkyscraperContextEvent.SpecialTsMode, "STiD135 encapsulated GS detected."); LogEvent(SkyscraperContextEvent.SpecialTsMode, "STiD135 encapsulated GS detected.");
SpecialTsType = 3; SpecialTsType = 3;
@ -322,6 +324,29 @@ namespace skyscraper5.Skyscraper.Scraper
} }
} }
private GsContextDto CreateGsContext()
{
//Build the object
GsContextDto child = new GsContextDto();
child.IpOutput = this;
child.TsOutput = this;
child.Rcs2Output = this;
//for futureproofing
PropertyInfo[] properties = typeof(GsContextDto).GetProperties();
foreach (PropertyInfo propertyInfo in properties)
{
object? value = propertyInfo.GetValue(child);
if (value == null)
{
throw new SkyscraperException(String.Format("While creating the {0}, the {1} was not properly set. This is a bug, tell Fey.", nameof(GsContextDto), propertyInfo.Name));
}
}
//actually return the object
return child;
}
private DocsisPacketProcessor docsisPacketProcessor; private DocsisPacketProcessor docsisPacketProcessor;
public int SpecialTsType { get; private set; } public int SpecialTsType { get; private set; }
private void CheckSpecialTs() private void CheckSpecialTs()
@ -361,7 +386,7 @@ namespace skyscraper5.Skyscraper.Scraper
{ {
if (!DvbContext.IsPidProcessorPresent(0x010e)) if (!DvbContext.IsPidProcessorPresent(0x010e))
{ {
DvbContext.RegisterPacketProcessor(0x010e, new Stid135BbFrameReader(this, this)); DvbContext.RegisterPacketProcessor(0x010e, new Stid135BbFrameReader(CreateGsContext()));
UiJunction?.SetGseMode(); UiJunction?.SetGseMode();
LogEvent(SkyscraperContextEvent.SpecialTsMode, "STiD135 encapsulated GS detected."); LogEvent(SkyscraperContextEvent.SpecialTsMode, "STiD135 encapsulated GS detected.");
SpecialTsType = 3; SpecialTsType = 3;