Began working on Threemedia OTT.
All checks were successful
🚀 Pack skyscraper8 / make-zip (push) Successful in 2m29s
All checks were successful
🚀 Pack skyscraper8 / make-zip (push) Successful in 2m29s
This commit is contained in:
parent
57c45c215e
commit
6e5bf2d2db
@ -134,7 +134,7 @@ namespace skyscraper5.Dvb.DataBroadcasting
|
||||
{
|
||||
if (!announcedLlcTraffic)
|
||||
{
|
||||
logger.InfoFormat("Detected LLC/SNAP traffic on PID {0:x4}", sourcePid);
|
||||
//logger.InfoFormat("Detected LLC/SNAP traffic on PID {0:x4}", sourcePid);
|
||||
announcedLlcTraffic = true;
|
||||
}
|
||||
|
||||
|
||||
51
skyscraper8/Ietf/FLUTE/CdsCompletionPollRequestExtension.cs
Normal file
51
skyscraper8/Ietf/FLUTE/CdsCompletionPollRequestExtension.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using skyscraper5.Skyscraper;
|
||||
using skyscraper5.Skyscraper.IO;
|
||||
|
||||
namespace skyscraper8.Ietf.FLUTE
|
||||
{
|
||||
internal class CdsCompletionPollRequestExtension : Validatable
|
||||
{
|
||||
public CdsCompletionPollRequestExtension(byte[] extensionBuffer)
|
||||
{
|
||||
MemoryStream ms = new MemoryStream(extensionBuffer, false);
|
||||
if (ms.GetAvailableBytes() < 1)
|
||||
{
|
||||
Valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
byte byteA = ms.ReadUInt8();
|
||||
this.Version = (byteA & 0xf0) >> 4;
|
||||
|
||||
if (ms.GetAvailableBytes() < 1)
|
||||
{
|
||||
Valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
byte byteB = ms.ReadUInt8();
|
||||
PollSequence = (byteA & 0x0f) << 8;
|
||||
PollSequence += byteB;
|
||||
|
||||
if (ms.GetAvailableBytes() < 4)
|
||||
{
|
||||
Valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
PollMask = ms.ReadUInt32BE();
|
||||
Valid = true;
|
||||
}
|
||||
|
||||
public uint PollMask { get; set; }
|
||||
|
||||
public int PollSequence { get; set; }
|
||||
|
||||
public int Version { get; private set; }
|
||||
}
|
||||
}
|
||||
@ -9,13 +9,28 @@ namespace skyscraper8.Ietf.FLUTE
|
||||
{
|
||||
internal class FecHeader
|
||||
{
|
||||
public FecHeader(MemoryStream ms)
|
||||
public FecHeader(MemoryStream ms, byte codepoint)
|
||||
{
|
||||
SourceBlockNumber = ms.ReadUInt16BE();
|
||||
EncodingSymbolId = ms.ReadUInt16BE();
|
||||
switch (codepoint)
|
||||
{
|
||||
case 0:
|
||||
SourceBlockNumber = ms.ReadUInt16BE();
|
||||
EncodingSymbolId = ms.ReadUInt16BE();
|
||||
break;
|
||||
case 129:
|
||||
SourceBlockNumber = ms.ReadUInt32BE();
|
||||
SourceBlockLength = ms.ReadUInt16BE();
|
||||
EncodingSymbolId = ms.ReadUInt16BE();
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException(String.Format("Unknown ALC CodePoint value {0}", codepoint));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public ushort SourceBlockNumber { get; }
|
||||
public ushort? SourceBlockLength { get; set; }
|
||||
|
||||
public uint SourceBlockNumber { get; }
|
||||
public ushort EncodingSymbolId { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@ -72,13 +72,13 @@ namespace skyscraper8.Ietf.FLUTE
|
||||
}
|
||||
|
||||
if (blocks == null)
|
||||
blocks = new Dictionary<Tuple<ushort, ushort>, FluteBlock>();
|
||||
blocks = new Dictionary<Tuple<uint, ushort>, FluteBlock>();
|
||||
|
||||
if (lctFrame.Atsc3Compliant)
|
||||
{
|
||||
if (blocks.Count == 0)
|
||||
{
|
||||
Tuple<ushort, ushort> fakeKey = new Tuple<ushort, ushort>(12345, 6789);
|
||||
Tuple<uint, ushort> fakeKey = new Tuple<uint, ushort>(12345, 6789);
|
||||
FluteBlock fakeBlock = new FluteBlock(0, 0, new byte[transferLength]);
|
||||
blocks.Add(fakeKey, fakeBlock);
|
||||
}
|
||||
@ -92,7 +92,7 @@ namespace skyscraper8.Ietf.FLUTE
|
||||
if (lctFrame.FecHeader == null)
|
||||
return;
|
||||
|
||||
ushort sbn = lctFrame.FecHeader.SourceBlockNumber;
|
||||
uint sbn = lctFrame.FecHeader.SourceBlockNumber;
|
||||
ushort esi = lctFrame.FecHeader.EncodingSymbolId;
|
||||
|
||||
//FluteBlock? fluteBlock = blocks.Find(x =>
|
||||
@ -122,7 +122,7 @@ namespace skyscraper8.Ietf.FLUTE
|
||||
blocksDeduplicated++;
|
||||
}*/
|
||||
|
||||
Tuple<ushort, ushort> coordinate = new Tuple<ushort, ushort>(sbn, esi);
|
||||
Tuple<uint, ushort> coordinate = new Tuple<uint, ushort>(sbn, esi);
|
||||
if (blocks.ContainsKey(coordinate))
|
||||
{
|
||||
blocksDeduplicated++;
|
||||
@ -222,19 +222,19 @@ namespace skyscraper8.Ietf.FLUTE
|
||||
}
|
||||
|
||||
private long transferLength;
|
||||
private Dictionary<Tuple<ushort,ushort>,FluteBlock> blocks;
|
||||
private Dictionary<Tuple<uint,ushort>,FluteBlock> blocks;
|
||||
private uint blocksDeduplicated;
|
||||
|
||||
public class FluteBlock
|
||||
{
|
||||
public FluteBlock(ushort sourceBlockNumer, ushort encodingSymbolId, byte[] payload)
|
||||
public FluteBlock(uint sourceBlockNumer, ushort encodingSymbolId, byte[] payload)
|
||||
{
|
||||
SourceBlockNumer = sourceBlockNumer;
|
||||
EncodingSymbolId = encodingSymbolId;
|
||||
Payload = payload;
|
||||
}
|
||||
|
||||
public ushort SourceBlockNumer;
|
||||
public uint SourceBlockNumer;
|
||||
public ushort EncodingSymbolId;
|
||||
public byte[] Payload;
|
||||
|
||||
|
||||
@ -53,7 +53,7 @@ namespace skyscraper8.Ietf.FLUTE
|
||||
//DVB-NIP sample: "Z:\Persönliches\Satellitescommunity\Skyscraper Test Fixture\astra1_11141h_gse_nip.ts"
|
||||
if (!isAtsc3)
|
||||
{
|
||||
this.FecHeader = new FecHeader(ms);
|
||||
this.FecHeader = new FecHeader(ms, this.Codepoint);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@ -83,6 +83,9 @@ namespace skyscraper8.Ietf.FLUTE
|
||||
case 64:
|
||||
this.FecObjectTransmissionInformation = new FecObjectTransmissionInformation(extensionBuffer);
|
||||
break;
|
||||
case 65:
|
||||
this.CdsCompletionPollRequest = new CdsCompletionPollRequestExtension(extensionBuffer);
|
||||
break;
|
||||
case 68:
|
||||
this.NipActualCarrierInformation = new NipActualCarrierInformation(extensionBuffer);
|
||||
break;
|
||||
@ -98,10 +101,14 @@ namespace skyscraper8.Ietf.FLUTE
|
||||
Valid = true;
|
||||
}
|
||||
|
||||
public CdsCompletionPollRequestExtension CdsCompletionPollRequest { get; set; }
|
||||
|
||||
private ulong ReadField(Stream stream, int bits)
|
||||
{
|
||||
switch(bits)
|
||||
{
|
||||
case 0:
|
||||
return 0;
|
||||
case 16:
|
||||
return stream.ReadUInt16BE();
|
||||
case 32:
|
||||
|
||||
56
skyscraper8/ThreemediaOtt/ThreemediaContentFragment.cs
Normal file
56
skyscraper8/ThreemediaOtt/ThreemediaContentFragment.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using skyscraper8.Ietf.FLUTE;
|
||||
|
||||
namespace skyscraper8.ThreemediaOtt
|
||||
{
|
||||
internal class ThreemediaContentFragment : IDisposable
|
||||
{
|
||||
public void IngestPacket(LctFrame lctFrame)
|
||||
{
|
||||
int totalBlocks = lctFrame.FecHeader.SourceBlockLength.Value;
|
||||
if (blocks == null)
|
||||
blocks = new byte[totalBlocks][];
|
||||
|
||||
int targetBlock = lctFrame.FecHeader.EncodingSymbolId;
|
||||
if (targetBlock >= blocks.Length)
|
||||
return;
|
||||
if (blocks[targetBlock] != null)
|
||||
return;
|
||||
|
||||
blocks[targetBlock] = lctFrame.Payload;
|
||||
}
|
||||
|
||||
private byte[][] blocks;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (blocks != null)
|
||||
{
|
||||
for (int i = 0; i < blocks.Length; i++)
|
||||
{
|
||||
blocks[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
blocks = null;
|
||||
}
|
||||
|
||||
public bool IsComplete()
|
||||
{
|
||||
if (blocks == null)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < blocks.Length; i++)
|
||||
{
|
||||
if (blocks[i] == null)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
118
skyscraper8/ThreemediaOtt/ThreemediaOttHandler.cs
Normal file
118
skyscraper8/ThreemediaOtt/ThreemediaOttHandler.cs
Normal file
@ -0,0 +1,118 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using log4net;
|
||||
using skyscraper5.Ietf.Rfc768;
|
||||
using skyscraper5.Ietf.Rfc971;
|
||||
using skyscraper5.Skyscraper.Plugins;
|
||||
using skyscraper5.Skyscraper.Scraper;
|
||||
using skyscraper8.Ietf.FLUTE;
|
||||
|
||||
namespace skyscraper8.ThreemediaOtt
|
||||
{
|
||||
[SkyscraperPlugin]
|
||||
internal class ThreemediaOttHandler : ISkyscraperMpePlugin
|
||||
{
|
||||
private static readonly IPAddress THREEMDIA_DESTINATION_IP = IPAddress.Parse("224.1.2.1");
|
||||
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
|
||||
|
||||
public void ConnectToStorage(object[] connector)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private SkyscraperContext context;
|
||||
public void SetContext(DateTime? currentTime, object skyscraperContext)
|
||||
{
|
||||
if (context != null)
|
||||
{
|
||||
context = skyscraperContext as SkyscraperContext;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CanHandlePacket(InternetHeader internetHeader, byte[] ipv4Packet)
|
||||
{
|
||||
if (!internetHeader.IsDestinationMulticast)
|
||||
return false;
|
||||
|
||||
if (!internetHeader.DestinationAddress.Equals(THREEMDIA_DESTINATION_IP))
|
||||
return false;
|
||||
if (internetHeader.Protocol != 17)
|
||||
return false;
|
||||
|
||||
if (ipv4Packet[2] != 0x04)
|
||||
return false;
|
||||
if (ipv4Packet[3] != 0x61)
|
||||
return false;
|
||||
if (ipv4Packet[8] != 0x10)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private Dictionary<ushort, ThreemediaSession> sessions;
|
||||
public void HandlePacket(InternetHeader internetHeader, byte[] ipv4Packet)
|
||||
{
|
||||
UserDatagram udpPacket = new UserDatagram(ipv4Packet);
|
||||
LctFrame lctFrame = new LctFrame(udpPacket.Payload, false);
|
||||
if (lctFrame.CloseSessionFlag)
|
||||
{
|
||||
AssembleSegment(udpPacket.DestinationPort);
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
IngestPacket(udpPacket.DestinationPort, lctFrame);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private void IngestPacket(ushort udpPacketDestinationPort, LctFrame lctFrame)
|
||||
{
|
||||
if (sessions == null)
|
||||
sessions = new Dictionary<ushort, ThreemediaSession>();
|
||||
|
||||
ThreemediaSession selectedSession = null;
|
||||
if (sessions.ContainsKey(udpPacketDestinationPort))
|
||||
{
|
||||
selectedSession = sessions[udpPacketDestinationPort];
|
||||
}
|
||||
else
|
||||
{
|
||||
selectedSession = new ThreemediaSession();
|
||||
sessions[udpPacketDestinationPort] = selectedSession;
|
||||
}
|
||||
|
||||
selectedSession.IngestPacket(lctFrame);
|
||||
}
|
||||
|
||||
private void AssembleSegment(ushort destinationPort)
|
||||
{
|
||||
if (sessions == null)
|
||||
return;
|
||||
|
||||
if (!sessions.ContainsKey(destinationPort))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ThreemediaSession selectedSession = sessions[destinationPort];
|
||||
if (!selectedSession.IsComplete())
|
||||
{
|
||||
logger.WarnFormat(String.Format("The session on Port {0} is incomplete and can not be recovered.", destinationPort));
|
||||
selectedSession.Dispose();
|
||||
return;
|
||||
}
|
||||
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool StopProcessingAfterThis()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
59
skyscraper8/ThreemediaOtt/ThreemediaSession.cs
Normal file
59
skyscraper8/ThreemediaOtt/ThreemediaSession.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using skyscraper8.Ietf.FLUTE;
|
||||
|
||||
namespace skyscraper8.ThreemediaOtt
|
||||
{
|
||||
internal class ThreemediaSession : IDisposable
|
||||
{
|
||||
public void IngestPacket(LctFrame lctFrame)
|
||||
{
|
||||
int numFragments = lctFrame.LctHeader.CdsCompletionPollRequest.PollSequence;
|
||||
if (fragments == null)
|
||||
fragments = new ThreemediaContentFragment[numFragments];
|
||||
|
||||
int currentFragment = (int)lctFrame.LctHeader.TransportObjectIdentifier;
|
||||
currentFragment--;
|
||||
if (fragments[currentFragment] == null)
|
||||
fragments[currentFragment] = new ThreemediaContentFragment();
|
||||
|
||||
fragments[currentFragment].IngestPacket(lctFrame);
|
||||
}
|
||||
|
||||
private ThreemediaContentFragment[] fragments;
|
||||
|
||||
public bool IsComplete()
|
||||
{
|
||||
if (fragments == null)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < fragments.Length; i++)
|
||||
{
|
||||
if (fragments[i] == null)
|
||||
return false;
|
||||
|
||||
if (!fragments[i].IsComplete())
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (fragments != null)
|
||||
{
|
||||
for (int i = 0; i < fragments.Length; i++)
|
||||
{
|
||||
fragments[i].Dispose();
|
||||
fragments[i] = null;
|
||||
}
|
||||
}
|
||||
|
||||
fragments = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user