Added basic ISDB-T SDT parsing.
All checks were successful
🚀 Pack skyscraper8 / make-zip (push) Successful in 50s

This commit is contained in:
fey 2026-09-03 21:30:59 +02:00
parent ddd4181dc3
commit 1e13c556ba
10 changed files with 217 additions and 41 deletions

View File

@ -12,7 +12,7 @@ using skyscraper5.Skyscraper.Text;
namespace skyscraper5.Dvb.Descriptors
{
[SkyscraperPlugin]
[TsDescriptor(0x48,"SDT","Astra SGT")]
[TsDescriptor(0x48,"SDT","Astra SGT", "ISDB SDT")]
[BannedTable("TSDT","PMT")]
public class ServiceDescriptor : TsDescriptor
{

View File

@ -9,7 +9,7 @@ using skyscraper8.Skyscraper;
namespace skyscraper5.Dvb.Psi
{
class Pid0x11Decoder : IPsiProcessor, IMultistandardTable
class Pid0x11Decoder : IPsiProcessor
{
public Pid0x11Decoder(IBatEventHandler batEventHandler, ISdtEventHandler sdtEventHandler)
@ -38,11 +38,5 @@ namespace skyscraper5.Dvb.Psi
return;
}
}
public void SetStandard(STD_TYPE standard)
{
SdtParser.SetStandard(standard);
BatParser.SetStandard(standard);
}
}
}

View File

@ -15,7 +15,7 @@ using skyscraper8.Skyscraper;
namespace skyscraper5.Dvb.Psi
{
class SdtParser : IPsiProcessor, IMultistandardTable
class SdtParser : IPsiProcessor
{
public ISdtEventHandler EventHandler { get; }
@ -83,7 +83,7 @@ namespace skyscraper5.Dvb.Psi
SdtService child = new SdtService(serviceId, eitScheduleFlag, eitPresentFollowingFlag, runningStatus, freeCaMode);
byte[] descriptorsData = ms.ReadBytes(descriptorsLoopLength);
IEnumerable<TsDescriptor> unpackDescriptors = TsDescriptorUnpacker.GetInstance().UnpackDescriptors(descriptorsData, GetTableType());
IEnumerable<TsDescriptor> unpackDescriptors = TsDescriptorUnpacker.GetInstance().UnpackDescriptors(descriptorsData, "SDT");
foreach (TsDescriptor dvbDescriptor in unpackDescriptors)
{
string name = dvbDescriptor.GetType().Name;
@ -214,23 +214,5 @@ namespace skyscraper5.Dvb.Psi
throw new NotImplementedException(name);
}
}
private STD_TYPE standard;
public void SetStandard(STD_TYPE standard)
{
this.standard = standard;
}
private string GetTableType()
{
if (IMultistandardTable.IsIsdb(standard))
{
return "ISDB SDT";
}
else
{
return "SDT";
}
}
}
}

View File

@ -0,0 +1,10 @@
using skyscraper8.Isdb.Tables;
namespace skyscraper8.Isdb.EventHandlers;
public interface IIsdbSdtEventHandler
{
void SetNetworkId(ushort originalNetworkId);
void SetTransportStreamId(ushort transportStreamId);
void OnSdtService(ushort transportStreamId, ushort originalNetworkId, IsdbSdtService child);
}

View File

@ -1,3 +1,4 @@
using System.Reflection.Metadata;
using log4net;
using log4net.Repository.Hierarchy;
using skyscraper5.Dvb.Descriptors;
@ -18,7 +19,7 @@ using skyscraper8.Skyscraper.Scraper.Storage;
namespace skyscraper8.Isdb;
public class Matenro : IPatEventHandler, ICatEventHandler, IBatEventHandler, ISdtEventHandler, IEitEventHandler, IRstEventHandler, ITdtEventHandler, ITotEventHandler, IIsdbPmtEventHandler, IBitEventHandler, IIsdbSubtitleHandler, IAutodetectionEventHandler
public class Matenro : IPatEventHandler, ICatEventHandler, IBatEventHandler, IEitEventHandler, IRstEventHandler, ITdtEventHandler, ITotEventHandler, IIsdbPmtEventHandler, IBitEventHandler, IIsdbSubtitleHandler, IAutodetectionEventHandler, IIsdbSdtEventHandler
{
public TsContext DvbContext { get; }
public DataStorage DataStorage { get; }
@ -43,10 +44,6 @@ public class Matenro : IPatEventHandler, ICatEventHandler, IBatEventHandler, ISd
logger = LogManager.GetLogger(this.GetType().Name);
Pid0x11Decoder pid0X11Decoder = new Pid0x11Decoder(this, this);
pid0X11Decoder.SetStandard(STD_TYPE.STD_ISDBT);
EitParser eitParser = new EitParser(this);
eitParser.SetStandard(STD_TYPE.STD_ISDBT);
@ -62,7 +59,7 @@ public class Matenro : IPatEventHandler, ICatEventHandler, IBatEventHandler, ISd
dvbContext.RegisterPacketProcessor(0x0000, new PsiDecoder(0x0000, new PatParser(this)));
dvbContext.RegisterPacketProcessor(0x0001, new PsiDecoder(0x0001, new CatParser(this)));
dvbContext.RegisterPacketProcessor(0x0011, new PsiDecoder(0x0011, pid0X11Decoder));
dvbContext.RegisterPacketProcessor(0x0011, new PsiDecoder(0x0011, new IsdbSdtParser(this)));
dvbContext.RegisterPacketProcessor(0x0012, new PsiDecoder(0x0012, eitParser));
dvbContext.RegisterPacketProcessor(0x0013, new PsiDecoder(0x0013, rstParser));
dvbContext.RegisterPacketProcessor(0x0014, new PsiDecoder(0x0014, tdtParser));
@ -110,14 +107,35 @@ public class Matenro : IPatEventHandler, ICatEventHandler, IBatEventHandler, ISd
}
}
public void OnSdtService(ushort transportStreamId, ushort originalNetworkId, SdtService sdtService)
{
throw new NotImplementedException();
}
private ushort? competingNetworkId;
public void SetNetworkId(ushort networkId)
{
this._networkId = networkId;
if (_networkId.HasValue)
{
if (_networkId.Value == networkId)
{
//Die neue Network ID ist die selbe, wie die, die wir kennen, also alles ok.
return;
}
else
{
//Die neue Network ID konkurriert!
if (competingNetworkId.HasValue)
{
return;
}
else
{
logger.WarnFormat("Multiple network IDs are announced for this stream: {0} <-> {1}", networkId, _networkId.Value);
competingNetworkId = networkId;
}
}
}
else
{
//Network ID noch nicht bekannt, kann also gefahrlos gesetzt werden.
this._networkId = networkId;
}
}
public void SetTransportStreamId(ushort transportStreamId)
@ -137,6 +155,25 @@ public class Matenro : IPatEventHandler, ICatEventHandler, IBatEventHandler, ISd
throw new NotImplementedException();
}
private List<long> _knownSdts;
public void OnSdtService(ushort transportStreamId, ushort originalNetworkId, IsdbSdtService child)
{
long key = originalNetworkId;
key <<= 16;
key += transportStreamId;
key <<= 16;
key += child.ServiceId;
if (_knownSdts == null)
_knownSdts = new List<long>();
if (!_knownSdts.Contains(key))
{
logger.InfoFormat("SDT Service {0},{1}: {2}", originalNetworkId, transportStreamId, child.TryGetName());
DataStorage.UpsertIsdbSdt(transportStreamId, originalNetworkId, child);
_knownSdts.Add(key);
}
}
public void OnEitEvent(EitEvent eitEvent)
{
throw new NotImplementedException();

View File

@ -0,0 +1,96 @@
using skyscraper5.Dvb.Descriptors;
using skyscraper5.Dvb.Psi.Model;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.IO;
using skyscraper8.Isdb.EventHandlers;
using skyscraper8.Isdb.Tables;
namespace skyscraper8.Isdb.Psi;
public class IsdbSdtParser : IPsiProcessor
{
public IsdbSdtParser(IIsdbSdtEventHandler handler)
{
this.EventHandler = handler;
}
public IIsdbSdtEventHandler EventHandler { get; set; }
public void GatherPsi(PsiSection section, int sourcePid)
{
MemoryStream ms = new MemoryStream(section.GetDataCopy(),false);
byte tableId = ms.ReadUInt8();
if (tableId != 0x42 && tableId != 0x46)
return;
ushort readUInt16Be = ms.ReadUInt16BE();
bool sectionSyntaxIndicator = (readUInt16Be & 0x8000) != 0;
if (!sectionSyntaxIndicator)
return;
int sectionLength = (readUInt16Be & 0x0fff);
ushort transportStreamId = ms.ReadUInt16BE();
byte readUInt8 = ms.ReadUInt8();
int versionNumber = (readUInt8 & 0x3e);
bool currentNextIndicator = (readUInt8 & 0x01) != 0;
byte sectionNumber = ms.ReadUInt8();
byte lastSectionNumber = ms.ReadUInt8();
ushort originalNetworkId = ms.ReadUInt16BE();
ms.ReadUInt8(); //reserved future use
if (tableId == 0x42)
{
//0x42 meaning current mux
EventHandler.SetNetworkId(originalNetworkId);
EventHandler.SetTransportStreamId(transportStreamId);
}
while (ms.GetAvailableBytes() > 4)
{
ReadIsdbService(ms, transportStreamId, originalNetworkId);
}
uint crc32 = ms.ReadUInt32BE();
}
private void ReadIsdbService(MemoryStream ms, ushort transportStreamId, ushort originalNetworkId)
{
ushort serviceId = ms.ReadUInt16BE();
byte readUInt8 = ms.ReadUInt8();
bool eitScheduleFlag = (readUInt8 & 0x02) != 0;
bool eitPresentFollowingFlag = (readUInt8 & 0x01) != 0;
ushort readUInt16Be = ms.ReadUInt16BE();
int rs = (readUInt16Be & 0xe000) >> 13;
RunningStatus runningStatus = (RunningStatus)rs;
bool freeCaMode = (readUInt16Be & 0x1000) != 0;
int descriptorsLoopLength = readUInt16Be & 0xfff;
IsdbSdtService child = new IsdbSdtService(serviceId, eitScheduleFlag, eitPresentFollowingFlag, runningStatus, freeCaMode);
byte[] descriptorsData = ms.ReadBytes(descriptorsLoopLength);
IEnumerable<TsDescriptor> unpackDescriptors = TsDescriptorUnpacker.GetInstance().UnpackDescriptors(descriptorsData, "ISDB SDT");
foreach (TsDescriptor dvbDescriptor in unpackDescriptors)
{
switch (dvbDescriptor)
{
case ServiceDescriptor sd:
if (child.ServiceDescriptor == null)
child.ServiceDescriptor = sd;
else
throw new NotImplementedException("Multiple service descriptors are not yet implemented.");
break;
default:
throw new NotImplementedException("Unknown ISDB SDTdescriptor type: " + dvbDescriptor.GetType().Name);
}
}
EventHandler.OnSdtService(transportStreamId, originalNetworkId, child);
}
}

View File

@ -0,0 +1,33 @@
using skyscraper5.Dvb.Descriptors;
using skyscraper5.Dvb.Psi.Model;
namespace skyscraper8.Isdb.Tables;
public class IsdbSdtService
{
public ushort ServiceId { get; }
public bool EitScheduleFlag { get; }
public bool EitPresentFollowingFlag { get; }
public RunningStatus RunningStatus { get; }
public bool FreeCaMode { get; }
public ServiceDescriptor ServiceDescriptor { get; set; }
public IsdbSdtService(ushort serviceId, bool eitScheduleFlag, bool eitPresentFollowingFlag, RunningStatus runningStatus, bool freeCaMode)
{
ServiceId = serviceId;
EitScheduleFlag = eitScheduleFlag;
EitPresentFollowingFlag = eitPresentFollowingFlag;
RunningStatus = runningStatus;
FreeCaMode = freeCaMode;
}
public string TryGetName()
{
if (ServiceDescriptor != null)
{
return ServiceDescriptor.ServiceName;
}
return "???";
}
}

View File

@ -221,5 +221,7 @@ namespace skyscraper8.Skyscraper.Scraper.Storage
/// </summary>
/// <param name="bit"></param>
void UpsertBit(Bit bit);
void UpsertIsdbSdt(ushort transportStreamId, ushort originalNetworkId, IsdbSdtService child);
}
}

View File

@ -1828,6 +1828,14 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.Filesystem
File.WriteAllText(fi.FullName, JsonConvert.SerializeObject(bit, jsonSerializerSettings));
}
public void UpsertIsdbSdt(ushort transportStreamId, ushort originalNetworkId, IsdbSdtService child)
{
string combine = Path.Combine(rootDirectory.FullName, "SDT", "ISDB", originalNetworkId.ToString(), transportStreamId.ToString() , child.ServiceId + ".json");
FileInfo fi = new FileInfo(combine);
fi.Directory.EnsureExists();
File.WriteAllText(fi.FullName, JsonConvert.SerializeObject(child, jsonSerializerSettings));
}
public RfSpectrumData GetRfSpectrum(Guid jobGuid)
{
string filename = Path.Combine(rootDirectory.FullName, "rf", jobGuid.ToString() + ".rf");

View File

@ -1959,5 +1959,19 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.InMemory
_bits = new Bit[ushort.MaxValue];
_bits[bit.OriginalNetworkId] = bit;
}
private Dictionary<long, IsdbSdtService> _isdbSdtServices;
public void UpsertIsdbSdt(ushort transportStreamId, ushort originalNetworkId, IsdbSdtService child)
{
long key = originalNetworkId;
key <<= 16;
key += transportStreamId;
key <<= 16;
key += child.ServiceId;
if (_isdbSdtServices == null)
_isdbSdtServices = new Dictionary<long, IsdbSdtService>();
_isdbSdtServices[key] = child;
}
}
}