1809 lines
46 KiB
C#
1809 lines
46 KiB
C#
using ImGuiNET;
|
|
using SDL2Demo;
|
|
using SDL2Demo.Forms;
|
|
using SDL2Demo.Jobs;
|
|
using SDL2Demo.Net;
|
|
using SDL2Demo.SdlWrapper;
|
|
using skyscraper5.Docsis;
|
|
using skyscraper5.Dvb.DataBroadcasting.SkyscraperVfs;
|
|
using skyscraper5.Dvb.Descriptors;
|
|
using skyscraper5.Dvb.Psi.Model;
|
|
using skyscraper5.Mhp.Descriptors;
|
|
using skyscraper5.Mhp.Si;
|
|
using skyscraper5.Mhp.Si.Model;
|
|
using skyscraper5.Mpeg2.Descriptors;
|
|
using skyscraper5.Mpeg2.Psi.Model;
|
|
using skyscraper5.Scte35;
|
|
using skyscraper5.Skyscraper.Equipment;
|
|
using skyscraper5.Skyscraper.IO.CrazycatStreamReader;
|
|
using skyscraper5.Skyscraper.Net;
|
|
using skyscraper5.Skyscraper.Scraper;
|
|
using skyscraper5.src.Skyscraper.FrequencyListGenerator;
|
|
using skyscraper5.Teletext.Wss;
|
|
using skyscraper8.Skyscraper.Drawing;
|
|
using skyscraper8.Skyscraper.FrequencyListGenerator;
|
|
using skyscraper8.UI.ImGui.Forms;
|
|
using SkyscraperUI;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Diagnostics;
|
|
using System.Drawing;
|
|
using System.Linq;
|
|
using System.Numerics;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using System.Xml.Serialization;
|
|
using testdrid.SdlWrapper;
|
|
using static SDL2Demo.Jobs.Blindscan;
|
|
|
|
namespace SDL2Demo.Jobs
|
|
{
|
|
internal class InheritedBlindscanUiJunction : ISkyscraperUiJunction, IRenderable
|
|
{
|
|
|
|
#region During TS scraping
|
|
|
|
DateTime prev, next;
|
|
private bool secondTick;
|
|
public void Render()
|
|
{
|
|
prev = next;
|
|
next = DateTime.Now;
|
|
secondTick = prev.Second != next.Second;
|
|
|
|
RenderPat();
|
|
RenderSdt();
|
|
RenderNit();
|
|
RenderCat();
|
|
RenderPmt();
|
|
RenderTdt();
|
|
RenderEit();
|
|
RenderAit();
|
|
RenderTot();
|
|
RenderBat();
|
|
RenderObjectCarousels();
|
|
RenderMpe();
|
|
RenderDataCarousels();
|
|
}
|
|
|
|
private void ResetWindows()
|
|
{
|
|
HasSdt = false;
|
|
sdtDisplay = null;
|
|
sdtTableUuid = null;
|
|
HasPat = false;
|
|
TsType = 0;
|
|
patDisplay = null;
|
|
patTableUuid = null;
|
|
HasPmt = false;
|
|
pmtTabBarUuid = null;
|
|
nitDisplay = null;
|
|
nitTableUuid = null;
|
|
HasNit = false;
|
|
streamTypes = null;
|
|
caTableUuid = null;
|
|
caDisplay = null;
|
|
HasCat = false;
|
|
tdtDisplay = null;
|
|
HasTdt = false;
|
|
eitDisplay = null;
|
|
aitDisplay = null;
|
|
aitTableUuid = null;
|
|
HasAit = false;
|
|
totTime = null;
|
|
totDescriptor = null;
|
|
totDisplayUuid = null;
|
|
HasTot = false;
|
|
batDisplay = null;
|
|
HasBat = false;
|
|
displayObjectCarouselRoots = null;
|
|
HasDsmCc = false;
|
|
trafficInfoComparer = null;
|
|
mpeTableUuid = null;
|
|
mpeDisplays = null;
|
|
trafficInfoComparer = null;
|
|
mpeTableUuid = null;
|
|
mpeDisplays = null;
|
|
HasMpe = false;
|
|
dsmCcDisplay = null;
|
|
objectCarouselTableUuid = null;
|
|
if (framegrabWindows != null)
|
|
{
|
|
while (framegrabWindows.Count > 0)
|
|
{
|
|
PictureWindow pictureWindow = framegrabWindows.Dequeue();
|
|
pictureWindow.Dispose();
|
|
}
|
|
}
|
|
}
|
|
|
|
private void SafeText(string s)
|
|
{
|
|
if (string.IsNullOrEmpty(s))
|
|
{
|
|
ImGui.Text("<null>");
|
|
return;
|
|
}
|
|
|
|
if (string.IsNullOrWhiteSpace(s))
|
|
{
|
|
ImGui.Text("[null]");
|
|
return;
|
|
}
|
|
|
|
if (s.Contains("% "))
|
|
s = s.Replace("% ", "%% ");
|
|
|
|
ImGui.Text(s);
|
|
}
|
|
|
|
#region EIT
|
|
private struct EitEventCoordinate
|
|
{
|
|
public DateTime StartTime;
|
|
public ushort NetworkId;
|
|
public ushort ServiceId;
|
|
}
|
|
|
|
private struct EitDay
|
|
{
|
|
public DateTime Date;
|
|
public bool Visible;
|
|
public Guid tableGuid;
|
|
}
|
|
|
|
private class EitDayComparer : IComparer<EitDay>
|
|
{
|
|
public int Compare(EitDay x, EitDay y)
|
|
{
|
|
return x.Date.CompareTo(y.Date);
|
|
}
|
|
}
|
|
|
|
private class EitEventCoordinateComparer : IComparer<EitEventCoordinate>
|
|
{
|
|
public int Compare(EitEventCoordinate x, EitEventCoordinate y)
|
|
{
|
|
return x.StartTime.Ticks.CompareTo(y.StartTime.Ticks);
|
|
}
|
|
}
|
|
|
|
private bool HasEit;
|
|
private SortedList<EitDay, SortedList<EitEventCoordinate, string>> eitDisplay;
|
|
private void RenderEit()
|
|
{
|
|
if (eitDisplay == null)
|
|
return;
|
|
|
|
if (ImGui.Begin("Event Information Table"))
|
|
{
|
|
lock (eitDisplay)
|
|
{
|
|
foreach (KeyValuePair<EitDay, SortedList<EitEventCoordinate, string>> keyValuePair in eitDisplay)
|
|
{
|
|
EitDay day = keyValuePair.Key;
|
|
if (ImGui.CollapsingHeader(keyValuePair.Key.Date.ToLongDateString(), ref day.Visible))
|
|
{
|
|
if (day.tableGuid == Guid.Empty)
|
|
day.tableGuid = Guid.NewGuid();
|
|
ImGui.BeginTable(day.ToString(), 3,
|
|
ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.NoSavedSettings);
|
|
foreach (KeyValuePair<EitEventCoordinate, string> valuePair in keyValuePair.Value)
|
|
{
|
|
ImGui.TableNextRow();
|
|
ImGui.TableSetColumnIndex(0);
|
|
SafeText(valuePair.Key.StartTime.ToShortTimeString());
|
|
ImGui.TableSetColumnIndex(1);
|
|
string sName = ResolveServiceDisplayName(valuePair.Key.ServiceId);
|
|
SafeText(sName);
|
|
ImGui.TableSetColumnIndex(2);
|
|
SafeText(valuePair.Value);
|
|
}
|
|
|
|
ImGui.EndTable();
|
|
}
|
|
}
|
|
}
|
|
|
|
ImGui.End();
|
|
}
|
|
}
|
|
|
|
public void NotifyEvent(EitEvent eitEvent)
|
|
{
|
|
if (eitDisplay == null)
|
|
eitDisplay = new SortedList<EitDay, SortedList<EitEventCoordinate, string>>(new EitDayComparer());
|
|
|
|
TsType = 1;
|
|
HasEit = true;
|
|
|
|
EitDay date = new EitDay();
|
|
date.Date = eitEvent.StartTime.Date;
|
|
date.Visible = true;
|
|
lock (eitDisplay)
|
|
{
|
|
if (!eitDisplay.ContainsKey(date))
|
|
{
|
|
eitDisplay[date] = new SortedList<EitEventCoordinate, string>(new EitEventCoordinateComparer());
|
|
}
|
|
|
|
SortedList<EitEventCoordinate, string> sortedList = eitDisplay[date];
|
|
|
|
EitEventCoordinate coordinate = new EitEventCoordinate();
|
|
coordinate.StartTime = eitEvent.StartTime;
|
|
coordinate.NetworkId = eitEvent.OriginalNetworkId;
|
|
coordinate.ServiceId = eitEvent.ServiceId;
|
|
if (!sortedList.ContainsKey(coordinate))
|
|
{
|
|
sortedList.Add(coordinate, eitEvent.EventName);
|
|
}
|
|
}
|
|
}
|
|
|
|
#endregion EIT
|
|
|
|
|
|
#region SDT
|
|
|
|
private bool HasSdt;
|
|
|
|
private string ResolveServiceDisplayName(ushort serviceId)
|
|
{
|
|
if (sdtDisplay == null)
|
|
return String.Format("0x{0:X4}", serviceId);
|
|
|
|
lock (sdtDisplay)
|
|
{
|
|
if (sdtDisplay.ContainsKey(serviceId))
|
|
{
|
|
string v = sdtDisplay[serviceId].ServiceName;
|
|
if (string.IsNullOrEmpty(v))
|
|
return "???";
|
|
else
|
|
return v;
|
|
}
|
|
}
|
|
|
|
return String.Format("0x{0:X4}", serviceId);
|
|
}
|
|
|
|
private SdtCoordinate ResolveService(ushort serviceId)
|
|
{
|
|
if (sdtDisplay == null)
|
|
return new SdtCoordinate();
|
|
|
|
lock (sdtDisplay)
|
|
{
|
|
if (sdtDisplay.ContainsKey(serviceId))
|
|
{
|
|
return sdtDisplay[serviceId];
|
|
}
|
|
}
|
|
|
|
return new SdtCoordinate();
|
|
}
|
|
|
|
private struct SdtCoordinate
|
|
{
|
|
public string ProviderName;
|
|
public string ServiceName;
|
|
public bool FreeCaMode;
|
|
public ushort[] CaIdentifiers;
|
|
public ServiceDescriptor.ServiceTypeCoding? ServiceType;
|
|
}
|
|
|
|
private SortedList<ushort, SdtCoordinate> sdtDisplay;
|
|
private string sdtTableUuid;
|
|
private void RenderSdt()
|
|
{
|
|
if (sdtDisplay == null)
|
|
return;
|
|
|
|
if (string.IsNullOrEmpty(sdtTableUuid))
|
|
sdtTableUuid = Guid.NewGuid().ToString();
|
|
|
|
|
|
ImGui.Begin("Service Description Table");
|
|
if (ImGui.BeginTable(sdtTableUuid, 4, ImGuiTableFlags.NoSavedSettings | ImGuiTableFlags.SizingFixedFit))
|
|
{
|
|
ImGui.TableSetupColumn("Service ID");
|
|
ImGui.TableSetupColumn("Name");
|
|
ImGui.TableSetupColumn("Provider");
|
|
ImGui.TableSetupColumn("CA");
|
|
ImGui.TableHeadersRow();
|
|
|
|
lock (sdtDisplay)
|
|
{
|
|
foreach (KeyValuePair<ushort, SdtCoordinate> keyValuePair in sdtDisplay)
|
|
{
|
|
ImGui.TableNextRow();
|
|
ImGui.TableSetColumnIndex(0);
|
|
SafeText(String.Format("{0:X4}", keyValuePair.Key));
|
|
|
|
ImGui.TableSetColumnIndex(1);
|
|
SafeText(keyValuePair.Value.ServiceName);
|
|
|
|
ImGui.TableSetColumnIndex(2);
|
|
SafeText(keyValuePair.Value.ProviderName);
|
|
|
|
ImGui.TableSetColumnIndex(3);
|
|
bool ca = keyValuePair.Value.FreeCaMode;
|
|
ImGui.BeginDisabled(true);
|
|
ImGui.Checkbox("", ref ca);
|
|
ImGui.EndDisabled();
|
|
}
|
|
}
|
|
|
|
ImGui.EndTable();
|
|
ImGui.End();
|
|
}
|
|
}
|
|
|
|
public void NotifySdtService(SdtService sdtService)
|
|
{
|
|
TsType = 1;
|
|
HasSdt = true;
|
|
if (sdtDisplay == null)
|
|
sdtDisplay = new SortedList<ushort, SdtCoordinate>();
|
|
|
|
if (sdtDisplay.ContainsKey(sdtService.ServiceId))
|
|
return;
|
|
|
|
SdtCoordinate child = new SdtCoordinate();
|
|
child.ProviderName = sdtService.ServiceProviderName;
|
|
child.ServiceName = sdtService.ServiceName;
|
|
child.FreeCaMode = sdtService.FreeCaMode;
|
|
child.CaIdentifiers = sdtService.CaIdentifiers;
|
|
child.ServiceType = sdtService.ServiceType;
|
|
|
|
lock (sdtDisplay)
|
|
{
|
|
sdtDisplay.Add(sdtService.ServiceId, child);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region PAT
|
|
private class PatEntry
|
|
{
|
|
public ushort programId;
|
|
public ProgramMapping pmt;
|
|
public string PmtViewUuid;
|
|
}
|
|
|
|
private bool HasPat;
|
|
private int TsType;
|
|
private SortedList<int, PatEntry> patDisplay;
|
|
public void NotifyPatProgram(int pmtPid, ushort programId)
|
|
{
|
|
HasPat = true;
|
|
TsType = 1;
|
|
|
|
if (patDisplay == null)
|
|
patDisplay = new SortedList<int, PatEntry>();
|
|
|
|
if (patDisplay.ContainsKey(pmtPid))
|
|
return;
|
|
|
|
PatEntry patEntry = new PatEntry();
|
|
patEntry.programId = programId;
|
|
lock (patDisplay)
|
|
{
|
|
patDisplay.Add(pmtPid, patEntry);
|
|
}
|
|
}
|
|
|
|
private string patTableUuid;
|
|
public void RenderPat()
|
|
{
|
|
if (patDisplay == null)
|
|
return;
|
|
|
|
if (string.IsNullOrEmpty(patTableUuid))
|
|
patTableUuid = Guid.NewGuid().ToString();
|
|
if (ImGui.Begin("Program Allocation Table"))
|
|
{
|
|
if (ImGui.BeginTable(patTableUuid, 2, ImGuiTableFlags.NoSavedSettings | ImGuiTableFlags.SizingFixedFit))
|
|
{
|
|
ImGui.TableSetupColumn("PMT PID");
|
|
ImGui.TableSetupColumn("Service");
|
|
ImGui.TableHeadersRow();
|
|
|
|
lock (patDisplay)
|
|
{
|
|
foreach (KeyValuePair<int, PatEntry> keyValuePair in patDisplay)
|
|
{
|
|
string k = String.Format("0x{0:X4}", keyValuePair.Key);
|
|
string v = ResolveServiceDisplayName(keyValuePair.Value.programId);
|
|
if (v == null)
|
|
v = "???";
|
|
|
|
ImGui.TableNextRow();
|
|
ImGui.TableSetColumnIndex(0);
|
|
SafeText(k);
|
|
|
|
ImGui.TableSetColumnIndex(1);
|
|
SafeText(v);
|
|
}
|
|
}
|
|
ImGui.EndTable();
|
|
}
|
|
ImGui.End();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region PMT
|
|
|
|
private bool HasPmt;
|
|
public void NotifyPmtProgram(ProgramMapping result, int pmtPid)
|
|
{
|
|
HasPmt = true;
|
|
TsType = 1;
|
|
|
|
if (!patDisplay.ContainsKey(pmtPid))
|
|
return;
|
|
|
|
PatEntry patEntry = patDisplay[pmtPid];
|
|
if (patEntry.pmt != null)
|
|
return;
|
|
|
|
patEntry.pmt = result;
|
|
}
|
|
|
|
|
|
private string pmtTabBarUuid;
|
|
public void RenderPmt()
|
|
{
|
|
if (!HasPmt)
|
|
return;
|
|
|
|
if (string.IsNullOrEmpty(pmtTabBarUuid))
|
|
pmtTabBarUuid = Guid.NewGuid().ToString();
|
|
|
|
if (ImGui.Begin("Program Map Table"))
|
|
{
|
|
if (ImGui.BeginTabBar(pmtTabBarUuid, ImGuiTabBarFlags.FittingPolicyScroll | ImGuiTabBarFlags.TabListPopupButton))
|
|
{
|
|
lock (patDisplay)
|
|
{
|
|
foreach (KeyValuePair<int, PatEntry> keyValuePair in patDisplay)
|
|
{
|
|
if (ImGui.BeginTabItem(ResolveServiceDisplayName(keyValuePair.Value.programId)))
|
|
{
|
|
if (string.IsNullOrEmpty(keyValuePair.Value.PmtViewUuid))
|
|
keyValuePair.Value.PmtViewUuid = Guid.NewGuid().ToString();
|
|
|
|
if (keyValuePair.Value.pmt == null)
|
|
continue;
|
|
|
|
ProgramMapping pmt = keyValuePair.Value.pmt;
|
|
|
|
SafeText(String.Format("Service ID: 0x{0:X4}", pmt.ProgramNumber));
|
|
|
|
ImGui.BeginTable(keyValuePair.Value.PmtViewUuid, 2, ImGuiTableFlags.NoSavedSettings);
|
|
ImGui.TableSetupColumn("PID");
|
|
ImGui.TableSetupColumn("Type");
|
|
ImGui.TableHeadersRow();
|
|
|
|
ImGui.TableNextRow();
|
|
ImGui.TableSetColumnIndex(0);
|
|
SafeText(String.Format("0x{0:X4}", keyValuePair.Key));
|
|
|
|
ImGui.TableSetColumnIndex(1);
|
|
SafeText("PMT");
|
|
|
|
ImGui.TableNextRow();
|
|
ImGui.TableSetColumnIndex(0);
|
|
SafeText(String.Format("0x{0:X4}", keyValuePair.Value.pmt.PcrPid));
|
|
|
|
ImGui.TableSetColumnIndex(1);
|
|
SafeText("PCR");
|
|
|
|
foreach (ProgramMappingStream programMappingStream in pmt.Streams)
|
|
{
|
|
ImGui.TableNextRow();
|
|
ImGui.TableSetColumnIndex(0);
|
|
SafeText(String.Format("0x{0:X4}", programMappingStream.ElementaryPid));
|
|
|
|
ImGui.TableSetColumnIndex(1);
|
|
SafeText(StreamTypeAsString(programMappingStream, pmt.RegistrationFormatIdentifier));
|
|
}
|
|
|
|
ImGui.EndTable();
|
|
ImGui.EndTabItem();
|
|
}
|
|
}
|
|
}
|
|
ImGui.EndTabBar();
|
|
}
|
|
ImGui.End();
|
|
}
|
|
}
|
|
|
|
private string StreamTypeAsString(ProgramMappingStream stream, uint? parentRegistrationFormatIdentifier)
|
|
{
|
|
if (streamTypes != null)
|
|
{
|
|
if (streamTypes.ContainsKey(stream.ElementaryPid))
|
|
{
|
|
return streamTypes[stream.ElementaryPid];
|
|
}
|
|
}
|
|
if (stream.StreamType == PmtStreamType.H262)
|
|
return "MPEG-2 Video";
|
|
if (stream.AvcStillPresent.HasValue)
|
|
return "MPEG-4 Video (still frame)";
|
|
if (stream.AudioType.HasValue)
|
|
{
|
|
switch (stream.AudioType)
|
|
{
|
|
case AudioType.CleanEffects: return "Audio (no effects)";
|
|
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.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.Subtitlings != null && stream.Subtitlings.Length > 0)
|
|
return "Subtitle";
|
|
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);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region NIT
|
|
|
|
private class NitNetworkMeta
|
|
{
|
|
public ushort ONID;
|
|
public string DisplayUUID;
|
|
|
|
public override string ToString()
|
|
{
|
|
return String.Format("Network 0x{0:X4}", ONID);
|
|
}
|
|
|
|
public bool Equals(NitNetworkMeta other)
|
|
{
|
|
return ONID == other.ONID;
|
|
}
|
|
|
|
public override bool Equals(object? obj)
|
|
{
|
|
return obj is NitNetworkMeta other && Equals(other);
|
|
}
|
|
|
|
public override int GetHashCode()
|
|
{
|
|
return ONID.GetHashCode();
|
|
}
|
|
}
|
|
|
|
private class NitCoordinateComparer : IComparer<NitNetworkMeta>
|
|
{
|
|
public int Compare(NitNetworkMeta x, NitNetworkMeta y)
|
|
{
|
|
return x.ONID.CompareTo(y.ONID);
|
|
}
|
|
}
|
|
|
|
private SortedList<NitNetworkMeta, SortedList<ushort, NitTransportStream>> nitDisplay;
|
|
private string nitTableUuid;
|
|
private bool HasNit;
|
|
|
|
public void NotifyNit(NitTransportStream transportStream)
|
|
{
|
|
TsType = 1;
|
|
HasNit = true;
|
|
|
|
if (nitDisplay == null)
|
|
nitDisplay = new SortedList<NitNetworkMeta, SortedList<ushort, NitTransportStream>>(new NitCoordinateComparer());
|
|
|
|
NitNetworkMeta nnm = new NitNetworkMeta();
|
|
nnm.ONID = transportStream.OriginalNetworkId;
|
|
if (!nitDisplay.ContainsKey(nnm))
|
|
{
|
|
lock (nitDisplay)
|
|
{
|
|
nitDisplay.Add(nnm, new SortedList<ushort, NitTransportStream>());
|
|
}
|
|
}
|
|
|
|
SortedList<ushort, NitTransportStream> nitTransportStreams = nitDisplay[nnm];
|
|
if (nitTransportStreams.ContainsKey(transportStream.TransportStreamId))
|
|
return;
|
|
|
|
lock (nitTransportStreams)
|
|
{
|
|
nitTransportStreams.Add(transportStream.TransportStreamId, transportStream);
|
|
}
|
|
}
|
|
|
|
private string GetFrequencyString(NitTransportStream nts)
|
|
{
|
|
if (nts.Frequency.HasValue && nts.Polarization.HasValue)
|
|
return String.Format("{0} Mhz, {1}", nts.Frequency.Value / 100, nts.Polarization.ToString().Substring(0, 1));
|
|
|
|
return "???";
|
|
}
|
|
|
|
private void RenderNit()
|
|
{
|
|
if (nitDisplay == null)
|
|
return;
|
|
|
|
if (string.IsNullOrWhiteSpace(nitTableUuid))
|
|
nitTableUuid = Guid.NewGuid().ToString();
|
|
|
|
if (ImGui.Begin("Network Information Table"))
|
|
{
|
|
lock (nitDisplay)
|
|
{
|
|
foreach (KeyValuePair<NitNetworkMeta, SortedList<ushort, NitTransportStream>> keyValuePair in nitDisplay)
|
|
{
|
|
if (ImGui.CollapsingHeader(keyValuePair.Key.ToString()))
|
|
{
|
|
if (string.IsNullOrEmpty(keyValuePair.Key.DisplayUUID))
|
|
keyValuePair.Key.DisplayUUID = Guid.NewGuid().ToString();
|
|
if (ImGui.BeginTable(keyValuePair.Key.DisplayUUID, 4, ImGuiTableFlags.NoSavedSettings | ImGuiTableFlags.SizingFixedFit))
|
|
{
|
|
lock (keyValuePair.Value)
|
|
{
|
|
foreach (KeyValuePair<ushort, NitTransportStream> nitTransportStream in keyValuePair
|
|
.Value)
|
|
{
|
|
ImGui.TableNextRow();
|
|
ImGui.TableSetColumnIndex(0);
|
|
SafeText(nitTransportStream.Value.DeliveryMethod.ToString().Replace('_', '_'));
|
|
|
|
ImGui.TableSetColumnIndex(1);
|
|
if (nitTransportStream.Value.OrbitalPosition.HasValue &&
|
|
nitTransportStream.Value.East.HasValue)
|
|
{
|
|
SafeText(String.Format("{0:F1} °{1}",
|
|
nitTransportStream.Value.OrbitalPosition.Value,
|
|
nitTransportStream.Value.East.Value ? "E" : "W"));
|
|
}
|
|
|
|
ImGui.TableSetColumnIndex(2);
|
|
SafeText(GetFrequencyString(nitTransportStream.Value));
|
|
|
|
ImGui.TableSetColumnIndex(3);
|
|
if (nitTransportStream.Value.SymbolRate.HasValue)
|
|
SafeText(String.Format("{0} ksym/s",
|
|
nitTransportStream.Value.SymbolRate / 10));
|
|
}
|
|
}
|
|
}
|
|
ImGui.EndTable();
|
|
}
|
|
}
|
|
}
|
|
ImGui.End();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region MPE
|
|
|
|
private IpTrafficInfoComparer trafficInfoComparer;
|
|
private string mpeTableUuid;
|
|
private List<KeyValuePair<IpTrafficInfo, IpPerformanceInfo>> mpeDisplays;
|
|
private bool HasMpe;
|
|
|
|
public void NotifyMpeTraffic(IpTrafficInfo iti, int ipv4PacketLength)
|
|
{
|
|
if (trafficInfoComparer == null)
|
|
trafficInfoComparer = new IpTrafficInfoComparer();
|
|
HasMpe = true;
|
|
if (mpeDisplays == null)
|
|
mpeDisplays = new List<KeyValuePair<IpTrafficInfo, IpPerformanceInfo>>();
|
|
|
|
lock (mpeDisplays)
|
|
{
|
|
foreach (KeyValuePair<IpTrafficInfo, IpPerformanceInfo> line in mpeDisplays)
|
|
{
|
|
if (line.Key.Equals(iti))
|
|
{
|
|
line.Value.CountPacket(ipv4PacketLength);
|
|
return;
|
|
}
|
|
}
|
|
|
|
KeyValuePair<IpTrafficInfo, IpPerformanceInfo> newChild = new KeyValuePair<IpTrafficInfo, IpPerformanceInfo>(iti, new IpPerformanceInfo());
|
|
newChild.Value.CountPacket(ipv4PacketLength);
|
|
mpeDisplays.Add(newChild);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
private void RenderMpe()
|
|
{
|
|
if (mpeDisplays == null)
|
|
return;
|
|
|
|
if (secondTick)
|
|
{
|
|
lock (mpeDisplays)
|
|
{
|
|
foreach (KeyValuePair<IpTrafficInfo, IpPerformanceInfo> line in mpeDisplays)
|
|
{
|
|
line.Value.UpdatePerSeconds();
|
|
}
|
|
}
|
|
}
|
|
|
|
string windowName = String.Format("{0} Encapsulation", TsType == 1 ? "Multiprotocol" : "Generic Stream");
|
|
if (ImGui.Begin(windowName))
|
|
{
|
|
if (mpeDisplays != null)
|
|
{
|
|
if (mpeDisplays.Count > 0)
|
|
{
|
|
SafeText(String.Format("Communication parties: {0}", mpeDisplays.Count));
|
|
}
|
|
}
|
|
if (string.IsNullOrEmpty(mpeTableUuid))
|
|
mpeTableUuid = Guid.NewGuid().ToString();
|
|
if (ImGui.BeginTable(mpeTableUuid, 5, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.NoSavedSettings))
|
|
{
|
|
ImGui.TableSetupColumn("Protocol");
|
|
ImGui.TableSetupColumn("Source IP");
|
|
ImGui.TableSetupColumn("Destination IP");
|
|
ImGui.TableSetupColumn("Packets");
|
|
ImGui.TableSetupColumn("Traffic");
|
|
ImGui.TableHeadersRow();
|
|
|
|
lock (mpeDisplays)
|
|
{
|
|
mpeDisplays.Sort(trafficInfoComparer);
|
|
foreach (KeyValuePair<IpTrafficInfo, IpPerformanceInfo> ipPerformanceInfo in mpeDisplays)
|
|
{
|
|
|
|
ImGui.TableNextRow();
|
|
ImGui.TableSetColumnIndex(0);
|
|
SafeText(IpTrafficInfo.GetProtocolName(ipPerformanceInfo.Key.Protocol));
|
|
|
|
ImGui.TableSetColumnIndex(1);
|
|
SafeText(RenderIp(ipPerformanceInfo, false));
|
|
|
|
ImGui.TableSetColumnIndex(2);
|
|
SafeText(RenderIp(ipPerformanceInfo, true));
|
|
|
|
ImGui.TableSetColumnIndex(3);
|
|
SafeText(ipPerformanceInfo.Value.TotalPackets.ToString());
|
|
|
|
ImGui.TableSetColumnIndex(4);
|
|
SafeText(String.Format("{0:F1} kb/s",
|
|
(double)ipPerformanceInfo.Value.BytesPerSecond / 1000.0));
|
|
}
|
|
}
|
|
|
|
ImGui.EndTable();
|
|
}
|
|
ImGui.End();
|
|
}
|
|
}
|
|
|
|
private string RenderIp(KeyValuePair<IpTrafficInfo, IpPerformanceInfo> ipPerformanceInfo, bool destination)
|
|
{
|
|
if (!destination)
|
|
{
|
|
if (string.IsNullOrEmpty(ipPerformanceInfo.Key.SourceName))
|
|
return ipPerformanceInfo.Key.Source.ToString();
|
|
else
|
|
return ipPerformanceInfo.Key.SourceName;
|
|
}
|
|
else
|
|
{
|
|
if (string.IsNullOrEmpty(ipPerformanceInfo.Key.TargetName))
|
|
return ipPerformanceInfo.Key.Target.ToString();
|
|
else
|
|
return ipPerformanceInfo.Key.TargetName;
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region AIT
|
|
|
|
private SortedList<ApplicationIdentifier, AitApplication> aitDisplay;
|
|
private string aitTableUuid;
|
|
private bool HasAit;
|
|
public void NotifyAit(AitApplication aitApplication)
|
|
{
|
|
TsType = 1;
|
|
HasAit = true;
|
|
|
|
if (aitDisplay == null)
|
|
aitDisplay = new SortedList<ApplicationIdentifier, AitApplication>(new ApplicationIdentifierComparer());
|
|
|
|
lock (aitDisplay)
|
|
{
|
|
if (!aitDisplay.ContainsKey(aitApplication.ApplicationIdentifier))
|
|
{
|
|
aitDisplay.Add(aitApplication.ApplicationIdentifier, aitApplication);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void RenderAit()
|
|
{
|
|
if (aitDisplay == null)
|
|
return;
|
|
|
|
if (ImGui.Begin("Application Identification Table"))
|
|
{
|
|
if (string.IsNullOrEmpty(aitTableUuid))
|
|
aitTableUuid = Guid.NewGuid().ToString();
|
|
|
|
if (ImGui.BeginTable(aitTableUuid, 2, ImGuiTableFlags.NoSavedSettings | ImGuiTableFlags.SizingFixedFit))
|
|
{
|
|
ImGui.TableSetupColumn("Application Name");
|
|
ImGui.TableSetupColumn("Transport");
|
|
ImGui.TableHeadersRow();
|
|
|
|
lock (aitDisplay)
|
|
{
|
|
foreach (KeyValuePair<ApplicationIdentifier, AitApplication> keyValuePair in aitDisplay)
|
|
{
|
|
ImGui.TableNextRow();
|
|
ImGui.TableSetColumnIndex(0);
|
|
SafeText(keyValuePair.Value.TryGetName());
|
|
|
|
ImGui.TableSetColumnIndex(1);
|
|
foreach (TransportProtocolDescriptor transportProtocolDescriptor in keyValuePair.Value.TransportProtocols)
|
|
{
|
|
SafeText(transportProtocolDescriptor.Selector.ToString());
|
|
}
|
|
}
|
|
}
|
|
|
|
ImGui.EndTable();
|
|
}
|
|
ImGui.End();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region DSM-CC Modules
|
|
|
|
private struct DsmCcModuleIdentifier
|
|
{
|
|
public int pid;
|
|
public ushort moduleId;
|
|
public byte moduleVersion;
|
|
|
|
}
|
|
|
|
private sealed class DsmCcModuleIdentifierComparer : IComparer<DsmCcModuleIdentifier>
|
|
{
|
|
public int Compare(DsmCcModuleIdentifier x, DsmCcModuleIdentifier y)
|
|
{
|
|
var pidComparison = x.pid.CompareTo(y.pid);
|
|
if (pidComparison != 0) return pidComparison;
|
|
var moduleIdComparison = x.moduleId.CompareTo(y.moduleId);
|
|
if (moduleIdComparison != 0) return moduleIdComparison;
|
|
return x.moduleVersion.CompareTo(y.moduleVersion);
|
|
}
|
|
}
|
|
|
|
|
|
private SortedList<DsmCcModuleIdentifier, double> dsmCcDisplay;
|
|
private string objectCarouselTableUuid;
|
|
|
|
public void DsmCcModuleAdd(int elementaryPid, ushort moduleInfoModuleId, byte moduleInfoModuleVersion)
|
|
{
|
|
TsType = 1;
|
|
HasDsmCc = true;
|
|
|
|
if (dsmCcDisplay == null)
|
|
dsmCcDisplay = new SortedList<DsmCcModuleIdentifier, double>(new DsmCcModuleIdentifierComparer());
|
|
|
|
DsmCcModuleIdentifier id = new DsmCcModuleIdentifier();
|
|
id.pid = elementaryPid;
|
|
id.moduleId = moduleInfoModuleId;
|
|
id.moduleVersion = moduleInfoModuleVersion;
|
|
|
|
if (dsmCcDisplay.ContainsKey(id))
|
|
return;
|
|
|
|
lock (dsmCcDisplay)
|
|
{
|
|
dsmCcDisplay.Add(id, 0);
|
|
}
|
|
}
|
|
|
|
public void DsmCcModuleProgress(int elementaryPid, ushort moduleInfoModuleId, byte moduleInfoModuleVersion,
|
|
double moduleInfoDownloadProgress)
|
|
{
|
|
TsType = 1;
|
|
HasDsmCc = true;
|
|
|
|
if (dsmCcDisplay == null)
|
|
return;
|
|
|
|
DsmCcModuleIdentifier id = new DsmCcModuleIdentifier();
|
|
id.pid = elementaryPid;
|
|
id.moduleId = moduleInfoModuleId;
|
|
id.moduleVersion = moduleInfoModuleVersion;
|
|
if (!dsmCcDisplay.ContainsKey(id))
|
|
return;
|
|
lock (dsmCcDisplay)
|
|
{
|
|
dsmCcDisplay[id] = moduleInfoDownloadProgress;
|
|
}
|
|
}
|
|
|
|
public void DsmCcModuleComplete(int elementaryPid, ushort moduleModuleId, byte moduleModuleVersion)
|
|
{
|
|
DsmCcModuleIdentifier id = new DsmCcModuleIdentifier();
|
|
id.pid = elementaryPid;
|
|
id.moduleId = moduleModuleId;
|
|
id.moduleVersion = moduleModuleVersion;
|
|
lock (dsmCcDisplay)
|
|
{
|
|
dsmCcDisplay.Remove(id);
|
|
}
|
|
}
|
|
|
|
|
|
private void RenderDataCarousels()
|
|
{
|
|
if (dsmCcDisplay == null)
|
|
return;
|
|
if (dsmCcDisplay.Count == 0)
|
|
return;
|
|
|
|
if (ImGui.Begin("Digital Storage Media Command & Control, Data Carousels"))
|
|
{
|
|
if (string.IsNullOrEmpty(objectCarouselTableUuid))
|
|
{
|
|
objectCarouselTableUuid = Guid.NewGuid().ToString();
|
|
}
|
|
|
|
if (ImGui.BeginTable(objectCarouselTableUuid, 4, ImGuiTableFlags.NoSavedSettings | ImGuiTableFlags.SizingFixedFit))
|
|
{
|
|
ImGui.TableSetupColumn("PID");
|
|
ImGui.TableSetupColumn("Module ID");
|
|
ImGui.TableSetupColumn("Version");
|
|
ImGui.TableSetupColumn("Progress");
|
|
ImGui.TableHeadersRow();
|
|
|
|
lock (dsmCcDisplay)
|
|
{
|
|
foreach (KeyValuePair<DsmCcModuleIdentifier, double> keyValuePair in dsmCcDisplay)
|
|
{
|
|
ImGui.TableNextRow();
|
|
ImGui.TableSetColumnIndex(0);
|
|
SafeText(String.Format("{0}", keyValuePair.Key.pid));
|
|
|
|
ImGui.TableSetColumnIndex(1);
|
|
SafeText(String.Format("{0}", keyValuePair.Key.moduleId));
|
|
|
|
ImGui.TableSetColumnIndex(2);
|
|
SafeText(String.Format("{0}", keyValuePair.Key.moduleVersion));
|
|
|
|
ImGui.TableSetColumnIndex(3);
|
|
ImGui.SetNextItemWidth(100);
|
|
ImGui.ProgressBar(Convert.ToSingle(keyValuePair.Value) / 100.0f, Vector2.Zero, String.Format("{0}%", keyValuePair.Value));
|
|
}
|
|
}
|
|
ImGui.EndTable();
|
|
}
|
|
ImGui.End();
|
|
}
|
|
|
|
}
|
|
|
|
#endregion
|
|
|
|
public void NotifyWss(ushort programNumber, WssDataBlock wssDataBlock)
|
|
{
|
|
}
|
|
|
|
#region Stream Type Autodetection
|
|
|
|
private Dictionary<int, string> streamTypes;
|
|
|
|
public void NotifyStreamTypeDetection(string contestantTag, int pid)
|
|
{
|
|
if (streamTypes == null)
|
|
streamTypes = new Dictionary<int, string>();
|
|
streamTypes[pid] = contestantTag;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region BAT
|
|
private struct DisplayableBat
|
|
{
|
|
public string Name;
|
|
public List<LinkageDescriptor> Linkages;
|
|
public string TableUuid;
|
|
public HashSet<BatTransportStream> TransportStreams;
|
|
}
|
|
|
|
private SortedList<ushort, DisplayableBat> batDisplay;
|
|
private bool HasBat;
|
|
|
|
public void NotifyBat(BatBouquet batBouquet)
|
|
{
|
|
TsType = 1;
|
|
HasBat = true;
|
|
|
|
if (batDisplay == null)
|
|
batDisplay = new SortedList<ushort, DisplayableBat>();
|
|
|
|
if (batDisplay.ContainsKey(batBouquet.BouquetId))
|
|
return;
|
|
|
|
DisplayableBat child = new DisplayableBat();
|
|
child.Name = batBouquet.TryGetName();
|
|
child.Linkages = batBouquet.Linkages;
|
|
child.TableUuid = Guid.NewGuid().ToString();
|
|
child.TransportStreams = new HashSet<BatTransportStream>();
|
|
|
|
lock (batDisplay)
|
|
{
|
|
batDisplay[batBouquet.BouquetId] = child;
|
|
}
|
|
}
|
|
|
|
|
|
public void NotifyBatTs(ushort batBouquetBouquetId, BatTransportStream child)
|
|
{
|
|
TsType = 1;
|
|
HasBat = true;
|
|
|
|
if (batDisplay == null)
|
|
return;
|
|
if (!batDisplay.ContainsKey(batBouquetBouquetId))
|
|
return;
|
|
|
|
batDisplay[batBouquetBouquetId].TransportStreams.Add(child);
|
|
}
|
|
|
|
private void RenderBat()
|
|
{
|
|
if (batDisplay == null)
|
|
return;
|
|
|
|
if (batDisplay.Count == 0)
|
|
return;
|
|
|
|
if (ImGui.Begin("Bouquet Association Table"))
|
|
{
|
|
lock (batDisplay)
|
|
{
|
|
foreach (KeyValuePair<ushort, DisplayableBat> keyValuePair in batDisplay)
|
|
{
|
|
if (ImGui.CollapsingHeader(String.Format("Bouquet #{0} - {1}", keyValuePair.Key, keyValuePair.Value.Name)))
|
|
{
|
|
if (ImGui.BeginTable(keyValuePair.Value.TableUuid, 5, ImGuiTableFlags.NoSavedSettings | ImGuiTableFlags.SizingFixedFit))
|
|
{
|
|
ImGui.TableSetupColumn("L/TS");
|
|
ImGui.TableSetupColumn("ONID");
|
|
ImGui.TableSetupColumn("TSID");
|
|
ImGui.TableSetupColumn("Service");
|
|
ImGui.TableSetupColumn("");
|
|
ImGui.TableHeadersRow();
|
|
|
|
lock (keyValuePair.Value.Linkages)
|
|
{
|
|
foreach (LinkageDescriptor linkageDescriptor in keyValuePair.Value.Linkages)
|
|
{
|
|
ImGui.TableNextRow();
|
|
ImGui.TableSetColumnIndex(0);
|
|
SafeText("Link");
|
|
|
|
ImGui.TableSetColumnIndex(1);
|
|
SafeText(String.Format("{0:X4}", linkageDescriptor.OriginalNetworkId));
|
|
|
|
ImGui.TableSetColumnIndex(2);
|
|
SafeText(String.Format("{0:X4}", linkageDescriptor.TransportStreamId));
|
|
|
|
ImGui.TableSetColumnIndex(3);
|
|
SafeText(ResolveServiceDisplayName(linkageDescriptor.ServiceId));
|
|
|
|
ImGui.TableSetColumnIndex(4);
|
|
SafeText(linkageDescriptor.LinkageType.ToString());
|
|
}
|
|
}
|
|
|
|
lock (keyValuePair.Value.TransportStreams)
|
|
{
|
|
foreach (BatTransportStream valueTransportStream in keyValuePair.Value.TransportStreams)
|
|
{
|
|
ImGui.TableNextRow();
|
|
ImGui.TableSetColumnIndex(0);
|
|
SafeText("TS");
|
|
|
|
ImGui.TableSetColumnIndex(1);
|
|
SafeText(String.Format("{0:X4}", valueTransportStream.OriginalNetworkId));
|
|
|
|
ImGui.TableSetColumnIndex(2);
|
|
SafeText(String.Format("{0:X4}", valueTransportStream.TransportStreamId));
|
|
|
|
if (valueTransportStream.ServiceList != null)
|
|
{
|
|
foreach (ServiceListDescriptor.Service service in valueTransportStream.ServiceList)
|
|
{
|
|
ImGui.TableNextRow();
|
|
ImGui.TableSetColumnIndex(0);
|
|
SafeText("Service");
|
|
|
|
ImGui.TableSetColumnIndex(3);
|
|
SafeText(ResolveServiceDisplayName(service.ServiceId));
|
|
|
|
ImGui.TableSetColumnIndex(4);
|
|
SafeText(service.ServiceType.ToString());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ImGui.EndTable();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
ImGui.End();
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region DSM-CC Object Carousel
|
|
private SortedList<int, VfsDirectory> displayObjectCarouselRoots;
|
|
private bool HasDsmCc;
|
|
|
|
private string GetServiceNameFromPid(int pid)
|
|
{
|
|
lock (patDisplay)
|
|
{
|
|
foreach (KeyValuePair<int, PatEntry> keyValuePair in patDisplay)
|
|
{
|
|
PatEntry patEntry = keyValuePair.Value;
|
|
if (patEntry.pmt == null)
|
|
continue;
|
|
|
|
foreach (ProgramMappingStream programMappingStream in patEntry.pmt.Streams)
|
|
{
|
|
if (programMappingStream.ElementaryPid == pid)
|
|
{
|
|
return ResolveServiceDisplayName(patEntry.programId);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return "???";
|
|
}
|
|
|
|
public void DsmCcVfs(VfsFile vfsFile)
|
|
{
|
|
TsType = 1;
|
|
HasDsmCc = true;
|
|
if (displayObjectCarouselRoots == null)
|
|
displayObjectCarouselRoots = new SortedList<int, VfsDirectory>();
|
|
if (displayObjectCarouselRoots.ContainsKey(vfsFile.SourcePid))
|
|
return;
|
|
|
|
VfsDirectory masterDirectory = vfsFile.ParentDirectory;
|
|
while (masterDirectory.ParentDirectory != null)
|
|
masterDirectory = masterDirectory.ParentDirectory;
|
|
|
|
lock (displayObjectCarouselRoots)
|
|
{
|
|
displayObjectCarouselRoots.Add(vfsFile.SourcePid, masterDirectory);
|
|
}
|
|
}
|
|
|
|
private void RenderObjectCarousels()
|
|
{
|
|
if (displayObjectCarouselRoots == null)
|
|
return;
|
|
|
|
if (ImGui.Begin("Digital Storage Media - Command & Control, Object Carousels"))
|
|
{
|
|
lock (displayObjectCarouselRoots)
|
|
{
|
|
foreach (KeyValuePair<int, VfsDirectory> displayObjectCarouselRoot in displayObjectCarouselRoots)
|
|
{
|
|
string name = String.Format("Object Carousel in PID 0x{1:X4} (Service: {0})", GetServiceNameFromPid(displayObjectCarouselRoot.Key), displayObjectCarouselRoot.Key);
|
|
if (ImGui.CollapsingHeader(name))
|
|
{
|
|
RenderDirectoryNode(displayObjectCarouselRoot.Value);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void RenderDirectoryNode(VfsDirectory directory)
|
|
{
|
|
if (!directory.SkyscrpaerUiData.ContainsKey("UUID"))
|
|
directory.SkyscrpaerUiData.Add("UUID", Guid.NewGuid().ToString());
|
|
|
|
string dname = directory.Name;
|
|
if (string.IsNullOrEmpty(dname) && directory.ParentDirectory == null)
|
|
dname = "<root directory>";
|
|
|
|
if (ImGui.TreeNode(directory.SkyscrpaerUiData["UUID"].ToString(), dname))
|
|
{
|
|
foreach (VfsDirectory subdirectory in directory.subdirectories)
|
|
{
|
|
RenderDirectoryNode(subdirectory);
|
|
}
|
|
|
|
foreach (VfsFile directoryFile in directory.files)
|
|
{
|
|
SafeText(directoryFile.Name);
|
|
}
|
|
|
|
foreach (VfsEvent directoryEvent in directory.events)
|
|
{
|
|
SafeText(directoryEvent.Name);
|
|
}
|
|
ImGui.TreePop();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region TOT
|
|
|
|
private DateTime? totTime;
|
|
private LocalTimeOffsetDescriptor totDescriptor;
|
|
private string totDisplayUuid;
|
|
private bool HasTot;
|
|
|
|
public void NotifyTot(DateTime utcTime, LocalTimeOffsetDescriptor ltod)
|
|
{
|
|
TsType = 1;
|
|
HasTot = true;
|
|
|
|
totTime = utcTime;
|
|
totDescriptor = ltod;
|
|
}
|
|
|
|
private void RenderTot()
|
|
{
|
|
if (!totTime.HasValue)
|
|
return;
|
|
|
|
if (ImGui.Begin("Time Offset Table"))
|
|
{
|
|
SafeText(totTime.ToString());
|
|
|
|
if (totDescriptor != null)
|
|
{
|
|
if (totDescriptor.Valid)
|
|
{
|
|
if (string.IsNullOrEmpty(totDisplayUuid))
|
|
totDisplayUuid = Guid.NewGuid().ToString();
|
|
|
|
if (ImGui.BeginTable(totDisplayUuid, 3, ImGuiTableFlags.SizingFixedFit | ImGuiTableFlags.NoSavedSettings))
|
|
{
|
|
ImGui.TableSetupColumn("Region");
|
|
ImGui.TableSetupColumn("Polarity");
|
|
ImGui.TableSetupColumn("Offset");
|
|
ImGui.TableHeadersRow();
|
|
|
|
foreach (LocalTimeOffsetDescriptor.LocalTime totDescriptorLocalTimeOffset in totDescriptor.LocalTimeOffsets)
|
|
{
|
|
ImGui.TableNextRow();
|
|
ImGui.TableSetColumnIndex(0);
|
|
SafeText(totDescriptorLocalTimeOffset.CountryCode);
|
|
|
|
ImGui.TableSetColumnIndex(1);
|
|
bool b = totDescriptorLocalTimeOffset.LocalTimeOffsetPolarity;
|
|
ImGui.BeginDisabled(true);
|
|
ImGui.Checkbox("", ref b);
|
|
ImGui.EndDisabled();
|
|
|
|
ImGui.TableSetColumnIndex(2);
|
|
SafeText(totDescriptorLocalTimeOffset.LocalTimeOffset.ToString());
|
|
}
|
|
ImGui.EndTable();
|
|
}
|
|
}
|
|
}
|
|
ImGui.End();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region TDT
|
|
private DateTime? tdtDisplay;
|
|
private bool HasTdt;
|
|
public void NotifyTdt(DateTime utcTime)
|
|
{
|
|
TsType = 1;
|
|
HasTdt = true;
|
|
tdtDisplay = utcTime;
|
|
}
|
|
|
|
private void RenderTdt()
|
|
{
|
|
if (tdtDisplay.HasValue)
|
|
{
|
|
if (ImGui.Begin("Time and Date Table"))
|
|
{
|
|
SafeText(tdtDisplay.Value.ToString());
|
|
ImGui.End();
|
|
}
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
#region CAT
|
|
private string caTableUuid;
|
|
private HashSet<CaDescriptor> caDisplay;
|
|
private bool HasCat;
|
|
public void NotifyCat(CaDescriptor caDescriptor)
|
|
{
|
|
TsType = 1;
|
|
HasCat = true;
|
|
|
|
if (caDisplay == null)
|
|
caDisplay = new HashSet<CaDescriptor>();
|
|
|
|
lock (caDisplay)
|
|
{
|
|
caDisplay.Add(caDescriptor);
|
|
}
|
|
}
|
|
|
|
private void RenderCat()
|
|
{
|
|
if (caDisplay == null)
|
|
return;
|
|
|
|
if (ImGui.Begin("Conditional Access Table"))
|
|
{
|
|
if (string.IsNullOrEmpty(caTableUuid))
|
|
caTableUuid = Guid.NewGuid().ToString();
|
|
|
|
if (ImGui.BeginTable(caTableUuid, 3, ImGuiTableFlags.NoSavedSettings | ImGuiTableFlags.SizingFixedFit))
|
|
{
|
|
ImGui.TableSetupColumn("CA System");
|
|
ImGui.TableSetupColumn("ECM/EMM PID");
|
|
ImGui.TableSetupColumn("Private Data");
|
|
ImGui.TableHeadersRow();
|
|
lock (caDisplay)
|
|
{
|
|
foreach (CaDescriptor caDescriptor in caDisplay)
|
|
{
|
|
ImGui.TableNextRow();
|
|
ImGui.TableSetColumnIndex(0);
|
|
SafeText(CaSystemNames.GetHumanReadableName(caDescriptor.CaSystemId));
|
|
|
|
ImGui.TableSetColumnIndex(1);
|
|
SafeText(String.Format("{0:X4}", caDescriptor.CaPid));
|
|
|
|
ImGui.TableSetColumnIndex(2);
|
|
if (caDescriptor.PrivateData != null)
|
|
{
|
|
if (caDescriptor.PrivateData.Length != 0)
|
|
SafeText(BitConverter.ToString(caDescriptor.PrivateData));
|
|
}
|
|
}
|
|
}
|
|
ImGui.EndTable();
|
|
}
|
|
ImGui.End();
|
|
}
|
|
}
|
|
#endregion
|
|
|
|
public void NotifyScte35(ushort programNumber, SpliceInsert spliceInsert)
|
|
{
|
|
|
|
}
|
|
|
|
public void NotifyScte35(ushort programNumber, TimeSignal spliceInsert)
|
|
{
|
|
}
|
|
|
|
public void SetMemorySaverMode(bool saveMemory)
|
|
{
|
|
|
|
}
|
|
|
|
public void NotifyDocsisCarrier(DocsisEnvironment docsisEnvironment)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void NotifyDocsisFrequency(uint? frequency, bool isUpstream, object mmm)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
private bool gseMode;
|
|
public void SetGseMode()
|
|
{
|
|
gseMode = true;
|
|
}
|
|
|
|
#region Framegrabs
|
|
|
|
private Queue<PictureWindow> framegrabWindows;
|
|
private int windowSpawnX = 100;
|
|
public void ShowFramegrab(int currentNetworkId, int transportStreamId, ushort mappingProgramNumber,
|
|
int mappingStreamElementaryPid, byte[] imageData)
|
|
{
|
|
if (framegrabWindows == null)
|
|
framegrabWindows = new Queue<PictureWindow>();
|
|
|
|
Tasks.EnqueueTask(() =>
|
|
{
|
|
string resolveServiceDisplayName = ResolveServiceDisplayName(mappingProgramNumber);
|
|
if (string.IsNullOrEmpty(resolveServiceDisplayName))
|
|
resolveServiceDisplayName = String.Format("Framegrab of Service #{0:X4}");
|
|
else
|
|
resolveServiceDisplayName = String.Format("Framegrab of \"{0}\"", resolveServiceDisplayName);
|
|
|
|
if (PictureWindow.Renderer == null)
|
|
return;
|
|
|
|
Renderer renderer = PictureWindow.Renderer;
|
|
string displayName = resolveServiceDisplayName;
|
|
|
|
PictureWindow child = new PictureWindow(renderer, displayName, imageData);
|
|
child.SetPosition(windowSpawnX, windowSpawnX);
|
|
child.SetTaskQueue(Tasks, jobContext.Renderables);
|
|
|
|
jobContext.Renderables.Add(child);
|
|
framegrabWindows.Enqueue(child);
|
|
});
|
|
}
|
|
#endregion
|
|
|
|
public void NotifyBlockstreamCarrier()
|
|
{
|
|
|
|
}
|
|
|
|
#region Database Callbacks
|
|
public IEnumerable<HumanReadableService> GetServices()
|
|
{
|
|
if (HasPmt)
|
|
{
|
|
foreach (var (pmtPid, patValue) in patDisplay)
|
|
{
|
|
ushort serviceId = patValue.programId;
|
|
SdtCoordinate sdt = ResolveService(serviceId);
|
|
string providerName = sdt.ProviderName;
|
|
string serviceName = sdt.ServiceName;
|
|
ushort? caId = ResolveCaId(patValue.pmt, sdt);
|
|
ServiceDescriptor.ServiceTypeCoding? serviceType = sdt.ServiceType;
|
|
yield return new HumanReadableService(serviceId, providerName, serviceName, caId, serviceType.GetValueOrDefault());
|
|
}
|
|
}
|
|
}
|
|
|
|
private ushort? ResolveCaId(ProgramMapping patValuePmt, SdtCoordinate sdt)
|
|
{
|
|
if (patValuePmt != null)
|
|
{
|
|
if (patValuePmt.CaSystemId.HasValue)
|
|
return patValuePmt.CaSystemId.Value;
|
|
|
|
foreach (ProgramMappingStream stream in patValuePmt.Streams)
|
|
{
|
|
if (stream.CaSystemId.HasValue)
|
|
return stream.CaSystemId;
|
|
}
|
|
}
|
|
|
|
if (sdt.CaIdentifiers != null)
|
|
{
|
|
if (sdt.CaIdentifiers.Length > 0)
|
|
return sdt.CaIdentifiers[0];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
#endregion
|
|
#endregion
|
|
|
|
|
|
#region During Blindscan
|
|
private FoundFrequenciesWindow2 foundFrequenciesWindow;
|
|
public void OnBlindscanOpenFoundFrquenciesWindow(List<BlindscanSearchResult> foundFrequencies, STD_TYPE tunerMetadataType)
|
|
{
|
|
foundFrequenciesWindow = new FoundFrequenciesWindow2(foundFrequencies);
|
|
|
|
Tasks.EnqueueTask(() =>
|
|
{
|
|
jobContext.Renderables.Add(foundFrequenciesWindow);
|
|
});
|
|
}
|
|
|
|
public void OnBlindscanJobDone(bool success)
|
|
{
|
|
jobContext.Puppets[0].AutoMoveToHome();
|
|
jobContext.Puppets[1].AutoMoveToHome();
|
|
jobContext.Puppets[2].AutoMoveTo(new Point(0, 720 / 2));
|
|
jobContext.Puppets[3].AutoMoveTo(new Point(1280 / 2, 0));
|
|
|
|
jobContext.ReadyForNextJob = true;
|
|
}
|
|
|
|
public void OnBlindscanErrorMessage(string blindscanningLowHorizontalAreaFailed)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void OnBlindscanBandComplete()
|
|
{
|
|
foreach (CharSet jobContextPuppet in jobContext.Puppets)
|
|
jobContextPuppet.AutoMoveToHome();
|
|
}
|
|
|
|
private BlindscanProgressWindow _blindscanProgressWindow;
|
|
public void OnBlindscanBeforeBLScan(int minimum, int currentProgress, int maximum)
|
|
{
|
|
_blindscanProgressWindow = new BlindscanProgressWindow();
|
|
_blindscanProgressWindow.Start = minimum;
|
|
_blindscanProgressWindow.Progress = minimum;
|
|
_blindscanProgressWindow.End = maximum;
|
|
Tasks.EnqueueTask(() =>
|
|
{
|
|
jobContext.Renderables.Add(_blindscanProgressWindow);
|
|
});
|
|
}
|
|
|
|
public void OnBlindscanAfterBLScan()
|
|
{
|
|
Tasks.EnqueueTask(() =>
|
|
{
|
|
jobContext.Renderables.Remove(_blindscanProgressWindow);
|
|
_blindscanProgressWindow = null;
|
|
});
|
|
}
|
|
|
|
public void OnBlindscanSearchResult1Callback(BlindscanSearchResult searchResult, int polarityIndex,
|
|
int lnbTypeMinimumFrequency, int lnbTypeMaximumFrequency)
|
|
{
|
|
Blindscan.BlindscanResult blindscanResult = new Blindscan.BlindscanResult(searchResult.SearchResult, lnbTypeMinimumFrequency, lnbTypeMaximumFrequency);
|
|
jobContext.Puppets[blindscanResult.sr1.Pol].AutoMoveTo(blindscanResult.Position);
|
|
lock (jobContext.PressurePlates)
|
|
{
|
|
jobContext.PressurePlates.Add(blindscanResult);
|
|
}
|
|
|
|
_blindscanProgressWindow.Progress = searchResult.SearchResult.Freq;
|
|
|
|
SoundPlayer.PlaySoundFile("lock.wav");
|
|
}
|
|
|
|
private Point GetFrequencyPosition(SearchResult searchResult, int satPositionMinFreq, int satPositionMaxFreq)
|
|
{
|
|
int x = 0, y = 0;
|
|
|
|
if (searchResult.Pol == 0)
|
|
{
|
|
//Horizontal
|
|
int w = (searchResult.Freq / 1000) - satPositionMinFreq;
|
|
int hundert = 1280;
|
|
int g = (satPositionMaxFreq - satPositionMinFreq);
|
|
|
|
x = w * hundert / g;
|
|
y = 720 / 2;
|
|
}
|
|
else
|
|
{
|
|
//Vertical
|
|
int w = (searchResult.Freq / 1000) - satPositionMinFreq;
|
|
int hundert = 720;
|
|
int g = (satPositionMaxFreq - satPositionMinFreq);
|
|
|
|
x = 1280 / 2;
|
|
y = w * hundert / g;
|
|
}
|
|
|
|
Point position = new Point(x, y);
|
|
return position;
|
|
}
|
|
|
|
public void OnBlindscanBeforeSetChannel(BlindscanSearchResult blindscanResult, LnbType lnb)
|
|
{
|
|
Point point = GetFrequencyPosition(blindscanResult.SearchResult, lnb.MinimumFrequency, lnb.MaximumFrequency);
|
|
jobContext.Puppets[2 + blindscanResult.SearchResult.Pol].AutoMoveTo(point);
|
|
}
|
|
|
|
public void OnScrapeBandComplete()
|
|
{
|
|
jobContext.Puppets[0].AutoMoveToHome();
|
|
jobContext.Puppets[1].AutoMoveToHome();
|
|
jobContext.Puppets[2].AutoMoveToHome();
|
|
jobContext.Puppets[3].AutoMoveToHome();
|
|
|
|
}
|
|
|
|
public void OnBlindscanScrapeTransponderComplete(BlindscanSearchResult blindscanResult)
|
|
{
|
|
lock (jobContext.PressurePlates)
|
|
{
|
|
foreach (IPressurePlate pressurePlate in jobContext.PressurePlates)
|
|
{
|
|
Blindscan.BlindscanResult result = pressurePlate as Blindscan.BlindscanResult;
|
|
if (result.Satellite)
|
|
{
|
|
if (result.GetFrequency() == blindscanResult.GetFrequency())
|
|
{
|
|
jobContext.PressurePlates.Remove(result);
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
throw new NotImplementedException("non satellite pressure plate.");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private SdlScottPlotWindowRfSpectrum rfSpectrumWindow;
|
|
public void OnBlindscanBeginRfSpectrum()
|
|
{
|
|
Tasks.EnqueueTask(() =>
|
|
{
|
|
rfSpectrumWindow = new SdlScottPlotWindowRfSpectrum(jobContext.ImgUiDevice);
|
|
jobContext.Renderables.Add(rfSpectrumWindow);
|
|
});
|
|
}
|
|
|
|
public void OnBlindscanRfSpectrumEnqueueSample(SatelliteDeliverySystemDescriptor.PolarizationEnum polarization, int frequency, double rf)
|
|
{
|
|
Tasks.EnqueueTask(() =>
|
|
{
|
|
rfSpectrumWindow.EnqueueSample(polarization, frequency, rf);
|
|
});
|
|
}
|
|
|
|
public void OnBlindscanEndRfSpectrum()
|
|
{
|
|
Tasks.EnqueueTask(() =>
|
|
{
|
|
jobContext.Renderables.Remove(rfSpectrumWindow);
|
|
rfSpectrumWindow.Dispose();
|
|
rfSpectrumWindow = null;
|
|
});
|
|
}
|
|
|
|
private IqWindow iqWindow;
|
|
public void OnBlindscanBeginIqSpectrum(IqChartData result)
|
|
{
|
|
Tasks.EnqueueTask(() =>
|
|
{
|
|
iqWindow = new IqWindow(jobContext.ImgUiDevice, result);
|
|
jobContext.Renderables.Add(iqWindow);
|
|
});
|
|
}
|
|
|
|
public void OnBlindscanEndIq()
|
|
{
|
|
Tasks.EnqueueTask(() =>
|
|
{
|
|
jobContext.Renderables.Remove(iqWindow);
|
|
iqWindow.Dispose();
|
|
iqWindow = null;
|
|
});
|
|
}
|
|
|
|
public void OnBlindscanLockFail(SearchResult satelliteSr, BlindscanResultState resultState)
|
|
{
|
|
SoundPlayer.PlaySoundFile("fail.wav");
|
|
}
|
|
|
|
public void OnBlindscanFilterSetUp()
|
|
{
|
|
Tasks.EnqueueTask(() =>
|
|
{
|
|
jobContext.Renderables.Add(this);
|
|
});
|
|
foundFrequenciesWindow.allowZapNow = true;
|
|
foundFrequenciesWindow.statusPacketsInQueue = 0;
|
|
foundFrequenciesWindow.statusPacketsInTotal = 0;
|
|
}
|
|
|
|
public void OnBlindscanScrapeStopCondition()
|
|
{
|
|
foundFrequenciesWindow.allowZapNow = false;
|
|
}
|
|
|
|
public void OnBlindscanAfterPacketDrain()
|
|
{
|
|
Tasks.EnqueueTask(() =>
|
|
{
|
|
jobContext.Renderables.Remove(this);
|
|
ResetWindows();
|
|
});
|
|
}
|
|
|
|
public void OnBlindscanPacketError(int errorCount, int length)
|
|
{
|
|
throw new NotImplementedException();
|
|
}
|
|
|
|
public void OnBlindscanPacketOk(int numPackets, int packetsQueueCount)
|
|
{
|
|
foundFrequenciesWindow.statusPacketsInTotal += (uint)numPackets;
|
|
foundFrequenciesWindow.statusPacketsInQueue = packetsQueueCount;
|
|
}
|
|
|
|
public bool IsZapNowRequested()
|
|
{
|
|
if (foundFrequenciesWindow.zapNowRequested)
|
|
{
|
|
foundFrequenciesWindow.zapNowRequested = false;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
public bool MayAutoZap()
|
|
{
|
|
return !foundFrequenciesWindow.doNotAutoZap;
|
|
}
|
|
|
|
public TaskQueue Tasks { get; set; }
|
|
|
|
internal JobContext jobContext;
|
|
#endregion
|
|
}
|
|
}
|