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(); streams = new List(); } private List descriptors; private List 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; } } }