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);
         }
     }
 }