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(""); 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 { public int Compare(EitDay x, EitDay y) { return x.Date.CompareTo(y.Date); } } private class EitEventCoordinateComparer : IComparer { public int Compare(EitEventCoordinate x, EitEventCoordinate y) { return x.StartTime.Ticks.CompareTo(y.StartTime.Ticks); } } private bool HasEit; private SortedList> eitDisplay; private void RenderEit() { if (eitDisplay == null) return; if (ImGui.Begin("Event Information Table")) { lock (eitDisplay) { foreach (KeyValuePair> 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 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>(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(new EitEventCoordinateComparer()); } SortedList 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 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 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(); 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 patDisplay; public void NotifyPatProgram(int pmtPid, ushort programId) { HasPat = true; TsType = 1; if (patDisplay == null) patDisplay = new SortedList(); 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 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 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 { public int Compare(NitNetworkMeta x, NitNetworkMeta y) { return x.ONID.CompareTo(y.ONID); } } private SortedList> nitDisplay; private string nitTableUuid; private bool HasNit; public void NotifyNit(NitTransportStream transportStream) { TsType = 1; HasNit = true; if (nitDisplay == null) nitDisplay = new SortedList>(new NitCoordinateComparer()); NitNetworkMeta nnm = new NitNetworkMeta(); nnm.ONID = transportStream.OriginalNetworkId; if (!nitDisplay.ContainsKey(nnm)) { lock (nitDisplay) { nitDisplay.Add(nnm, new SortedList()); } } SortedList 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> 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 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> 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>(); lock (mpeDisplays) { foreach (KeyValuePair line in mpeDisplays) { if (line.Key.Equals(iti)) { line.Value.CountPacket(ipv4PacketLength); return; } } KeyValuePair newChild = new KeyValuePair(iti, new IpPerformanceInfo()); newChild.Value.CountPacket(ipv4PacketLength); mpeDisplays.Add(newChild); } } private void RenderMpe() { if (mpeDisplays == null) return; if (secondTick) { lock (mpeDisplays) { foreach (KeyValuePair 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 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 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 aitDisplay; private string aitTableUuid; private bool HasAit; public void NotifyAit(AitApplication aitApplication) { TsType = 1; HasAit = true; if (aitDisplay == null) aitDisplay = new SortedList(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 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 { 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 dsmCcDisplay; private string objectCarouselTableUuid; public void DsmCcModuleAdd(int elementaryPid, ushort moduleInfoModuleId, byte moduleInfoModuleVersion) { TsType = 1; HasDsmCc = true; if (dsmCcDisplay == null) dsmCcDisplay = new SortedList(new DsmCcModuleIdentifierComparer()); DsmCcModuleIdentifier id = new DsmCcModuleIdentifier(); id.pid = elementaryPid; id.moduleId = moduleInfoModuleId; id.moduleVersion = moduleInfoModuleVersion; 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 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 streamTypes; public void NotifyStreamTypeDetection(string contestantTag, int pid) { if (streamTypes == null) streamTypes = new Dictionary(); streamTypes[pid] = contestantTag; } #endregion #region BAT private struct DisplayableBat { public string Name; public List Linkages; public string TableUuid; public HashSet TransportStreams; } private SortedList batDisplay; private bool HasBat; public void NotifyBat(BatBouquet batBouquet) { TsType = 1; HasBat = true; if (batDisplay == null) batDisplay = new SortedList(); 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(); 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 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 displayObjectCarouselRoots; private bool HasDsmCc; private string GetServiceNameFromPid(int pid) { lock (patDisplay) { foreach (KeyValuePair 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(); 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 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 = ""; 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 caDisplay; private bool HasCat; public void NotifyCat(CaDescriptor caDescriptor) { TsType = 1; HasCat = true; if (caDisplay == null) caDisplay = new HashSet(); 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 framegrabWindows; private int windowSpawnX = 100; public void ShowFramegrab(int currentNetworkId, int transportStreamId, ushort mappingProgramNumber, int mappingStreamElementaryPid, byte[] imageData) { if (framegrabWindows == null) framegrabWindows = new Queue(); 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() { throw new NotImplementedException(); } #region Database Callbacks public IEnumerable 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 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 } }