Began work on DVB-SIS
All checks were successful
🚀 Pack skyscraper8 / make-zip (push) Successful in 2m37s

This commit is contained in:
Fey 2025-12-14 18:28:34 +01:00
parent 559a62249f
commit e7db7cb364
16 changed files with 565 additions and 35 deletions

View File

@ -0,0 +1,67 @@
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.IO;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.DvbSis
{
internal class DsAciHandler : IPsiProcessor
{
private readonly SisHandler sisOutput;
public DsAciHandler(SisHandler sisOutput)
{
this.sisOutput = sisOutput;
}
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 reservedFutureUse = (byteA & 0x40) != 0;
int reservedA = (byteA & 0x30) >> 4;
int sectionLength = (byteA & 0x0f);
sectionLength <<= 8;
sectionLength += ms.ReadUInt8();
ushort currentDsaGroupId = ms.ReadUInt16BE();
byte byteB = ms.ReadUInt8();
int reservedB = (byteB & 0xc0) >> 6;
int versionNumber = (byteB & 0x3e) >> 1;
bool currentNextIndicator = (byteB & 0x01) != 0;
byte sectionNumber = ms.ReadUInt8();
byte lastSectionNumber = ms.ReadUInt8();
byte[] dsaciFileData = ms.ReadBytes(ms.GetAvailableBytes() - 4);
uint crc32 = ms.ReadUInt32BE();
PushSection(currentDsaGroupId, versionNumber, sectionNumber, lastSectionNumber, dsaciFileData);
}
private void PushSection(ushort currentDsaGroupId, int versionNumber, byte sectionNumber, byte lastSectionNumber, byte[] dsaciFileData)
{
if (sectionNumber == 0 && lastSectionNumber == 0)
{
MemoryStream ms = new MemoryStream(dsaciFileData, false);
sisOutput.OnSisDsaci(currentDsaGroupId, versionNumber, sectionNumber, lastSectionNumber, ms);
return;
}
else
{
throw new NotImplementedException("A DSACI Configuration spanning more than one section was detected. This is not supported yet. It would be great if you could share a sample of this stream, so I can fix it. \n - Cheers, Fey");
}
}
}
}

View File

@ -0,0 +1,96 @@
using skyscraper5.Mpeg2;
using skyscraper5.T2MI;
using skyscraper5.T2MI.Packets;
using skyscraper8.T2MI.Packets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.DvbSis
{
internal class FtiHandler : ITsPacketProcessor, IPayloadUnitDecoder, T2MIEventHandler
{
public FtiHandler(int pid, SisHandler sisOutput, T2MIEventHandler t2miOutput)
{
this.t2miProxy = new T2MIDecoder(pid, this);
this.t2miOutput = t2miOutput;
this.sisOutput = sisOutput;
}
private SisHandler sisOutput;
private T2MIEventHandler t2miOutput;
private T2MIDecoder t2miProxy;
public void PacketLoss()
{
t2miProxy.PacketLoss();
}
public void PushPacket(TsPacket packet)
{
t2miProxy.PushPacket(packet);
}
public void OnT2MiPacketLoss(int pid, byte expectedPacket, T2MIHeader header)
{
throw new NotImplementedException();
}
public void OnT2MiPacket(int pid, byte basebandFramePlpId, byte[] basebandPacket)
{
throw new NotImplementedException();
}
public void OnT2MiTimestamp(int pid, _0x20_DvbT2Timestamp t2Timestamp)
{
sisOutput.OnSisTimestamp(pid, t2Timestamp);
}
public void OnT2MiIqData(int relatedPid, _0x31_IqData iqData)
{
throw new NotImplementedException();
}
public void OnT2MiIqData(int relatedPid, _0x01_IqData iqData2)
{
throw new NotImplementedException();
}
public void OnT2MiError(int relatedPid, int skyscraperErrorCode)
{
throw new NotImplementedException();
}
public void OnT2MiL1Current(int relatedPid, _0x10_L1Current l1Current)
{
t2miOutput.OnT2MiL1Current(relatedPid, l1Current);
}
public void OnT2MiArbitraryCellInsertion(int relatedPid, _0x02_ArbitraryCellInsertion arbitraryCellInsertion)
{
throw new NotImplementedException();
}
public void OnT2MiBalancingCells(int relatedPid, byte frameIndex, uint numActiveBiasCellsPerP2)
{
throw new NotImplementedException();
}
public void OnT2MiL1Future(int relatedPid, _0x11_L1Future l1Future)
{
throw new NotImplementedException();
}
public void OnT2MiIndividualAddressing(int relatedPid, _0x21_IndividualAddressing individualAddressing)
{
throw new NotImplementedException();
}
public void OnFramingAndTimingInformation(int relatedPid, _0xF0_FramingTimingInformation fti)
{
sisOutput.OnSisFti(relatedPid, fti);
}
}
}

View File

@ -0,0 +1,35 @@
using skyscraper5.T2MI.Packets;
using skyscraper8.T2MI.Packets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.DvbSis
{
internal class NullSisHandler : SisHandler
{
public void OnSisDsaci(ushort currentDsaGroupId, int versionNumber, byte sectionNumber, byte lastSectionNumber, Stream dsaci)
{
}
public void OnSisEit(int sourcePid, SisEitContainer eitContainer)
{
}
public void OnSisFti(int relatedPid, _0xF0_FramingTimingInformation fti)
{
}
public void OnSisPat(int sourcePid, SisPatContainer patContainer)
{
}
public void OnSisTimestamp(int pid, _0x20_DvbT2Timestamp t2Timestamp)
{
}
}
}

View File

@ -0,0 +1,46 @@
using skyscraper5.Dvb.Psi;
using skyscraper5.Dvb.Psi.Model;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.DvbSis
{
internal class SisEitContainer : IEitEventHandler
{
public void OnEitEvent(EitEvent eitEvent)
{
if (_eitEvents == null)
_eitEvents = new List<EitEvent>();
_eitEvents.Add(eitEvent);
}
public void SetNetworkId(ushort networkId, bool forceOverwrite = false)
{
NetworkId = networkId;
}
public void SetTransportStreamId(ushort transportStreamId)
{
TransportStreamId = transportStreamId;
}
public ushort? TransportStreamId { get; private set; }
public ushort? NetworkId { get; private set; }
public IReadOnlyList<EitEvent> Events
{
get
{
if (_eitEvents == null)
return new List<EitEvent>();
return _eitEvents.AsReadOnly();
}
}
private List<EitEvent> _eitEvents;
}
}

View File

@ -0,0 +1,19 @@
using skyscraper5.T2MI.Packets;
using skyscraper8.T2MI.Packets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.DvbSis
{
internal interface SisHandler
{
void OnSisDsaci(ushort currentDsaGroupId, int versionNumber, byte sectionNumber, byte lastSectionNumber, Stream dsaci);
void OnSisEit(int sourcePid, SisEitContainer eitContainer);
void OnSisFti(int relatedPid, _0xF0_FramingTimingInformation fti);
void OnSisPat(int sourcePid, SisPatContainer patContainer);
void OnSisTimestamp(int pid, _0x20_DvbT2Timestamp t2Timestamp);
}
}

View File

@ -0,0 +1,46 @@
using skyscraper5.Mpeg2.Psi;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.DvbSis
{
internal class SisPatContainer : IPatEventHandler
{
public ushort? TransportStreamId { get; private set; }
public int? NetworkPid { get; private set; }
public ReadOnlyDictionary<int,ushort> ProgramMappings
{
get
{
if (_ProgramMappings == null)
{
return new ReadOnlyDictionary<int, ushort>(new Dictionary<int, ushort>());
}
return _ProgramMappings.AsReadOnly();
}
}
private Dictionary<int,ushort> _ProgramMappings;
public void NetworkPidFromPat(int networkPid)
{
NetworkPid = networkPid;
}
public void ProgramMapPidFromPat(int pmtPid, ushort programNumber)
{
if (_ProgramMappings == null)
_ProgramMappings = new Dictionary<int,ushort>();
_ProgramMappings.Add(pmtPid, programNumber);
}
public void SetTransportStreamId(ushort transportStreamId)
{
TransportStreamId = transportStreamId;
}
}
}

View File

@ -0,0 +1,42 @@
using skyscraper5.Dvb.Psi;
using skyscraper5.Mpeg2;
using skyscraper5.Mpeg2.Psi;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.DvbSis
{
internal class SisPsiHandler : IPsiProcessor
{
public SisPsiHandler(SisHandler handler)
{
_handler = handler;
}
private SisHandler _handler;
public void GatherPsi(PsiSection section, int sourcePid)
{
switch (section.TableId)
{
case 0x00:
SisPatContainer patContainer = new SisPatContainer();
PatParser patParser = new PatParser(patContainer);
patParser.GatherPsi(section, 0);
_handler.OnSisPat(sourcePid, patContainer);
break;
case 0x50:
SisEitContainer eitContainer = new SisEitContainer();
EitParser eitParser = new EitParser(eitContainer);
eitParser.GatherPsi(section, sourcePid);
_handler.OnSisEit(sourcePid, eitContainer);
break;
default:
throw new NotImplementedException(String.Format("Table ID 0x{0:X2} in DVB-SIS PSI/SI not supported yet. To get this fixed, please share a sample of this stream.", section.TableId));
}
}
}
}

View File

@ -2,7 +2,7 @@
"profiles": {
"skyscraper8": {
"commandName": "Project",
"commandLineArgs": "\"C:\\devel\\skyscraper8\\skyscraper8\\bin\\Debug\\net8.0\\testsuite\\thor_11049v_simmin-radiomidun.ts\"",
"commandLineArgs": "\"G:\\Stash\\utena\\dvb-sis_eutelsat5_12522_v.ts\"",
"remoteDebugEnabled": false
},
"Container (Dockerfile)": {

View File

@ -95,6 +95,8 @@ using skyscraper8.T2MI;
using Tsubasa.IO;
using Platform = skyscraper5.Dvb.SystemSoftwareUpdate.Model.Platform;
using RntParser = skyscraper5.Dvb.TvAnytime.RntParser;
using skyscraper8.DvbSis;
using skyscraper8.T2MI.Packets;
namespace skyscraper5.Skyscraper.Scraper
{
@ -694,10 +696,21 @@ namespace skyscraper5.Skyscraper.Scraper
case StreamType.Id3:
DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PesDecoder(new Id3PesProcessor(this)));
break;
case StreamType.SisFramingAndTiming:
DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new FtiHandler(mappingStream.ElementaryPid, new NullSisHandler(), this));
break;
case StreamType.SisDaughterSiteAdapterConfiguration:
DsAciHandler dsaciHandler = new DsAciHandler(new NullSisHandler());
DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, dsaciHandler));
break;
case StreamType.SisPsiTables:
SisPsiHandler sisPsiHandler = new SisPsiHandler(new NullSisHandler());
DvbContext.RegisterPacketProcessor(mappingStream.ElementaryPid, new PsiDecoder(mappingStream.ElementaryPid, sisPsiHandler));
break;
default:
throw new NotImplementedException(String.Format(
"Detection of Stream type for PID 0x{0:X4} in Service {1}", pmtPid,
result.ProgramNumber));
"Detection of Stream type for PID 0x{0:X4} in Service {1} - was detected as {2}, but handling for {2} is not implemented yet.", pmtPid,
result.ProgramNumber, guessedStreamType));
}
}
}
@ -998,6 +1011,22 @@ namespace skyscraper5.Skyscraper.Scraper
return StreamType.Id3;
}
if (stream.StreamType == PmtStreamType.Iso13818_1PesPackets && stream.DataBroadcastId == 0x000e && stream.DataBroadcastSelector != null)
{
if (stream.DataBroadcastSelector[0] == 0x01)
{
return StreamType.SisFramingAndTiming;
}
if (stream.DataBroadcastSelector[0] == 0x02)
{
return StreamType.SisDaughterSiteAdapterConfiguration;
}
if (stream.DataBroadcastSelector[0] == 0x03)
{
return StreamType.SisPsiTables;
}
}
if (ALLOW_STREAM_TYPE_AUTODETECTION)
{
//Abandon all hope, ye who enter here...
@ -3275,5 +3304,10 @@ namespace skyscraper5.Skyscraper.Scraper
LogEvent(SkyscraperContextEvent.EthernetLinkLayerDiscovery, frame.ToString());
}
}
void T2MIEventHandler.OnFramingAndTimingInformation(int relatedPid, _0xF0_FramingTimingInformation fti)
{
logger.WarnFormat("Found T2MI F&TI Information on PID 0x{0:X4}. This isn't supported yet. It would be great if you could share a sample of this stream, so this can be implemented.", relatedPid);
}
}
}

View File

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using skyscraper5.Skyscraper.Plugins;
using skyscraper5.T2MI;
using skyscraper5.T2MI.Packets;
using skyscraper8.T2MI.Packets;
namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
{
@ -99,5 +100,11 @@ namespace skyscraper5.Skyscraper.Scraper.StreamAutodetection.Contestants
if (hasPackets)
Score++;
}
void T2MIEventHandler.OnFramingAndTimingInformation(int relatedPid, _0xF0_FramingTimingInformation fti)
{
if (fti.NumberOfPlps > 0)
Score++;
}
}
}

View File

@ -29,6 +29,9 @@ namespace skyscraper5.Skyscraper.Scraper
InteractionChannelForSatellite,
OpenTvPrivate,
BSkyBPrivate,
Id3
}
Id3,
SisFramingAndTiming,
SisDaughterSiteAdapterConfiguration,
SisPsiTables
}
}

View File

@ -0,0 +1,123 @@
using skyscraper5.Skyscraper.IO;
using skyscraper5.Skyscraper.Plugins;
using skyscraper5.T2MI;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace skyscraper8.T2MI.Packets
{
[SkyscraperPlugin]
[T2MiPacketType(0xf0)]
internal class _0xF0_FramingTimingInformation : T2MiPacket
{
public _0xF0_FramingTimingInformation(T2MIHeader header, byte[] buffer) : base(header, buffer)
{
MemoryStream ms = new MemoryStream(buffer, false);
FrameIndex = ms.ReadUInt8();
NumberOfPlps = ms.GetAvailableBytes() / 32;
InBitStream bitStream = new InBitStream(ms);
Plps = new Plp[NumberOfPlps];
for (long u = 0; u < NumberOfPlps; u++)
{
Plp plp = new Plp();
plp.PlpId = bitStream.ReadBitsAsByte(8);
plp.IntlFrameStart = bitStream.ReadBitAsBoolean();
plp.Rfu = bitStream.ReadBitsAsByte(7);
plp.Matype1 = bitStream.ReadBitsAsByte(8);
plp.Matype2 = bitStream.ReadBitsAsByte(8);
plp.TtoE = bitStream.ReadBitsAsByte(5);
plp.TtoM = bitStream.ReadBitsAsByte(7);
plp.TtoL = bitStream.ReadBitsAsByte(8);
plp.FirstIscr = bitStream.ReadBitsAsUint(22);
plp.Bufs = bitStream.ReadBitsAsUInt16(12);
plp.FirstDfl = bitStream.ReadBitsAsUInt16(16);
plp.FirstSyncd = bitStream.ReadBitsAsUInt16(16);
plp.NextFirstSyncd = bitStream.ReadBitsAsUInt16(16);
plp.Mode = bitStream.ReadBitsAsByte(8);
plp.Pcr = bitStream.ReadBitsAsULong(48);
plp.FramePktCount = bitStream.ReadBitsAsUint(32);
plp.Dpcr = bitStream.ReadBitsAsUint(32);
Plps[u] = plp;
}
Valid = NumberOfPlps > 0;
}
public byte FrameIndex { get; }
public long NumberOfPlps { get; }
public Plp[] Plps { get; }
public override bool Equals(object? obj)
{
if (obj == null)
return false;
if (!(obj is _0xF0_FramingTimingInformation))
return false;
_0xF0_FramingTimingInformation that = (_0xF0_FramingTimingInformation)obj;
if (this.FrameIndex != that.FrameIndex)
return false;
if (this.NumberOfPlps != that.NumberOfPlps)
return false;
for (int i = 0; i < Plps.Length; i++)
{
if (!this.Plps[i].Equals(that.Plps[i]))
return false;
}
return true;
}
public class Plp
{
public byte PlpId { get; internal set; }
public bool IntlFrameStart { get; internal set; }
public byte Rfu { get; internal set; }
public byte Matype1 { get; internal set; }
public byte Matype2 { get; internal set; }
public byte TtoE { get; internal set; }
public byte TtoM { get; internal set; }
public byte TtoL { get; internal set; }
public uint FirstIscr { get; internal set; }
public ushort Bufs { get; internal set; }
public ushort FirstDfl { get; internal set; }
public ushort FirstSyncd { get; internal set; }
public ushort NextFirstSyncd { get; internal set; }
public byte Mode { get; internal set; }
public ulong Pcr { get; internal set; }
public uint FramePktCount { get; internal set; }
public uint Dpcr { get; internal set; }
public override bool Equals(object? obj)
{
return obj is Plp plp &&
PlpId == plp.PlpId &&
IntlFrameStart == plp.IntlFrameStart &&
Rfu == plp.Rfu &&
Matype1 == plp.Matype1 &&
Matype2 == plp.Matype2 &&
TtoE == plp.TtoE &&
TtoM == plp.TtoM &&
TtoL == plp.TtoL &&
FirstIscr == plp.FirstIscr &&
Bufs == plp.Bufs &&
FirstDfl == plp.FirstDfl &&
FirstSyncd == plp.FirstSyncd &&
NextFirstSyncd == plp.NextFirstSyncd &&
Mode == plp.Mode &&
Pcr == plp.Pcr &&
FramePktCount == plp.FramePktCount &&
Dpcr == plp.Dpcr;
}
}
}
}

View File

@ -10,6 +10,7 @@ using skyscraper5.Skyscraper.IO;
using skyscraper5.Skyscraper.Plugins;
using skyscraper5.T2MI.Baseband;
using skyscraper5.T2MI.Packets;
using skyscraper8.T2MI.Packets;
namespace skyscraper5.T2MI
{
@ -204,6 +205,10 @@ namespace skyscraper5.T2MI
throw new NotImplementedException(subpart.Subpart.ToString());
}
break;
case 0xf0:
_0xF0_FramingTimingInformation fti = (_0xF0_FramingTimingInformation)t2MiPacket;
t2MiEventHandler.OnFramingAndTimingInformation(RelatedPid, fti);
break;
default:
throw new NotImplementedException(t2MiPacket.GetType().Name);
}
@ -300,34 +305,37 @@ namespace skyscraper5.T2MI
private T2MiPacket DecodePacket(T2MIHeader header, byte[] buffer)
{
if (header.PacketType > 0x33 || header.PacketType == 0x03 || header.PacketType == 0x0f || header.PacketType == 0x19 || header.PacketType == 0x18 ||
header.PacketType == 0x0a || header.PacketType == 0x2e || header.PacketType == 0x2b || header.PacketType == 0x1e || header.PacketType == 0x05 ||
header.PacketType == 0x1f || header.PacketType == 0x1d || header.PacketType == 0x1c || header.PacketType == 0x06 || header.PacketType == 0x25 ||
header.PacketType == 0x28 || header.PacketType == 0x08 || header.PacketType == 0x24 || header.PacketType == 0x17 || header.PacketType == 0x2a ||
header.PacketType == 0x23 ||
header.PacketType == 0x15 ||
header.PacketType == 0x0e ||
header.PacketType == 0x2f ||
header.PacketType == 0x2d ||
header.PacketType == 0x04 ||
header.PacketType == 0x26 ||
header.PacketType == 0x22 ||
header.PacketType == 0x0d ||
header.PacketType == 0x13 ||
header.PacketType == 0x29 ||
header.PacketType == 0x09 ||
header.PacketType == 0x0b ||
header.PacketType == 0x2c ||
header.PacketType == 0x1a ||
header.PacketType == 0x16 ||
header.PacketType == 0x1b ||
header.PacketType == 0x14 ||
header.PacketType == 0x27 ||
header.PacketType == 0x0c ||
header.PacketType == 0x07)
if (header.PacketType != 0xf0)
{
//reserved for future use
return null;
if (header.PacketType > 0x33 || header.PacketType == 0x03 || header.PacketType == 0x0f || header.PacketType == 0x19 || header.PacketType == 0x18 ||
header.PacketType == 0x0a || header.PacketType == 0x2e || header.PacketType == 0x2b || header.PacketType == 0x1e || header.PacketType == 0x05 ||
header.PacketType == 0x1f || header.PacketType == 0x1d || header.PacketType == 0x1c || header.PacketType == 0x06 || header.PacketType == 0x25 ||
header.PacketType == 0x28 || header.PacketType == 0x08 || header.PacketType == 0x24 || header.PacketType == 0x17 || header.PacketType == 0x2a ||
header.PacketType == 0x23 ||
header.PacketType == 0x15 ||
header.PacketType == 0x0e ||
header.PacketType == 0x2f ||
header.PacketType == 0x2d ||
header.PacketType == 0x04 ||
header.PacketType == 0x26 ||
header.PacketType == 0x22 ||
header.PacketType == 0x0d ||
header.PacketType == 0x13 ||
header.PacketType == 0x29 ||
header.PacketType == 0x09 ||
header.PacketType == 0x0b ||
header.PacketType == 0x2c ||
header.PacketType == 0x1a ||
header.PacketType == 0x16 ||
header.PacketType == 0x1b ||
header.PacketType == 0x14 ||
header.PacketType == 0x27 ||
header.PacketType == 0x0c ||
header.PacketType == 0x07)
{
//reserved for future use
return null;
}
}
if (packetConstructorInfos == null)

View File

@ -4,6 +4,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using skyscraper5.T2MI.Packets;
using skyscraper8.T2MI.Packets;
namespace skyscraper5.T2MI
{
@ -20,5 +21,6 @@ namespace skyscraper5.T2MI
void OnT2MiBalancingCells(int relatedPid, byte frameIndex, uint numActiveBiasCellsPerP2);
void OnT2MiL1Future(int relatedPid, _0x11_L1Future l1Future);
void OnT2MiIndividualAddressing(int relatedPid, _0x21_IndividualAddressing individualAddressing);
void OnFramingAndTimingInformation(int relatedPid, _0xF0_FramingTimingInformation fti);
}
}

View File

@ -22,9 +22,6 @@ namespace skyscraper5.T2MI
(buffer[4], buffer[5]) = (buffer[5], buffer[4]);
PayloadLength = BitConverter.ToUInt16(buffer, 4);
if (PacketCount == 104)
return;
}
public ushort PayloadLength { get; private set; }

View File

@ -6,6 +6,7 @@ using System.Text;
using System.Threading.Tasks;
using skyscraper5.Mpeg2;
using skyscraper5.T2MI.Packets;
using skyscraper8.T2MI.Packets;
namespace skyscraper5.T2MI
{
@ -101,5 +102,9 @@ namespace skyscraper5.T2MI
{
}
void T2MIEventHandler.OnFramingAndTimingInformation(int relatedPid, _0xF0_FramingTimingInformation fti)
{
}
}
}