From 23cffcda70bd36e6b0db8b1c417f44116af5d8b6 Mon Sep 17 00:00:00 2001 From: waterliu99 <qqcc2012game@163.com> Date: Tue, 19 May 2020 23:36:57 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84SDT=E5=8D=8F=E8=AE=AE?= =?UTF-8?q?=E5=8C=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/JT1078.Hls.Test/TS_SDT_Package_Test.cs | 20 +++ src/JT1078.Hls/Enums/RunningStatus.cs | 19 +++ src/JT1078.Hls/JT1078.Hls.csproj | 3 + .../MessagePack/TSMessagePackWriter.cs | 6 + src/JT1078.Hls/TSConstants.cs | 6 + src/JT1078.Hls/TS_SDT_Package.cs | 43 +++--- src/JT1078.Hls/TS_SDT_Service.cs | 76 +++++++++++ src/JT1078.Hls/TS_SDT_Service_.cs | 123 ------------------ src/JT1078.Hls/TS_SDT_Service_Descriptor.cs | 106 ++++----------- 9 files changed, 170 insertions(+), 232 deletions(-) create mode 100644 src/JT1078.Hls.Test/TS_SDT_Package_Test.cs create mode 100644 src/JT1078.Hls/Enums/RunningStatus.cs create mode 100644 src/JT1078.Hls/TS_SDT_Service.cs delete mode 100644 src/JT1078.Hls/TS_SDT_Service_.cs diff --git a/src/JT1078.Hls.Test/TS_SDT_Package_Test.cs b/src/JT1078.Hls.Test/TS_SDT_Package_Test.cs new file mode 100644 index 0000000..7348366 --- /dev/null +++ b/src/JT1078.Hls.Test/TS_SDT_Package_Test.cs @@ -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() + { + } + } +} diff --git a/src/JT1078.Hls/Enums/RunningStatus.cs b/src/JT1078.Hls/Enums/RunningStatus.cs new file mode 100644 index 0000000..92d06e4 --- /dev/null +++ b/src/JT1078.Hls/Enums/RunningStatus.cs @@ -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, + + } +} diff --git a/src/JT1078.Hls/JT1078.Hls.csproj b/src/JT1078.Hls/JT1078.Hls.csproj index 20792fa..0d097b9 100644 --- a/src/JT1078.Hls/JT1078.Hls.csproj +++ b/src/JT1078.Hls/JT1078.Hls.csproj @@ -33,4 +33,7 @@ <PackagePath></PackagePath> </None> </ItemGroup> + <ItemGroup> + <PackageReference Include="System.Text.Encoding.CodePages" Version="4.7.1" /> + </ItemGroup> </Project> diff --git a/src/JT1078.Hls/MessagePack/TSMessagePackWriter.cs b/src/JT1078.Hls/MessagePack/TSMessagePackWriter.cs index 4ae781f..08791c9 100644 --- a/src/JT1078.Hls/MessagePack/TSMessagePackWriter.cs +++ b/src/JT1078.Hls/MessagePack/TSMessagePackWriter.cs @@ -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); + } } } diff --git a/src/JT1078.Hls/TSConstants.cs b/src/JT1078.Hls/TSConstants.cs index 9f1fff9..78cd0a3 100644 --- a/src/JT1078.Hls/TSConstants.cs +++ b/src/JT1078.Hls/TSConstants.cs @@ -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> diff --git a/src/JT1078.Hls/TS_SDT_Package.cs b/src/JT1078.Hls/TS_SDT_Package.cs index 80cac8e..5610478 100644 --- a/src/JT1078.Hls/TS_SDT_Package.cs +++ b/src/JT1078.Hls/TS_SDT_Package.cs @@ -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()); diff --git a/src/JT1078.Hls/TS_SDT_Service.cs b/src/JT1078.Hls/TS_SDT_Service.cs new file mode 100644 index 0000000..50458cd --- /dev/null +++ b/src/JT1078.Hls/TS_SDT_Service.cs @@ -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); + } + } +} diff --git a/src/JT1078.Hls/TS_SDT_Service_.cs b/src/JT1078.Hls/TS_SDT_Service_.cs deleted file mode 100644 index e347080..0000000 --- a/src/JT1078.Hls/TS_SDT_Service_.cs +++ /dev/null @@ -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()); - } - } -} diff --git a/src/JT1078.Hls/TS_SDT_Service_Descriptor.cs b/src/JT1078.Hls/TS_SDT_Service_Descriptor.cs index 19e0406..0c501a4 100644 --- a/src/JT1078.Hls/TS_SDT_Service_Descriptor.cs +++ b/src/JT1078.Hls/TS_SDT_Service_Descriptor.cs @@ -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); } } }