279 lines
12 KiB
C#
279 lines
12 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.IO;
|
|
using System.Reflection;
|
|
using skyscraper5.Dvb.Descriptors;
|
|
using skyscraper5.Dvb.Psi.Model;
|
|
using skyscraper5.Mpeg2;
|
|
using skyscraper5.Mpeg2.Descriptors;
|
|
using skyscraper5.Skyscraper.IO;
|
|
using skyscraper5.Skyscraper.IO.CrazycatStreamReader;
|
|
using skyscraper5.Skyscraper.Plugins;
|
|
using skyscraper8.Dvb.Descriptors.Extension;
|
|
using skyscraper8.Skyscraper;
|
|
|
|
namespace skyscraper5.Dvb.Psi
|
|
{
|
|
public class EitParser : IPsiProcessor, IMultistandardTable
|
|
{
|
|
public EitParser(IEitEventHandler eventHandler)
|
|
{
|
|
this.EventHandler = eventHandler;
|
|
}
|
|
|
|
public IEitEventHandler EventHandler { get; private set; }
|
|
|
|
public void GatherPsi(PsiSection section, int sourcePid)
|
|
{
|
|
byte[] buffer = section.GetDataCopy();
|
|
MemoryStream ms = new MemoryStream(buffer, false);
|
|
|
|
byte tableId = ms.ReadUInt8();
|
|
ushort readUInt16Be = ms.ReadUInt16BE();
|
|
bool sectionSyntaxIndicator = (readUInt16Be & 0x8000) != 0;
|
|
if (!sectionSyntaxIndicator)
|
|
{
|
|
//According to en_300468v011601p.pdf, page 34 this shall be set to true
|
|
return;
|
|
}
|
|
int sectionLength = (readUInt16Be & 0x0fff);
|
|
|
|
bool isActualTs = false;
|
|
if (tableId == 0x4e)
|
|
isActualTs = true;
|
|
else if (tableId == 0x4f)
|
|
isActualTs = false;
|
|
else if (tableId >= 0x50 && tableId <= 0x5f)
|
|
isActualTs = true;
|
|
else if (tableId >= 0x60 && tableId <= 0x6f)
|
|
isActualTs = false;
|
|
else if (tableId < 0x4e)
|
|
return;
|
|
else if (tableId >= 0x70)
|
|
return;
|
|
else
|
|
throw new NotImplementedException("wait, what?");
|
|
|
|
if (ms.Length <= 14)
|
|
return;
|
|
|
|
ushort serviceId = ms.ReadUInt16BE();
|
|
|
|
byte readUInt8 = ms.ReadUInt8();
|
|
int versionNumber = (readUInt8 & 0x3e);
|
|
bool currentNextIndicator = (readUInt8 & 0x01) != 0;
|
|
|
|
byte sectionNumber = ms.ReadUInt8();
|
|
|
|
byte lastSectionNumber = ms.ReadUInt8();
|
|
|
|
ushort transportStreamId = ms.ReadUInt16BE();
|
|
ushort originalNetworkId = ms.ReadUInt16BE();
|
|
if (isActualTs)
|
|
{
|
|
EventHandler.SetTransportStreamId(transportStreamId);
|
|
EventHandler.SetNetworkId(originalNetworkId);
|
|
}
|
|
|
|
byte segmentLastSectionNumber = ms.ReadUInt8();
|
|
byte lastTableId = ms.ReadUInt8();
|
|
|
|
while ((ms.Length - ms.Position) > 7)
|
|
{
|
|
EitEvent eitEvent = new EitEvent(serviceId, transportStreamId, originalNetworkId);
|
|
eitEvent.EventId = ms.ReadUInt16BE();
|
|
|
|
DateTime? tmp = ms.ReadEtsiEn300468AnnexCDateTime();
|
|
if (tmp == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
eitEvent.StartTime = tmp.Value;
|
|
|
|
eitEvent.Duration = ReadEitDuration(ms);
|
|
|
|
readUInt16Be = ms.ReadUInt16BE();
|
|
eitEvent.RunningStatus = (RunningStatus)((readUInt16Be & 0xe000) >> 13);
|
|
eitEvent.FreeCa = (readUInt16Be & 0x1000) != 0;
|
|
|
|
int descriptorsLoopLength = readUInt16Be & 0x0fff;
|
|
if (ms.GetAvailableBytes() < descriptorsLoopLength)
|
|
break;
|
|
byte[] readBytes = ms.ReadBytes(descriptorsLoopLength);
|
|
UnpackDescriptors(readBytes, eitEvent);
|
|
if (!string.IsNullOrEmpty(eitEvent.EventName))
|
|
EventHandler.OnEitEvent(eitEvent);
|
|
else
|
|
return;
|
|
}
|
|
|
|
uint crc32 = ms.ReadUInt32BE();
|
|
}
|
|
|
|
private static TimeSpan ReadEitDuration(MemoryStream ms)
|
|
{
|
|
long hours = ms.ReadUInt8().UnpackBcd();
|
|
long minutes = ms.ReadUInt8().UnpackBcd();
|
|
long seconds = ms.ReadUInt8().UnpackBcd();
|
|
return new TimeSpan((int)hours, (int)minutes, (int)seconds);
|
|
}
|
|
|
|
private void UnpackDescriptors(byte[] input, EitEvent output)
|
|
{
|
|
IEnumerable<TsDescriptor> dvbDescriptors = TsDescriptorUnpacker.GetInstance().UnpackDescriptors(input, GetTableType());
|
|
foreach (TsDescriptor dvbDescriptor in dvbDescriptors)
|
|
{
|
|
string name = dvbDescriptor.GetType().Name;
|
|
switch (name)
|
|
{
|
|
case nameof(ShortEventDescriptor):
|
|
ShortEventDescriptor shortEventDescriptor = (ShortEventDescriptor)dvbDescriptor;
|
|
if (string.IsNullOrEmpty(shortEventDescriptor.Text) && string.IsNullOrEmpty(shortEventDescriptor.EventName))
|
|
return;
|
|
output.Iso639LanguageCode = shortEventDescriptor.Iso639LanguageCode;
|
|
output.EventName = shortEventDescriptor.EventName;
|
|
output.Text = shortEventDescriptor.Text;
|
|
break;
|
|
case nameof(ExtendedEventDescriptor):
|
|
ExtendedEventDescriptor extendedEventDescriptor = (ExtendedEventDescriptor)dvbDescriptor;
|
|
if (extendedEventDescriptor.Text == null)
|
|
break;
|
|
if (!string.IsNullOrEmpty(output.Iso639LanguageCode))
|
|
{
|
|
if (!output.Iso639LanguageCode.Equals(extendedEventDescriptor.Iso639LanguageCode))
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
output.Iso639LanguageCode = extendedEventDescriptor.Iso639LanguageCode;
|
|
}
|
|
extendedEventDescriptor.Items?.ForEach(output.AddItem);
|
|
if (output.ExtendedText == null)
|
|
output.ExtendedText = new string[extendedEventDescriptor.LastDescriptorNumber + 1];
|
|
if (extendedEventDescriptor.DescriptorNumber == output.ExtendedText.Length)
|
|
{
|
|
string[] resized = new string[output.ExtendedText.Length + 1];
|
|
Array.Copy(output.ExtendedText, 0, resized, 0, output.ExtendedText.Length);
|
|
output.ExtendedText = resized;
|
|
}
|
|
output.ExtendedText[extendedEventDescriptor.DescriptorNumber] = extendedEventDescriptor.Text;
|
|
break;
|
|
case nameof(PdcDescriptor):
|
|
PdcDescriptor pdcDescriptor = (PdcDescriptor)dvbDescriptor;
|
|
if (pdcDescriptor.Valid)
|
|
{
|
|
output.Pdc = new DateTime(output.StartTime.Year, pdcDescriptor.Month, pdcDescriptor.Day,
|
|
pdcDescriptor.Hour, pdcDescriptor.Minute, 0);
|
|
}
|
|
break;
|
|
case nameof(ComponentDescriptor):
|
|
ComponentDescriptor componentDescriptor = (ComponentDescriptor)dvbDescriptor;
|
|
if (!componentDescriptor.Valid)
|
|
break;
|
|
if (output.Components == null)
|
|
output.Components = new HashSet<ComponentDescriptor>();
|
|
output.Components.Add(componentDescriptor);
|
|
break;
|
|
case nameof(ContentDescriptor):
|
|
ContentDescriptor cd = (ContentDescriptor)dvbDescriptor;
|
|
output.Content = cd.Content;
|
|
break;
|
|
case nameof(PrivateDataSpecifierDescriptor):
|
|
output.PrivateDataSpecifier = ((PrivateDataSpecifierDescriptor)dvbDescriptor).PrivateDataSpecifier;
|
|
break;
|
|
case nameof(UserDefinedDescriptor):
|
|
if (!output.PrivateDataSpecifier.HasValue)
|
|
break;
|
|
TsDescriptor unpacked = UserDefinedDescriptorUnpacker.GetInstance().UnpackUserDefinedDescriptor((UserDefinedDescriptor)dvbDescriptor, output.PrivateDataSpecifier.Value, "EIT");
|
|
if (unpacked == null)
|
|
break;
|
|
HandleUserDefinedDescriptor(unpacked, output);
|
|
break;
|
|
case nameof(ParentalRatingDescriptor):
|
|
ParentalRatingDescriptor ratingDescriptor = (ParentalRatingDescriptor)dvbDescriptor;
|
|
output.ParentalRatings = ratingDescriptor.ParentalRatings;
|
|
break;
|
|
case nameof(LinkageDescriptor):
|
|
LinkageDescriptor ld = (LinkageDescriptor)dvbDescriptor;
|
|
output.Linkages.Add(ld);
|
|
break;
|
|
case nameof(CaIdentifierDescriptor):
|
|
CaIdentifierDescriptor cid = (CaIdentifierDescriptor)dvbDescriptor;
|
|
output.CaSystems = cid.CaSystemIds;
|
|
break;
|
|
case nameof(TimeShiftedEventDescriptor):
|
|
TimeShiftedEventDescriptor tsed = (TimeShiftedEventDescriptor)dvbDescriptor;
|
|
output.ReferenceServiceId = tsed.ReferenceServiceId;
|
|
output.ReferenceEventId = tsed.ReferenceEventId;
|
|
break;
|
|
case nameof(ContentIdentifierDescriptor):
|
|
ContentIdentifierDescriptor coid = (ContentIdentifierDescriptor)dvbDescriptor;
|
|
output.Crids = coid.Crids;
|
|
break;
|
|
case nameof(FtaContentManagementDescriptor):
|
|
FtaContentManagementDescriptor fsnd = (FtaContentManagementDescriptor)dvbDescriptor;
|
|
output.ControlRemoteAccessOverInternet = fsnd.ControlRemoteAccessOverInternet;
|
|
output.DoNotApplyRevocation = fsnd.DoNotApplyRevocation;
|
|
output.DoNotScramble = fsnd.DoNotScramble;
|
|
break;
|
|
case nameof(_0x00_ImageIconDescriptor):
|
|
_0x00_ImageIconDescriptor iid = (_0x00_ImageIconDescriptor)dvbDescriptor;
|
|
if (iid.LastDescriptorNumber != 0)
|
|
{
|
|
if (output.IconComponents == null)
|
|
{
|
|
output.IconComponents = new _0x00_ImageIconDescriptor[iid.LastDescriptorNumber];
|
|
}
|
|
output.IconComponents[iid.DescriptiorNumber] = iid;
|
|
}
|
|
else
|
|
{
|
|
output.IconUrl = iid.Url;
|
|
output.IconData = iid.IconData;
|
|
output.IconType = iid.IconType;
|
|
output.IconVerticalOrigin = iid.IconVerticalOrigin;
|
|
output.IconHorizontalOrigin = iid.IconHorizontalOrigin;
|
|
output.IconCoordinateSystem = iid.CoordinateSystem;
|
|
output.IconTransportMode = iid.IconTransportMode;
|
|
}
|
|
break;
|
|
default:
|
|
throw new NotImplementedException(name);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void HandleUserDefinedDescriptor(TsDescriptor unpacked, EitEvent output)
|
|
{
|
|
Attribute customAttribute = unpacked.GetType().GetCustomAttribute(typeof(DescriptorPluginEitHandlerAttribute));
|
|
if (customAttribute == null)
|
|
{
|
|
throw new NotImplementedException(String.Format("{0} has no {1} defined.", unpacked.GetType().Name, nameof(DescriptorPluginEitHandlerAttribute)));
|
|
}
|
|
|
|
DescriptorPluginEitHandlerAttribute handlerAttribute = (DescriptorPluginEitHandlerAttribute)customAttribute;
|
|
handlerAttribute.Handler.HandleEit(output, unpacked);
|
|
}
|
|
|
|
private STD_TYPE standard;
|
|
public void SetStandard(STD_TYPE standard)
|
|
{
|
|
this.standard = standard;
|
|
}
|
|
|
|
private string GetTableType()
|
|
{
|
|
if (IMultistandardTable.IsIsdb(standard))
|
|
{
|
|
return "ISDB EIT";
|
|
}
|
|
else
|
|
{
|
|
return "EIT";
|
|
}
|
|
}
|
|
}
|
|
}
|