457 lines
15 KiB
C#
457 lines
15 KiB
C#
using Newtonsoft.Json;
|
|
using skyscraper5.Docsis;
|
|
using skyscraper5.Dvb.DataBroadcasting.SkyscraperVfs;
|
|
using skyscraper5.Dvb.Descriptors;
|
|
using skyscraper5.Dvb.Psi.Model;
|
|
using skyscraper5.Mhp.Si.Model;
|
|
using skyscraper5.Mpeg2.Descriptors;
|
|
using skyscraper5.Mpeg2.Psi.Model;
|
|
using skyscraper5.Scte35;
|
|
using skyscraper5.Skyscraper.Net;
|
|
using skyscraper5.Skyscraper.Scraper;
|
|
using skyscraper5.src.Skyscraper.FrequencyListGenerator;
|
|
using skyscraper5.Teletext.Wss;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Xml.Linq;
|
|
|
|
namespace skyscraper5.UI.Overrides
|
|
{
|
|
internal class Form1UiJunction : ISkyscraperUiJunction
|
|
{
|
|
private INodeEngine form1;
|
|
public Dictionary<uint, string> SdtNames { get; private set; }
|
|
public Dictionary<int, uint> PidToPrograms { get; private set; }
|
|
private JsonSerializerSettings jsonSerializerSettings;
|
|
public Dictionary<int, string> UsageLabels { get; private set; }
|
|
|
|
public Form1UiJunction(INodeEngine form1)
|
|
{
|
|
this.form1 = form1;
|
|
this.jsonSerializerSettings = new JsonSerializerSettings();
|
|
this.jsonSerializerSettings.NullValueHandling = NullValueHandling.Ignore;
|
|
this.jsonSerializerSettings.Formatting = Formatting.Indented;
|
|
SetPidUsage(0x0000, "PAT");
|
|
SetPidUsage(0x0001, "CAT");
|
|
SetPidUsage(0x0002, "TSDT");
|
|
SetPidUsage(0x0010, "NIT");
|
|
SetPidUsage(0x0011, "SDT/BAT");
|
|
SetPidUsage(0x0012, "EIT/CIT");
|
|
SetPidUsage(0x0013, "RST");
|
|
SetPidUsage(0x0014, "TDT/TOT");
|
|
SetPidUsage(0x0015, "network synchronization");
|
|
SetPidUsage(0x0016, "RNT");
|
|
SetPidUsage(0x001c, "link-local inband signalling");
|
|
SetPidUsage(0x001d, "measurement");
|
|
SetPidUsage(0x001e, "DIT");
|
|
SetPidUsage(0x001f, "SIT");
|
|
}
|
|
|
|
private void SetPidUsage(int pid, string name)
|
|
{
|
|
if (UsageLabels == null)
|
|
UsageLabels = new Dictionary<int, string>();
|
|
UsageLabels[pid] = name;
|
|
}
|
|
|
|
public void DsmCcModuleAdd(int elementaryPid, ushort moduleInfoModuleId, byte moduleInfoModuleVersion)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void DsmCcModuleComplete(int elementaryPid, ushort moduleModuleId, byte moduleModuleVersion)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void DsmCcModuleProgress(int elementaryPid, ushort moduleInfoModuleId, byte moduleInfoModuleVersion, double moduleInfoDownloadProgress)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void DsmCcVfs(VfsFile vfsFile)
|
|
{
|
|
SkyscraperUiNode dsmCcNode = form1.EnsureNodeExists("DSM-CC");
|
|
form1.SetIcon(dsmCcNode, 1);
|
|
|
|
string outName = String.Format("DSM-CC\\Object Carousels\\PID 0x{0:X4}\\{1}", vfsFile.SourcePid, vfsFile.Name);
|
|
string[] args = outName.Split("\\");
|
|
form1.EnsureNodeExists(args);
|
|
}
|
|
|
|
public IEnumerable<HumanReadableService> GetServices()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void NotifyAit(AitApplication aitApplication)
|
|
{
|
|
SkyscraperUiNode applicationNode = form1.EnsureNodeExists("AIT", aitApplication.TryGetName());
|
|
form1.SetIcon((SkyscraperUiNode)applicationNode.Parent, 1);
|
|
}
|
|
|
|
private Dictionary<ushort, string> bats;
|
|
public void NotifyBat(BatBouquet batBouquet)
|
|
{
|
|
if (bats == null)
|
|
bats = new Dictionary<ushort, string>();
|
|
|
|
string name = String.Format("{0} ({1})", batBouquet.BouquetId, batBouquet.BouquetName);
|
|
if (!bats.ContainsKey(batBouquet.BouquetId))
|
|
bats.Add(batBouquet.BouquetId, name);
|
|
|
|
SkyscraperUiNode bouquetNode = form1.EnsureNodeExists("BAT", name);
|
|
form1.SetIcon((SkyscraperUiNode)bouquetNode.Parent, 1);
|
|
form1.SetIcon(bouquetNode, 7);
|
|
}
|
|
|
|
public void NotifyBatTs(ushort batBouquetBouquetId, BatTransportStream child)
|
|
{
|
|
string name = bats[batBouquetBouquetId];
|
|
string name2 = String.Format("TS #{0}", child.TransportStreamId);
|
|
SkyscraperUiNode batTsNode = form1.EnsureNodeExists("BAT", name, name2);
|
|
form1.SetIcon(batTsNode, 4);
|
|
}
|
|
|
|
public void NotifyBlockstreamCarrier()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void NotifyCat(CaDescriptor caDescriptor)
|
|
{
|
|
string systemName = CaSystemNames.GetHumanReadableName(caDescriptor.CaSystemId);
|
|
string caName = String.Format("0x{0:X4} ({1})",caDescriptor.CaSystemId,systemName);
|
|
SkyscraperUiNode catNode = form1.EnsureNodeExists("CAT", caName);
|
|
if (!catNode.FillOutComplete)
|
|
{
|
|
form1.SetIcon((SkyscraperUiNode)catNode.Parent, 1);
|
|
form1.SetIcon(catNode, 6);
|
|
catNode.DetailedText = JsonConvert.SerializeObject(caDescriptor, jsonSerializerSettings);
|
|
SetPidUsage(caDescriptor.CaPid, String.Format("{0} ECM/EMM", systemName));
|
|
catNode.FillOutComplete = true;
|
|
}
|
|
}
|
|
|
|
public void NotifyDocsisCarrier(DocsisEnvironment docsisEnvironment)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void NotifyDocsisFrequency(uint? frequency, bool isUpstream, object mmm)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void NotifyEvent(EitEvent eitEvent)
|
|
{
|
|
SkyscraperUiNode serviceNode = form1.EnsureNodeExists("EIT", eitEvent.StartTime.ToShortDateString(), eitEvent.ServiceId.ToString());
|
|
form1.SetIcon((SkyscraperUiNode)serviceNode.Parent.Parent, 1);
|
|
form1.SetIcon((SkyscraperUiNode)serviceNode.Parent, 5);
|
|
form1.SetIcon(serviceNode, 8);
|
|
}
|
|
|
|
public void NotifyMpeTraffic(IpTrafficInfo iti, int ipv4PacketLength)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void NotifyNit(NitTransportStream transportStream)
|
|
{
|
|
SkyscraperUiNode nitNode = form1.EnsureNodeExists("NIT", transportStream.RenderForUi());
|
|
if (!nitNode.FillOutComplete)
|
|
{
|
|
nitNode.DetailedText = JsonConvert.SerializeObject(nitNode, jsonSerializerSettings);
|
|
nitNode.FillOutComplete = true;
|
|
form1.SetIcon((SkyscraperUiNode)nitNode.Parent, 1);
|
|
form1.SetIcon(nitNode, 4);
|
|
}
|
|
}
|
|
|
|
public void NotifyPatProgram(int pmtPid, ushort programId)
|
|
{
|
|
string name = String.Format("PMT PID 0x{0:X4} - Program {0}", programId, pmtPid);
|
|
SkyscraperUiNode patNode = form1.EnsureNodeExists("PAT", name);
|
|
form1.SetIcon((SkyscraperUiNode)patNode.Parent, 1);
|
|
}
|
|
|
|
public void NotifyPmtProgram(ProgramMapping result, int pmtPid)
|
|
{
|
|
string name = String.Format("PMT PID 0x{0:X4} - Program {0}", result.ProgramNumber,pmtPid);
|
|
SkyscraperUiNode programNode = form1.EnsureNodeExists("PAT",name);
|
|
if (!programNode.FillOutComplete)
|
|
{
|
|
form1.RunOnUiThread(() => form1.EnsureNodeExists("PAT").Expand());
|
|
|
|
if (!programNode.FillOutComplete)
|
|
{
|
|
programNode.DetailedText = JsonConvert.SerializeObject(result, jsonSerializerSettings);
|
|
programNode.FillOutComplete = true;
|
|
}
|
|
|
|
string sdtName = null;
|
|
form1.RunOnUiThread(() => sdtName = TrySdtFromPmt(result.ProgramNumber));
|
|
if (sdtName != null)
|
|
{
|
|
form1.EnsureNodeExists("PAT", name, String.Format("SDT: {0}", sdtName));
|
|
form1.RunOnUiThread(() => programNode.Expand());
|
|
}
|
|
|
|
foreach (ProgramMappingStream pmtEntry in result.Streams)
|
|
{
|
|
string name2 = String.Format("PID 0x{0:X4}", pmtEntry.ElementaryPid);
|
|
SkyscraperUiNode pidNode = form1.EnsureNodeExists("PAT", name, name2);
|
|
form1.SetIcon((SkyscraperUiNode)pidNode.Parent, 8);
|
|
pidNode.DetailedText = JsonConvert.SerializeObject(pmtEntry, jsonSerializerSettings);
|
|
|
|
if (PidToPrograms == null)
|
|
PidToPrograms = new Dictionary<int, uint>();
|
|
PidToPrograms.Add(pmtEntry.ElementaryPid, result.ProgramNumber);
|
|
SetPidUsage(pmtEntry.ElementaryPid, StreamTypeAsString(pmtEntry,result.PrivateDataSpecifier));
|
|
}
|
|
|
|
PidToPrograms.Add(pmtPid, result.ProgramNumber);
|
|
SetPidUsage(pmtPid, "PMT");
|
|
|
|
programNode.FillOutComplete = true;
|
|
}
|
|
}
|
|
|
|
private string TrySdtFromPmt(ushort programNumber)
|
|
{
|
|
if (!form1.TestForNode("SDT"))
|
|
return null;
|
|
|
|
SkyscraperUiNode sdtNode = form1.EnsureNodeExists("SDT");
|
|
foreach(TreeNode node in sdtNode.Nodes)
|
|
{
|
|
string prefix = String.Format("{0} ", programNumber);
|
|
if (node.Text.StartsWith(prefix))
|
|
{
|
|
string result = node.Text.Substring(node.Text.Length);
|
|
return result;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
public void NotifyScte35(ushort programNumber, SpliceInsert spliceInsert)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void NotifyScte35(ushort programNumber, TimeSignal spliceInsert)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void NotifySdtService(SdtService sdtService)
|
|
{
|
|
string name = String.Format("{0} {1}", sdtService.ServiceId, sdtService.ServiceName);
|
|
SkyscraperUiNode node = form1.EnsureNodeExists("SDT", name);
|
|
if (!node.FillOutComplete)
|
|
{
|
|
if (SdtNames == null)
|
|
SdtNames = new Dictionary<uint, string>();
|
|
SdtNames.Add(sdtService.ServiceId, sdtService.ServiceName);
|
|
|
|
node.DetailedText = JsonConvert.SerializeObject(sdtService, jsonSerializerSettings);
|
|
form1.RunOnUiThread(new Action(() => { TrySdtToPmt(sdtService.ServiceId, sdtService.ServiceName); }));
|
|
form1.SetIcon((SkyscraperUiNode)node.Parent, 1);
|
|
node.FillOutComplete = true;
|
|
}
|
|
}
|
|
|
|
private void TrySdtToPmt(uint programNo, string serviceName)
|
|
{
|
|
if (!form1.TestForNode("PAT"))
|
|
return;
|
|
|
|
string query = String.Format(" {0}", programNo);
|
|
SkyscraperUiNode patNode = form1.EnsureNodeExists("PAT");
|
|
foreach(TreeNode node in patNode.Nodes)
|
|
{
|
|
if (node.Text.EndsWith(query))
|
|
{
|
|
SkyscraperUiNode childNode = new SkyscraperUiNode();
|
|
childNode.Text = String.Format("SDT: {0}", serviceName);
|
|
node.Nodes.Add(childNode);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void NotifyStreamTypeDetection(string contestantTag, int pid)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void NotifyTdt(DateTime utcTime)
|
|
{
|
|
SkyscraperUiNode skyscraperUiNode = form1.EnsureNodeExists("TDT");
|
|
form1.SetIcon(skyscraperUiNode, 1);
|
|
if (skyscraperUiNode.Nodes.Count == 0)
|
|
{
|
|
SkyscraperUiNode child = new SkyscraperUiNode();
|
|
child.Text = utcTime.ToString();
|
|
form1.RunOnUiThread(() =>
|
|
{
|
|
skyscraperUiNode.Nodes.Add(child);
|
|
skyscraperUiNode.Expand();
|
|
}
|
|
);
|
|
form1.SetIcon(child, 3);
|
|
}
|
|
else
|
|
{
|
|
SkyscraperUiNode oldChild = (SkyscraperUiNode)skyscraperUiNode.Nodes[0];
|
|
form1.RunOnUiThread(() => oldChild.Text = utcTime.ToString());
|
|
}
|
|
}
|
|
|
|
public void NotifyTot(DateTime utcTime, LocalTimeOffsetDescriptor ltod)
|
|
{
|
|
|
|
SkyscraperUiNode skyscraperUiNode = form1.EnsureNodeExists("TOT");
|
|
form1.SetIcon(skyscraperUiNode, 1);
|
|
if (skyscraperUiNode.Nodes.Count == 0)
|
|
{
|
|
SkyscraperUiNode child = new SkyscraperUiNode();
|
|
child.Text = utcTime.ToString();
|
|
form1.RunOnUiThread(() =>
|
|
{
|
|
skyscraperUiNode.Nodes.Add(child);
|
|
skyscraperUiNode.Expand();
|
|
}
|
|
);
|
|
if (!child.FillOutComplete)
|
|
{
|
|
form1.SetIcon(child, 3);
|
|
child.DetailedText = JsonConvert.SerializeObject(ltod, jsonSerializerSettings);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SkyscraperUiNode oldChild = (SkyscraperUiNode)skyscraperUiNode.Nodes[0];
|
|
form1.RunOnUiThread(() => oldChild.Text = utcTime.ToString());
|
|
}
|
|
}
|
|
|
|
public void NotifyWss(ushort programNumber, WssDataBlock wssDataBlock)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void SetGseMode()
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void SetMemorySaverMode(bool saveMemory)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void ShowFramegrab(int currentNetworkId, int transportStreamId, ushort mappingProgramNumber, int mappingStreamElementaryPid, byte[] imageData)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
private string StreamTypeAsString(ProgramMappingStream stream, uint? parentRegistrationFormatIdentifier)
|
|
{
|
|
if (stream.StreamType == PmtStreamType.H262)
|
|
return "MPEG-2 Video";
|
|
if (stream.AvcStillPresent.HasValue)
|
|
return "MPEG-4 Video";
|
|
if (stream.AudioType.HasValue)
|
|
{
|
|
switch (stream.AudioType)
|
|
{
|
|
case AudioType.CleanEffects: return "Audio";
|
|
case AudioType.HearingImpaired: return "Audio (for hearing impaired)";
|
|
case AudioType.VisualImpairedCommentary: return "Audio (for visually impaired)";
|
|
}
|
|
}
|
|
|
|
if (stream.StreamType == PmtStreamType.AvcVideoStream)
|
|
{
|
|
return "MPEG-4 Video";
|
|
}
|
|
|
|
if (stream.StreamType == PmtStreamType.Iso11172Audio)
|
|
{
|
|
return "Audio";
|
|
}
|
|
|
|
if (stream.StreamType == PmtStreamType.Iso13818_3Audio)
|
|
return "MPEG-2 Audio";
|
|
if (stream.StreamType == PmtStreamType.Iso13818_7AudioADTS)
|
|
return "AAC Audio";
|
|
if (stream.StreamType == PmtStreamType.HevcVideoStream)
|
|
return "H.265 Video";
|
|
if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.Ac4ChannelMode.HasValue)
|
|
return "Dolby AC-4 Audio";
|
|
if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.BSID.HasValue)
|
|
return "Dolby AC-3 Audio";
|
|
if (stream.StreamType == PmtStreamType.Iso14496_3Audio && stream.AacProfileAndLevel.HasValue)
|
|
return "AAC Audio";
|
|
if ((int)stream.StreamType == 0x81 && stream.ComponentType.HasValue)
|
|
return "Dolby AC-3 Audio";
|
|
if (stream.Teletexts != null)
|
|
return "Teletext";
|
|
|
|
if (stream.Applications != null)
|
|
return "Red-button Application";
|
|
|
|
if (stream.DataBroadcastId == 0x0123)
|
|
return "Red-button Application";
|
|
|
|
if (stream.DataBroadcastId == 0x000a)
|
|
return "System Software Update";
|
|
|
|
if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.Subtitlings != null && stream.Subtitlings.Length > 0)
|
|
return "Subtitle";
|
|
|
|
if (stream.DataBroadcastId == 0xf0)
|
|
return "MHP Application";
|
|
|
|
|
|
if (stream.FormatIdentifier.HasValue && stream.FormatIdentifier == 0x43554549 && (int)stream.StreamType == 0x86)
|
|
return "Advertising Metadata";
|
|
|
|
if ((int)stream.StreamType == 0x86 && parentRegistrationFormatIdentifier.HasValue && parentRegistrationFormatIdentifier.Value == 0x43554549)
|
|
return "Advertising Metadata";
|
|
|
|
if (stream.DataBroadcastId == 0x0007)
|
|
return "Object Carousel";
|
|
|
|
if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.VbiData != null)
|
|
return "Teletext";
|
|
|
|
if ((byte)stream.StreamType == 0x89 && stream.AncillaryDataDescriptor != null && stream.AncillaryDataDescriptor.RdsOnly)
|
|
return "Radio Data Service";
|
|
|
|
if (stream.DataBroadcastId.HasValue && stream.DataBroadcastId.Value == 0x0005 /*&& stream.StreamType == PmtStreamType.Iso13818_6TypeD*/)
|
|
return "Multiprotocol Encapsulation";
|
|
|
|
if (stream.DataBroadcastId == 0x0106)
|
|
return "MHEG-5";
|
|
|
|
if (stream.DataBroadcastId == 0x000b)
|
|
return "IP/MAC Notification";
|
|
|
|
if (stream.RelatedContentDescriptorPresent.HasValue)
|
|
if (stream.RelatedContentDescriptorPresent.Value && stream.StreamType == PmtStreamType.Iso13818_1PrivateSections)
|
|
return "Related Content Table Information";
|
|
|
|
if (stream.NumT2MiStreams.HasValue && stream.StreamType == PmtStreamType.Iso13818_1PesPackets)
|
|
return "T2-MI";
|
|
|
|
return String.Format("??? (Type 0x{0:X2})", (int)stream.StreamType);
|
|
}
|
|
}
|
|
}
|