skyscraper8/skyscraper8/Scorcher/PmtGenerator.cs
feyris-tan ef86554f9a Import
2025-05-12 22:09:16 +02:00

118 lines
3.3 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using skyscraper5.Dvb.Descriptors;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.IO;
namespace skyscraper5.Scorcher
{
public class PmtGenerator : PsiGenerator
{
public ushort ProgramNumber { get; }
public ushort PcrPid { get; }
public PmtGenerator(uint pid, ushort programNumber, ushort PcrPid) : base(new TimeSpan(0,0,3), pid)
{
ProgramNumber = programNumber;
this.PcrPid = PcrPid;
descriptors = new List<TsDescriptor>();
streams = new List<PmtGeneratorStream>();
}
private List<TsDescriptor> descriptors;
private List<PmtGeneratorStream> streams;
private byte[] SerializeDescriptors()
{
MemoryStream ms = new MemoryStream();
foreach (TsDescriptor descriptor in descriptors)
{
ms.WriteUInt8(descriptor.GetDescriptorId()); //descriptor_tag
byte[] descriptorBytes = descriptor.Serialize();
ms.WriteUInt8((byte)descriptorBytes.Length); //descriptor_length
ms.Write(descriptorBytes, 0, descriptorBytes.Length);
}
return ms.ToArray();
}
private byte[] SerializeStreams()
{
MemoryStream ms = new MemoryStream();
foreach (PmtGeneratorStream stream in streams)
{
ms.WriteUInt8(stream.StreamType);
ms.WriteUInt16BE((ushort)(stream.ElementaryPid | 0xe000));
byte[] descriptorLoop = stream.SerializeDescriptors();
ms.WriteUInt16BE((ushort)(descriptorLoop.Length | 0xf000)); //ES_Info_length
ms.Write(descriptorLoop, 0, descriptorLoop.Length);
}
return ms.ToArray();
}
public override byte[] BuildPsi()
{
byte[] descriptorBuffer = SerializeDescriptors();
int programInfoLength = descriptorBuffer.Length;
byte[] streamBuffer = SerializeStreams();
int sectionLength = 9 + descriptorBuffer.Length + streamBuffer.Length + 4;
//TODO: calculate section length here
MemoryStream ms = new MemoryStream();
ms.WriteUInt8(0x02); //table_id
byte byte2 = 0;
byte2 |= 0x80; //section_syntax_indicator
//'0'
byte2 |= 0x30; //reserved
byte2 += (byte)((sectionLength & 0x0300) >> 8);
ms.WriteUInt8(byte2); //section length, part 1
byte byte3 = (byte)(sectionLength & 0x00ff);
ms.WriteUInt8(byte3); //section length, part 2
ms.WriteUInt16BE(ProgramNumber);
byte byte4 = 0;
byte4 |= 0xc0; //reserved
byte4 |= (byte)((versionNumber & 0x1f) << 1); //version number
byte4 |= 0x01; //current next indicator
ms.WriteUInt8(byte4);
ms.WriteUInt8(0); //section number
ms.WriteUInt8(0); //last section number
ms.WriteUInt16BE((ushort)(PcrPid | 0xe000)); //reserved & PCR_PID
ms.WriteUInt16BE((ushort)(programInfoLength | 0xf000)); //reserved & program info length
ms.Write(descriptorBuffer, 0, descriptorBuffer.Length); //descriptors()
ms.Write(streamBuffer, 0, streamBuffer.Length);
uint crc = DvbCrc32.CreateCrc(ms, 0, (int)ms.Position);
ms.WriteUInt32BE(crc);
return ms.ToArray();
}
public void AddDescriptor(PrivateDataSpecifierDescriptor privateDataSpecifierDescriptor)
{
descriptors.Add(privateDataSpecifierDescriptor);
versionNumber++;
}
public PmtGeneratorStream AddStream(byte streamType, ushort pid)
{
PmtGeneratorStream stream = new PmtGeneratorStream(streamType, pid);
streams.Add(stream);
versionNumber++;
return stream;
}
}
}