Added basic parsing of ATSC Pipes.
All checks were successful
🚀 Pack skyscraper8 / make-zip (push) Successful in 37s
All checks were successful
🚀 Pack skyscraper8 / make-zip (push) Successful in 37s
This commit is contained in:
parent
64b1639e2f
commit
f4193297d2
@ -1,4 +1,5 @@
|
||||
using skyscraper5.Skyscraper.IO;
|
||||
using skyscraper8.Atsc.A330;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@ -30,7 +31,7 @@ namespace skyscraper8.Atsc.A322
|
||||
byte b = ms.ReadUInt8();
|
||||
pointer |= (((b >> 2) & 0x3F) << 7);
|
||||
OfiDescription ofi = (OfiDescription)(b & 0x3);
|
||||
switch(ofi)
|
||||
switch (ofi)
|
||||
{
|
||||
case OfiDescription.NoExtensionMode:
|
||||
break;
|
||||
@ -57,8 +58,93 @@ namespace skyscraper8.Atsc.A322
|
||||
}
|
||||
}
|
||||
|
||||
throw new NotImplementedException("Actually do the ATSC packets here.")
|
||||
while (ms.GetAvailableBytes() > 0)
|
||||
{
|
||||
switch(stateMachineState)
|
||||
{
|
||||
case 0: //Initial state, nothing parsed yet.
|
||||
if (pointer == 8191)
|
||||
{
|
||||
return; //no new packet to be found in this BBFRAME.
|
||||
}
|
||||
ms.Position = pointer + addToPointer;
|
||||
neededBuffer = null;
|
||||
neededBufferOffset = 0;
|
||||
currentAlpPacket = null;
|
||||
stateMachineState = 1;
|
||||
break;
|
||||
case 1: //Prepare get Base Header for ALP packet encapsulation
|
||||
neededBuffer = new byte[2];
|
||||
stateMachineState = 2;
|
||||
neededBufferOffset = 0;
|
||||
break;
|
||||
case 2: //Get Base Header for ALP packet encapsulation
|
||||
int readSucessful = ms.Read(neededBuffer, neededBufferOffset, neededBuffer.Length - neededBufferOffset);
|
||||
neededBufferOffset += readSucessful;
|
||||
if (neededBufferOffset == neededBuffer.Length)
|
||||
{
|
||||
stateMachineState = 3;
|
||||
}
|
||||
break;
|
||||
case 3: //Parse current ALP packet
|
||||
currentAlpPacket = new AlpPacket(neededBuffer);
|
||||
if (!currentAlpPacket.PayloadConfiguration)
|
||||
{
|
||||
if (currentAlpPacket.HeaderMode.Value)
|
||||
{
|
||||
throw new NotImplementedException("Single Packet Header not yet implemented.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!currentAlpPacket.SegmentationConcatenation.Value)
|
||||
{
|
||||
throw new NotImplementedException("Segmentation Header not yet implemented.");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException("Concatenation Header not yet implemented.");
|
||||
}
|
||||
}
|
||||
stateMachineState = 4;
|
||||
break;
|
||||
case 4: //Prepate get packet payload
|
||||
neededBufferOffset = 0;
|
||||
neededBuffer = new byte[currentAlpPacket.Length];
|
||||
stateMachineState = 5;
|
||||
break;
|
||||
case 5: //Get packet payload
|
||||
int readSuccesful2 = ms.Read(neededBuffer, neededBufferOffset, neededBuffer.Length - neededBufferOffset);
|
||||
neededBufferOffset += readSuccesful2;
|
||||
if (neededBufferOffset == neededBuffer.Length)
|
||||
{
|
||||
stateMachineState = 6;
|
||||
}
|
||||
break;
|
||||
case 6: //Deliver packet
|
||||
DeliverPacket(currentAlpPacket, neededBuffer);
|
||||
stateMachineState = 1;
|
||||
break;
|
||||
default:
|
||||
throw new NotImplementedException(String.Format("ATSC PLP Baseband Parser State machine state #{0}", stateMachineState));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DeliverPacket(AlpPacket? currentAlpPacket, byte[]? neededBuffer)
|
||||
{
|
||||
Console.WriteLine("PacketType = {0} \t Length = {1}", currentAlpPacket.PacketType, neededBuffer.Length);
|
||||
}
|
||||
|
||||
internal void OnSyncLoss()
|
||||
{
|
||||
stateMachineState = 0;
|
||||
}
|
||||
|
||||
private AlpPacket currentAlpPacket;
|
||||
private int stateMachineState;
|
||||
private byte[] neededBuffer;
|
||||
private int neededBufferOffset;
|
||||
}
|
||||
|
||||
internal enum OfiDescription
|
||||
|
||||
101
skyscraper8/Atsc/A322/L1BasicSignalling.cs
Normal file
101
skyscraper8/Atsc/A322/L1BasicSignalling.cs
Normal file
@ -0,0 +1,101 @@
|
||||
using skyscraper5.Skyscraper;
|
||||
using skyscraper5.Skyscraper.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper8.Atsc.A322
|
||||
{
|
||||
internal class L1BasicSignalling : Validatable
|
||||
{
|
||||
public L1BasicSignalling(byte[] buffer)
|
||||
{
|
||||
InBitStream bitstream = new InBitStream(buffer);
|
||||
this.Version = new Version(bitstream.ReadBitsAsUInt16(3), 0);
|
||||
MimoScatteredPilotEncoding = bitstream.ReadBitAsBoolean();
|
||||
LlsFlag = bitstream.ReadBitAsBoolean();
|
||||
TimeInfoFlag = (TimeInfoFlagSignalingFormat)bitstream.ReadBitsAsByte(2);
|
||||
ReturnChannelFlag = bitstream.ReadBitAsBoolean();
|
||||
PaprReduction = (PaprReductionSignalingFormat)bitstream.ReadBitsAsByte(2);
|
||||
bool frameLengthMode = bitstream.ReadBitAsBoolean();
|
||||
if (!frameLengthMode)
|
||||
{
|
||||
FrameLength = bitstream.ReadBitsAsUint(10);
|
||||
ExcessSamplesPerSymbol = bitstream.ReadBitsAsUint(13);
|
||||
}
|
||||
else
|
||||
{
|
||||
TimeOffset = bitstream.ReadBitsAsUint(16);
|
||||
AdditionalSamples = bitstream.ReadBitsAsByte(7);
|
||||
}
|
||||
NumSubframes = bitstream.ReadBitsAsByte(8);
|
||||
PreambleNumSymbols = bitstream.ReadBitsAsByte(3);
|
||||
PreambleReducedCarriers = bitstream.ReadBitsAsByte(3);
|
||||
L1DetailContentTag = bitstream.ReadBitsAsByte(2);
|
||||
L1DetailSizeBytes = bitstream.ReadBitsAsUint(13);
|
||||
L1DetailFecType = bitstream.ReadBitsAsByte(3);
|
||||
L1DetailAdditionalParityMode = bitstream.ReadBitsAsByte(2);
|
||||
L1DetailTotalCells = bitstream.ReadBitsAsUint(19);
|
||||
FirstSubMimo = bitstream.ReadBitAsBoolean();
|
||||
FirstSubMiso = bitstream.ReadBitsAsByte(2);
|
||||
FirstSubFftSize = bitstream.ReadBitsAsByte(2);
|
||||
FirstSubReducedCarries = bitstream.ReadBitsAsByte(3);
|
||||
FirstSubGuardInterval = bitstream.ReadBitsAsByte(4);
|
||||
FirstSubNumOfdmSymbols = bitstream.ReadBitsAsUint(11);
|
||||
FirstSubScatteredPilotPattern = bitstream.ReadBitsAsByte(5);
|
||||
FirstSubScatteredPilotBoost = bitstream.ReadBitsAsByte(3);
|
||||
FirstSubSbsFirst = bitstream.ReadBitAsBoolean();
|
||||
FirstSubSbsLast = bitstream.ReadBitAsBoolean();
|
||||
FirstSubMimoMixed = bitstream.ReadBitAsBoolean();
|
||||
Valid = true;
|
||||
}
|
||||
|
||||
public Version Version { get; }
|
||||
public bool MimoScatteredPilotEncoding { get; }
|
||||
public bool LlsFlag { get; }
|
||||
public TimeInfoFlagSignalingFormat TimeInfoFlag { get; }
|
||||
public bool ReturnChannelFlag { get; }
|
||||
public PaprReductionSignalingFormat PaprReduction { get; }
|
||||
public uint? FrameLength { get; }
|
||||
public uint? ExcessSamplesPerSymbol { get; }
|
||||
public uint? TimeOffset { get; }
|
||||
public byte AdditionalSamples { get; }
|
||||
public byte NumSubframes { get; }
|
||||
public byte PreambleNumSymbols { get; }
|
||||
public byte PreambleReducedCarriers { get; }
|
||||
public byte L1DetailContentTag { get; }
|
||||
public uint L1DetailSizeBytes { get; }
|
||||
public byte L1DetailFecType { get; }
|
||||
public byte L1DetailAdditionalParityMode { get; }
|
||||
public uint L1DetailTotalCells { get; }
|
||||
public bool FirstSubMimo { get; }
|
||||
public byte FirstSubMiso { get; }
|
||||
public byte FirstSubFftSize { get; }
|
||||
public byte FirstSubReducedCarries { get; }
|
||||
public byte FirstSubGuardInterval { get; private set; }
|
||||
public uint FirstSubNumOfdmSymbols { get; }
|
||||
public byte FirstSubScatteredPilotPattern { get; }
|
||||
public byte FirstSubScatteredPilotBoost { get; }
|
||||
public bool FirstSubSbsFirst { get; }
|
||||
public bool FirstSubSbsLast { get; }
|
||||
public bool FirstSubMimoMixed { get; }
|
||||
}
|
||||
|
||||
enum TimeInfoFlagSignalingFormat
|
||||
{
|
||||
NotIncluded,
|
||||
IncludedMilliseconds,
|
||||
IncludedMicroseconds,
|
||||
IncludedNanoseconds,
|
||||
}
|
||||
|
||||
enum PaprReductionSignalingFormat
|
||||
{
|
||||
NoPaprReduction,
|
||||
ToneReservationOnly,
|
||||
AceOnly,
|
||||
TrAndAce
|
||||
}
|
||||
}
|
||||
16
skyscraper8/Atsc/A322/L1DetailSignalling.cs
Normal file
16
skyscraper8/Atsc/A322/L1DetailSignalling.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using skyscraper5.Skyscraper;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper8.Atsc.A322
|
||||
{
|
||||
internal class L1DetailSignalling : Validatable
|
||||
{
|
||||
public L1DetailSignalling(byte[] bytes)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -62,6 +62,7 @@ namespace skyscraper8.Atsc.A324
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private ushort expectedSequenceNumber;
|
||||
private bool warnedAboutNonMarkedPackets;
|
||||
public void HandlePacket(InternetHeader internetHeader, byte[] ipv4Packet)
|
||||
{
|
||||
@ -79,6 +80,8 @@ namespace skyscraper8.Atsc.A324
|
||||
return;
|
||||
}
|
||||
|
||||
EnsurePlpSync(plp, rtpPacket);
|
||||
|
||||
if (plp == 64)
|
||||
{
|
||||
HandlePreambleData(rtpPacket.RtpPayload);
|
||||
@ -96,6 +99,44 @@ namespace skyscraper8.Atsc.A324
|
||||
}
|
||||
}
|
||||
|
||||
private ushort[] plpSequenceNumbers;
|
||||
private void EnsurePlpSync(ushort plp, RtpPacket rtpPacket)
|
||||
{
|
||||
if (plpSequenceNumbers == null)
|
||||
{
|
||||
plpSequenceNumbers = new ushort[66];
|
||||
}
|
||||
|
||||
if (plpSequenceNumbers[plp] != rtpPacket.RtpSequenceNumber)
|
||||
{
|
||||
if (plp == 64)
|
||||
{
|
||||
DesyncPreamble();
|
||||
}
|
||||
else if (plp == 65)
|
||||
{
|
||||
throw new NotImplementedException("desynced timing and management");
|
||||
}
|
||||
else if (plp <= 63)
|
||||
{
|
||||
plps?[plp]?.OnSyncLoss();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotImplementedException(String.Format("Unknown PLP: {0}", plp));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void DesyncPreamble()
|
||||
{
|
||||
if (preambleData != null)
|
||||
{
|
||||
preambleData.Valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
private AtscPlpBasebandParser[] plps;
|
||||
private void HandlePlp(ushort plp, byte[] rtpPayload)
|
||||
{
|
||||
@ -115,9 +156,10 @@ namespace skyscraper8.Atsc.A324
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
private PreambleData preambleData;
|
||||
private void HandlePreambleData(byte[] rtpPayload)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
preambleData = new PreambleData(rtpPayload);
|
||||
}
|
||||
|
||||
private SkyscraperContext context;
|
||||
|
||||
40
skyscraper8/Atsc/A324/PreambleData.cs
Normal file
40
skyscraper8/Atsc/A324/PreambleData.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using skyscraper5.Skyscraper;
|
||||
using skyscraper5.Skyscraper.IO;
|
||||
using skyscraper8.Atsc.A322;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper8.Atsc.A324
|
||||
{
|
||||
internal class PreambleData : Validatable
|
||||
{
|
||||
public PreambleData(byte[] buffer)
|
||||
{
|
||||
MemoryStream ms = new MemoryStream(buffer);
|
||||
long expectedLength = ms.ReadUInt16BE();
|
||||
long actualLength = ms.Length - 4;
|
||||
if (actualLength != expectedLength)
|
||||
{
|
||||
Valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
BasicSignalling = new L1BasicSignalling(ms.ReadBytes(25));
|
||||
if (!BasicSignalling.Valid)
|
||||
{
|
||||
Valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
long detailLength = expectedLength - 25;
|
||||
DetailSignalling = new L1DetailSignalling(ms.ReadBytes(detailLength));
|
||||
Valid = DetailSignalling.Valid;
|
||||
}
|
||||
|
||||
public L1BasicSignalling BasicSignalling { get; }
|
||||
public L1DetailSignalling DetailSignalling { get; }
|
||||
}
|
||||
}
|
||||
45
skyscraper8/Atsc/A330/AlpPacket.cs
Normal file
45
skyscraper8/Atsc/A330/AlpPacket.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using skyscraper5.Skyscraper.IO;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace skyscraper8.Atsc.A330
|
||||
{
|
||||
internal class AlpPacket
|
||||
{
|
||||
public AlpPacket(byte[] buffer)
|
||||
{
|
||||
MemoryStream ms = new MemoryStream(buffer, false);
|
||||
ushort first16bits = ms.ReadUInt16BE();
|
||||
PacketType = (AlpPacketType)((first16bits & 0xe000) >> 13);
|
||||
PayloadConfiguration = (first16bits & 0x1000) != 0;
|
||||
if (!PayloadConfiguration)
|
||||
{
|
||||
HeaderMode = (first16bits & 0x0800) != 0;
|
||||
Length = (first16bits & 0x07ff);
|
||||
}
|
||||
else
|
||||
{
|
||||
SegmentationConcatenation = (first16bits & 0x0800) != 0;
|
||||
Length = (first16bits & 0x07ff);
|
||||
}
|
||||
}
|
||||
|
||||
public AlpPacketType PacketType { get; private set; }
|
||||
public bool PayloadConfiguration { get; private set; }
|
||||
public bool? HeaderMode { get; }
|
||||
public bool? SegmentationConcatenation { get; }
|
||||
public int Length { get; }
|
||||
}
|
||||
|
||||
enum AlpPacketType
|
||||
{
|
||||
Ipv4 = 0,
|
||||
CompressedIp = 2,
|
||||
LinkLayerSignalling = 4,
|
||||
PacketTypeExtension = 6,
|
||||
Mpeg2Ts = 7
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user