skyscraper8/skyscraper8/Atsc/A331/Atsc3Unpacker.cs
feyris-tan 2e173d4156
All checks were successful
🚀 Pack skyscraper8 / make-zip (push) Successful in 1m16s
Added an option for parsing FLUTE-LCT Frames with ATSC3's peculiarities.
2026-06-07 21:56:39 +02:00

123 lines
3.1 KiB
C#

using log4net;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.Ietf.Rfc768;
using skyscraper5.Ietf.Rfc971;
using skyscraper5.Skyscraper;
using skyscraper5.Skyscraper.Plugins;
using skyscraper5.Skyscraper.Scraper;
using skyscraper8.Atsc.A331.Schema;
using skyscraper8.Ietf.FLUTE;
namespace skyscraper8.Atsc.A331
{
[SkyscraperPlugin]
[PluginPriority(3)]
internal class Atsc3Unpacker : ISkyscraperMpePlugin
{
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
private static readonly IPAddress LLS_IP = IPAddress.Parse("224.0.23.60");
private static readonly ushort LLS_PORT = 4937;
private IAtsc3EventHandler eventHandler;
private bool systimeDetected;
public void ConnectToStorage(object[] connector)
{
throw new NotImplementedException();
}
public void SetContext(DateTime? currentTime, object skyscraperContext)
{
eventHandler = (IAtsc3EventHandler)skyscraperContext;
}
private bool atsc3detected;
public bool CanHandlePacket(InternetHeader internetHeader, byte[] ipv4Packet)
{
if (internetHeader.Protocol != 0x11)
return false;
if (atsc3detected && internetHeader.IsDestinationMulticast)
return true;
if (internetHeader.DestinationAddress.Equals(LLS_IP))
{
if (ipv4Packet.GetUInt16BE(2) == LLS_PORT)
{
return true;
}
}
return false;
}
public void HandlePacket(InternetHeader internetHeader, byte[] ipv4Packet)
{
_stopProcessIndicator = false;
UserDatagram udpPacket = new UserDatagram(ipv4Packet);
if (internetHeader.DestinationAddress.Equals(LLS_IP) && udpPacket.DestinationPort == LLS_PORT)
{
//Handle LLS
LlsTable lls = new LlsTable(udpPacket.Payload);
HandleLls(lls);
return;
}
if (!atsc3detected)
{
return;
}
LctFrame lctFrame = new LctFrame(udpPacket.Payload, true);
}
private void HandleLls(LlsTable lls)
{
if (!lls.Valid)
return;
_stopProcessIndicator = true;
switch (lls.LlsTableId)
{
case 0x01:
//SLT
if (!atsc3detected)
{
atsc3detected = true;
eventHandler.OnAtsc3Detected();
}
sltType slt = Atsc3Utilities.UnpackSlt(lls.Payload);
eventHandler.OnAtsc3ServiceList(slt);
break;
case 0x03:
SysTimeType systime = Atsc3Utilities.UnpackSystime(lls.Payload);
if (systime.ptpPrepend != 0 && !systimeDetected)
{
logger.WarnFormat("Found valid ATSC A/331 SYSTIME, however it is not implemented yet. ");
systimeDetected = true;
}
break;
case 0xff:
//User defined, can be removed.
break;
default:
logger.InfoFormat(
"Encountered unknown ATSC A/331 LLS Table: 0x{0:X2} This means that this stream uses a version of ATSC 3 than skyscraper8 knows about. It would be great if you could share a recording of this stream so this can be implemented.", lls.LlsTableId);
break;
}
}
private bool _stopProcessIndicator;
public bool StopProcessingAfterThis()
{
return _stopProcessIndicator;
}
}
}