Added support for ATSC 3.0 Baseband Packet Data Stream Protocol and parsing of ATSC 3.0 BBFRAMEs.
Some checks failed
🚀 Pack skyscraper8 / make-zip (push) Failing after 14s

This commit is contained in:
feyris-tan 2026-05-21 22:14:39 +02:00
parent d33a0003ef
commit 64b1639e2f
4 changed files with 215 additions and 3 deletions

View File

@ -0,0 +1,71 @@
using skyscraper5.Skyscraper.IO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
using static skyscraper5.Dvb.SystemSoftwareUpdate.SystemSoftwareUpdateInfo;
namespace skyscraper8.Atsc.A322
{
internal class AtscPlpBasebandParser
{
internal void PushBbframe(byte[] payload)
{
MemoryStream ms = new MemoryStream(payload);
byte a = ms.ReadUInt8();
bool mode = ((a >> 7) & 0x01) != 0;
int pointer = (a & 0x7f);
int addToPointer;
if (!mode)
{
//1 byte done.
addToPointer = 1;
}
else
{
addToPointer = 2;
byte b = ms.ReadUInt8();
pointer |= (((b >> 2) & 0x3F) << 7);
OfiDescription ofi = (OfiDescription)(b & 0x3);
switch(ofi)
{
case OfiDescription.NoExtensionMode:
break;
case OfiDescription.LongExtensionMode:
byte lc = ms.ReadUInt8();
addToPointer++;
int extType = (lc >> 5) & 0x7;
int extLen = (lc) & 0x1F;
byte ld = ms.ReadUInt8();
addToPointer++;
extLen |= (((ld) & 0xFF) << 5);
// see A322-2026-04-Physical-Layer-Protocol.pdf, Table 5.2
//0 = counter
//7 = padding
byte[] extensionFiled = ms.ReadBytes(extLen);
addToPointer += extLen;
if (extType != 7)
{
throw new NotImplementedException(String.Format("ATSC 3.0 BBFRAME Padding Type {0} not yet implemented.", extType));
}
break;
default:
throw new NotImplementedException(String.Format("{0} is not yet implemented in the ATSC 3.0 BBFrame Parser.", ofi));
}
}
throw new NotImplementedException("Actually do the ATSC packets here.")
}
}
internal enum OfiDescription
{
NoExtensionMode,
ShortExtensionMode,
LongExtensionMode,
MixedExtensionMode,
}
}

View File

@ -0,0 +1,134 @@
using log4net;
using skyscraper5.Ietf.Rfc768;
using skyscraper5.Ietf.Rfc971;
using skyscraper5.Skyscraper.IO;
using skyscraper5.Skyscraper.Net.Pcap;
using skyscraper5.Skyscraper.Plugins;
using skyscraper5.Skyscraper.Scraper;
using skyscraper8.Atsc.A322;
using skyscraper8.Ietf.Rfc3550_RTP;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.Atsc.A324
{
[SkyscraperPlugin]
internal class BasebandPacketDataStreamReceiver : ISkyscraperMpePlugin
{
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
private readonly IPAddress BPPS_IP_ADDRESS = IPAddress.Parse("239.0.51.48");
private byte[] plpIndexHelpBuffer = new byte[2];
public bool CanHandlePacket(InternetHeader internetHeader, byte[] ipv4Packet)
{
if (internetHeader.Protocol != 0x11)
return false;
if (ipv4Packet[8] != 0x80)
return false;
if (!internetHeader.DestinationAddress.Equals(BPPS_IP_ADDRESS))
return false;
if (BitConverter.IsLittleEndian)
{
plpIndexHelpBuffer[0] = ipv4Packet[3];
plpIndexHelpBuffer[1] = ipv4Packet[2];
}
else
{
plpIndexHelpBuffer[0] = ipv4Packet[2];
plpIndexHelpBuffer[1] = ipv4Packet[3];
}
ushort dstPort = BitConverter.ToUInt16(plpIndexHelpBuffer, 0);
if (dstPort < 30000)
return false;
if (dstPort > 30066)
return false;
return true;
}
public void ConnectToStorage(object[] connector)
{
throw new NotImplementedException();
}
private bool warnedAboutNonMarkedPackets;
public void HandlePacket(InternetHeader internetHeader, byte[] ipv4Packet)
{
UserDatagram udpPacket = new UserDatagram(ipv4Packet);
ushort plp = (ushort)(udpPacket.DestinationPort - 30000);
RtpPacket rtpPacket = new RtpPacket(udpPacket.Payload);
if (!rtpPacket.RtpMarker)
{
if (!warnedAboutNonMarkedPackets)
{
logger.WarnFormat("ATSC 3.0 BBFRAMEs spanning multiple packets are not supported yet. It would be great if you could share a sample of this, so this can be implemented.");
warnedAboutNonMarkedPackets = true;
}
return;
}
if (plp == 64)
{
HandlePreambleData(rtpPacket.RtpPayload);
return;
}
else if (plp == 65)
{
HandleTimingAndManagementData(rtpPacket.RtpPayload);
return;
}
else if (plp <= 63)
{
HandlePlp(plp, rtpPacket.RtpPayload);
return;
}
}
private AtscPlpBasebandParser[] plps;
private void HandlePlp(ushort plp, byte[] rtpPayload)
{
if (plps == null)
{
plps = new AtscPlpBasebandParser[64];
}
if (plps[plp] == null)
{
plps[plp] = new AtscPlpBasebandParser();
}
plps[plp].PushBbframe(rtpPayload);
}
private void HandleTimingAndManagementData(byte[] rtpPayload)
{
throw new NotImplementedException();
}
private void HandlePreambleData(byte[] rtpPayload)
{
throw new NotImplementedException();
}
private SkyscraperContext context;
public void SetContext(DateTime? currentTime, object skyscraperContext)
{
context = skyscraperContext as SkyscraperContext;
}
public bool StopProcessingAfterThis()
{
return true;
}
}
}

View File

@ -114,8 +114,6 @@ namespace skyscraper8.Atsc.A324
}
break;
case 4: //Deliver the packet
currentIpPacketBuffer[20] = 0x69;
currentIpPacketBuffer[21] = 0x69;
context.OnIpDatagram(0x1fff, currentIpPacketBuffer.AsSpan().Slice(0, currentIpPacketBufferOffset).ToArray());
stateMachineState = 1;
break;

View File

@ -13,6 +13,15 @@ namespace skyscraper5.Skyscraper.Net.Pcap
PPPoE = 51,
RawIp = 101,
WLAN = 105,
UserDefined = 147
FibreChannel = 122,
DocsisMac = 143,
/// <summary>
/// Voile uses DLT_USER0 for LLC PDUs
/// </summary>
UserDefined = 147,
/// <summary>
/// Voile uses DLT_USER1 for RTP packets without any Transport layer headers.
/// </summary>
UserDefined2 = 148,
}
}