@@ -0,0 +1,20 @@ | |||
using JT1078.Hls.Enums; | |||
using JT1078.Hls.MessagePack; | |||
using JT1078.Protocol.Extensions; | |||
using System; | |||
using System.Collections.Generic; | |||
using Xunit; | |||
namespace JT1078.Hls.Test | |||
{ | |||
/// <summary> | |||
/// ʹÓÃdoc/video/demo0.ts | |||
/// </summary> | |||
public class TS_SDT_Package_Test | |||
{ | |||
[Fact] | |||
public void ToBufferTest() | |||
{ | |||
} | |||
} | |||
} |
@@ -0,0 +1,19 @@ | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Text; | |||
namespace JT1078.Hls.Enums | |||
{ | |||
/// <summary> | |||
/// 运行状态 | |||
/// </summary> | |||
public enum RunningStatus | |||
{ | |||
未定义=0, | |||
未运行=1, | |||
几秒后开始=2, | |||
暂停=3, | |||
运行=4, | |||
} | |||
} |
@@ -33,4 +33,7 @@ | |||
<PackagePath></PackagePath> | |||
</None> | |||
</ItemGroup> | |||
<ItemGroup> | |||
<PackageReference Include="System.Text.Encoding.CodePages" Version="4.7.1" /> | |||
</ItemGroup> | |||
</Project> |
@@ -163,5 +163,11 @@ namespace JT1078.Hls.MessagePack | |||
{ | |||
return writer.WrittenCount; | |||
} | |||
public void WriteString(string value) | |||
{ | |||
byte[] codeBytes = TSConstants.Encoding.GetBytes(value); | |||
codeBytes.CopyTo(writer.Free); | |||
writer.Advance(codeBytes.Length); | |||
} | |||
} | |||
} |
@@ -6,6 +6,12 @@ namespace JT1078.Hls | |||
{ | |||
public static class TSConstants | |||
{ | |||
static TSConstants() | |||
{ | |||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); | |||
Encoding = Encoding.GetEncoding("GBK"); | |||
} | |||
public static Encoding Encoding { get; } | |||
/// <summary> | |||
/// 固定包长度 | |||
/// </summary> | |||
@@ -3,6 +3,7 @@ using JT1078.Hls.Interfaces; | |||
using JT1078.Hls.MessagePack; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Diagnostics.Tracing; | |||
using System.Linq; | |||
using System.Text; | |||
@@ -15,12 +16,12 @@ namespace JT1078.Hls | |||
{ | |||
public TS_Header Header { get; set; } | |||
/// <summary> | |||
/// PAT表固定为0x00 | |||
/// | |||
/// 8bit | |||
/// </summary> | |||
public byte TableId { get; set; } = 0x42; | |||
/// <summary> | |||
/// 固定为二进制1 | |||
/// | |||
/// 1bit | |||
/// </summary> | |||
internal byte SectionSyntaxIndicator { get; set; } | |||
@@ -43,14 +44,14 @@ namespace JT1078.Hls | |||
/// 传输流ID | |||
/// 16bit | |||
/// </summary> | |||
internal ushort TransportStreamId { get; set; } = 0x0001; | |||
internal ushort TransportStreamId { get; set; } | |||
/// <summary> | |||
/// | |||
/// 2bit | |||
/// </summary> | |||
internal byte Reserved2 { get; set; } | |||
/// <summary> | |||
/// 版本号, | |||
/// | |||
/// 5bit | |||
/// </summary> | |||
public byte VersionNumber { get; set; } | |||
@@ -79,7 +80,7 @@ namespace JT1078.Hls | |||
/// 1Byte | |||
/// </summary> | |||
internal byte ReservedFutureUse2 { get; set; } | |||
public List<TS_SDT_Service_Descriptor> Services { get; set; } | |||
public List<TS_SDT_Service> Services { get; set; } | |||
/// <summary> | |||
/// 前面数据的CRC32校验码 | |||
@@ -88,33 +89,21 @@ namespace JT1078.Hls | |||
public void ToBuffer(ref TSMessagePackWriter writer) | |||
{ | |||
Header.PackageType = PackageType.PAT; | |||
Header.ToBuffer(ref writer); | |||
writer.WriteByte(TableId); | |||
//SectionSyntaxIndicator Zero Reserved1 SectionLength | |||
//1 0 11 0000 0000 0000 | |||
//(ushort)(0b_1011_0000_0000_0000 | SectionLength) | |||
writer.Skip(2, out int SectionLengthPosition); | |||
writer.WriteUInt16(TransportStreamId); | |||
//Reserved2 VersionNumber CurrentNextIndicator | |||
//11 00000 1 | |||
var a = 0xC0 & (Reserved2 << 6); | |||
var b = 0x3E & (VersionNumber << 3); | |||
var c = (byte)(a | b | CurrentNextIndicator); | |||
writer.WriteByte(c); | |||
writer.WriteByte((byte)(Reserved2 << 6 | VersionNumber << 1 | CurrentNextIndicator)); | |||
writer.WriteByte(SectionNumber); | |||
writer.WriteByte(LastSectionNumber); | |||
//if (Programs != null) | |||
//{ | |||
// foreach (var program in Programs) | |||
// { | |||
// program.ToBuffer(ref writer); | |||
// } | |||
//} | |||
const int crcLength= 4; | |||
writer.WriteUInt16Return((ushort)(0b_1011_0000_0000_0000 | (ushort)(writer.GetCurrentPosition() - SectionLengthPosition - 2)+ crcLength), SectionLengthPosition); | |||
//打包ts流时PAT和PMT表是没有adaptation field的,不够的长度直接补0xff即可。 | |||
//ts header(4B) + adaptation field length(1) | |||
writer.WriteUInt16(OriginalNetworkId); | |||
writer.WriteByte(ReservedFutureUse2); | |||
foreach (var service in Services) | |||
{ | |||
service.ToBuffer(ref writer); | |||
} | |||
ushort servicesLength =(ushort)( writer.GetCurrentPosition() - SectionLengthPosition); | |||
const int crcLength = 4; | |||
writer.WriteUInt16Return((ushort)(SectionSyntaxIndicator<<15 | ReservedFutureUse1<<14 | servicesLength+ crcLength), SectionLengthPosition); | |||
writer.WriteCRC32(5); | |||
var size = TSConstants.FiexdPackageLength - writer.GetCurrentPosition(); | |||
writer.WriteArray(Enumerable.Range(0, size).Select(s => (byte)0xFF).ToArray()); | |||
@@ -0,0 +1,76 @@ | |||
using JT1078.Hls.Enums; | |||
using JT1078.Hls.Interfaces; | |||
using JT1078.Hls.MessagePack; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
namespace JT1078.Hls | |||
{ | |||
/// <summary> | |||
/// 业务描述服务 | |||
/// </summary> | |||
public class TS_SDT_Service : ITSMessagePackFormatter | |||
{ | |||
/// <summary> | |||
/// 业务标识符 | |||
/// 用于在 TS 流中识别不同的业务。service_id 与program_map_section 中的 program_number 取同一值 | |||
/// 16bit | |||
/// </summary> | |||
internal ushort ServiceId { get; set; } | |||
/// <summary> | |||
/// | |||
/// 6bit | |||
/// </summary> | |||
internal byte ReservedFutureUse { get; set; } | |||
/// <summary> | |||
/// EIT 时间表标志 | |||
/// 置“1”时,表示业务的 EIT 时间表信息存在于当前 TS 中(一个 EIT 时间表子表两次出现的最大时间间隔信息见 ETR 211)。 | |||
/// 置“0”时,表示业务的 EIT 时间表信息不在当前 TS 中 | |||
/// 1bit | |||
/// </summary> | |||
internal byte EITScheduleFlag { get; set; } | |||
/// <summary> | |||
/// EIT 当前后续标志 | |||
/// 置“1”时,表示业务的 EIT 当前后续信息存在于当前 TS 中(一个 EIT 当前后续子表两次出现的最大时间间隔信息见ETR 211) | |||
/// 置“0”时,表示业务的 EIT 当前后续信息不在当前 TS 中。 | |||
/// 1bit | |||
/// </summary> | |||
public byte EITPresentFollowingFlag { get; set; } | |||
/// <summary> | |||
/// 运行状态 | |||
/// 对于一个 NVOD 业务,running_status 的值都置“0” | |||
/// 3bit | |||
/// </summary> | |||
internal RunningStatus RunningStatus { get; set; } | |||
/// <summary> | |||
/// 自由条件接收模式 | |||
/// 置“0”时,表示业务的所有组件都未被加扰 | |||
/// 置“1”时,表示一路或多路码流的接收由 CA 系统控制。 | |||
/// 1bit | |||
/// </summary> | |||
internal byte FreeCAMode { get; set; } | |||
/// <summary> | |||
/// 描述符循环长度 | |||
/// 指出从本字段的下一个字节开始的描述符的总字节长度。 | |||
/// 12bit | |||
/// </summary> | |||
public ushort DescriptorsLoopLength { get; set; } | |||
public List<TS_SDT_Service_Descriptor> Descriptors { get; set; } | |||
public void ToBuffer(ref TSMessagePackWriter writer) | |||
{ | |||
writer.WriteUInt16(ServiceId); | |||
writer.WriteByte((byte)((ReservedFutureUse << 2) | (EITScheduleFlag << 1) | EITPresentFollowingFlag)); | |||
writer.Skip(2, out var position); | |||
foreach (var descriptor in Descriptors) | |||
{ | |||
descriptor.ToBuffer(ref writer); | |||
} | |||
DescriptorsLoopLength = (ushort)(writer.GetCurrentPosition() - position); | |||
writer.WriteUInt16Return((ushort)(((ushort)RunningStatus << 13) | ((ushort)FreeCAMode << 12) | DescriptorsLoopLength), position); | |||
} | |||
} | |||
} |
@@ -1,123 +0,0 @@ | |||
using JT1078.Hls.Enums; | |||
using JT1078.Hls.Interfaces; | |||
using JT1078.Hls.MessagePack; | |||
using System; | |||
using System.Collections.Generic; | |||
using System.Linq; | |||
using System.Text; | |||
namespace JT1078.Hls | |||
{ | |||
/// <summary> | |||
/// 业务描述服务 | |||
/// </summary> | |||
public class TS_SDT_Service : ITSMessagePackFormatter | |||
{ | |||
public TS_Header Header { get; set; } | |||
/// <summary> | |||
/// PAT表固定为0x00 | |||
/// 8bit | |||
/// </summary> | |||
public byte TableId { get; set; } = 0x42; | |||
/// <summary> | |||
/// 固定为二进制1 | |||
/// 1bit | |||
/// </summary> | |||
internal byte SectionSyntaxIndicator { get; set; } | |||
/// <summary> | |||
/// | |||
/// 1bit | |||
/// </summary> | |||
internal byte ReservedFutureUse1 { get; set; } | |||
/// <summary> | |||
/// | |||
/// 2bit | |||
/// </summary> | |||
internal byte Reserved1 { get; set; } | |||
/// <summary> | |||
/// 后面数据的长度 | |||
/// 12bit | |||
/// </summary> | |||
public ushort SectionLength { get; set; } | |||
/// <summary> | |||
/// 传输流ID | |||
/// 16bit | |||
/// </summary> | |||
internal ushort TransportStreamId { get; set; } = 0x0001; | |||
/// <summary> | |||
/// | |||
/// 2bit | |||
/// </summary> | |||
internal byte Reserved2 { get; set; } | |||
/// <summary> | |||
/// 版本号, | |||
/// 5bit | |||
/// </summary> | |||
public byte VersionNumber { get; set; } | |||
/// <summary> | |||
/// | |||
/// 1bit | |||
/// </summary> | |||
public byte CurrentNextIndicator { get; set; } | |||
/// <summary> | |||
/// | |||
/// bit8 | |||
/// </summary> | |||
internal byte SectionNumber { get; set; } | |||
/// <summary> | |||
/// | |||
/// bit8 | |||
/// </summary> | |||
internal byte LastSectionNumber { get; set; } | |||
/// <summary> | |||
/// | |||
/// bit8 | |||
/// </summary> | |||
internal ushort OriginalNetworkId { get; set; } | |||
/// <summary> | |||
/// | |||
/// 1Byte | |||
/// </summary> | |||
internal byte ReservedFutureUse2 { get; set; } | |||
public List<TS_PAT_Program> Services { get; set; } | |||
/// <summary> | |||
/// 前面数据的CRC32校验码 | |||
/// </summary> | |||
public uint CRC32 { get; set; } | |||
public void ToBuffer(ref TSMessagePackWriter writer) | |||
{ | |||
Header.PackageType = PackageType.PAT; | |||
Header.ToBuffer(ref writer); | |||
writer.WriteByte(TableId); | |||
//SectionSyntaxIndicator Zero Reserved1 SectionLength | |||
//1 0 11 0000 0000 0000 | |||
//(ushort)(0b_1011_0000_0000_0000 | SectionLength) | |||
writer.Skip(2, out int SectionLengthPosition); | |||
writer.WriteUInt16(TransportStreamId); | |||
//Reserved2 VersionNumber CurrentNextIndicator | |||
//11 00000 1 | |||
var a = 0xC0 & (Reserved2 << 6); | |||
var b = 0x3E & (VersionNumber << 3); | |||
var c = (byte)(a | b | CurrentNextIndicator); | |||
writer.WriteByte(c); | |||
writer.WriteByte(SectionNumber); | |||
writer.WriteByte(LastSectionNumber); | |||
//if (Programs != null) | |||
//{ | |||
// foreach (var program in Programs) | |||
// { | |||
// program.ToBuffer(ref writer); | |||
// } | |||
//} | |||
const int crcLength= 4; | |||
writer.WriteUInt16Return((ushort)(0b_1011_0000_0000_0000 | (ushort)(writer.GetCurrentPosition() - SectionLengthPosition - 2)+ crcLength), SectionLengthPosition); | |||
//打包ts流时PAT和PMT表是没有adaptation field的,不够的长度直接补0xff即可。 | |||
//ts header(4B) + adaptation field length(1) | |||
writer.WriteCRC32(5); | |||
var size = TSConstants.FiexdPackageLength - writer.GetCurrentPosition(); | |||
writer.WriteArray(Enumerable.Range(0, size).Select(s => (byte)0xFF).ToArray()); | |||
} | |||
} | |||
} |
@@ -13,111 +13,53 @@ namespace JT1078.Hls | |||
/// </summary> | |||
public class TS_SDT_Service_Descriptor : ITSMessagePackFormatter | |||
{ | |||
public TS_Header Header { get; set; } | |||
/// <summary> | |||
/// PAT表固定为0x00 | |||
/// 8bit | |||
/// </summary> | |||
public byte TableId { get; set; } = 0x42; | |||
/// <summary> | |||
/// 固定为二进制1 | |||
/// 1bit | |||
/// </summary> | |||
internal byte SectionSyntaxIndicator { get; set; } | |||
/// <summary> | |||
/// | |||
/// 1bit | |||
/// </summary> | |||
internal byte ReservedFutureUse1 { get; set; } | |||
/// <summary> | |||
/// | |||
/// 2bit | |||
/// </summary> | |||
internal byte Reserved1 { get; set; } | |||
/// <summary> | |||
/// 后面数据的长度 | |||
/// 12bit | |||
/// </summary> | |||
public ushort SectionLength { get; set; } | |||
/// <summary> | |||
/// 传输流ID | |||
/// 16bit | |||
/// 8bit | |||
/// </summary> | |||
internal ushort TransportStreamId { get; set; } = 0x0001; | |||
public byte DescriptorTag { get; set; } = 0x48; | |||
/// <summary> | |||
/// | |||
/// 2bit | |||
/// </summary> | |||
internal byte Reserved2 { get; set; } | |||
/// <summary> | |||
/// 版本号, | |||
/// 5bit | |||
/// 8bit | |||
/// </summary> | |||
public byte VersionNumber { get; set; } | |||
internal byte DescriptorLength { get; set; } = 0x12; | |||
/// <summary> | |||
/// | |||
/// 1bit | |||
/// 8bit | |||
/// </summary> | |||
public byte CurrentNextIndicator { get; set; } | |||
internal byte ServiceType { get; set; } = 0x01; | |||
/// <summary> | |||
/// | |||
/// bit8 | |||
/// 8bit | |||
/// </summary> | |||
internal byte SectionNumber { get; set; } | |||
internal byte ServiceProviderLength { get; set; } | |||
/// <summary> | |||
/// | |||
/// bit8 | |||
/// ServiceProviderLength | |||
/// </summary> | |||
internal byte LastSectionNumber { get; set; } | |||
public string ServiceProvider { get; set; } | |||
/// <summary> | |||
/// | |||
/// bit8 | |||
/// 8bit | |||
/// </summary> | |||
internal ushort OriginalNetworkId { get; set; } | |||
internal byte ServiceNameLenth { get; set; } | |||
/// <summary> | |||
/// | |||
/// 1Byte | |||
/// ServiceNameLenth | |||
/// </summary> | |||
internal byte ReservedFutureUse2 { get; set; } | |||
public List<TS_PAT_Program> Services { get; set; } | |||
/// <summary> | |||
/// 前面数据的CRC32校验码 | |||
/// </summary> | |||
public uint CRC32 { get; set; } | |||
internal string ServiceName { get; set; } | |||
public void ToBuffer(ref TSMessagePackWriter writer) | |||
{ | |||
Header.PackageType = PackageType.PAT; | |||
Header.ToBuffer(ref writer); | |||
writer.WriteByte(TableId); | |||
//SectionSyntaxIndicator Zero Reserved1 SectionLength | |||
//1 0 11 0000 0000 0000 | |||
//(ushort)(0b_1011_0000_0000_0000 | SectionLength) | |||
writer.Skip(2, out int SectionLengthPosition); | |||
writer.WriteUInt16(TransportStreamId); | |||
//Reserved2 VersionNumber CurrentNextIndicator | |||
//11 00000 1 | |||
var a = 0xC0 & (Reserved2 << 6); | |||
var b = 0x3E & (VersionNumber << 3); | |||
var c = (byte)(a | b | CurrentNextIndicator); | |||
writer.WriteByte(c); | |||
writer.WriteByte(SectionNumber); | |||
writer.WriteByte(LastSectionNumber); | |||
//if (Programs != null) | |||
//{ | |||
// foreach (var program in Programs) | |||
// { | |||
// program.ToBuffer(ref writer); | |||
// } | |||
//} | |||
const int crcLength= 4; | |||
writer.WriteUInt16Return((ushort)(0b_1011_0000_0000_0000 | (ushort)(writer.GetCurrentPosition() - SectionLengthPosition - 2)+ crcLength), SectionLengthPosition); | |||
//打包ts流时PAT和PMT表是没有adaptation field的,不够的长度直接补0xff即可。 | |||
//ts header(4B) + adaptation field length(1) | |||
writer.WriteCRC32(5); | |||
var size = TSConstants.FiexdPackageLength - writer.GetCurrentPosition(); | |||
writer.WriteArray(Enumerable.Range(0, size).Select(s => (byte)0xFF).ToArray()); | |||
writer.WriteByte(DescriptorTag); | |||
writer.Skip(1,out var position); | |||
writer.WriteByte(ServiceType); | |||
writer.Skip(1, out var serviceProviderLengthPosition); | |||
writer.WriteString(ServiceProvider); | |||
writer.WriteByteReturn((byte)(writer.GetCurrentPosition() - serviceProviderLengthPosition), serviceProviderLengthPosition); | |||
writer.Skip(1, out int SeviceNameLengthPosition); | |||
writer.WriteString(ServiceName); | |||
writer.WriteByteReturn((byte)(writer.GetCurrentPosition() - SeviceNameLengthPosition), SeviceNameLengthPosition); | |||
writer.WriteByteReturn((byte)(writer.GetCurrentPosition() - position), position); | |||
} | |||
} | |||
} |