From cc8e1edd90e8c8d6f226f950d9c252d729b1aaa6 Mon Sep 17 00:00:00 2001 From: feyris-tan <4116042+feyris-tan@users.noreply.github.com> Date: Sun, 14 Sep 2025 21:47:58 +0200 Subject: [PATCH] Public release to satellitescomunity.de --- .../MinioObjectStorage.cs | 64 ++- .../skyscraper5.Data.Minio.csproj | 6 +- .../skyscraper5.Data.MySql/Skyscraper.cs | 2 +- .../PostgresqlDataStore.cs | 4 +- Documentation/satip-commandline.txt | 1 + .../Jobs/InheritedBlindscanConfigWindow.cs | 35 +- .../Jobs/InheritedBlindscanUiJunction.cs | 12 +- .../skyscraper8.UI.SDL2.csproj | 8 + .../MediaHighway2/Mhw2Scraper.cs | 3 + skyscraper8/Ietf/FLUTE/FluteListener.cs | 1 + skyscraper8/InteractionChannel/Model/Cmt.cs | 21 + .../Descriptors/0x4a_LinkageDescriptor.cs | 21 + .../0xa8_SatelliteForwardLinkDescriptor.cs | 21 + .../0xa9_SatelliteReturnLinkDescriptor.cs | 21 + skyscraper8/InteractionChannel/Model/Fct.cs | 18 + skyscraper8/InteractionChannel/Model/Rmt.cs | 60 +++ skyscraper8/InteractionChannel/Model/Sct.cs | 21 + skyscraper8/InteractionChannel/Model/Spt.cs | 21 + skyscraper8/Program.cs | 27 +- skyscraper8/Properties/launchSettings.json | 2 +- skyscraper8/QuickAndDirtySatIpClient.cs | 26 +- skyscraper8/SatIp/RtspClient.cs | 15 +- skyscraper8/SatIpReadme.txt | 22 + .../ISsdpCache.cs} | 5 +- .../SsdpClient.cs | 5 +- .../BlindscanSearchResult.cs | 1 + .../SatIpWithStreamReaderProxy.cs | 508 ++++++++++++++++++ .../Skyscraper/Plugins/PluginManager.cs | 41 +- skyscraper8/Skyscraper/Scraper/PmtTracker.cs | 74 +++ .../Skyscraper/Scraper/SkyscraperContext.cs | 52 +- .../Skyscraper/Scraper/Storage/DataStorage.cs | 2 +- .../Storage/Filesystem/FilesystemStorage.cs | 4 +- .../InMemory/InMemoryScraperStorage.cs | 175 +++++- .../Scraper/Storage/ObjectStorage.cs | 4 +- .../Contestants/AitContestant.cs | 5 + .../Contestants/DataCarouselContestant.cs | 6 + .../Contestants/TeletextContestant.cs | 15 +- .../StreamAutodetection/ProgramContext.cs | 11 +- .../Text/Encodings/dvb-iso-8859-14.cs | 1 + .../Text/Encodings/dvb-iso-8859-3.cs | 2 + skyscraper8/skyscraper8.csproj | 5 + 41 files changed, 1252 insertions(+), 96 deletions(-) create mode 100644 Documentation/satip-commandline.txt create mode 100644 skyscraper8/SatIpReadme.txt rename skyscraper8/{SatIp/IRtspCache.cs => SimpleServiceDiscoveryProtocol/ISsdpCache.cs} (74%) create mode 100644 skyscraper8/Skyscraper/FrequencyListGenerator/SatIpWithStreamReaderProxy.cs create mode 100644 skyscraper8/Skyscraper/Scraper/PmtTracker.cs diff --git a/BlobStorages/skyscraper5.Data.Minio/MinioObjectStorage.cs b/BlobStorages/skyscraper5.Data.Minio/MinioObjectStorage.cs index 3d9f3da..83ef2b6 100644 --- a/BlobStorages/skyscraper5.Data.Minio/MinioObjectStorage.cs +++ b/BlobStorages/skyscraper5.Data.Minio/MinioObjectStorage.cs @@ -54,26 +54,41 @@ namespace skyscraper5.Data { putObjectArgs = putObjectArgs.WithObjectSize(buffer.Length); } - - lock (_tasks) + else if (optionalData.ContainsKey("X-Skyscraper-Content-Length")) { - _tasks.Add(_minioClient.PutObjectAsync(putObjectArgs).ContinueWith(task => - { - droppedFiles.Add(fullName); - - Monitor.Enter(definetlyKnownFiles); - definetlyKnownFiles.Add(fullName); - Monitor.Exit(definetlyKnownFiles); - - Monitor.Enter(definetlyMissingFiles); - definetlyMissingFiles.Remove(fullName); - Monitor.Exit(definetlyMissingFiles); - - buffer.Close(); - buffer.Dispose(); - })); + putObjectArgs = putObjectArgs.WithObjectSize(long.Parse(optionalData["X-Skyscraper-Content-Length"])); } + if (definetlyKnownFiles == null) + definetlyKnownFiles = new HashSet(); + + if (definetlyMissingFiles == null) + definetlyMissingFiles = new HashSet(); + + + lock (_tasks) + { + _tasks.Add(_minioClient.PutObjectAsync(putObjectArgs).ContinueWith(task => + { + if (task.IsFaulted) + { + throw new MinioException("A minio upload task failed."); + } + droppedFiles.Add(fullName); + + Monitor.Enter(definetlyKnownFiles); + definetlyKnownFiles.Add(fullName); + Monitor.Exit(definetlyKnownFiles); + + Monitor.Enter(definetlyMissingFiles); + definetlyMissingFiles.Remove(fullName); + Monitor.Exit(definetlyMissingFiles); + + buffer.Close(); + buffer.Dispose(); + })); + } + CleanTaskList(); } @@ -352,9 +367,20 @@ namespace skyscraper5.Data public void DvbNipFileArrival(NipActualCarrierInformation carrier, FluteListener listener) { - string path = "/nip/" + DvbNipUtilities.MakeFilename(listener.FileAssociation.ContentLocation); + Dictionary bonusInfo = new Dictionary(); + bonusInfo.Add("X-Skyscraper-NIP-StreamProviderName", carrier.NipStreamProviderName); + bonusInfo.Add("X-Skyscraper-Event", nameof(DvbNipFileArrival)); + bonusInfo.Add("X-Skyscraper-Content-Encoding",listener.FileAssociation.ContentEncoding); + bonusInfo.Add("X-Skyscraper-Transfer-Length", listener.FileAssociation.TransferLength.ToString()); + bonusInfo.Add("X-Skyscraper-Content-Length", listener.FileAssociation.ContentLength.ToString()); + + string mime = !string.IsNullOrEmpty(listener.FileAssociation.ContentType) + ? listener.FileAssociation.ContentType + : "application/octet-stream"; + + string path = "/nip/" + DvbNipUtilities.MakeFilename(listener.FileAssociation.ContentLocation); Stream stream = listener.ToStream(); - WriteObject(path, stream); + WriteObject(path, stream, mime, bonusInfo); } public void StoreIqGraph(Guid jobGuid, long frequency, char polarity, IqChartData plot) diff --git a/BlobStorages/skyscraper5.Data.Minio/skyscraper5.Data.Minio.csproj b/BlobStorages/skyscraper5.Data.Minio/skyscraper5.Data.Minio.csproj index e66e7c2..8676a00 100644 --- a/BlobStorages/skyscraper5.Data.Minio/skyscraper5.Data.Minio.csproj +++ b/BlobStorages/skyscraper5.Data.Minio/skyscraper5.Data.Minio.csproj @@ -5,11 +5,15 @@ - + + + + true + diff --git a/DataTableStorages/skyscraper5.Data.MySql/Skyscraper.cs b/DataTableStorages/skyscraper5.Data.MySql/Skyscraper.cs index d214718..ad0cc22 100644 --- a/DataTableStorages/skyscraper5.Data.MySql/Skyscraper.cs +++ b/DataTableStorages/skyscraper5.Data.MySql/Skyscraper.cs @@ -125,7 +125,7 @@ namespace skyscraper5.Data.MySql } public void InsertUiBlindscanSettingHistory(int settingsWindowBlScanTunerSelection, - bool settingsWindowUseDifferentTunerForSetFilter, int settingsWindowSetFilterTunerSelection, + int multitunerMode, int settingsWindowSetFilterTunerSelection, int settingsWindowDiseqc, bool settingsWindowCollectIqGraphs, bool settingsWindowCollectRfSpectrum, bool settingsWindowCaptureFile, int settingsWindowSatellite, int settingsWindowLnb, int dish, bool settingsWindowScanHorizontalLow, bool settingsWindowScanHorizontalHigh, bool settingsWindowScanVerticalLow, diff --git a/DataTableStorages/skyscraper5.Data.PostgreSql/PostgresqlDataStore.cs b/DataTableStorages/skyscraper5.Data.PostgreSql/PostgresqlDataStore.cs index 787c578..20ba90b 100644 --- a/DataTableStorages/skyscraper5.Data.PostgreSql/PostgresqlDataStore.cs +++ b/DataTableStorages/skyscraper5.Data.PostgreSql/PostgresqlDataStore.cs @@ -169,7 +169,7 @@ namespace skyscraper5.Data.PostgreSql } public void InsertUiBlindscanSettingHistory(int settingsWindowBlScanTunerSelection, - bool settingsWindowUseDifferentTunerForSetFilter, int settingsWindowSetFilterTunerSelection, + int multitunerMode, int settingsWindowSetFilterTunerSelection, int settingsWindowDiseqc, bool settingsWindowCollectIqGraphs, bool settingsWindowCollectRfSpectrum, bool settingsWindowCaptureFile, int settingsWindowSatellite, int settingsWindowLnb, int dish, bool settingsWindowScanHorizontalLow, bool settingsWindowScanHorizontalHigh, bool settingsWindowScanVerticalLow, @@ -182,7 +182,7 @@ namespace skyscraper5.Data.PostgreSql command.CommandText = "INSERT INTO ui_blindscan_setting_history VALUES (DEFAULT,@bstselection,@ustfsfilter,@sftselection,@diseqc,@cigraphs,@crspectrum,@cfilters,@satellite,@lnb,@dish,@hl,@hh,@vl,@vh);"; command.Parameters.AddWithValue("@bstselection", NpgsqlDbType.Integer, settingsWindowBlScanTunerSelection); - command.Parameters.AddWithValue("@ustfsfilter", NpgsqlDbType.Boolean, settingsWindowUseDifferentTunerForSetFilter); + command.Parameters.AddWithValue("@ustfsfilter", NpgsqlDbType.Integer, multitunerMode); command.Parameters.AddWithValue("@sftselection", NpgsqlDbType.Integer, settingsWindowSetFilterTunerSelection); command.Parameters.AddWithValue("@diseqc", NpgsqlDbType.Integer, settingsWindowDiseqc); command.Parameters.AddWithValue("@cigraphs", NpgsqlDbType.Boolean, settingsWindowCollectIqGraphs); diff --git a/Documentation/satip-commandline.txt b/Documentation/satip-commandline.txt new file mode 100644 index 0000000..ba6c3f7 --- /dev/null +++ b/Documentation/satip-commandline.txt @@ -0,0 +1 @@ +satip autodetect 1 H 11141 S2 23500 \ No newline at end of file diff --git a/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanConfigWindow.cs b/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanConfigWindow.cs index 999f8dc..27e7c14 100644 --- a/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanConfigWindow.cs +++ b/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanConfigWindow.cs @@ -19,7 +19,7 @@ namespace SDL2Demo.Jobs private readonly TaskQueue _taskQueue; public int settingsWindowBLScanTunerSelection; - public bool settingsWindowUseDifferentTunerForSetFilter; + public int multitunerMode; public int settingsWindowSetFilterTunerSelection; public int settingsWindowDiseqc; public bool settingsWindowCollectIqGraphs; @@ -34,6 +34,8 @@ namespace SDL2Demo.Jobs public bool settingsWindowScanVerticalLow; public bool settingsWindowScanVerticalHigh; + + private DataStorage dataStorage; private ObjectStorage objectStorage; private IGpsReceiver gpsReceiver; @@ -43,7 +45,7 @@ namespace SDL2Demo.Jobs private void StoreSettings() { dataStorage.InsertUiBlindscanSettingHistory(settingsWindowBLScanTunerSelection, - settingsWindowUseDifferentTunerForSetFilter, settingsWindowSetFilterTunerSelection, + multitunerMode, settingsWindowSetFilterTunerSelection, settingsWindowDiseqc, settingsWindowCollectIqGraphs, settingsWindowCollectRfSpectrum, settingsWindowCaptureFile, settingsWindowSatellite, settingsWindowLNB, settingsWindowDish, settingsWindowScanHorizontalLow, settingsWindowScanHorizontalHigh, @@ -71,7 +73,7 @@ namespace SDL2Demo.Jobs if (previousSettings != null) { settingsWindowBLScanTunerSelection = Convert.ToInt32(previousSettings[1]); - settingsWindowUseDifferentTunerForSetFilter = Convert.ToBoolean(previousSettings[2]); + multitunerMode = Convert.ToInt32(previousSettings[2]); settingsWindowSetFilterTunerSelection = Convert.ToInt32(previousSettings[3]); settingsWindowDiseqc = Convert.ToInt32(previousSettings[4]); settingsWindowCollectIqGraphs = Convert.ToBoolean(previousSettings[5]); @@ -112,11 +114,21 @@ namespace SDL2Demo.Jobs bjc.ObjectStorage = objectStorage; bjc.SatellitePosition = satellites[settingsWindowSatellite]; - if (settingsWindowUseDifferentTunerForSetFilter) - bjc.StreamReader = new CoopBlindscanStreamReaderProxy(streamReader, settingsWindowBLScanTunerSelection, settingsWindowSetFilterTunerSelection); - else - bjc.StreamReader = streamReader; - + switch (multitunerMode) + { + case 1: + bjc.StreamReader = streamReader; + break; + case 2: + bjc.StreamReader = new CoopBlindscanStreamReaderProxy(streamReader, settingsWindowBLScanTunerSelection, settingsWindowSetFilterTunerSelection); + break; + case 4: + bjc.StreamReader = new SatIpWithStreamReaderProxy(streamReader, objectStorage); + break; + default: + throw new NotImplementedException(String.Format("Multituner Mode {0}", multitunerMode)); + } + bjc.TunerMetadata = tuners[settingsWindowBLScanTunerSelection]; bjc.Ui = new InheritedBlindscanUiJunction(); bjc.Ui.Tasks = _taskQueue; @@ -150,9 +162,10 @@ namespace SDL2Demo.Jobs if (tuners[settingsWindowBLScanTunerSelection].IsSatellite()) { - ImGui.Checkbox("Use different Tuner for IQScan and SetFilter", ref settingsWindowUseDifferentTunerForSetFilter); + ImGui.RadioButton("Use the same Tuner for IQScan and SetFilter", ref multitunerMode, 1); + ImGui.RadioButton("Use different Tuner for IQScan and SetFilter", ref multitunerMode, 2); - if (settingsWindowUseDifferentTunerForSetFilter) + if (multitunerMode == 2) { ImGui.Text("This assumes that both tuners are connected to the same antenna set-up, using e.g. a splitter."); @@ -171,6 +184,8 @@ namespace SDL2Demo.Jobs } ImGui.PopID(); } + + ImGui.RadioButton("Use same Tuner for IQScan, but SAT>IP Server for SetFilter", ref multitunerMode, 4); ImGui.Text("DiSEqC"); ImGui.SameLine(); diff --git a/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanUiJunction.cs b/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanUiJunction.cs index 983745c..58b4220 100644 --- a/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanUiJunction.cs +++ b/GUIs/skyscraper8.UI.ImGui/Jobs/InheritedBlindscanUiJunction.cs @@ -1594,13 +1594,19 @@ namespace SDL2Demo.Jobs _blindscanProgressWindow.Start = minimum; _blindscanProgressWindow.Progress = minimum; _blindscanProgressWindow.End = maximum; - jobContext.Renderables.Add(_blindscanProgressWindow); + Tasks.EnqueueTask(() => + { + jobContext.Renderables.Add(_blindscanProgressWindow); + }); } public void OnBlindscanAfterBLScan() { - jobContext.Renderables.Remove(_blindscanProgressWindow); - _blindscanProgressWindow = null; + Tasks.EnqueueTask(() => + { + jobContext.Renderables.Remove(_blindscanProgressWindow); + _blindscanProgressWindow = null; + }); } public void OnBlindscanSearchResult1Callback(BlindscanSearchResult searchResult, int polarityIndex, diff --git a/GUIs/skyscraper8.UI.ImGui/skyscraper8.UI.SDL2.csproj b/GUIs/skyscraper8.UI.ImGui/skyscraper8.UI.SDL2.csproj index 4b62cb1..3351dab 100644 --- a/GUIs/skyscraper8.UI.ImGui/skyscraper8.UI.SDL2.csproj +++ b/GUIs/skyscraper8.UI.ImGui/skyscraper8.UI.SDL2.csproj @@ -9,6 +9,14 @@ true + + False + + + + False + + diff --git a/PrivateDataSpecifiers/skyscraper8.EPGCollectorPort/SkyscraperSide/MediaHighway2/Mhw2Scraper.cs b/PrivateDataSpecifiers/skyscraper8.EPGCollectorPort/SkyscraperSide/MediaHighway2/Mhw2Scraper.cs index 71f6d11..7fa8dd6 100644 --- a/PrivateDataSpecifiers/skyscraper8.EPGCollectorPort/SkyscraperSide/MediaHighway2/Mhw2Scraper.cs +++ b/PrivateDataSpecifiers/skyscraper8.EPGCollectorPort/SkyscraperSide/MediaHighway2/Mhw2Scraper.cs @@ -97,6 +97,9 @@ namespace skyscraper8.EPGCollectorPort.SkyscraperSide.MediaHighway2 public void OnMhw2Summary(int sourcePid, MediaHighway2SummarySection summarySection) { + if (summarySection == null) + return; + if (_binders == null) _binders = new Dictionary(); diff --git a/skyscraper8/Ietf/FLUTE/FluteListener.cs b/skyscraper8/Ietf/FLUTE/FluteListener.cs index c7b2192..1da3b8f 100644 --- a/skyscraper8/Ietf/FLUTE/FluteListener.cs +++ b/skyscraper8/Ietf/FLUTE/FluteListener.cs @@ -171,6 +171,7 @@ namespace skyscraper8.Ietf.FLUTE case "ll": case "nunull": case "nulull": + case "nl": break; case "gzip": GZipStream level2 = new GZipStream(level1, CompressionMode.Decompress, false); diff --git a/skyscraper8/InteractionChannel/Model/Cmt.cs b/skyscraper8/InteractionChannel/Model/Cmt.cs index eccbc00..1bf1067 100644 --- a/skyscraper8/InteractionChannel/Model/Cmt.cs +++ b/skyscraper8/InteractionChannel/Model/Cmt.cs @@ -60,6 +60,27 @@ namespace skyscraper5.src.InteractionChannel.Model public int? PowerCorrection { get; internal set; } public int? EsN0 { get; internal set; } public ushort FrequencyCorrection { get; internal set; } + + protected bool Equals(CmtEntry other) + { + return GroupId == other.GroupId && LoginId == other.LoginId && SlotType == other.SlotType; + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) + return false; + if (ReferenceEquals(this, obj)) + return true; + if (obj.GetType() != this.GetType()) + return false; + return Equals((CmtEntry)obj); + } + + public override int GetHashCode() + { + return HashCode.Combine(GroupId, LoginId, (int)SlotType); + } } } } diff --git a/skyscraper8/InteractionChannel/Model/Descriptors/0x4a_LinkageDescriptor.cs b/skyscraper8/InteractionChannel/Model/Descriptors/0x4a_LinkageDescriptor.cs index 3aa9bd6..28bd375 100644 --- a/skyscraper8/InteractionChannel/Model/Descriptors/0x4a_LinkageDescriptor.cs +++ b/skyscraper8/InteractionChannel/Model/Descriptors/0x4a_LinkageDescriptor.cs @@ -81,5 +81,26 @@ namespace skyscraper5.src.InteractionChannel.Model.Descriptors { return new DatabaseKeyRmtLinkage(TransportStreamId, OriginalNetworkId, ServiceId, LinkageType, InteractiveNetworkId); } + + protected bool Equals(_0x4a_LinkageDescriptor other) + { + return TransportStreamId == other.TransportStreamId && OriginalNetworkId == other.OriginalNetworkId && ServiceId == other.ServiceId && LinkageType == other.LinkageType && InteractiveNetworkId == other.InteractiveNetworkId; + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) + return false; + if (ReferenceEquals(this, obj)) + return true; + if (obj.GetType() != this.GetType()) + return false; + return Equals((_0x4a_LinkageDescriptor)obj); + } + + public override int GetHashCode() + { + return HashCode.Combine(TransportStreamId, OriginalNetworkId, ServiceId, LinkageType, InteractiveNetworkId); + } } } diff --git a/skyscraper8/InteractionChannel/Model/Descriptors/0xa8_SatelliteForwardLinkDescriptor.cs b/skyscraper8/InteractionChannel/Model/Descriptors/0xa8_SatelliteForwardLinkDescriptor.cs index 3d2f697..81c182a 100644 --- a/skyscraper8/InteractionChannel/Model/Descriptors/0xa8_SatelliteForwardLinkDescriptor.cs +++ b/skyscraper8/InteractionChannel/Model/Descriptors/0xa8_SatelliteForwardLinkDescriptor.cs @@ -134,5 +134,26 @@ namespace skyscraper5.src.InteractionChannel.Model.Descriptors { return String.Format("{0} kHz,{1}, {2} sym/s", Frequency, Polarization.ToString()[0], SymbolRate); } + + protected bool Equals(_0xa8_SatelliteForwardLinkDescriptor other) + { + return SatelliteId == other.SatelliteId && BeamId == other.BeamId && Frequency == other.Frequency && OrbitalPosition == other.OrbitalPosition && East == other.East && Polarization == other.Polarization && SymbolRate == other.SymbolRate; + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) + return false; + if (ReferenceEquals(this, obj)) + return true; + if (obj.GetType() != this.GetType()) + return false; + return Equals((_0xa8_SatelliteForwardLinkDescriptor)obj); + } + + public override int GetHashCode() + { + return HashCode.Combine(SatelliteId, BeamId, Frequency, OrbitalPosition, East, (int)Polarization, SymbolRate); + } } } diff --git a/skyscraper8/InteractionChannel/Model/Descriptors/0xa9_SatelliteReturnLinkDescriptor.cs b/skyscraper8/InteractionChannel/Model/Descriptors/0xa9_SatelliteReturnLinkDescriptor.cs index 27b31d4..270c6ad 100644 --- a/skyscraper8/InteractionChannel/Model/Descriptors/0xa9_SatelliteReturnLinkDescriptor.cs +++ b/skyscraper8/InteractionChannel/Model/Descriptors/0xa9_SatelliteReturnLinkDescriptor.cs @@ -43,5 +43,26 @@ namespace skyscraper5.src.InteractionChannel.Model.Descriptors { return String.Format("Sat-ID {0}, Beam-ID {1}, Gateway-ID {2}, Superframe-ID {3}, Freq-Offset {4}", SatelliteId, BeamId, GatewayId, SuperframeId, TxFrequencyOffset); } + + protected bool Equals(_0xa9_SatelliteReturnLinkDescriptor other) + { + return SatelliteId == other.SatelliteId && BeamId == other.BeamId && GatewayId == other.GatewayId && OrbitalPosition == other.OrbitalPosition && Eastern == other.Eastern && SuperframeId == other.SuperframeId && TxFrequencyOffset == other.TxFrequencyOffset; + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) + return false; + if (ReferenceEquals(this, obj)) + return true; + if (obj.GetType() != this.GetType()) + return false; + return Equals((_0xa9_SatelliteReturnLinkDescriptor)obj); + } + + public override int GetHashCode() + { + return HashCode.Combine(SatelliteId, BeamId, GatewayId, OrbitalPosition, Eastern, SuperframeId, TxFrequencyOffset); + } } } diff --git a/skyscraper8/InteractionChannel/Model/Fct.cs b/skyscraper8/InteractionChannel/Model/Fct.cs index e7a1ee1..b245839 100644 --- a/skyscraper8/InteractionChannel/Model/Fct.cs +++ b/skyscraper8/InteractionChannel/Model/Fct.cs @@ -62,6 +62,24 @@ namespace skyscraper5.src.InteractionChannel.Model public byte TimeslotId { get; internal set; } public byte RepeatCount { get; internal set; } } + + protected bool Equals(Frame other) + { + return FrameId == other.FrameId && FrameDuration == other.FrameDuration && TotalTimeslotCount == other.TotalTimeslotCount && StartTimeslotNumber == other.StartTimeslotNumber; + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((Frame)obj); + } + + public override int GetHashCode() + { + return HashCode.Combine(FrameId, FrameDuration, TotalTimeslotCount, StartTimeslotNumber); + } } public Frame[] Frames { get; } diff --git a/skyscraper8/InteractionChannel/Model/Rmt.cs b/skyscraper8/InteractionChannel/Model/Rmt.cs index 9c01c6a..826493b 100644 --- a/skyscraper8/InteractionChannel/Model/Rmt.cs +++ b/skyscraper8/InteractionChannel/Model/Rmt.cs @@ -171,6 +171,66 @@ namespace skyscraper5.src.InteractionChannel.Model { return new DatabaseKeyRmtTransportStream(networkId, TransportStreamId, OriginalNetworkId); } + + protected bool Equals(TransportStream other) + { + if (this.TransportStreamId != other.TransportStreamId) + return false; + if (this.OriginalNetworkId != other.OriginalNetworkId) + return false; + if (this.SatelliteForwardLink != null) + { + if (other.SatelliteForwardLink != null) + { + if (!this.SatelliteForwardLink.Equals(other.SatelliteForwardLink)) + return false; + } + else + { + return false; + } + } + else + { + if (other.SatelliteForwardLink != null) + return false; + } + if (this.SatelliteReturnLink != null) + { + if (other.SatelliteReturnLink != null) + { + if (!this.SatelliteReturnLink.Equals(other.SatelliteReturnLink)) + return false; + } + else + { + return false; + } + } + else + { + if (other.SatelliteReturnLink != null) + return false; + } + + return true; + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) + return false; + if (ReferenceEquals(this, obj)) + return true; + if (obj.GetType() != this.GetType()) + return false; + return Equals((TransportStream)obj); + } + + public override int GetHashCode() + { + return HashCode.Combine(TransportStreamId, OriginalNetworkId, SatelliteReturnLink, SatelliteForwardLink); + } } } } diff --git a/skyscraper8/InteractionChannel/Model/Sct.cs b/skyscraper8/InteractionChannel/Model/Sct.cs index 0b76cd0..544a08e 100644 --- a/skyscraper8/InteractionChannel/Model/Sct.cs +++ b/skyscraper8/InteractionChannel/Model/Sct.cs @@ -72,6 +72,27 @@ namespace skyscraper5.src.InteractionChannel.Model public uint FrameStartTime { get; internal set; } public uint FrameCentreFrequencyOffset { get; internal set; } } + + protected bool Equals(Superframe other) + { + return SuperframeId == other.SuperframeId && UplinkPolarization == other.UplinkPolarization && SuperframeCentreFrequency == other.SuperframeCentreFrequency; + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) + return false; + if (ReferenceEquals(this, obj)) + return true; + if (obj.GetType() != this.GetType()) + return false; + return Equals((Superframe)obj); + } + + public override int GetHashCode() + { + return HashCode.Combine(SuperframeId, (int)UplinkPolarization, SuperframeCentreFrequency); + } } } } diff --git a/skyscraper8/InteractionChannel/Model/Spt.cs b/skyscraper8/InteractionChannel/Model/Spt.cs index 980df28..78423d5 100644 --- a/skyscraper8/InteractionChannel/Model/Spt.cs +++ b/skyscraper8/InteractionChannel/Model/Spt.cs @@ -34,6 +34,27 @@ namespace skyscraper5.src.InteractionChannel.Model public uint X { get; internal set; } public uint Y { get; internal set; } public uint Z { get; internal set; } + + protected bool Equals(Satellite other) + { + return Id == other.Id; + } + + public override bool Equals(object? obj) + { + if (ReferenceEquals(null, obj)) + return false; + if (ReferenceEquals(this, obj)) + return true; + if (obj.GetType() != this.GetType()) + return false; + return Equals((Satellite)obj); + } + + public override int GetHashCode() + { + return Id.GetHashCode(); + } } } } diff --git a/skyscraper8/Program.cs b/skyscraper8/Program.cs index a893481..0f2d51d 100644 --- a/skyscraper8/Program.cs +++ b/skyscraper8/Program.cs @@ -39,21 +39,31 @@ namespace skyscraper5 class Program { private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); - private const int PUBLIC_RELEASE = 5; + private const int PUBLIC_RELEASE = 7; private static void IntegrationTest() { - /*List ssdpDevices = SsdpClient.GetSsdpDevices(1000).ToList(); - foreach (SsdpDevice ssdpDevice in ssdpDevices) - { - Console.WriteLine("SSDP device: {0}", ssdpDevice.Server); - }*/ + PluginManager pluginManager = PluginManager.GetInstance(); + StorageConnectionManager storageConnectionManager = StorageConnectionManager.GetInstance(); + DataStorageFactory dataStorageFactory = storageConnectionManager.GetDefaultDataStorageFactory(); + ObjectStorageFactory objectStorageFactory = storageConnectionManager.GetDefaultObjectStorageFactory(); + M3U8Stream m3U8Stream = new M3U8Stream("D:\\NIP-Research\\nip.m3u8"); - //"urn:ses-com:device:SatIPServer:1" + SkyscraperContext context = new SkyscraperContext(new TsContext(), dataStorageFactory.CreateDataStorage(), objectStorageFactory.CreateObjectStorage()); + context.InitalizeFilterChain(); + context.IngestFromStream(m3U8Stream); + + /*List ssdpDevices = SsdpClient.GetSsdpDevices(1000).ToList(); + foreach (SsdpDevice ssdpDevice in ssdpDevices) + { + Console.WriteLine("SSDP device: {0}", ssdpDevice.Server); + }*/ + + //"urn:ses-com:device:SatIPServer:1" /*PluginManager pluginManager = PluginManager.GetInstance(); StorageConnectionManager storageConnectionManager = StorageConnectionManager.GetInstance(); ObjectStorageFactory objectStorageFactory = storageConnectionManager.GetDefaultObjectStorageFactory(); ObjectStorage objectStorage = objectStorageFactory.CreateObjectStorage();*/ - + /*url = RtspClient.MakeUrl(DiSEqC_Opcode.DISEQC_OPTION_A | DiSEqC_Opcode.DISEQC_POSITION_A | DiSEqC_Opcode.DISEQC_HORIZONTAL, 11141, true, 23500); describe = rtspClient.GetDescribe(url); sessionDescriptionProtocol = describe.GetSessionDescriptionProtocol(); @@ -285,6 +295,7 @@ namespace skyscraper5 Console.WriteLine("for example: .\\skyscraper8.exe cscan tcp://127.0.0.1:6969"); Console.WriteLine(" or: .\\skyscraper8.exe \"C:\\path\\to\\file.ts\\"); Console.WriteLine(" or: .\\skyscraper8.exe \"C:\\path\\to\\my\\folder\\with\\ts\\files\\\" (for batch extraction)"); + Console.WriteLine(" or: .\\skyscraper8.exe satip IP_ADDRESS DISEQC POLARITY FREQUENCY SYSTEM SYMBOL_RATE (see README file)"); Console.WriteLine(); Console.WriteLine("Bonus feature:"); Console.WriteLine(".\\skyscraper8.exe hlsproxy \"C:\\path\\to\\hls\\files\\\" - to pipe a HLS stream from a local directory into VLC."); diff --git a/skyscraper8/Properties/launchSettings.json b/skyscraper8/Properties/launchSettings.json index 8edf834..4075ac8 100644 --- a/skyscraper8/Properties/launchSettings.json +++ b/skyscraper8/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "skyscraper8": { "commandName": "Project", - "commandLineArgs": "satip autodetect 1 V 12363 S 27500", + "commandLineArgs": "cscan tcp://172.20.20.203:6969", "remoteDebugEnabled": false }, "Container (Dockerfile)": { diff --git a/skyscraper8/QuickAndDirtySatIpClient.cs b/skyscraper8/QuickAndDirtySatIpClient.cs index 8fa3653..360bd1f 100644 --- a/skyscraper8/QuickAndDirtySatIpClient.cs +++ b/skyscraper8/QuickAndDirtySatIpClient.cs @@ -118,6 +118,7 @@ namespace skyscraper8 context.InitalizeFilterChain(); RtspPlayResponse play = rtspClient.GetPlay(setup); + DateTime lastTimestamp = DateTime.Now; while (true) { @@ -137,25 +138,40 @@ namespace skyscraper8 if (context.IsAbortConditionMet()) break; + + if (DateTime.Now.Second != lastTimestamp.Second) + { + Keepalive(url); + lastTimestamp = DateTime.Now; + } } rtspClient.GetTeardown(setup); rtspClient.Dispose(); } + private uint stuffingBytes; private Queue packetQueue; private ObjectStorage objectStorage; private DataStorage dataStorage; private SkyscraperContext context; private void Setup_OnRtpPacket(byte[] data, int length) { - for (int i = 12; i < length; i += 188) + for (int i = 12; i < length; i += 1) { - byte[] buffer = new byte[188]; - Array.Copy(data, i, buffer, 0, 188); - lock (packetQueue) + if (data[i] == 'G') { - packetQueue.Enqueue(buffer); + byte[] buffer = new byte[188]; + Array.Copy(data, i, buffer, 0, 188); + lock (packetQueue) + { + packetQueue.Enqueue(buffer); + } + i += 187; + } + else if (data[i] == 0xff) + { + stuffingBytes++; } } } diff --git a/skyscraper8/SatIp/RtspClient.cs b/skyscraper8/SatIp/RtspClient.cs index 0debcd7..5cd33c8 100644 --- a/skyscraper8/SatIp/RtspClient.cs +++ b/skyscraper8/SatIp/RtspClient.cs @@ -255,24 +255,29 @@ namespace skyscraper8.SatIp public static string MakeUrl(DiSEqC_Opcode diseqcChannel, int freq, bool isS2, int symbolrate) { - byte diseqc; + bool diseqcOk = false; + byte diseqc = 1; if (diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_OPTION_A) && diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_POSITION_A)) { diseqc = 1; + diseqcOk = true; } - else if (diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_OPTION_A) && diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_POSITION_B)) + if (diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_OPTION_A) && diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_POSITION_B)) { diseqc = 2; + diseqcOk = true; } - else if (diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_OPTION_B) && diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_POSITION_A)) + if (diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_OPTION_B) && diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_POSITION_A)) { diseqc = 3; + diseqcOk = true; } - else if (diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_OPTION_B) && diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_POSITION_B)) + if (diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_OPTION_B) && diseqcChannel.HasFlag(DiSEqC_Opcode.DISEQC_POSITION_B)) { diseqc = 4; + diseqcOk = true; } - else + if (!diseqcOk) { throw new ArgumentOutOfRangeException(nameof(diseqcChannel)); } diff --git a/skyscraper8/SatIpReadme.txt b/skyscraper8/SatIpReadme.txt new file mode 100644 index 0000000..f03e8c1 --- /dev/null +++ b/skyscraper8/SatIpReadme.txt @@ -0,0 +1,22 @@ +How to use skyscraper8 with a SAT>IP server: +The general commandline is as follows: + +.\skyscraper8.exe satip IP_ADDRESS DISEQC POLARITY FREQUENCY SYSTEM SYMBOL_RATE + +IP_ADDRESS is either the IP address (for example 172.20.20.122) of your SAT>IP server, or "auto" for autodetection of a SAT>IP server. + +DISEQC is the DiSEqC 1.0 Port you want to use. Say "1" here for A/A, "2" for B/A, "3" for A/B, 4 for B/B + +POLARITY is either "H" or "V" + +FREQUENCY is the frequency you want to tune to in MHz. (for example 12226) + +SYSTEM is either "S" or "S2" + +SYMBOL_RATE is the symbol rate of the transponder you want to tune to in Ks. (for example 27500) + +So a valid command would be for example ".\skyscraper8.exe satip 172.20.20.122 2 V 12226 S2 27500" to tune to the Hotbird DVB-NIP demo transponder, assuming Hotbird is at DiSEqC B/A. + +If you don't know your SAT>IP server address, the following command would accomplish the same: ".\skyscraper8.exe satip auto 2 V 12226 S2 27500" + +If your SAT>IP server features a StiD135 chipset, you can also catch GS/GSE with it. \ No newline at end of file diff --git a/skyscraper8/SatIp/IRtspCache.cs b/skyscraper8/SimpleServiceDiscoveryProtocol/ISsdpCache.cs similarity index 74% rename from skyscraper8/SatIp/IRtspCache.cs rename to skyscraper8/SimpleServiceDiscoveryProtocol/ISsdpCache.cs index 9bc0bc3..718cdef 100644 --- a/skyscraper8/SatIp/IRtspCache.cs +++ b/skyscraper8/SimpleServiceDiscoveryProtocol/ISsdpCache.cs @@ -3,11 +3,10 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; -using skyscraper8.SimpleServiceDiscoveryProtocol; -namespace skyscraper8.SatIp +namespace skyscraper8.SimpleServiceDiscoveryProtocol { - public interface IRtspCache + public interface ISsdpCache { bool SsdpDeviceKnown(SsdpDevice ssdpDevice); void SsdpStoreMetadata(SsdpDevice ssdpDevice, byte[] ssdpMetadataByteArray); diff --git a/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpClient.cs b/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpClient.cs index db632c8..13a4cc7 100644 --- a/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpClient.cs +++ b/skyscraper8/SimpleServiceDiscoveryProtocol/SsdpClient.cs @@ -8,7 +8,6 @@ using System.Net.Sockets; using System.Text; using System.Threading.Tasks; using System.Xml.Serialization; -using skyscraper8.SatIp; using skyscraper8.Ssdp.Schema; namespace skyscraper8.SimpleServiceDiscoveryProtocol @@ -125,7 +124,7 @@ namespace skyscraper8.SimpleServiceDiscoveryProtocol return Int32.MinValue; } - public static List GetSsdpDevices(int timeout = 1000, string searchTarget = null, IRtspCache cache = null) + public static List GetSsdpDevices(int timeout = 1000, string searchTarget = null, ISsdpCache cache = null) { List inputList = GetSsdpDevices(timeout).ToList(); List outputList = new List(); @@ -168,7 +167,7 @@ namespace skyscraper8.SimpleServiceDiscoveryProtocol return outputList; } - public static SsdpDevice GetFirstSatIpServer(int timeout = 1000, IRtspCache cache = null) + public static SsdpDevice GetFirstSatIpServer(int timeout = 1000, ISsdpCache cache = null) { List ssdpDevices = GetSsdpDevices(1000, "urn:ses-com:device:SatIPServer:1", cache); if (ssdpDevices.Count == 0) diff --git a/skyscraper8/Skyscraper/FrequencyListGenerator/BlindscanSearchResult.cs b/skyscraper8/Skyscraper/FrequencyListGenerator/BlindscanSearchResult.cs index 5fcaf46..d86b836 100644 --- a/skyscraper8/Skyscraper/FrequencyListGenerator/BlindscanSearchResult.cs +++ b/skyscraper8/Skyscraper/FrequencyListGenerator/BlindscanSearchResult.cs @@ -29,6 +29,7 @@ namespace skyscraper8.Skyscraper.FrequencyListGenerator case STD_TYPE.STD_DVBC2: return false; case STD_TYPE.STD_DVBT: return false; case STD_TYPE.STD_DVBT2: return false; + case STD_TYPE.STD_AUTO: return true; default: throw new NotImplementedException(Standard.ToString()); } } diff --git a/skyscraper8/Skyscraper/FrequencyListGenerator/SatIpWithStreamReaderProxy.cs b/skyscraper8/Skyscraper/FrequencyListGenerator/SatIpWithStreamReaderProxy.cs new file mode 100644 index 0000000..0d116cb --- /dev/null +++ b/skyscraper8/Skyscraper/FrequencyListGenerator/SatIpWithStreamReaderProxy.cs @@ -0,0 +1,508 @@ +using log4net; +using skyscraper5.Skyscraper.IO; +using skyscraper5.Skyscraper.IO.CrazycatStreamReader; +using skyscraper8.SatIp; +using skyscraper8.SatIp.RtspResponses; +using skyscraper8.SimpleServiceDiscoveryProtocol; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Reflection.Emit; +using System.Runtime.InteropServices; +using System.Security.Policy; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Skyscraper.FrequencyListGenerator +{ + public class SatIpWithStreamReaderProxy : IStreamReader + { + public SatIpWithStreamReaderProxy(IStreamReader streamReader, ISsdpCache cache = null) + { + this.ProxiedStreamReader = streamReader; + this.SsdpDescriptorCache = cache; + streamReader.StopDVB(); + } + + private int satIpLof1; + private bool satIpS2Mode; + private int satipFrequency; + private int satipSymbolrate; + private DiSEqC_Opcode satIpDiseqc; + private IPAddress satIpServerAddress; + + private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + public ISsdpCache SsdpDescriptorCache { get; private set; } + public IStreamReader ProxiedStreamReader { get; private set; } + public void Dispose() + { + throw new NotImplementedException(); + } + + public bool CheckForDVB() + { + throw new NotImplementedException(); + } + + public bool CheckForDVBEx(DvbEnumCallback func) + { + throw new NotImplementedException(); + } + + public bool CheckForDVBExEx(DvbEnumCallbackEx func) + { + throw new NotImplementedException(); + } + + public bool StartDVB() + { + throw new NotImplementedException(); + } + + public bool StartDvbEx(int index) + { + if (satIpServerAddress == null) + { + logger.Info("Looking for SAT>IP Server..."); + SsdpDevice satIpServer = SsdpClient.GetFirstSatIpServer(1000, SsdpDescriptorCache); + if (satIpServer == null) + { + logger.Error("Couldn't find any SAT>IP servers."); + return false; + } + + satIpServerAddress = satIpServer.GetIpAddress(); + if (satIpServerAddress == null) + { + logger.ErrorFormat("Failed to find the IP Address of {0}", satIpServer.Server); + return false; + } + logger.InfoFormat("Found SAT>IP Server at {0}", satIpServerAddress); + } + + return ProxiedStreamReader.StartDvbEx(index); + } + + public bool StopDVB() + { + throw new NotImplementedException(); + } + + public bool GetTunerType(ref STD_TYPE type) + { + throw new NotImplementedException(); + } + + public bool SendDiSEqC(uint diseqcType, DiSEqC_Opcode data) + { + bool result = ProxiedStreamReader.SendDiSEqC(diseqcType, data); + if (result) + satIpDiseqc = data; + return result; + } + + public bool SendDiseqCmd(byte[] buffer, int length) + { + throw new NotImplementedException(); + } + + public bool SendDiseqCmdEx(nint pCmd, int length, nint reply, int replyLength) + { + throw new NotImplementedException(); + } + + public bool SetChannel(int freq, int symbrate, int pol, VITERBIRATE_TYPE fec, int lof1, int lof2, int lofsw) + { + satipFrequency = freq / 1000; + satipSymbolrate = symbrate / 1000; + satIpLof1 = lof1; + return ProxiedStreamReader.SetChannel(freq, symbrate, pol, fec, lof1, lof2, lofsw); + } + + public bool SetChannelEx(int freq, int symbrate, int pol, VITERBIRATE_TYPE fec, int lof1, int lof2, int lofsw, MOD_TYPE mod) + { + throw new NotImplementedException(); + } + + public bool SetChannelExEx(int freq, int symbrate, int pol, VITERBIRATE_TYPE fec, int lof1, int lof2, int lofsw, MOD_TYPE mod, + int inv, int pilot, ROLLOFF_TYPE rolloff) + { + throw new NotImplementedException(); + } + + private bool rtspStopped; + private bool rtspStopAsked; + private Thread rtspWorkerThread; + private IntPtr rtspDummyHandle; + private StdcallDvbCallback rtspCallback; + private RtspSetupResponse rtspSetup; + private Queue rtspPacketQueue; + private string rtspUrl; + private RtspClient rtspClient; + public bool SetFilter(int pid, StdcallDvbCallback func, int callbackType, int size, ref nint lpFilterNum) + { + rtspClient = new RtspClient(satIpServerAddress, 554); + RtspKeepalive(); + rtspUrl = RtspClient.MakeUrl(satIpDiseqc, satipFrequency, satIpS2Mode, satipSymbolrate); + RtspDescribeResponse describe = rtspClient.GetDescribe(rtspUrl); + if (describe.RtspStatusCode != 200) + { + return false; + } + SessionDescriptionProtocol sessionDescriptionProtocol = describe.GetSessionDescriptionProtocol(); + + rtspPacketQueue = new Queue(); + rtspSetup = rtspClient.GetSetup(rtspUrl); + if (rtspSetup.RtspStatusCode != 200) + { + return false; + } + rtspSetup.OnRtcpPacket += RtspSetup_OnRtcpPacket; + rtspSetup.OnRtpPacket += RtspSetup_OnRtpPacket; + rtspCallback = func; + + RtspPlayResponse play = rtspClient.GetPlay(rtspSetup); + if (play.RtspStatusCode != 200) + { + return false; + } + + rtspDummyHandle = new nint(9001); + lpFilterNum = rtspDummyHandle; + rtspStopAsked = false; + rtspWorkerThread = new Thread(RtspWorkerThreadFunction); + rtspWorkerThread.Name = "RTSP Worker Thread"; + rtspWorkerThread.Start(); + return true; + } + + private void RtspWorkerThreadFunction() + { + IntPtr unsafeBuffer = Marshal.AllocHGlobal(188); + + DateTime lastKnownTimestamp = DateTime.Now; + while (!rtspStopAsked) + { + DateTime currentTimestamp = DateTime.Now; + if (currentTimestamp.Second != lastKnownTimestamp.Second) + { + RtspKeepalive(rtspUrl); + lastKnownTimestamp = currentTimestamp; + } + + if (rtspPacketQueue.Count > 0) + { + byte[] dequeue = rtspPacketQueue.Dequeue(); + if (dequeue == null) + continue; + for (int i = 12; i < dequeue.Length; i += 1) + { + if (dequeue[i] == 'G') + { + Marshal.Copy(dequeue, i, unsafeBuffer, 188); + i += 187; + rtspCallback(unsafeBuffer, 188); + } + else + { + throw new Exception("Help! I lost my sync byte!"); + } + } + } + else + { + Thread.Sleep(1); + } + } + + RtspTeardownResponse teardown = rtspClient.GetTeardown(rtspSetup); + rtspStopAsked = false; + rtspStopped = true; + Marshal.FreeHGlobal(unsafeBuffer); + } + + private void RtspSetup_OnRtpPacket(byte[] data, int length) + { + byte[] queuableBuffer = new byte[length]; + Array.Copy(data, 0, queuableBuffer, 0, length); + rtspPacketQueue.Enqueue(queuableBuffer); + } + + private long rtcps; + private void RtspSetup_OnRtcpPacket(byte[] data, int length) + { + rtcps++; + } + + private void RtspKeepalive(string url = "/") + { + RtspOptionsResponse options = rtspClient.GetOptions("/"); + if (options.RtspStatusCode != 200) + { + throw new RtspException(String.Format("Unexpected RTSP Status code. Wanted {0}, got {1}", 200, options.RtspStatusCode)); + } + } + + public bool SetFilterEx(int pid, StdcallDvbCallbackEx lpFunc, int callbackType, int size, ref nint lpFilterNum) + { + throw new NotImplementedException(); + } + + public bool SetBitFilter(int pid, nint filterData, nint filterMask, byte filterLength, StdcallDvbCallback lpFunc, + ref nint lpFilterNum) + { + throw new NotImplementedException(); + } + + public bool SetRemoteControl(int irtype, short devAddr, StdcallDvbCallback func, ref nint lpFilterNum) + { + throw new NotImplementedException(); + } + + public bool DelFilter(nint filterNum) + { + rtspStopAsked = true; + while (!rtspStopped) + Thread.Sleep(10); + + rtspStopped = false; + rtspStopAsked = false; + rtspWorkerThread = null; + rtspDummyHandle = IntPtr.Zero; + rtspCallback = null; + rtspSetup = null; + rtspPacketQueue = null; + rtspUrl = null; + rtspClient = null; + + return true; + } + + public bool GetSignal(ref int pStrength, ref int pQuality) + { + throw new NotImplementedException(); + } + + public bool GetSignalStrength(ref float pStrength, ref float pQuality) + { + throw new NotImplementedException(); + } + + public bool GetSignalEx(ref float pSNR, ref float pBER) + { + throw new NotImplementedException(); + } + + public bool GetSignalExEx(ref bool pPresent, ref bool pLock, ref int pRFLevel, ref float pSNR, ref float pBER) + { + throw new NotImplementedException(); + } + + public bool Statistic(int[] pStat) + { + throw new NotImplementedException(); + } + + public bool GetMAC(byte[] pMac) + { + throw new NotImplementedException(); + } + + public Caps GetCaps() + { + throw new NotImplementedException(); + } + + public bool RFScan(int freq, int pol, int lof1, int lof2, int lofsw, out double pRFLevel) + { + throw new NotImplementedException(); + } + + public bool FFTInit() + { + throw new NotImplementedException(); + } + + public bool FFTScan(int freq, int pol, int lof1, int lof2, int lofsw, uint range, byte mode, byte nb_acc, nint pTab, + nint pBegin, nint pNum) + { + throw new NotImplementedException(); + } + + public bool BLScan(int freq, int freq_range, int pol, int lof1, int lof2, int lofsw, int minsr, + ref SearchResult pSearchResult) + { + throw new NotImplementedException(); + } + + public bool BLScanEx(int freq, int freq_range, int pol, int lof1, int lof2, int lofsw, int minsr, STD_TYPE std, + ref SearchResult pSearchResult) + { + bool result = ProxiedStreamReader.BLScanEx(freq, freq_range, pol, lof1, lof2, lofsw, minsr, std, ref pSearchResult); + if (result) + { + satipFrequency = pSearchResult.Freq / 1000; + satipSymbolrate = pSearchResult.SR / 1000; + switch (pSearchResult.StdType) + { + case 0: + //For some reason, StreamReader says this when there's no lock? + satIpS2Mode = false; + break; + case 1: + satIpS2Mode = false; + break; + case 2: + satIpS2Mode = true; + break; + default: + throw new NotImplementedException(String.Format("{0} {1}", nameof(pSearchResult.StdType), pSearchResult.StdType)); + } + } + + return result; + } + + public bool BLScan2(int freq_start, int freq_stop, int pol, int lof1, int lof2, int lofsw, nint pSearchResult, ref int pTpNum, + BlScanCallback lpFunc) + { + return ProxiedStreamReader.BLScan2(freq_start, freq_stop, pol, lof1, lof2, lofsw, pSearchResult, ref pTpNum, lpFunc); + } + + public bool SignalInfo(ref SearchResult pSearchResult) + { + bool result = ProxiedStreamReader.SignalInfo(ref pSearchResult); + if (result) + { + switch (pSearchResult.StdType) + { + case 0: + //For some reason, StreamReader says this when there's no lock? + satIpS2Mode = false; + break; + case 1: + satIpS2Mode = false; + break; + case 2: + satIpS2Mode = true; + break; + default: + throw new NotImplementedException(String.Format("{0} {1}", nameof(pSearchResult.StdType), pSearchResult.StdType)); + } + } + return result; + } + + public bool IQScan(uint input, sbyte[] pIQ, uint num) + { + throw new NotImplementedException(); + } + + public bool IQScan2(uint point, short[] pIQ, uint num) + { + throw new NotImplementedException(); + } + + public bool IQScan2Range(byte input, ref ushort pMinPoint, ref ushort pMaxPoint) + { + throw new NotImplementedException(); + } + + public bool CIRScanRange(bool bHiRes, ref ushort pMinCnum, ref ushort pMaxCnum, ref int pMinDelayNs, ref int pMaxDelayNs) + { + throw new NotImplementedException(); + } + + public bool CIRScan(bool bHiRes, int[] pPowers, int[] pDelays) + { + throw new NotImplementedException(); + } + + public bool CarRange(ref ushort pMinCnum, ref ushort pMaxCnum) + { + throw new NotImplementedException(); + } + + public bool CarEsNo(ref ushort cnum, ref double pEsNo) + { + throw new NotImplementedException(); + } + + public bool MISSel(bool bEnable, byte misFilter, byte misFilterMask) + { + throw new NotImplementedException(); + } + + public bool PLSSel(byte plsMode, uint code) + { + throw new NotImplementedException(); + } + + public bool PLSGet(byte pMode, ref uint pCode) + { + throw new NotImplementedException(); + } + + public bool ModSel(ref S2Mode ps2Modes, uint num) + { + throw new NotImplementedException(); + } + + public bool ModInv(uint WaitMs, ref S2Mode pS2Modes, ref uint pNum) + { + throw new NotImplementedException(); + } + + public bool SetChannel2(uint freq, uint bandwidth) + { + throw new NotImplementedException(); + } + + public bool SetChannel2Ex(uint freq, uint bandwidth, STD_TYPE std, int stream) + { + throw new NotImplementedException(); + } + + public bool SetChannel2ExEx(uint freq, uint bandwidth, uint symbrate, STD_TYPE std, int stream) + { + throw new NotImplementedException(); + } + + public bool SignalInfo2(ref SearchResult2 si2) + { + throw new NotImplementedException(); + } + + public bool RFScan2(uint freq, STD_TYPE std, ref double pRFLevel) + { + throw new NotImplementedException(); + } + + public bool AirScan(int freq_start, int freq_stop, uint step, uint bandwidth, int std, nint pSearchResult, ref int pTpNum, + AirScanCallback lpFunc) + { + throw new NotImplementedException(); + } + + public bool GetEEPROM(byte[] buffer, int offset, int len) + { + throw new NotImplementedException(); + } + + public bool SetEEPROM(byte[] buffer, int offset, int len) + { + throw new NotImplementedException(); + } + + public Version GetEngineVersion() + { + throw new NotImplementedException(); + } + + public string GetEngineName() + { + throw new NotImplementedException(); + } + } +} diff --git a/skyscraper8/Skyscraper/Plugins/PluginManager.cs b/skyscraper8/Skyscraper/Plugins/PluginManager.cs index 100d7d0..fcadb7b 100644 --- a/skyscraper8/Skyscraper/Plugins/PluginManager.cs +++ b/skyscraper8/Skyscraper/Plugins/PluginManager.cs @@ -42,7 +42,7 @@ namespace skyscraper5.Skyscraper.Plugins _mpeg2ExtensionDescriptors = new ConstructorInfo[256]; ScanAssembly(this.GetType().Assembly); - + FileInfo iniFileInfo = new FileInfo(iniFilename); if (iniFileInfo.Exists) { @@ -77,6 +77,45 @@ namespace skyscraper5.Skyscraper.Plugins { Debug.WriteLine(String.Format("{0} was not found. Create it using the UI!", iniFileInfo.FullName)); } + + FileInfo fi = GetSkyscraperMainAssembly(); + if (fi != null) + { + DirectoryInfo directory = fi.Directory; + logger.DebugFormat("Found skyscraper main assembly at: {0}", directory.FullName); + FileInfo[] fileInfos = directory.GetFiles("skyscraper5.*.dll"); + foreach (FileInfo fileInfo in fileInfos) + { + try + { + logger.Info(String.Format("Trying to load: {0}", fileInfo.Name)); + Assembly loadFile = Assembly.LoadFile(fileInfo.FullName); + ScanAssembly(loadFile); + logger.Debug(String.Format("Loaded {0}", fileInfo.Name)); + } + catch (Exception e) + { + logger.ErrorFormat("Failed to scan assembly {0}", fileInfo.Name); + } + } + } + } + + private FileInfo GetSkyscraperMainAssembly() + { + try + { + Type type = typeof(PluginManager); + Assembly assembly = type.Assembly; + string location = assembly.Location; + FileInfo fileInfo = new FileInfo(location); + return fileInfo; + } + catch (Exception e) + { + logger.Warn(String.Format("Failed to resolve skyscraper main assembly."), e); + return null; + } } private HashSet resolveDirectoryInfos; diff --git a/skyscraper8/Skyscraper/Scraper/PmtTracker.cs b/skyscraper8/Skyscraper/Scraper/PmtTracker.cs new file mode 100644 index 0000000..a43821b --- /dev/null +++ b/skyscraper8/Skyscraper/Scraper/PmtTracker.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using log4net; + +namespace skyscraper8.Skyscraper.Scraper +{ + internal class PmtTracker + { + private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); + + class PmtInfo + { + public bool IsProcessed { get; set; } + } + + private Dictionary knownPmts; + + public bool AllPmtsProcessed + { + get + { + foreach (KeyValuePair kvp in knownPmts) + { + if (!kvp.Value.IsProcessed) + return false; + } + + return true; + } + } + + public void AddPmtPid(int pmtPid) + { + if (knownPmts == null) + knownPmts = new Dictionary(); + + if (!knownPmts.ContainsKey(pmtPid)) + knownPmts.Add(pmtPid, new PmtInfo()); + } + + private bool allProccessedAnnounced; + public void MarkAsProcessed(int pmtPid) + { + if (!knownPmts.ContainsKey(pmtPid)) + return; + + knownPmts[pmtPid].IsProcessed = true; + + if (!allProccessedAnnounced && AllPmtsProcessed) + { + logger.DebugFormat("All {0} PMTs have now been checked.", knownPmts.Count); + allProccessedAnnounced = true; + } + } + + private bool autodetectionFired; + public bool ShouldFireAutodetection() + { + if (autodetectionFired) + return false; + + if (AllPmtsProcessed) + { + autodetectionFired = true; + return true; + } + + return false; + } + } +} diff --git a/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs b/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs index b0f4a94..e1adfc2 100644 --- a/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs +++ b/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs @@ -78,6 +78,7 @@ using System.Security.Policy; using System.Text; using skyscraper8.Experimentals.NdsSsu; using skyscraper8.Experimentals.OtvSsu; +using skyscraper8.Skyscraper.Scraper; using Tsubasa.IO; using Platform = skyscraper5.Dvb.SystemSoftwareUpdate.Model.Platform; using RntParser = skyscraper5.Dvb.TvAnytime.RntParser; @@ -417,6 +418,8 @@ namespace skyscraper5.Skyscraper.Scraper LogEvent(SkyscraperContextEvent.NetworkPidFromPat); } + private PmtTracker pmtTracker; + public void ProgramMapPidFromPat(int pmtPid, ushort programId) { SpecialTsType = 1; @@ -437,6 +440,10 @@ namespace skyscraper5.Skyscraper.Scraper DvbContext.RegisterPacketProcessor(pmtPid, pmtParser); LogEvent(SkyscraperContextEvent.ProgramMapPidFromPat); UiJunction?.NotifyPatProgram(pmtPid, programId); + + if (pmtTracker == null) + pmtTracker = new PmtTracker(); + pmtTracker.AddPmtPid(pmtPid); } public void SetTransportStreamId(ushort transportStreamId) @@ -453,7 +460,7 @@ namespace skyscraper5.Skyscraper.Scraper public void PmtEvent(ProgramMapping result, int pmtPid) { - bool logworthy = false; + bool logworthy = false; if (CurrentNetworkId.HasValue && CurrentTransportStreamId.HasValue) { @@ -665,6 +672,12 @@ namespace skyscraper5.Skyscraper.Scraper LogEvent(SkyscraperContextEvent.PmtEvent, String.Format("#{0}", result.ProgramNumber)); UiJunction?.NotifyPmtProgram(result, pmtPid); + + pmtTracker?.MarkAsProcessed(pmtPid); + if (pmtTracker.ShouldFireAutodetection()) + { + CheckForHiddenMpes(); + } } public void MakeUpComponentTags(ProgramMapping target) @@ -2264,7 +2277,7 @@ namespace skyscraper5.Skyscraper.Scraper { if (!DataStorage.TestForCmtEntry(interactiveNetworkId,entry)) { - LogEvent(SkyscraperContextEvent.CorrectionMessage, String.Format("Network ID = {0}, Group ID = {1}, Logon ID = {2}", interactiveNetworkId, entry.GroupId, entry.LoginId)); + LogEvent(SkyscraperContextEvent.CorrectionMessage, String.Format("Network ID = {0}, Group ID = {1}, Logon ID = {2}, Slot Type = {3}", interactiveNetworkId, entry.GroupId, entry.LoginId,entry.SlotType.ToString())); DataStorage.InsertCmtEntry(interactiveNetworkId, entry); } } @@ -2305,7 +2318,7 @@ namespace skyscraper5.Skyscraper.Scraper { if (!DataStorage.TestForRmtLinkage(linkage)) { - LogEvent(SkyscraperContextEvent.RmtLinkage, String.Format("{0} -> {1},{2}", linkage.InteractiveNetworkId, linkage.OriginalNetworkId, linkage.TransportStreamId)); + LogEvent(SkyscraperContextEvent.RmtLinkage, String.Format("Interactive Network #{0} -> ONID {1}, TSID {2}", linkage.InteractiveNetworkId, linkage.OriginalNetworkId, linkage.TransportStreamId)); DataStorage.InsertRmtLinkage(linkage); } } @@ -2319,9 +2332,36 @@ namespace skyscraper5.Skyscraper.Scraper LogEvent(SkyscraperContextEvent.RmtTransportStream, String.Format("{0} -> {1},{2}", rmt.NetworkId, transportStream.OriginalNetworkId, transportStream.TransportStreamId)); DataStorage.InsertRmtTransportStream(rmt.NetworkId, transportStream); } - } + } } } + + private void CheckForHiddenMpes() + { + uint threshold = 1000; + if (pmtTracker != null) + { + if (!pmtTracker.AllPmtsProcessed) + { + return; + } + + threshold = 1; + } + int[] occupiedPids = DvbContext.GetOccupiedPids(); + ulong[] pidStatistics = DvbContext.GetPidStatistics(); + for (int i = 0; i < (pidStatistics.Length - 1); i++) + { + if (pidStatistics[i] > threshold) + { + if (!occupiedPids.Contains(i)) + { + LogEvent(SkyscraperContextEvent.SpecialTsMode, String.Format("Attaching stream-type autodetector to PID 0x{0:X4}", i)); + DvbContext.RegisterPacketProcessor(i, new StreamTypeAutodetection(i, this)); + } + } + } + } public void OnSatellitePosition(ushort interactiveNetworkId, Spt spt) { @@ -2329,7 +2369,7 @@ namespace skyscraper5.Skyscraper.Scraper { if (!DataStorage.TestForSatellitePosition(interactiveNetworkId,satellite)) { - LogEvent(SkyscraperContextEvent.SatellitePosition, String.Format("NID = {0}, Satellite ID = {1}", interactiveNetworkId, satellite.Id)); + LogEvent(SkyscraperContextEvent.SatellitePosition, String.Format("NID = {0}, Satellite ID = {1} (X = {2}, Y = {3}, Z = {4})", interactiveNetworkId, satellite.Id, satellite.X, satellite.Y, satellite.Z)); DataStorage.StoreSatellitePosition(interactiveNetworkId, satellite); } } @@ -2341,7 +2381,7 @@ namespace skyscraper5.Skyscraper.Scraper { if (!DataStorage.TestForSuperframeComposition(interactiveNetworkId,superframe)) { - LogEvent(SkyscraperContextEvent.SuperframeComposition, String.Format("Network ID = {0}, Superframe ID = {1}", interactiveNetworkId, superframe.SuperframeId)); + LogEvent(SkyscraperContextEvent.SuperframeComposition, String.Format("Network ID = {0}, Superframe ID = {1}, Frequency = {2}/{3}", interactiveNetworkId, superframe.SuperframeId, superframe.SuperframeCentreFrequency,superframe.UplinkPolarization)); DataStorage.StoreSuperframeComposition(interactiveNetworkId, superframe); } } diff --git a/skyscraper8/Skyscraper/Scraper/Storage/DataStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/DataStorage.cs index cab001e..169f456 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/DataStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/DataStorage.cs @@ -191,7 +191,7 @@ namespace skyscraper8.Skyscraper.Scraper.Storage void Ping(); IEnumerable> GetBlindscanResultFrequencies(Guid selectedGuid); - void InsertUiBlindscanSettingHistory(int settingsWindowBlScanTunerSelection, bool settingsWindowUseDifferentTunerForSetFilter, int settingsWindowSetFilterTunerSelection, int settingsWindowDiseqc, bool settingsWindowCollectIqGraphs, bool settingsWindowCollectRfSpectrum, bool settingsWindowCaptureFile, int settingsWindowSatellite, int settingsWindowLnb, int dish, bool settingsWindowScanHorizontalLow, bool settingsWindowScanHorizontalHigh, bool settingsWindowScanVerticalLow, bool settingsWindowScanVerticalHigh); + void InsertUiBlindscanSettingHistory(int settingsWindowBlScanTunerSelection, int settingsWindowUseDifferentTunerForSetFilter, int settingsWindowSetFilterTunerSelection, int settingsWindowDiseqc, bool settingsWindowCollectIqGraphs, bool settingsWindowCollectRfSpectrum, bool settingsWindowCaptureFile, int settingsWindowSatellite, int settingsWindowLnb, int dish, bool settingsWindowScanHorizontalLow, bool settingsWindowScanHorizontalHigh, bool settingsWindowScanVerticalLow, bool settingsWindowScanVerticalHigh); object[] GetLastUiBlindscanSettings(); } } diff --git a/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs index eeb2947..bba180d 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs @@ -1124,7 +1124,7 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.Filesystem } public void InsertUiBlindscanSettingHistory(int settingsWindowBlScanTunerSelection, - bool settingsWindowUseDifferentTunerForSetFilter, int settingsWindowSetFilterTunerSelection, + int multitunerMode, int settingsWindowSetFilterTunerSelection, int settingsWindowDiseqc, bool settingsWindowCollectIqGraphs, bool settingsWindowCollectRfSpectrum, bool settingsWindowCaptureFile, int settingsWindowSatellite, int settingsWindowLnb, int dish, bool settingsWindowScanHorizontalLow, bool settingsWindowScanHorizontalHigh, bool settingsWindowScanVerticalLow, @@ -1133,7 +1133,7 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.Filesystem object[] data = new object[] { DateTime.Now, - settingsWindowBlScanTunerSelection, settingsWindowUseDifferentTunerForSetFilter, + settingsWindowBlScanTunerSelection, multitunerMode, settingsWindowSetFilterTunerSelection, settingsWindowDiseqc, settingsWindowCollectIqGraphs, settingsWindowCollectRfSpectrum, settingsWindowCaptureFile, settingsWindowSatellite, settingsWindowLnb, dish, settingsWindowScanHorizontalLow, settingsWindowScanHorizontalHigh, diff --git a/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs index 958f3cd..c047c50 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/InMemory/InMemoryScraperStorage.cs @@ -952,7 +952,7 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.InMemory } public void InsertUiBlindscanSettingHistory(int settingsWindowBlScanTunerSelection, - bool settingsWindowUseDifferentTunerForSetFilter, int settingsWindowSetFilterTunerSelection, + int multitunerMode, int settingsWindowSetFilterTunerSelection, int settingsWindowDiseqc, bool settingsWindowCollectIqGraphs, bool settingsWindowCollectRfSpectrum, bool settingsWindowCaptureFile, int settingsWindowSatellite, int settingsWindowLnb, int dish, bool settingsWindowScanHorizontalLow, bool settingsWindowScanHorizontalHigh, bool settingsWindowScanVerticalLow, @@ -1161,9 +1161,15 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.InMemory throw new NotImplementedException(); } + private Dictionary, Tbtp.TbtpFrame.BtpEntity> _tbtpEntities; public bool TestForTerminalBurstTimePlan(ushort interactiveNetworkId, uint groupId, uint logonId) { - throw new NotImplementedException(); + if (_tbtpEntities == null) + return false; + + Tuple tuple = new Tuple(interactiveNetworkId, groupId, logonId); + + return _tbtpEntities.ContainsKey(tuple); } public void StoreTerminalBurstTimePlan(ushort interactiveNetworkId, uint gtoupId, uint superframeCount, @@ -1172,19 +1178,43 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.InMemory throw new NotImplementedException(); } + private HashSet[] cmtEntries; public bool TestForCmtEntry(ushort interactiveNetworkId, Cmt.CmtEntry entry) { - throw new NotImplementedException(); + if (cmtEntries == null) + return false; + if (cmtEntries[interactiveNetworkId] == null) + return false; + + return cmtEntries[interactiveNetworkId].Contains(entry); } public void InsertCmtEntry(ushort interactiveNetworkId, Cmt.CmtEntry entry) { - throw new NotImplementedException(); + if (cmtEntries == null) + cmtEntries = new HashSet[ushort.MaxValue]; + if (cmtEntries[interactiveNetworkId] == null) + cmtEntries[interactiveNetworkId] = new HashSet(); + cmtEntries[interactiveNetworkId].Add(entry); } + private bool rmtWasSeen; public int GetRmtTransmissionStandard(ushort networkId) { - throw new NotImplementedException(); + if (!rmtWasSeen) + return 0; + + if (_rmtTransportStreams[networkId] == null) + return 0; + + HashSet rmtSet = _rmtTransportStreams[networkId]; + foreach (Rmt.TransportStream transportStream in rmtSet) + { + if (transportStream.SatelliteForwardLink != null) + return (int)transportStream.SatelliteForwardLink.TransmissionStandard; + } + + return 0; } public byte[] GetTmst(ushort interactiveNetworkId) @@ -1202,64 +1232,135 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.InMemory throw new NotImplementedException(); } + private HashSet<_0x4a_LinkageDescriptor> _rmtLinkages; public bool TestForRmtLinkage(_0x4a_LinkageDescriptor linkage) { - throw new NotImplementedException(); + if (_rmtLinkages == null) + return false; + + return _rmtLinkages.Contains(linkage); } public void InsertRmtLinkage(_0x4a_LinkageDescriptor linkage) { - throw new NotImplementedException(); + if (_rmtLinkages == null) + _rmtLinkages = new HashSet<_0x4a_LinkageDescriptor>(); + + _rmtLinkages.Add(linkage); } + private HashSet[] _rmtTransportStreams; public bool TestForRmtTransportStream(ushort networkId, Rmt.TransportStream transportStream) { - throw new NotImplementedException(); + if (_rmtTransportStreams == null) + return false; + if (_rmtTransportStreams[networkId] == null) + return false; + + return _rmtTransportStreams[networkId].Contains(transportStream); } public void InsertRmtTransportStream(ushort networkId, Rmt.TransportStream transportStream) { - throw new NotImplementedException(); + if (_rmtTransportStreams == null) + _rmtTransportStreams = new HashSet[ushort.MaxValue]; + if (_rmtTransportStreams[networkId] == null) + _rmtTransportStreams[networkId] = new HashSet(); + + _rmtTransportStreams[networkId].Add(transportStream); + if (transportStream.SatelliteForwardLink != null) + rmtWasSeen = true; } + private HashSet[] _sctSuperframes; public bool TestForSuperframeComposition(ushort interactiveNetworkId, Sct.Superframe superframe) { - throw new NotImplementedException(); + if (_sctSuperframes == null) + return false; + + if (_sctSuperframes[interactiveNetworkId] == null) + return false; + + return _sctSuperframes[interactiveNetworkId].Contains(superframe); } public void StoreSuperframeComposition(ushort interactiveNetworkId, Sct.Superframe superframe) { - throw new NotImplementedException(); + if (_sctSuperframes == null) + _sctSuperframes = new HashSet[ushort.MaxValue]; + + if (_sctSuperframes[interactiveNetworkId] == null) + _sctSuperframes[interactiveNetworkId] = new HashSet(); + + _sctSuperframes[interactiveNetworkId].Add(superframe); } + private HashSet[] _fctFrames; public bool TestForFrameComposition(ushort interactiveNetworkId, Fct.Frame frame) { - throw new NotImplementedException(); + if (_fctFrames == null) + return false; + if (_fctFrames[interactiveNetworkId] == null) + return false; + + return _fctFrames[interactiveNetworkId].Contains(frame); } public void InsertFctFrame(ushort interactiveNetworkId, Fct.Frame frame) { - throw new NotImplementedException(); + if (_fctFrames == null) + _fctFrames = new HashSet[ushort.MaxValue]; + if (_fctFrames[interactiveNetworkId] == null) + _fctFrames[interactiveNetworkId] = new HashSet(); + + _fctFrames[interactiveNetworkId].Add(frame); } + private HashSet[] _sptSatellites; public bool TestForSatellitePosition(ushort interactiveNetworkId, Spt.Satellite satellite) { - throw new NotImplementedException(); + if (_sptSatellites == null) + return false; + if (_sptSatellites[interactiveNetworkId] == null) + return false; + + return _sptSatellites[interactiveNetworkId].Contains(satellite); } public void StoreSatellitePosition(ushort interactiveNetworkId, Spt.Satellite satellite) { - throw new NotImplementedException(); + if (_sptSatellites == null) + _sptSatellites = new HashSet[ushort.MaxValue]; + if (_sptSatellites[interactiveNetworkId] == null) + _sptSatellites[interactiveNetworkId] = new HashSet(); + + _sptSatellites[interactiveNetworkId].Add(satellite); } + class TimContainer + { + public _0xab_ContentionControlDescriptor ContentionControl { get; set; } + public _0xac_CorrectionControlDescriptor CorrectionControl { get; set; } + public DateTime NetworkLayerInfoTimestamp { get; set; } + public _0xa0_NetworkLayerInfoDescriptor NetworkLayerInfoDescriptor { get; set; } + } + + private Dictionary _timContainers; + public bool TestForTim(PhysicalAddress mac) { - throw new NotImplementedException(); + if (_timContainers == null) + return false; + + return _timContainers.ContainsKey(mac); } public void CreateTim(PhysicalAddress mac) { - throw new NotImplementedException(); + if (_timContainers == null) + _timContainers = new Dictionary(); + + _timContainers.Add(mac, new TimContainer()); } public bool CorrectTim(PhysicalAddress mac, _0xa1_CorrectionMessageDescriptor cmd) @@ -1269,18 +1370,38 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.InMemory public bool ContentionTim(PhysicalAddress mac, _0xab_ContentionControlDescriptor ccdNew) { - throw new NotImplementedException(); + TimContainer container = _timContainers[mac]; + if (container.ContentionControl == null) + { + container.ContentionControl = ccdNew; + return true; + } + + return false; } public bool CorrectionControlTim(PhysicalAddress mac, _0xac_CorrectionControlDescriptor descriptor) { - throw new NotImplementedException(); + TimContainer container = _timContainers[mac]; + if (container.CorrectionControl == null) + { + container.CorrectionControl = descriptor; + return true; + } + return false; } public bool NetworkLayerInfoTim(PhysicalAddress mac, _0xa0_NetworkLayerInfoDescriptor nlid, DateTime timestamped) { - throw new NotImplementedException(); + TimContainer container = _timContainers[mac]; + if (container.NetworkLayerInfoTimestamp < timestamped) + { + container.NetworkLayerInfoTimestamp = timestamped; + container.NetworkLayerInfoDescriptor = nlid; + return true; + } + return false; } public IEnumerable GetDbBlindscanJobs() @@ -1312,7 +1433,19 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.InMemory public bool TestForIp(IPAddress iP) { - throw new NotImplementedException(); + if (dnsRecords == null) + return false; + + foreach (DnsRecord dnsRecord in dnsRecords) + { + if (dnsRecord.RecordType.Item1 != 1 && dnsRecord.RecordType.Item1 != 28) + continue; + + if (dnsRecord.IP.Equals(iP)) + return true; + } + + return false; } private HashSet dnsRecords; diff --git a/skyscraper8/Skyscraper/Scraper/Storage/ObjectStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/ObjectStorage.cs index cedf99d..41511a8 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/ObjectStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/ObjectStorage.cs @@ -10,12 +10,12 @@ using skyscraper5.Teletext; using skyscraper8.DvbNip; using skyscraper8.Experimentals.NdsSsu; using skyscraper8.Ietf.FLUTE; -using skyscraper8.SatIp; +using skyscraper8.SimpleServiceDiscoveryProtocol; using skyscraper8.Skyscraper.Drawing; namespace skyscraper8.Skyscraper.Scraper.Storage { - public interface ObjectStorage : IRtspCache + public interface ObjectStorage : ISsdpCache { bool ObjectCarouselFileArrival(VfsFile vfsFile, int transportStreamId, int networkId); void DataCarouselModuleArrival(int currentNetworkId, int currentTransportStreamId, int elementaryPid, ushort moduleModuleId, byte moduleModuleVersion, Stream result); diff --git a/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/AitContestant.cs b/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/AitContestant.cs index a23122a..f7c2c19 100644 --- a/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/AitContestant.cs +++ b/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/AitContestant.cs @@ -7,6 +7,7 @@ using skyscraper5.Mhp; using skyscraper5.Mhp.Si; using skyscraper5.Mhp.Si.Model; using skyscraper5.Mpeg2; +using skyscraper5.Mpeg2.Psi.Model; using skyscraper5.Skyscraper.Plugins; namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants @@ -31,6 +32,10 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext) { + if (programContext.Program == null) + { + programContext.Program = new ProgramMapping(0x1fff, 0x1ff); + } skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid, new AitParser(skyscraperContext, programContext.ProgramNumber))); } diff --git a/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/DataCarouselContestant.cs b/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/DataCarouselContestant.cs index 097aef1..b4a446f 100644 --- a/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/DataCarouselContestant.cs +++ b/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/DataCarouselContestant.cs @@ -100,6 +100,12 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext) { + if (programContext.Stream == null) + { + programContext.Stream = new ProgramMappingStream(PmtStreamType.Iso13818_1PrivateSections, 0x1fff); + programContext.Program = new ProgramMapping(0x1fff, 0x1fff); + programContext.Program.Streams.Add(programContext.Stream); + } if (!programContext.Stream.ComponentTag.HasValue) { skyscraperContext.MakeUpComponentTags(programContext.Program); diff --git a/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/TeletextContestant.cs b/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/TeletextContestant.cs index bb078ac..0201a57 100644 --- a/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/TeletextContestant.cs +++ b/skyscraper8/Skyscraper/Scraper/StreamAutodetection/Contestants/TeletextContestant.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Text; using System.Threading.Tasks; using skyscraper5.Mpeg2; +using skyscraper5.Mpeg2.Psi.Model; using skyscraper5.Skyscraper.Plugins; using skyscraper5.Skyscraper.Scraper.Utils; using skyscraper5.src.Teletext; @@ -45,10 +46,22 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants { if (!skyscraperContext.CurrentNetworkId.HasValue) { - //Since we need the network id for teletext, but we don't have it - we'll just have to discard this. + //Since we need the network id skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PacketDiscarder()); return; } + + if (!skyscraperContext.CurrentTransportStreamId.HasValue) + { + //We need the TSID for teletext, but we don't have it - we'll just have to discard this. + skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PacketDiscarder()); + return; + } + + if (programContext.Program == null) + { + programContext.Program = new ProgramMapping(0x1fff, 0x1fff); + } TeletextPesProcessor ttp = new TeletextPesProcessor(skyscraperContext, skyscraperContext.CurrentNetworkId.Value, skyscraperContext.CurrentTransportStreamId.Value, programContext.ProgramNumber); ttp.PrivateDataSpecifier = programContext.PrivateDataSpecifier; skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PesDecoder(ttp)); diff --git a/skyscraper8/Skyscraper/Scraper/StreamAutodetection/ProgramContext.cs b/skyscraper8/Skyscraper/Scraper/StreamAutodetection/ProgramContext.cs index 9024384..dfecf14 100644 --- a/skyscraper8/Skyscraper/Scraper/StreamAutodetection/ProgramContext.cs +++ b/skyscraper8/Skyscraper/Scraper/StreamAutodetection/ProgramContext.cs @@ -12,13 +12,22 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection { public ProgramMapping Program { get; set; } - public ushort ProgramNumber => Program.ProgramNumber; + public ushort ProgramNumber + { + get + { + return Program.ProgramNumber; + } + } + public ProgramMappingStream Stream { get; set; } public uint? PrivateDataSpecifier { get { + if (Stream == null) + return null; if (Stream.PrivateDataSpecifier.HasValue) return Stream.PrivateDataSpecifier; if (Program.PrivateDataSpecifier.HasValue) diff --git a/skyscraper8/Skyscraper/Text/Encodings/dvb-iso-8859-14.cs b/skyscraper8/Skyscraper/Text/Encodings/dvb-iso-8859-14.cs index 21707ed..12d3f9d 100644 --- a/skyscraper8/Skyscraper/Text/Encodings/dvb-iso-8859-14.cs +++ b/skyscraper8/Skyscraper/Text/Encodings/dvb-iso-8859-14.cs @@ -58,6 +58,7 @@ namespace skyscraper5.Skyscraper.Text.Encodings case 0xfa: resultBuilder.Append('ú'); break; case 0xfc: resultBuilder.Append('ü'); break; case 0xfd: resultBuilder.Append('ý'); break; + case 0xfe: resultBuilder.Append('ŷ'); break; default: throw new NotImplementedException(String.Format("0x{0:X2}", preprocessed[i])); } diff --git a/skyscraper8/Skyscraper/Text/Encodings/dvb-iso-8859-3.cs b/skyscraper8/Skyscraper/Text/Encodings/dvb-iso-8859-3.cs index dcba3e9..d4e3dcf 100644 --- a/skyscraper8/Skyscraper/Text/Encodings/dvb-iso-8859-3.cs +++ b/skyscraper8/Skyscraper/Text/Encodings/dvb-iso-8859-3.cs @@ -26,6 +26,7 @@ namespace skyscraper5.Skyscraper.Text.Encodings case 0xa2: resultBuilder.Append('˘'); break; case 0xa3: resultBuilder.Append('£'); break; case 0xa4: resultBuilder.Append('¤'); break; + case 0xb7: resultBuilder.Append('·'); break; case 0xc0: resultBuilder.Append('À'); break; case 0xc1: resultBuilder.Append('Á'); break; case 0xc9: resultBuilder.Append('É'); break; @@ -47,6 +48,7 @@ namespace skyscraper5.Skyscraper.Text.Encodings case 0xf3: resultBuilder.Append('ó'); break; case 0xf6: resultBuilder.Append('ö'); break; case 0xfa: resultBuilder.Append('ù'); break; + case 0xfb: resultBuilder.Append('û'); break; case 0xfc: resultBuilder.Append('ü'); break; default: throw new NotImplementedException(String.Format("0x{0:X2}", preprocessed[i])); diff --git a/skyscraper8/skyscraper8.csproj b/skyscraper8/skyscraper8.csproj index 7e848a4..dc8b3e8 100644 --- a/skyscraper8/skyscraper8.csproj +++ b/skyscraper8/skyscraper8.csproj @@ -12,10 +12,12 @@ False + False False + False @@ -32,6 +34,9 @@ PreserveNewest + + PreserveNewest +