307 lines
16 KiB
C#
307 lines
16 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Collections.ObjectModel;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using skyscraper5.Dvb.Descriptors;
|
|
using skyscraper5.Dvb.Descriptors.Extension;
|
|
using skyscraper5.Dvb.Psi.Model;
|
|
using skyscraper5.Mpeg2;
|
|
using skyscraper5.Mpeg2.Descriptors;
|
|
using skyscraper5.Skyscraper.IO;
|
|
using skyscraper5.Skyscraper.Plugins;
|
|
|
|
namespace skyscraper5.Dvb.Psi
|
|
{
|
|
public class NitParser : IPsiProcessor
|
|
{
|
|
public INitEventHandler EventHandler { get; }
|
|
|
|
public NitParser(INitEventHandler eventHandler)
|
|
{
|
|
EventHandler = eventHandler;
|
|
}
|
|
|
|
public void GatherPsi(PsiSection section, int sourcePid)
|
|
{
|
|
MemoryStream ms = new MemoryStream(section.GetDataCopy());
|
|
byte tableId = ms.ReadUInt8();
|
|
bool actualNetwork;
|
|
switch (tableId)
|
|
{
|
|
case 0x40:
|
|
actualNetwork = true;
|
|
break;
|
|
case 0x41:
|
|
actualNetwork = false;
|
|
break;
|
|
case 0x72:
|
|
//stuffing area
|
|
return;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
ushort readUInt16Be = ms.ReadUInt16BE();
|
|
bool sectionSyntaxSelector = (readUInt16Be & 0x8000) != 0;
|
|
if (!sectionSyntaxSelector)
|
|
return;
|
|
int sectionLength = readUInt16Be & 0x0fff;
|
|
|
|
ushort networkId = ms.ReadUInt16BE();
|
|
NitNetwork nitNetwork = new NitNetwork(networkId);
|
|
if (actualNetwork)
|
|
{
|
|
//I'd trust the NIT more than the EIT.
|
|
EventHandler.SetNetworkId(networkId,true);
|
|
}
|
|
|
|
byte readUInt8 = ms.ReadUInt8();
|
|
int versionNumber = (readUInt8 & 0x3e) >> 1;
|
|
bool currentNextIndicator = (readUInt8 & 0x01) != 0;
|
|
|
|
byte sectionNumber = ms.ReadUInt8();
|
|
|
|
byte lastSectionNumber = ms.ReadUInt8();
|
|
|
|
readUInt16Be = ms.ReadUInt16BE();
|
|
int networkDescriptorsLength = readUInt16Be & 0x0fff;
|
|
byte[] networkDescriptorsBuffer = ms.ReadBytes(networkDescriptorsLength);
|
|
IEnumerable<TsDescriptor> networkDescriptors = TsDescriptorUnpacker.GetInstance().UnpackDescriptors(networkDescriptorsBuffer, "NIT");
|
|
foreach (TsDescriptor dvbDescriptor in networkDescriptors)
|
|
{
|
|
switch (dvbDescriptor.GetType().Name)
|
|
{
|
|
case nameof(NetworkNameDescriptor):
|
|
NetworkNameDescriptor networkNameDescriptor = (NetworkNameDescriptor)dvbDescriptor;
|
|
nitNetwork.Name = networkNameDescriptor.NetworkName;
|
|
break;
|
|
case nameof(LinkageDescriptor):
|
|
LinkageDescriptor linkageDescriptor = (LinkageDescriptor)dvbDescriptor;
|
|
nitNetwork.Linkages.Add(linkageDescriptor);
|
|
break;
|
|
case nameof(PrivateDataSpecifierDescriptor):
|
|
nitNetwork.PrivateDataSpecifierId = ((PrivateDataSpecifierDescriptor)dvbDescriptor).PrivateDataSpecifier;
|
|
break;
|
|
case nameof(UserDefinedDescriptor):
|
|
if (!nitNetwork.PrivateDataSpecifierId.HasValue)
|
|
break;
|
|
TsDescriptor descriptor = UserDefinedDescriptorUnpacker.GetInstance().UnpackUserDefinedDescriptor((UserDefinedDescriptor)dvbDescriptor, nitNetwork.PrivateDataSpecifierId.Value, "NIT");
|
|
if (descriptor == null)
|
|
break;
|
|
switch (descriptor)
|
|
{
|
|
default:
|
|
throw new NotImplementedException(descriptor.GetType().Name);
|
|
}
|
|
break;
|
|
case nameof(CellListDescriptor):
|
|
nitNetwork.Cells = ((CellListDescriptor)dvbDescriptor).Cells;
|
|
break;
|
|
case nameof(XaitPidDescriptor):
|
|
XaitPidDescriptor xpd = (XaitPidDescriptor)dvbDescriptor;
|
|
nitNetwork.XaitPid = xpd.XaitPid;
|
|
break;
|
|
case nameof(MultilingualNetworkNameDescriptor):
|
|
MultilingualNetworkNameDescriptor mnnd = (MultilingualNetworkNameDescriptor)dvbDescriptor;
|
|
nitNetwork.MultilingualNetworkName = mnnd.MultilingualNetworkName;
|
|
break;
|
|
case nameof(TargetRegionNameDescriptor):
|
|
TargetRegionNameDescriptor trnd = (TargetRegionNameDescriptor)dvbDescriptor;
|
|
nitNetwork.RegionNames = trnd.Regions;
|
|
nitNetwork.RegionNameCountryCode = trnd.CountryCode;
|
|
nitNetwork.RegionNameLanguageCode = trnd.Iso639LanguageCode;
|
|
break;
|
|
case nameof(TargetRegionDescriptor):
|
|
TargetRegionDescriptor trd = (TargetRegionDescriptor)dvbDescriptor;
|
|
nitNetwork.Regions = trd.TargetRegions;
|
|
nitNetwork.RegionCountryCode = trd.CountryCode;
|
|
break;
|
|
case nameof(MessageDescriptor):
|
|
MessageDescriptor message = (MessageDescriptor)dvbDescriptor;
|
|
if (nitNetwork.Messages == null)
|
|
nitNetwork.Messages = new HashSet<MessageDescriptor>();
|
|
nitNetwork.Messages.Add(message);
|
|
break;
|
|
case nameof(UriLinkageDescriptor):
|
|
UriLinkageDescriptor uriLinkage = (UriLinkageDescriptor)dvbDescriptor;
|
|
nitNetwork.MinPollingInterval = uriLinkage.MinPollingInterval;
|
|
nitNetwork.Uri = uriLinkage.Uri;
|
|
nitNetwork.UriLinkageType = uriLinkage.UriLinkageType;
|
|
break;
|
|
case nameof(ServiceListDescriptor):
|
|
ServiceListDescriptor serviceList = (ServiceListDescriptor)dvbDescriptor;
|
|
nitNetwork.ServiceList = serviceList.Services;
|
|
break;
|
|
case nameof(ExtensionUserDefinedDescriptor):
|
|
ExtensionUserDefinedDescriptor eudd = (ExtensionUserDefinedDescriptor)dvbDescriptor;
|
|
//might be everything... idk...
|
|
break;
|
|
default:
|
|
throw new NotImplementedException(dvbDescriptor.GetType().Name);
|
|
}
|
|
}
|
|
|
|
readUInt16Be = ms.ReadUInt16BE();
|
|
int transportStreamLoopLength = readUInt16Be & 0x0fff;
|
|
byte[] transportStreamsBuffer = ms.ReadBytes(transportStreamLoopLength);
|
|
|
|
|
|
|
|
uint crc32 = ms.ReadUInt32BE();
|
|
|
|
ReadOnlyCollection<NitTransportStream> nitTransportStreams = UnpackTransportStreams(networkId, transportStreamsBuffer).ToList().AsReadOnly();
|
|
nitNetwork.Streams = nitTransportStreams;
|
|
EventHandler.OnNitNetwork(nitNetwork);
|
|
foreach (NitTransportStream stream in nitTransportStreams)
|
|
{
|
|
EventHandler.OnNitTransportStream(networkId, stream);
|
|
}
|
|
}
|
|
|
|
private IEnumerable<NitTransportStream> UnpackTransportStreams(ushort networkId, byte[] buffer)
|
|
{
|
|
MemoryStream ms = new MemoryStream(buffer, false);
|
|
while ((ms.Length - ms.Position) > 6)
|
|
{
|
|
ushort transportStreamId = ms.ReadUInt16BE();
|
|
ushort originalNetworkId = ms.ReadUInt16BE();
|
|
NitTransportStream child = new NitTransportStream(originalNetworkId, transportStreamId);
|
|
|
|
ushort readUInt16Be = ms.ReadUInt16BE();
|
|
int transportDescriptorsLength = readUInt16Be & 0x0fff;
|
|
if (transportDescriptorsLength > ms.GetAvailableBytes())
|
|
yield break;
|
|
byte[] transportDescriptorBuffer = ms.ReadBytes(transportDescriptorsLength);
|
|
IEnumerable<TsDescriptor> descriptors = TsDescriptorUnpacker.GetInstance().UnpackDescriptors(transportDescriptorBuffer, "NIT");
|
|
foreach (TsDescriptor dvbDescriptor in descriptors)
|
|
{
|
|
switch (dvbDescriptor.GetType().Name)
|
|
{
|
|
case nameof(SatelliteDeliverySystemDescriptor):
|
|
SatelliteDeliverySystemDescriptor satelliteDeliverySystemDescriptor = (SatelliteDeliverySystemDescriptor)dvbDescriptor;
|
|
child.East = satelliteDeliverySystemDescriptor.East;
|
|
child.FecInner = satelliteDeliverySystemDescriptor.FecInner;
|
|
child.Frequency = satelliteDeliverySystemDescriptor.Frequency;
|
|
child.ModulationType = satelliteDeliverySystemDescriptor.ModulationType;
|
|
child.OrbitalPosition = satelliteDeliverySystemDescriptor.OrbitalPosition;
|
|
child.Polarization = satelliteDeliverySystemDescriptor.Polarization;
|
|
child.RollOff = satelliteDeliverySystemDescriptor.RollOff;
|
|
child.S2 = satelliteDeliverySystemDescriptor.S2;
|
|
child.SymbolRate = satelliteDeliverySystemDescriptor.SymbolRate;
|
|
child.DeliveryMethod = NitTransportStream.TransportMedium.DVB_S;
|
|
break;
|
|
case nameof(ServiceListDescriptor):
|
|
ServiceListDescriptor sld = (ServiceListDescriptor)dvbDescriptor;
|
|
child.Services = sld;
|
|
break;
|
|
case nameof(S2SatelliteDeliverySystemDescriptor):
|
|
S2SatelliteDeliverySystemDescriptor s2sdsd = (S2SatelliteDeliverySystemDescriptor)dvbDescriptor;
|
|
child.ScramblingSequenceIndex = s2sdsd.ScramblingSequenceIndex;
|
|
child.InputStreamIdentifier = s2sdsd.InputStreamIdentifier;
|
|
child.TimesliceNumber = s2sdsd.TimesliceNumber;
|
|
child.TsGsMode = s2sdsd.TsGsMode;
|
|
if (child.East.HasValue)
|
|
{
|
|
child.S2 = true;
|
|
child.DeliveryMethod = NitTransportStream.TransportMedium.DVB_S2;
|
|
}
|
|
|
|
break;
|
|
case nameof(PrivateDataSpecifierDescriptor):
|
|
child.PrivateDataSpecifierId = ((PrivateDataSpecifierDescriptor)dvbDescriptor).PrivateDataSpecifier;
|
|
break;
|
|
case nameof(UserDefinedDescriptor):
|
|
if (!child.PrivateDataSpecifierId.HasValue)
|
|
break;
|
|
TsDescriptor unpacked = UserDefinedDescriptorUnpacker.GetInstance().UnpackUserDefinedDescriptor((UserDefinedDescriptor)dvbDescriptor, child.PrivateDataSpecifierId.Value, "NIT");
|
|
if (unpacked == null)
|
|
break;
|
|
HandleUserDefinedDescriptor(unpacked, child);
|
|
break;
|
|
case nameof(LinkageDescriptor):
|
|
child.Linkages.Add((LinkageDescriptor)dvbDescriptor);
|
|
break;
|
|
case nameof(T2DeliverySystemDescriptor):
|
|
child.DeliveryMethod = NitTransportStream.TransportMedium.DVB_T2;
|
|
T2DeliverySystemDescriptor t2dsd = (T2DeliverySystemDescriptor)dvbDescriptor;
|
|
child.TfsFlag = t2dsd.TfsFlag;
|
|
child.Bandwidth = t2dsd.Bandwidth;
|
|
child.CellInfos = t2dsd.CellInfos;
|
|
child.GuardInterval = t2dsd.GuardInterval;
|
|
child.OtherFrequencyFlag = t2dsd.OtherFrequencyFlag;
|
|
child.PlpId = t2dsd.PlpId;
|
|
child.SisoMiso = t2dsd.SisoMiso;
|
|
child.T2SystemId = t2dsd.T2SystemId;
|
|
child.TransmissionMode = t2dsd.TransmissionMode;
|
|
break;
|
|
case nameof(FrequencyListDescriptor):
|
|
FrequencyListDescriptor fld = (FrequencyListDescriptor)dvbDescriptor;
|
|
child.CodingType = fld.CodingType;
|
|
child.CentreFrequencies = fld.CentreFrequencies;
|
|
break;
|
|
case nameof(CellListDescriptor):
|
|
CellListDescriptor cld = (CellListDescriptor)dvbDescriptor;
|
|
child.Cells = cld.Cells;
|
|
break;
|
|
case nameof(CableDeliverySystemDescriptor):
|
|
CableDeliverySystemDescriptor cdsd = (CableDeliverySystemDescriptor)dvbDescriptor;
|
|
child.Frequency = cdsd.Frequency;
|
|
child.SymbolRate = cdsd.SymbolRate;
|
|
child.FecInner = cdsd.FecInner;
|
|
child.FecOuter = cdsd.FecOuter;
|
|
child.ModulationType = cdsd.Modulation;
|
|
child.DeliveryMethod = NitTransportStream.TransportMedium.DVB_C;
|
|
break;
|
|
case nameof(TerristialDeliverySystemDescriptor):
|
|
TerristialDeliverySystemDescriptor tdsd = (TerristialDeliverySystemDescriptor)dvbDescriptor;
|
|
child.Bandwidth = tdsd.Bandwidth;
|
|
child.Frequency = tdsd.CentreFrequency;
|
|
child.CodeRateHpStream = tdsd.CodeRateHpStream;
|
|
child.CodeRateLpStream = tdsd.CodeRateLpStream;
|
|
child.ModulationType = tdsd.Constellation;
|
|
child.GuardInterval = tdsd.GuardInterval;
|
|
child.HierarchyInformation = tdsd.HierarchyInformation;
|
|
child.MpeFecIndicator = tdsd.MpeFecIndicator;
|
|
child.OtherFrequencyFlag = tdsd.OtherFrequencyFlag;
|
|
child.Priority = tdsd.Priority;
|
|
child.TimeSlicingIndicator = tdsd.TimeSlicingIndicator ? 1 : 0;
|
|
child.TransmissionMode = tdsd.TransmissionMode;
|
|
break;
|
|
case nameof(NetworkNameDescriptor):
|
|
NetworkNameDescriptor nnd = (NetworkNameDescriptor)dvbDescriptor;
|
|
child.NetworkName = nnd.NetworkName;
|
|
break;
|
|
case nameof(TargetRegionDescriptor):
|
|
TargetRegionDescriptor trd = (TargetRegionDescriptor)dvbDescriptor;
|
|
child.TargetRegions = trd.TargetRegions;
|
|
child.TargetRegionCountryCode = trd.CountryCode;
|
|
break;
|
|
case nameof(CellFrequencyLinkDescriptor):
|
|
CellFrequencyLinkDescriptor cfld = (CellFrequencyLinkDescriptor)dvbDescriptor;
|
|
child.CellFrequencies = cfld.Cells;
|
|
break;
|
|
default:
|
|
throw new NotImplementedException(dvbDescriptor.GetType().Name);
|
|
}
|
|
}
|
|
|
|
yield return child;
|
|
//EventHandler.OnNitTransportStream(networkId, child);
|
|
}
|
|
}
|
|
|
|
private void HandleUserDefinedDescriptor(TsDescriptor unpacked, NitTransportStream outputTs)
|
|
{
|
|
Attribute customAttribute = unpacked.GetType().GetCustomAttribute(typeof(DescriptorPluginNitHandlerAttribute));
|
|
if (customAttribute == null)
|
|
{
|
|
throw new NotImplementedException(String.Format("{0} has no {1} defined.", unpacked.GetType().Name, nameof(DescriptorPluginNitHandlerAttribute)));
|
|
}
|
|
|
|
DescriptorPluginNitHandlerAttribute handlerAttribute = (DescriptorPluginNitHandlerAttribute)customAttribute;
|
|
handlerAttribute.Handler.HandleNit(outputTs, unpacked);
|
|
}
|
|
}
|
|
}
|