diff --git a/skyscraper8/Experimentals/NdsSsu/NdsSsuDetector.cs b/skyscraper8/Experimentals/NdsSsu/NdsSsuDetector.cs new file mode 100644 index 0000000..b3a1bb7 --- /dev/null +++ b/skyscraper8/Experimentals/NdsSsu/NdsSsuDetector.cs @@ -0,0 +1,117 @@ +using skyscraper5.Mpeg2; +using skyscraper5.Skyscraper.Plugins; +using skyscraper5.Skyscraper.Scraper; +using skyscraper5.Skyscraper.Scraper.StreamAutodetection; +using skyscraper8.Mpeg2.Psi; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Experimentals.NdsSsu +{ + [SkyscraperPlugin] + internal class NdsSsuDetector : Contestant, NdsSsuHandler + { + public NdsSsuDetector(int pid) : base("NDS France SSU", pid) + { + PacketProcessor = new PsiDecoder(pid, new NdsSsuDetectorWorker(this, pid)); + } + + public override void Dispose() + { + PacketProcessor = null; + } + + public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext) + { + skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid,new NdsSsuParser(skyscraperContext,pid))); + } + + public override void Introduce(ProgramContext programContext) + { + } + + class NdsSsuDetectorWorker : PrivateSectionParser + { + private readonly NdsSsuHandler _handler; + private readonly int _pid; + private bool[] tidExtensions; + + public NdsSsuDetectorWorker(NdsSsuHandler handler, int pid) + { + _handler = handler; + _pid = pid; + } + + protected override void HandleTable(byte tableId, int sourcePid, byte sectionNumber, byte lastSectionNumber, ushort tableIdExtension, + byte[] payload) + { + if (tableId != 0x9e) + { + _handler.OnNdsSsuError(_pid,NdsSsuError.WrongTable); + return; + } + + if (payload[0] != 0x01) + { + _handler.OnNdsSsuError(_pid, NdsSsuError.InvalidMagic); + return; + } + + if (payload[1] != 0xff) + { + _handler.OnNdsSsuError(_pid, NdsSsuError.InvalidMagic); + return; + } + + if (payload[2] != 0x00) + { + _handler.OnNdsSsuError(_pid, NdsSsuError.InvalidMagic); + return; + } + + if (payload[3] > 0x10) + { + _handler.OnNdsSsuError(_pid,NdsSsuError.InvalidMagic); + return; + } + + if (tidExtensions == null) + tidExtensions = new bool[ushort.MaxValue]; + + if (tidExtensions[tableIdExtension]) + { + _handler.OnNdsSsuProgress(_pid,tableIdExtension, sectionNumber, lastSectionNumber, payload[3]); + } + else + { + _handler.OnNdsFileAccouncement(_pid,tableIdExtension); + tidExtensions[tableIdExtension] = true; + } + } + } + + public void OnNdsSsuError(NdsSsuError error) + { + Score--; + } + + public void OnNdsSsuError(int pid, NdsSsuError error) + { + throw new NotImplementedException(); + } + + public void OnNdsSsuProgress(int pid, ushort tableIdExtension, byte sectionNumber, byte lastSectionNumber, byte b) + { + Score++; + } + + public void OnNdsFileAccouncement(int pid, ushort tableIdExtension) + { + Score--; + } + } +} diff --git a/skyscraper8/Experimentals/NdsSsu/NdsSsuHandler.cs b/skyscraper8/Experimentals/NdsSsu/NdsSsuHandler.cs new file mode 100644 index 0000000..1f7df96 --- /dev/null +++ b/skyscraper8/Experimentals/NdsSsu/NdsSsuHandler.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Experimentals.NdsSsu +{ + interface NdsSsuHandler + { + void OnNdsSsuError(int pid, NdsSsuError error); + void OnNdsSsuProgress(int pid, ushort tableIdExtension, byte sectionNumber, byte lastSectionNumber, byte b); + void OnNdsFileAccouncement(int pid, ushort tableIdExtension); + } + + public enum NdsSsuError + { + WrongTable, + InvalidMagic + } +} diff --git a/skyscraper8/Experimentals/NdsSsu/NdsSsuParser.cs b/skyscraper8/Experimentals/NdsSsu/NdsSsuParser.cs new file mode 100644 index 0000000..45583f1 --- /dev/null +++ b/skyscraper8/Experimentals/NdsSsu/NdsSsuParser.cs @@ -0,0 +1,140 @@ +using skyscraper8.Mpeg2.Psi; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Metadata; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Experimentals.NdsSsu +{ + internal class NdsSsuParser : PrivateSectionParser + { + private readonly NdsSsuHandler _handler; + private readonly int _pid; + + public NdsSsuParser(NdsSsuHandler handler, int pid) + { + _handler = handler; + _pid = pid; + } + + protected override void HandleTable(byte tableId, int sourcePid, byte sectionNumber, byte lastSectionNumber, ushort tableIdExtension, byte[] payload) + { + if (tableId != 0x9e) + { + _handler.OnNdsSsuError(_pid, NdsSsuError.WrongTable); + return; + } + + if (payload[0] == 0x00 && payload[1] == 0xff && payload[2] == 0x00 && payload[3] == 0x00) + { + //TODO: payload name + return; + } + + if (payload[0] != 0x01) + { + _handler.OnNdsSsuError(_pid, NdsSsuError.InvalidMagic); + return; + } + + if (payload[1] != 0xff) + { + _handler.OnNdsSsuError(_pid, NdsSsuError.InvalidMagic); + return; + } + + if (payload[2] != 0x00) + { + _handler.OnNdsSsuError(_pid, NdsSsuError.InvalidMagic); + return; + } + + if (payload[3] > 0x10) + { + _handler.OnNdsSsuError(_pid, NdsSsuError.InvalidMagic); + return; + } + + if (dataMaps == null) + dataMaps = new DataMap[ushort.MaxValue]; + if (dataMaps[tableIdExtension] == null) + { + dataMaps[tableIdExtension] = new DataMap(); + _handler.OnNdsFileAccouncement(_pid, tableIdExtension); + } + + if (dataMaps[tableIdExtension].WasAlreadyPushed(payload, sectionNumber, lastSectionNumber)) + { + throw new NotImplementedException("the file is completed!"); + } + dataMaps[tableIdExtension].PushPacket(payload,sectionNumber,lastSectionNumber); + } + + private DataMap[] dataMaps; + class DataMap + { + + private Superblock[] superblocks; + public void PushPacket(byte[] payload,byte currentSection, byte lastSection) + { + byte maxNumSuperblocks = payload[3]; + maxNumSuperblocks++; + if (superblocks == null) + superblocks = new Superblock[maxNumSuperblocks]; + if (superblocks.Length < maxNumSuperblocks) + Array.Resize(ref superblocks, maxNumSuperblocks); + if (superblocks[payload[3]] == null) + { + superblocks[payload[3]] = new Superblock(lastSection); + } + superblocks[payload[3]].PushPacket(payload,currentSection,lastSection); + } + + class Superblock + { + private byte[][] blocks; + public Superblock(byte lastSection) + { + int maxNumBlocks = lastSection; + maxNumBlocks++; + blocks = new byte[maxNumBlocks][]; + } + + public void PushPacket(byte[] payload, byte currentSection, byte lastSection) + { + int maxNumBlocks = lastSection; + maxNumBlocks++; + if (blocks.Length > maxNumBlocks) + Array.Resize(ref blocks, maxNumBlocks); + blocks[currentSection] = payload; + } + + public bool WasAlreadyPushed(byte currentSection) + { + byte maxNumBlocks = currentSection; + maxNumBlocks++; + + if (blocks.Length < currentSection) + return false; + + return blocks[currentSection] != null; + } + } + + public bool WasAlreadyPushed(byte[] payload, byte sectionNumber, byte lastSectionNumber) + { + if (superblocks == null) + return false; + + byte maxNumSuperblocks = payload[3]; + maxNumSuperblocks++; + if (superblocks.Length < maxNumSuperblocks) + return false; + + return superblocks[payload[3]].WasAlreadyPushed(sectionNumber); + } + } + } +} diff --git a/skyscraper8/Experimentals/OtvSsu/OtvSsuDetector.cs b/skyscraper8/Experimentals/OtvSsu/OtvSsuDetector.cs new file mode 100644 index 0000000..ce836ff --- /dev/null +++ b/skyscraper8/Experimentals/OtvSsu/OtvSsuDetector.cs @@ -0,0 +1,144 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using skyscraper5.Mpeg2; +using skyscraper5.Skyscraper.IO; +using skyscraper5.Skyscraper.Plugins; +using skyscraper5.Skyscraper.Scraper; +using skyscraper5.Skyscraper.Scraper.StreamAutodetection; +using skyscraper8.Mpeg2.Psi; + +namespace skyscraper8.Experimentals.OtvSsu +{ + [SkyscraperPlugin] + internal class OtvSsuDetector : Contestant, OtvSsuHandler + { + private OtvSsuDetectorParser parser; + public OtvSsuDetector(int pid) : base("OpenTV SSU", pid) + { + parser = new OtvSsuDetectorParser(this, pid); + PacketProcessor = new PsiDecoder(pid, parser); + } + + public override void Dispose() + { + parser = null; + PacketProcessor = null; + } + + public override void DeclareWinner(SkyscraperContext skyscraperContext, int pid, ProgramContext programContext) + { + skyscraperContext.DvbContext.RegisterPacketProcessor(pid, new PsiDecoder(pid,new OtvSsuParser(skyscraperContext))); + } + + public override void Introduce(ProgramContext programContext) + { + } + + class OtvSsuDetectorParser : PrivateSectionParser + { + private readonly OtvSsuHandler _handler; + private readonly int _pid; + private List _coordinates; + + public OtvSsuDetectorParser(OtvSsuHandler handler, int pid) + { + _handler = handler; + _pid = pid; + _coordinates = new List(); + } + + class Coordinate + { + public ushort tableIdExtension; + public uint fileId; + public uint unknown1; + public uint length; + + public Coordinate(ushort tableIdExtension1, uint u, uint unknown2, uint length1) + { + this.tableIdExtension = tableIdExtension1; + this.fileId = u; + this.unknown1 = unknown2; + this.length = length1; + } + + public long hits; + } + + protected override void HandleTable(byte tableId, int sourcePid, byte sectionNumber, byte lastSectionNumber, ushort tableIdExtension, + byte[] payload) + { + MemoryStream ms = new MemoryStream(payload, false); + uint fileId = ms.ReadUInt32BE(); + uint unknown1 = ms.ReadUInt32BE(); + uint offset = ms.ReadUInt32BE(); + uint length = ms.ReadUInt32BE(); + if (length > Int32.MaxValue) + { + _handler.OnOtvSsuError(_pid, OtvSsuError.FileTooLarge); + return; + } + if (offset > length) + { + _handler.OnOtvSsuError(_pid,OtvSsuError.OffsetOutOfRange); + return; + } + + if (tableIdExtension == 1 && (fileId & 0x00ff0000) == 0x00ff0000) + { + _handler.OnOtvSsuError(_pid, OtvSsuError.NdsOverlap); + return; + } + + Coordinate coordinate = _coordinates.Find(x => + x.tableIdExtension == tableIdExtension && x.fileId == fileId && x.unknown1 == unknown1 && + x.length == length); + if (coordinate == null) + { + coordinate = new Coordinate(tableIdExtension, fileId, unknown1, length); + _handler.OnOtvSsuFileAnnouncement(_pid,tableIdExtension, fileId, unknown1, length); + _coordinates.Add(coordinate); + } + else + { + coordinate.hits++; + _handler.OnOtvSsuBlock(_pid, tableIdExtension, fileId, unknown1, length); + } + } + + protected override void HandleTable(byte tableId, int sourcePid, byte[] payload) + { + _handler.OnOtvSsuError(_pid, OtvSsuError.SectionSyntaxIndicatorMissing); + } + } + + public void OnOtvSsuError(int pid, OtvSsuError offsetOutOfRange) + { + Score--; + } + + public void OnOtvSsuFileAnnouncement(int pid, ushort tableIdExtension, uint fileId, uint unknown1, uint length) + { + Score--; + } + + public void OnOtvSsuBlock(int pid, ushort tableIdExtension, uint fileId, uint unknown1, uint length) + { + Score++; + } + + public void OnOtvSsuComplete(int sourcePid, Stream getStream, ushort tableIdExtension, uint fileId, uint unknown1, + uint length) + { + throw new NotImplementedException(); + } + + public bool OnOtvCheckFileAlreadyKnown(int sourcePid, ushort tableIdExtension, uint fileId, uint unknown1, uint length) + { + throw new NotImplementedException(); + } + } +} diff --git a/skyscraper8/Experimentals/OtvSsu/OtvSsuHandler.cs b/skyscraper8/Experimentals/OtvSsu/OtvSsuHandler.cs new file mode 100644 index 0000000..b66649a --- /dev/null +++ b/skyscraper8/Experimentals/OtvSsu/OtvSsuHandler.cs @@ -0,0 +1,26 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace skyscraper8.Experimentals.OtvSsu +{ + internal interface OtvSsuHandler + { + void OnOtvSsuError(int pid, OtvSsuError offsetOutOfRange); + void OnOtvSsuFileAnnouncement(int pid, ushort tableIdExtension, uint fileId, uint unknown1, uint length); + void OnOtvSsuBlock(int pid, ushort tableIdExtension, uint fileId, uint unknown1, uint length); + void OnOtvSsuComplete(int sourcePid, Stream getStream, ushort tableIdExtension, uint fileId, uint unknown1, uint length); + bool OnOtvCheckFileAlreadyKnown(int sourcePid, ushort tableIdExtension, uint fileId, uint unknown1, uint length); + } + + public enum OtvSsuError + { + OffsetOutOfRange, + PacketDeliveredTooMuchData, + SectionSyntaxIndicatorMissing, + NdsOverlap, + FileTooLarge + } +} diff --git a/skyscraper8/Experimentals/OtvSsu/OtvSsuParser.cs b/skyscraper8/Experimentals/OtvSsu/OtvSsuParser.cs new file mode 100644 index 0000000..8b875eb --- /dev/null +++ b/skyscraper8/Experimentals/OtvSsu/OtvSsuParser.cs @@ -0,0 +1,202 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using skyscraper5.Skyscraper.IO; +using skyscraper8.Mpeg2.Psi; + +namespace skyscraper8.Experimentals.OtvSsu +{ + internal class OtvSsuParser : PrivateSectionParser + { + private readonly OtvSsuHandler _handler; + + public OtvSsuParser(OtvSsuHandler handler) + { + _handler = handler; + } + + private Dictionary _dataMaps; + protected override void HandleTable(byte tableId, int sourcePid, byte sectionNumber, byte lastSectionNumber, ushort tableIdExtension, byte[] payload) + { + MemoryStream ms = new MemoryStream(payload, false); + uint fileId = ms.ReadUInt32BE(); + uint unknown1 = ms.ReadUInt32BE(); + uint offset = ms.ReadUInt32BE(); + uint length = ms.ReadUInt32BE(); + if (offset > length) + { + _handler.OnOtvSsuError(sourcePid, OtvSsuError.OffsetOutOfRange); + return; + } + + if (length > Int32.MaxValue) + { + _handler.OnOtvSsuError(sourcePid, OtvSsuError.FileTooLarge); + return; + } + if (tableIdExtension < 10 && (fileId & 0x00ff0000) == 0x00ff0000) + { + _handler.OnOtvSsuError(sourcePid, OtvSsuError.NdsOverlap); + return; + } + + Coordinate coords = new Coordinate(tableIdExtension, fileId, unknown1, length); + if (_dataMaps == null) + _dataMaps = new Dictionary(); + DataMap map; + if (_dataMaps.ContainsKey(coords)) + { + map = _dataMaps[coords]; + _handler.OnOtvSsuBlock(sourcePid, tableIdExtension, fileId, unknown1, length); + } + else + { + map = new DataMap(length); + if (_handler.OnOtvCheckFileAlreadyKnown(sourcePid, tableIdExtension, fileId, unknown1, length)) + { + map.Dispose(); + _dataMaps.Add(coords, map); + return; + } + else + { + _handler.OnOtvSsuFileAnnouncement(sourcePid, tableIdExtension, fileId, unknown1, length); + _dataMaps.Add(coords, map); + } + } + + if (map.IsComplete) + { + return; + } + if (map.WasWrittenBefore(offset)) + { + return; + } + map.PushPacket(payload,offset); + if (map.IsErronous) + { + _handler.OnOtvSsuError(sourcePid, OtvSsuError.PacketDeliveredTooMuchData); + _dataMaps.Remove(coords); + map.Dispose(); + return; + } + if (map.IsComplete) + { + _handler.OnOtvSsuComplete(sourcePid, map.GetStream(), tableIdExtension, fileId, unknown1, length); + map.Dispose(); + } + } + + class Coordinate + { + private readonly ushort _tableIdExtension; + private readonly uint _fileId; + private readonly uint _unknown1; + private readonly uint _length; + + public Coordinate(ushort tableIdExtension, uint fileId, uint unknown1, uint length) + { + _tableIdExtension = tableIdExtension; + _fileId = fileId; + _unknown1 = unknown1; + _length = length; + } + + protected bool Equals(Coordinate other) + { + return _tableIdExtension == other._tableIdExtension && _fileId == other._fileId && _unknown1 == other._unknown1 && _length == other._length; + } + + 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((Coordinate)obj); + } + + public override int GetHashCode() + { + return HashCode.Combine(_tableIdExtension, _fileId, _unknown1, _length); + } + } + + class DataMap : IDisposable + { + private MemoryStream ms; + private uint length; + private uint needed; + private List knownOffsets; + private bool disposed; + + public DataMap(uint length) + { + ms = new MemoryStream((int)length); + this.length = length; + this.needed = length; + this.knownOffsets = new List(); + } + + public void PushPacket(byte[] payload, uint offset) + { + if (disposed) + throw new ObjectDisposedException(this.ToString()); + ms.Position = offset; + ms.Write(payload, 16, payload.Length - 16); + needed -= (uint)(payload.Length - 16); + knownOffsets.Add(offset); + } + + public bool WasWrittenBefore(uint offset) + { + if (disposed) + return true; + if (knownOffsets == null) + return false; + + return knownOffsets.Contains(offset); + } + + public bool IsComplete + { + get + { + if (disposed) + return false; + return needed == 0; + } + } + + public bool IsErronous + { + get + { + if (disposed) + throw new ObjectDisposedException(this.ToString()); + return length < needed; + } + } + + public Stream GetStream() + { + if (disposed) + throw new ObjectDisposedException(this.ToString()); + return ms; + } + + public void Dispose() + { + ms = null; + needed = 0; + knownOffsets = null; + disposed = true; + } + } + } +} diff --git a/skyscraper8/Mpeg2/Psi/PrivateSectionParser.cs b/skyscraper8/Mpeg2/Psi/PrivateSectionParser.cs new file mode 100644 index 0000000..1a9dd07 --- /dev/null +++ b/skyscraper8/Mpeg2/Psi/PrivateSectionParser.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using skyscraper5.Mpeg2; +using skyscraper5.Skyscraper.IO; + +namespace skyscraper8.Mpeg2.Psi +{ + internal abstract class PrivateSectionParser : IPsiProcessor + { + public void GatherPsi(PsiSection section, int sourcePid) + { + byte[] bytes = section.GetData(); + MemoryStream ms = new MemoryStream(bytes, false); + byte tableId = ms.ReadUInt8(); + + byte byteA = ms.ReadUInt8(); + bool sectionSyntaxIndicator = (byteA & 0x80) != 0; + bool privateIndicator = (byteA & 0x40) != 0; + int reserved = (byteA & 0x30) >> 4; + int privateSectionLength = (byteA & 0xf); + privateSectionLength <<= 8; + privateSectionLength += ms.ReadUInt8(); + if (!sectionSyntaxIndicator) + { + byte[] payload = ms.ReadBytes(ms.GetAvailableBytes()); + HandleTable(tableId, sourcePid, payload); + } + else + { + ushort tableIdExtension = ms.ReadUInt16BE(); + + byte byteB = ms.ReadUInt8(); + reserved = (byteB & 0xc0) >> 6; + int versionNumber = (byteB & 0x3e) >> 1; + bool currentNextIndicator = (byteB & 0x01) != 0; + + byte sectionNumber = ms.ReadUInt8(); + byte lastSectionNumber = ms.ReadUInt8(); + int blockLength = privateSectionLength - 9; + byte[] payload = ms.ReadBytes(blockLength); + uint crc32 = ms.ReadUInt32BE(); + HandleTable(tableId, sourcePid, sectionNumber, lastSectionNumber, tableIdExtension, payload); + } + } + + protected virtual void HandleTable(byte tableId, int sourcePid, byte sectionNumber, byte lastSectionNumber, ushort tableIdExtension, byte[] payload) + { + throw new PsiException("You should implement the override for no section syntax indicator."); + } + + protected virtual void HandleTable(byte tableId, int sourcePid, byte[] payload) + { + throw new PsiException("You should implement the override for the section syntax indicator."); + } + } +} diff --git a/skyscraper8/Mpeg2/Psi/PsiException.cs b/skyscraper8/Mpeg2/Psi/PsiException.cs new file mode 100644 index 0000000..756690e --- /dev/null +++ b/skyscraper8/Mpeg2/Psi/PsiException.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using skyscraper5.Mpeg2; + +namespace skyscraper8.Mpeg2.Psi +{ + class PsiException : Mpeg2Exception + { + public PsiException() + : base("PSI Error") + { + } + + public PsiException(string message) : base(message) + { + } + + public PsiException(string message, Exception inner) : base(message, inner) + { + } + } +} diff --git a/skyscraper8/Program.cs b/skyscraper8/Program.cs index 9e6acfa..74e5bed 100644 --- a/skyscraper8/Program.cs +++ b/skyscraper8/Program.cs @@ -39,11 +39,11 @@ namespace skyscraper5 private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name); private static void IntegrationTest() { - List ssdpDevices = SsdpClient.GetSsdpDevices(1000).ToList(); + /*List ssdpDevices = SsdpClient.GetSsdpDevices(1000).ToList(); foreach (SsdpDevice ssdpDevice in ssdpDevices) { Console.WriteLine("SSDP device: {0}", ssdpDevice.Server); - } + }*/ Console.WriteLine("yeet!"); /*RtspClient rtspClient = new RtspClient("172.20.20.121", 554); diff --git a/skyscraper8/Properties/launchSettings.json b/skyscraper8/Properties/launchSettings.json index d79f1dc..86e3b0a 100644 --- a/skyscraper8/Properties/launchSettings.json +++ b/skyscraper8/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "skyscraper8": { "commandName": "Project", - "commandLineArgs": "\"C:\\devel\\skyscraper8\\skyscraper8\\bin\\Debug\\net8.0\\36E-12226L.ts\"", + "commandLineArgs": "\"C:\\Temp\\bem-service-a01.ts\"", "remoteDebugEnabled": false }, "Container (Dockerfile)": { diff --git a/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs b/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs index f06bcda..034d6c8 100644 --- a/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs +++ b/skyscraper8/Skyscraper/Scraper/SkyscraperContext.cs @@ -76,6 +76,8 @@ using System.Net; using System.Net.NetworkInformation; using System.Security.Policy; using System.Text; +using skyscraper8.Experimentals.NdsSsu; +using skyscraper8.Experimentals.OtvSsu; using Tsubasa.IO; using Platform = skyscraper5.Dvb.SystemSoftwareUpdate.Model.Platform; using RntParser = skyscraper5.Dvb.TvAnytime.RntParser; @@ -88,7 +90,7 @@ namespace skyscraper5.Skyscraper.Scraper UpdateNotificationEventHandler, DataCarouselEventHandler, RdsEventHandler, IScte35EventHandler, IAutodetectionEventHandler, IRstEventHandler, IRntEventHandler, IMultiprotocolEncapsulationEventHandler, ObjectCarouselEventHandler, T2MIEventHandler, IDisposable, IFrameGrabberEventHandler, IntEventHandler, IRctEventHandler, IGsEventHandler, ISkyscraperContext, IDocsisEventHandler, AbertisDecoderEventHandler, Id3Handler, - InteractionChannelHandler, SgtEventHandler, IDvbNipEventHandler, UleEventHandler + InteractionChannelHandler, SgtEventHandler, IDvbNipEventHandler, UleEventHandler, OtvSsuHandler, NdsSsuHandler { public const bool ALLOW_STREAM_TYPE_AUTODETECTION = true; public const bool ALLOW_FFMPEG_FRAMEGRABBER = true; @@ -2910,5 +2912,46 @@ namespace skyscraper5.Skyscraper.Scraper } throw new NotImplementedException("LLC/SNAP"); } + + public void OnOtvSsuError(int pid, OtvSsuError offsetOutOfRange) + { + DvbContext.RegisterPacketProcessor(pid, new PacketDiscarder()); + } + + public void OnOtvSsuFileAnnouncement(int pid, ushort tableIdExtension, uint fileId, uint unknown1, uint length) + { + LogEvent(SkyscraperContextEvent.OtvSsuFileDetected, String.Format("TID = {0}, FID = {1:X8}, Length = {2}", tableIdExtension, fileId, length)); + } + + public void OnOtvSsuBlock(int pid, ushort tableIdExtension, uint fileId, uint unknown1, uint length) + { + } + + public void OnOtvSsuComplete(int sourcePid, Stream getStream, ushort tableIdExtension, uint fileId, uint unknown1, + uint length) + { + LogEvent(SkyscraperContextEvent.OtvSsuComplete, String.Format("TID = {0}, FID = {1:X8}, Length = {2}", tableIdExtension, fileId, length)); + ObjectStorage.OnOtvSsuComplete(CurrentNetworkId, CurrentTransportStreamId, sourcePid, getStream, tableIdExtension, fileId, unknown1, length); + } + + public bool OnOtvCheckFileAlreadyKnown(int sourcePid, ushort tableIdExtension, uint fileId, uint unknown1, uint length) + { + return ObjectStorage.OtvSsuTestFile(CurrentNetworkId, CurrentTransportStreamId, sourcePid, tableIdExtension, fileId, unknown1, length); + } + + public void OnNdsSsuError(int pid, NdsSsuError error) + { + throw new NotImplementedException(); + } + + public void OnNdsSsuProgress(int pid, ushort tableIdExtension, byte sectionNumber, byte lastSectionNumber, byte b) + { + throw new NotImplementedException(); + } + + public void OnNdsFileAccouncement(int pid, ushort tableIdExtension) + { + LogEvent(SkyscraperContextEvent.NdsSsuFileAnnounced, String.Format("PID = 0x{1:X4}, Table ID Extension = {0}", tableIdExtension, pid)); + } } } diff --git a/skyscraper8/Skyscraper/Scraper/SkyscraperContextEvent.cs b/skyscraper8/Skyscraper/Scraper/SkyscraperContextEvent.cs index d68fd97..f9f978b 100644 --- a/skyscraper8/Skyscraper/Scraper/SkyscraperContextEvent.cs +++ b/skyscraper8/Skyscraper/Scraper/SkyscraperContextEvent.cs @@ -81,6 +81,9 @@ DvbNipService, DvbNipMulticastSession, DvbNipMulticastGatewayConfigurationTransportSession, - FluteFileAnnouncement + FluteFileAnnouncement, + OtvSsuFileDetected, + OtvSsuComplete, + NdsSsuFileAnnounced } } diff --git a/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs index f117fe5..e343ab7 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/Filesystem/FilesystemStorage.cs @@ -1524,6 +1524,34 @@ namespace skyscraper5.Skyscraper.Scraper.Storage.Filesystem throw new NotImplementedException(); } + public bool OtvSsuTestFile(int? currentNetworkId, int? currentTransportStreamId, int sourcePid, ushort tableIdExtension, + uint fileId, uint unknown1, uint length) + { + string cnid = currentNetworkId.HasValue ? currentNetworkId.Value.ToString() : "unknown"; + string ctsid = currentTransportStreamId.HasValue ? currentTransportStreamId.Value.ToString() : "unknown"; + string fname = String.Format("{0}_{1:X8}_{2:X8}.bin", tableIdExtension,fileId,unknown1); + string path = Path.Combine(rootDirectory.FullName, "OTV-SSU", cnid, ctsid, sourcePid.ToString(), fname); + FileInfo fi = new FileInfo(path); + return fi.Exists; + } + + public void OnOtvSsuComplete(int? currentNetworkId, int? currentTransportStreamId, int sourcePid, Stream getStream, + ushort tableIdExtension, uint fileId, uint unknown1, uint length) + { + string cnid = currentNetworkId.HasValue ? currentNetworkId.Value.ToString() : "unknown"; + string ctsid = currentTransportStreamId.HasValue ? currentTransportStreamId.Value.ToString() : "unknown"; + string fname = String.Format("{0}_{1:X8}_{2:X8}.bin", tableIdExtension, fileId, unknown1); + string path = Path.Combine(rootDirectory.FullName, "OTV-SSU", cnid, ctsid, sourcePid.ToString(), fname); + FileInfo fi = new FileInfo(path); + fi.Directory.EnsureExists(); + FileStream fileStream = fi.OpenWrite(); + getStream.Position = 0; + getStream.CopyTo(fileStream); + fileStream.Flush(true); + fileStream.Close(); + getStream.Dispose(); + } + class NipPds { public DateTime VersionUpdate; diff --git a/skyscraper8/Skyscraper/Scraper/Storage/NullObjectStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/NullObjectStorage.cs index 8c092aa..1dafdb9 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/NullObjectStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/NullObjectStorage.cs @@ -99,5 +99,17 @@ namespace skyscraper8.Skyscraper.Scraper.Storage { throw new NotImplementedException(); } + + public bool OtvSsuTestFile(int? currentNetworkId, int? currentTransportStreamId, int sourcePid, ushort tableIdExtension, + uint fileId, uint unknown1, uint length) + { + throw new NotImplementedException(); + } + + public void OnOtvSsuComplete(int? currentNetworkId, int? currentTransportStreamId, int sourcePid, Stream getStream, + ushort tableIdExtension, uint fileId, uint unknown1, uint length) + { + throw new NotImplementedException(); + } } } diff --git a/skyscraper8/Skyscraper/Scraper/Storage/ObjectStorage.cs b/skyscraper8/Skyscraper/Scraper/Storage/ObjectStorage.cs index 270b21a..4674ee9 100644 --- a/skyscraper8/Skyscraper/Scraper/Storage/ObjectStorage.cs +++ b/skyscraper8/Skyscraper/Scraper/Storage/ObjectStorage.cs @@ -31,5 +31,7 @@ namespace skyscraper8.Skyscraper.Scraper.Storage void StoreRfSpectrum(Guid jobGuid, RfSpectrumData rfSpectrum); void DeleteIqGraph(Guid selectedGuid, int frequencyItem1, SatelliteDeliverySystemDescriptor.PolarizationEnum frequencyItem2); void DeleteRfSpectrum(Guid selectedGuid); + bool OtvSsuTestFile(int? currentNetworkId, int? currentTransportStreamId, int sourcePid, ushort tableIdExtension, uint fileId, uint unknown1, uint length); + void OnOtvSsuComplete(int? currentNetworkId, int? currentTransportStreamId, int sourcePid, Stream getStream, ushort tableIdExtension, uint fileId, uint unknown1, uint length); } }