The Atsc3Receiver.cs now understands ATSC3 FDTs.
All checks were successful
🚀 Pack skyscraper8 / make-zip (push) Successful in 1m25s
All checks were successful
🚀 Pack skyscraper8 / make-zip (push) Successful in 1m25s
This commit is contained in:
parent
2e173d4156
commit
4fe40e082a
23
skyscraper8/Atsc/A331/A331Exception.cs
Normal file
23
skyscraper8/Atsc/A331/A331Exception.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace skyscraper8.Atsc.A331
|
||||||
|
{
|
||||||
|
public class A331Exception : AtscException
|
||||||
|
{
|
||||||
|
public A331Exception()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public A331Exception(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public A331Exception(string message, Exception inner) : base(message, inner)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
37
skyscraper8/Atsc/A331/Atsc3Fdt.cs
Normal file
37
skyscraper8/Atsc/A331/Atsc3Fdt.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace skyscraper8.Atsc.A331
|
||||||
|
{
|
||||||
|
internal class Atsc3Fdt
|
||||||
|
{
|
||||||
|
public uint Expires { get; set; }
|
||||||
|
public uint EfdtVersion { get; set; }
|
||||||
|
|
||||||
|
private List<Atsc3FdtFile> _files;
|
||||||
|
public IReadOnlyList<Atsc3FdtFile> Files
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_files == null)
|
||||||
|
return ImmutableList<Atsc3FdtFile>.Empty;
|
||||||
|
|
||||||
|
return _files.AsReadOnly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddFile(Atsc3FdtFile resultFile)
|
||||||
|
{
|
||||||
|
if (_files == null)
|
||||||
|
_files = new List<Atsc3FdtFile>();
|
||||||
|
|
||||||
|
_files.Add(resultFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
45
skyscraper8/Atsc/A331/Atsc3FdtFile.cs
Normal file
45
skyscraper8/Atsc/A331/Atsc3FdtFile.cs
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace skyscraper8.Atsc.A331
|
||||||
|
{
|
||||||
|
internal class Atsc3FdtFile
|
||||||
|
{
|
||||||
|
public Atsc3FdtFile(Dictionary<string, string> result)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<string, string> entry in result)
|
||||||
|
{
|
||||||
|
switch (entry.Key)
|
||||||
|
{
|
||||||
|
case "Content-Location":
|
||||||
|
this.ContentLocation = entry.Value;
|
||||||
|
break;
|
||||||
|
case "TOI":
|
||||||
|
this.TOI = ulong.Parse(entry.Value);
|
||||||
|
break;
|
||||||
|
case "Content-Length":
|
||||||
|
this.ContentLength = int.Parse(entry.Value);
|
||||||
|
break;
|
||||||
|
case "Content-Type":
|
||||||
|
this.ContentType = entry.Value;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException(entry.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string ContentType { get; set; }
|
||||||
|
|
||||||
|
public int ContentLength { get; set; }
|
||||||
|
|
||||||
|
public ulong TOI { get; set; }
|
||||||
|
|
||||||
|
public string ContentLocation { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
23
skyscraper8/Atsc/A331/Atsc3FilenameTable.cs
Normal file
23
skyscraper8/Atsc/A331/Atsc3FilenameTable.cs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace skyscraper8.Atsc.A331
|
||||||
|
{
|
||||||
|
internal class Atsc3FilenameTable
|
||||||
|
{
|
||||||
|
private List<Tuple<IPEndPoint, ulong, string>> staticFilenames;
|
||||||
|
public void LearnFilename(IPEndPoint endpoint, Atsc3Fdt fdt)
|
||||||
|
{
|
||||||
|
foreach (Atsc3FdtFile file in fdt.Files)
|
||||||
|
{
|
||||||
|
if (staticFilenames == null)
|
||||||
|
staticFilenames = new List<Tuple<IPEndPoint, ulong, string>>();
|
||||||
|
staticFilenames.Add(new Tuple<IPEndPoint, ulong, string>(endpoint, file.TOI, file.ContentLocation));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -17,7 +17,7 @@ namespace skyscraper8.Atsc.A331
|
|||||||
{
|
{
|
||||||
[SkyscraperPlugin]
|
[SkyscraperPlugin]
|
||||||
[PluginPriority(3)]
|
[PluginPriority(3)]
|
||||||
internal class Atsc3Unpacker : ISkyscraperMpePlugin
|
internal class Atsc3Receiver : ISkyscraperMpePlugin
|
||||||
{
|
{
|
||||||
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
|
private static readonly ILog logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
|
||||||
private static readonly IPAddress LLS_IP = IPAddress.Parse("224.0.23.60");
|
private static readonly IPAddress LLS_IP = IPAddress.Parse("224.0.23.60");
|
||||||
@ -45,9 +45,17 @@ namespace skyscraper8.Atsc.A331
|
|||||||
if (atsc3detected && internetHeader.IsDestinationMulticast)
|
if (atsc3detected && internetHeader.IsDestinationMulticast)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
ushort destPort = ipv4Packet.GetUInt16BE(2);
|
||||||
|
if (nonAtsc3 != null)
|
||||||
|
{
|
||||||
|
IPEndPoint possibleEvildoer = new IPEndPoint(internetHeader.DestinationAddress, destPort);
|
||||||
|
if (nonAtsc3.Contains(possibleEvildoer))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (internetHeader.DestinationAddress.Equals(LLS_IP))
|
if (internetHeader.DestinationAddress.Equals(LLS_IP))
|
||||||
{
|
{
|
||||||
if (ipv4Packet.GetUInt16BE(2) == LLS_PORT)
|
if (destPort == LLS_PORT)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -56,10 +64,22 @@ namespace skyscraper8.Atsc.A331
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private HashSet<IPEndPoint> nonAtsc3;
|
||||||
|
private Dictionary<Tuple<IPAddress, ushort, ulong, ulong>, FluteListener> flutes;
|
||||||
|
private Atsc3FilenameTable filenames;
|
||||||
public void HandlePacket(InternetHeader internetHeader, byte[] ipv4Packet)
|
public void HandlePacket(InternetHeader internetHeader, byte[] ipv4Packet)
|
||||||
{
|
{
|
||||||
_stopProcessIndicator = false;
|
_stopProcessIndicator = false;
|
||||||
UserDatagram udpPacket = new UserDatagram(ipv4Packet);
|
UserDatagram udpPacket = new UserDatagram(ipv4Packet);
|
||||||
|
IPEndPoint destination = new IPEndPoint(internetHeader.DestinationAddress, udpPacket.DestinationPort);
|
||||||
|
if (nonAtsc3 != null)
|
||||||
|
{
|
||||||
|
if (nonAtsc3.Contains(destination))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (internetHeader.DestinationAddress.Equals(LLS_IP) && udpPacket.DestinationPort == LLS_PORT)
|
if (internetHeader.DestinationAddress.Equals(LLS_IP) && udpPacket.DestinationPort == LLS_PORT)
|
||||||
{
|
{
|
||||||
//Handle LLS
|
//Handle LLS
|
||||||
@ -74,6 +94,63 @@ namespace skyscraper8.Atsc.A331
|
|||||||
}
|
}
|
||||||
|
|
||||||
LctFrame lctFrame = new LctFrame(udpPacket.Payload, true);
|
LctFrame lctFrame = new LctFrame(udpPacket.Payload, true);
|
||||||
|
if (lctFrame.Version != 1)
|
||||||
|
{
|
||||||
|
//Doesn't look like FLUTE, go away.
|
||||||
|
if (nonAtsc3 == null)
|
||||||
|
nonAtsc3 = new HashSet<IPEndPoint>();
|
||||||
|
nonAtsc3.Add(destination);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong tsi = lctFrame.LctHeader.TransportSessionIdentifier;
|
||||||
|
ulong toi = lctFrame.LctHeader.TransportObjectIdentifier;
|
||||||
|
Tuple<IPAddress, ushort, ulong, ulong> fluteCoordinate = new Tuple<IPAddress, ushort, ulong, ulong>(internetHeader.DestinationAddress, udpPacket.DestinationPort, tsi, toi);
|
||||||
|
FluteListener targetListener;
|
||||||
|
|
||||||
|
if (flutes == null)
|
||||||
|
{
|
||||||
|
flutes = new Dictionary<Tuple<IPAddress, ushort, ulong, ulong>, FluteListener>();
|
||||||
|
filenames = new Atsc3FilenameTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flutes.ContainsKey(fluteCoordinate))
|
||||||
|
{
|
||||||
|
targetListener = flutes[fluteCoordinate];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FluteListener newListener = new FluteListener(internetHeader.DestinationAddress, udpPacket.DestinationPort, tsi, toi);
|
||||||
|
flutes.Add(fluteCoordinate, newListener);
|
||||||
|
targetListener = newListener;
|
||||||
|
}
|
||||||
|
|
||||||
|
targetListener.PushPacket(lctFrame);
|
||||||
|
_stopProcessIndicator = true;
|
||||||
|
if (targetListener.IsComplete())
|
||||||
|
{
|
||||||
|
GuessedFluteDataType guessedFluteDataType = FluteUtilities.GuessDataType(targetListener);
|
||||||
|
ProcessMetafile(guessedFluteDataType, targetListener, destination);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ProcessMetafile(GuessedFluteDataType guessedFluteDataType, FluteListener targetListener, IPEndPoint destination)
|
||||||
|
{
|
||||||
|
switch (guessedFluteDataType)
|
||||||
|
{
|
||||||
|
case GuessedFluteDataType.Xml:
|
||||||
|
string contentsAsString = targetListener.GetContentsAsString();
|
||||||
|
if (contentsAsString.Contains("<FDT-Instance "))
|
||||||
|
{
|
||||||
|
Atsc3Fdt fdt = Atsc3Utilities.ParseFdt(contentsAsString);
|
||||||
|
filenames.LearnFilename(destination, fdt);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException(guessedFluteDataType.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void HandleLls(LlsTable lls)
|
private void HandleLls(LlsTable lls)
|
||||||
@ -1,10 +1,11 @@
|
|||||||
using System;
|
using skyscraper8.Atsc.A331.Schema;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using System.Xml;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using skyscraper8.Atsc.A331.Schema;
|
|
||||||
|
|
||||||
namespace skyscraper8.Atsc.A331
|
namespace skyscraper8.Atsc.A331
|
||||||
{
|
{
|
||||||
@ -36,5 +37,94 @@ namespace skyscraper8.Atsc.A331
|
|||||||
SysTimeType result = (SysTimeType)deserialize;
|
SysTimeType result = (SysTimeType)deserialize;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Atsc3Fdt ParseFdt(string rawXml)
|
||||||
|
{
|
||||||
|
Atsc3Fdt result = null;
|
||||||
|
|
||||||
|
NameTable nt = new NameTable();
|
||||||
|
XmlNamespaceManager ns = new XmlNamespaceManager(nt);
|
||||||
|
ns.AddNamespace("fdt", "ignore");
|
||||||
|
ns.AddNamespace("afdt", "ignore");
|
||||||
|
XmlParserContext context = new XmlParserContext(nt, ns, null, XmlSpace.None);
|
||||||
|
XmlReaderSettings settings = new XmlReaderSettings()
|
||||||
|
{
|
||||||
|
ConformanceLevel = ConformanceLevel.Fragment,
|
||||||
|
IgnoreWhitespace = true,
|
||||||
|
IgnoreComments = true
|
||||||
|
};
|
||||||
|
|
||||||
|
XmlReader xr = XmlReader.Create(new StringReader(rawXml), settings, context);
|
||||||
|
|
||||||
|
while (xr.Read())
|
||||||
|
{
|
||||||
|
switch (xr.NodeType)
|
||||||
|
{
|
||||||
|
case XmlNodeType.XmlDeclaration:
|
||||||
|
//Ok, we know this is valid XML.
|
||||||
|
break;
|
||||||
|
case XmlNodeType.Whitespace:
|
||||||
|
//Understandable.
|
||||||
|
break;
|
||||||
|
case XmlNodeType.Element:
|
||||||
|
switch (xr.Name)
|
||||||
|
{
|
||||||
|
case "FDT-Instance":
|
||||||
|
result = new Atsc3Fdt();
|
||||||
|
Dictionary<string, string> extractXmlAttributes = ExtractXmlAttributes(xr);
|
||||||
|
HandleFdtInstanceAttributes(result, extractXmlAttributes);
|
||||||
|
break;
|
||||||
|
case "fdt:File":
|
||||||
|
Dictionary<string, string> fileAttributes = ExtractXmlAttributes(xr);
|
||||||
|
Atsc3FdtFile resultFile = new Atsc3FdtFile(fileAttributes);
|
||||||
|
result.AddFile(resultFile);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException(xr.ToString());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case XmlNodeType.EndElement:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException(xr.ToString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void HandleFdtInstanceAttributes(Atsc3Fdt result, Dictionary<string, string> extractXmlAttributes)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<string, string> entry in extractXmlAttributes)
|
||||||
|
{
|
||||||
|
switch (entry.Key)
|
||||||
|
{
|
||||||
|
case "Expires":
|
||||||
|
result.Expires = uint.Parse(entry.Value);
|
||||||
|
break;
|
||||||
|
case "efdtVersion":
|
||||||
|
case "afdt:efdtVersion":
|
||||||
|
result.EfdtVersion = uint.Parse(entry.Value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new NotImplementedException(entry.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Dictionary<string, string> ExtractXmlAttributes(XmlReader xr)
|
||||||
|
{
|
||||||
|
Dictionary<string, string> result = new Dictionary<string, string>();
|
||||||
|
if (!xr.HasAttributes)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
xr.MoveToFirstAttribute();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
result.Add(xr.Name,xr.Value);
|
||||||
|
} while (xr.MoveToNextAttribute());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
24
skyscraper8/Atsc/AtscException.cs
Normal file
24
skyscraper8/Atsc/AtscException.cs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using skyscraper5;
|
||||||
|
|
||||||
|
namespace skyscraper8.Atsc
|
||||||
|
{
|
||||||
|
public class AtscException : SkyscraperException
|
||||||
|
{
|
||||||
|
public AtscException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AtscException(string message) : base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public AtscException(string message, Exception inner) : base(message, inner)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,4 +1,7 @@
|
|||||||
using skyscraper8.DvbNip;
|
using log4net.Core;
|
||||||
|
using MimeKit;
|
||||||
|
using skyscraper5.Teletext.Wss;
|
||||||
|
using skyscraper8.DvbNip;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
@ -9,8 +12,6 @@ using System.Runtime.Serialization;
|
|||||||
using System.Security.Cryptography.X509Certificates;
|
using System.Security.Cryptography.X509Certificates;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MimeKit;
|
|
||||||
using skyscraper5.Teletext.Wss;
|
|
||||||
|
|
||||||
namespace skyscraper8.Ietf.FLUTE
|
namespace skyscraper8.Ietf.FLUTE
|
||||||
{
|
{
|
||||||
@ -73,6 +74,21 @@ namespace skyscraper8.Ietf.FLUTE
|
|||||||
if (blocks == null)
|
if (blocks == null)
|
||||||
blocks = new Dictionary<Tuple<ushort, ushort>, FluteBlock>();
|
blocks = new Dictionary<Tuple<ushort, ushort>, FluteBlock>();
|
||||||
|
|
||||||
|
if (lctFrame.Atsc3Compliant)
|
||||||
|
{
|
||||||
|
if (blocks.Count == 0)
|
||||||
|
{
|
||||||
|
Tuple<ushort, ushort> fakeKey = new Tuple<ushort, ushort>(12345, 6789);
|
||||||
|
FluteBlock fakeBlock = new FluteBlock(0, 0, new byte[transferLength]);
|
||||||
|
blocks.Add(fakeKey, fakeBlock);
|
||||||
|
}
|
||||||
|
|
||||||
|
FluteBlock atsc3Block = blocks.First().Value;
|
||||||
|
Array.Copy(lctFrame.Payload, 0, atsc3Block.Payload, lctFrame.Atsc3ObjectStartOffset.Value, lctFrame.Payload.Length);
|
||||||
|
_dataWritten += lctFrame.Payload.Length;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (lctFrame.FecHeader == null)
|
if (lctFrame.FecHeader == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -293,5 +309,31 @@ namespace skyscraper8.Ietf.FLUTE
|
|||||||
|
|
||||||
public double LastReportedProgress { get; internal set; }
|
public double LastReportedProgress { get; internal set; }
|
||||||
public long? TrimmedLength { get; set; }
|
public long? TrimmedLength { get; set; }
|
||||||
|
|
||||||
|
internal byte[] GetFirstBlock()
|
||||||
|
{
|
||||||
|
if (blocks == null)
|
||||||
|
return null;
|
||||||
|
if (blocks.Count == 0)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
if (blocks.Count == 1)
|
||||||
|
return blocks.Values.First().Payload;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<FluteBlock> blockPayloads = blocks.Values.ToList();
|
||||||
|
blockPayloads.Sort(new FluteBlockComparer());
|
||||||
|
return blockPayloads[0].Payload;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal string GetContentsAsString()
|
||||||
|
{
|
||||||
|
Stream stream = ToStream();
|
||||||
|
StreamReader sr = new StreamReader(stream);
|
||||||
|
string result = sr.ReadToEnd();
|
||||||
|
stream.Dispose();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,6 +21,24 @@ namespace skyscraper8.Ietf.FLUTE
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static FDTInstanceType UnpackFluteFdt(string source)
|
||||||
|
{
|
||||||
|
if (fdtSerializer == null)
|
||||||
|
fdtSerializer = new XmlSerializer(typeof(FDTInstanceType));
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
StringReader sr = new StringReader(source);
|
||||||
|
FDTInstanceType result = (FDTInstanceType)fdtSerializer.Deserialize(sr);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
catch (InvalidOperationException e)
|
||||||
|
{
|
||||||
|
Console.WriteLine(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static FDTInstanceType UnpackFluteFdt(Stream ms)
|
public static FDTInstanceType UnpackFluteFdt(Stream ms)
|
||||||
{
|
{
|
||||||
if (fdtSerializer == null)
|
if (fdtSerializer == null)
|
||||||
@ -62,5 +80,18 @@ namespace skyscraper8.Ietf.FLUTE
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static GuessedFluteDataType GuessDataType(FluteListener targetListener)
|
||||||
|
{
|
||||||
|
byte[] firstBlock = targetListener.GetFirstBlock();
|
||||||
|
if (firstBlock[0] == 0x3c && firstBlock[1] == 0x3f && firstBlock[2] == 0x78 && firstBlock[3] == 0x6d && firstBlock[4] == 0x6c)
|
||||||
|
return GuessedFluteDataType.Xml;
|
||||||
|
return GuessedFluteDataType.Unknown;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum GuessedFluteDataType
|
||||||
|
{
|
||||||
|
Unknown,
|
||||||
|
Xml
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user