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

110 lines
3.1 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using skyscraper5.Dvb.Psi.Model;
using skyscraper5.Mpeg2;
using skyscraper5.Skyscraper.IO;
namespace skyscraper5.Scorcher
{
internal class SdtGenerator : PsiGenerator
{
public ushort TransportStreamId { get; }
public ushort OriginalNetworkId { get; }
public SdtGenerator(ushort transportStreamId, ushort originalNetworkId) : base(new TimeSpan(0, 0, 4), 0x0011)
{
TransportStreamId = transportStreamId;
OriginalNetworkId = originalNetworkId;
services = new List<SdtGeneratorService>();
}
public SdtGeneratorService CreateService(ushort serviceId, bool eitScheduleFlag = false,
bool eitPresentFollowingFlag = false, RunningStatus runningStatus = RunningStatus.Running,
bool freeCaMode = false)
{
SdtGeneratorService result = new SdtGeneratorService(serviceId, eitScheduleFlag, eitPresentFollowingFlag, runningStatus, freeCaMode);
services.Add(result);
return result;
}
private List<SdtGeneratorService> services;
private byte[] SerializeServices()
{
MemoryStream ms = new MemoryStream();
foreach (SdtGeneratorService service in services)
{
byte[] descriptorBuffer = service.SerializeDescriptors();
ushort descriptorLength = (ushort)descriptorBuffer.Length;
ms.WriteUInt16BE(service.ServiceId);
byte byteA = 0;
byteA |= 0xfc; //reserved
if (service.EitScheduleFlag)
byteA |= 0x02;
if (service.EitPresentFollowingFlag)
byteA |= 0x01;
ms.WriteUInt8(byteA);
byte byteB = 0;
byteB |= (byte)((int)service.RunningStatus << 5);
if (service.FreeCaMode)
byteB |= 0x10;
byteB |= (byte)((descriptorLength & 0x0f00) >> 8);
ms.WriteUInt8(byteB);
ms.WriteUInt8((byte)(descriptorLength & 0x00ff));
ms.Write(descriptorBuffer, 0, descriptorBuffer.Length);
}
return ms.ToArray();
}
public override byte[] BuildPsi()
{
byte[] serializedServices = SerializeServices();
ushort sectionLength = (ushort)(2 + 3 + 2 + 1 + serializedServices.Length + 4); //TODO: calculate section length
if (sectionLength > 1021)
throw new Exception("section too long");
sectionLength &= 0x3fff;
MemoryStream ms = new MemoryStream();
ms.WriteUInt8(0x42);
byte byteA = 0;
byteA |= 0x80; //section_syntax_indicator
byteA |= 0x40; //reserved_future_use
byteA |= 0x30; //reserved
byteA |= (byte)(sectionLength >> 8);
ms.WriteUInt8(byteA);
byte byteB = (byte)(sectionLength & 0x00ff);
ms.WriteUInt8(byteB);
ms.WriteUInt16BE(TransportStreamId);
byte byteC = 0;
byteC |= 0xc0; //reserved
byteC |= (byte)(versionNumber << 1); //version_number
byteC |= 0x01; //current_next_indicator
ms.WriteUInt8(byteC);
ms.WriteUInt8(0x00); //section number
ms.WriteUInt8(0x00); //last section number
ms.WriteUInt16BE(OriginalNetworkId); //original network id
ms.WriteUInt8(0xff); //reserved future use
ms.Write(serializedServices, 0, serializedServices.Length);
uint crc = DvbCrc32.CreateCrc(ms, 0, (int)ms.Position);
ms.WriteUInt32BE(crc);
return ms.ToArray();
}
}
}