@@ -15,6 +15,47 @@ namespace JT1078.Hls.Test | |||||
[Fact] | [Fact] | ||||
public void ToBufferTest() | public void ToBufferTest() | ||||
{ | { | ||||
TS_SDT_Package package = new TS_SDT_Package(); | |||||
package.Header = new TS_Header(); | |||||
package.Header.PID = 0x0011; | |||||
package.Header.AdaptationFieldControl = AdaptationFieldControl.无自适应域_仅含有效负载; | |||||
package.Header.ContinuityCounter = 0; | |||||
package.TableId = 0x42; | |||||
package.TransportStreamId = 0x0001; | |||||
package.VersionNumber = 0; | |||||
package.CurrentNextIndicator = 0x01; | |||||
package.SectionNumber = 0x00; | |||||
package.LastSectionNumber = 0x00; | |||||
package.OriginalNetworkId = 0xFF01; | |||||
package.Services = new List<TS_SDT_Service>(); | |||||
package.Services.Add(new TS_SDT_Service() | |||||
{ | |||||
ServiceId = 0x0001, | |||||
EITScheduleFlag = 0x00, | |||||
EITPresentFollowingFlag = 0x00, | |||||
RunningStatus = TS_SDT_Service_RunningStatus.运行, | |||||
FreeCAMode = 0x00, | |||||
Descriptors = new List<Descriptors.TS_SDT_Service_Descriptor> { | |||||
new Descriptors.TS_SDT_Service_Descriptor{ | |||||
DescriptorTag=0x48, | |||||
ServiceType= TS_SDT_Service_Descriptor_ServiceType.数字电视业务, | |||||
ServiceProvider="FFmpeg", | |||||
ServiceName="Service01" | |||||
} | |||||
} | |||||
}) ; | |||||
TSMessagePackWriter writer = new TSMessagePackWriter(new byte[188]); | |||||
package.ToBuffer(ref writer); | |||||
var patData = writer.FlushAndGetArray().ToHexString(); | |||||
Assert.Equal("47 40 11 10 00 42 F0 25 00 01 C1 00 00 FF 01 FF 00 01 FC 80 14 48 12 01 06 46 46 6D 70 65 67 09 53 65 72 76 69 63 65 30 31 77 7C 43 CA FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF".Replace(" ", ""), patData); | |||||
} | |||||
[Fact] | |||||
public void Test() { | |||||
byte a = 0x01; | |||||
var b = (ushort)(a << 15); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -6,7 +6,7 @@ using System.Collections.Generic; | |||||
using System.Linq; | using System.Linq; | ||||
using System.Text; | using System.Text; | ||||
namespace JT1078.Hls | |||||
namespace JT1078.Hls.Descriptors | |||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// 业务描述服务描述 | /// 业务描述服务描述 | ||||
@@ -14,7 +14,7 @@ namespace JT1078.Hls | |||||
public class TS_SDT_Service_Descriptor : ITSMessagePackFormatter | public class TS_SDT_Service_Descriptor : ITSMessagePackFormatter | ||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// | |||||
/// 业务描述符 | |||||
/// 8bit | /// 8bit | ||||
/// </summary> | /// </summary> | ||||
public byte DescriptorTag { get; set; } = 0x48; | public byte DescriptorTag { get; set; } = 0x48; | ||||
@@ -22,12 +22,12 @@ namespace JT1078.Hls | |||||
/// | /// | ||||
/// 8bit | /// 8bit | ||||
/// </summary> | /// </summary> | ||||
internal byte DescriptorLength { get; set; } = 0x12; | |||||
internal byte DescriptorLength { get; set; } | |||||
/// <summary> | /// <summary> | ||||
/// | /// | ||||
/// 8bit | /// 8bit | ||||
/// </summary> | /// </summary> | ||||
internal byte ServiceType { get; set; } = 0x01; | |||||
internal TS_SDT_Service_Descriptor_ServiceType ServiceType { get; set; } = TS_SDT_Service_Descriptor_ServiceType.数字电视业务; | |||||
/// <summary> | /// <summary> | ||||
/// | /// | ||||
/// 8bit | /// 8bit | ||||
@@ -52,14 +52,14 @@ namespace JT1078.Hls | |||||
{ | { | ||||
writer.WriteByte(DescriptorTag); | writer.WriteByte(DescriptorTag); | ||||
writer.Skip(1,out var position); | writer.Skip(1,out var position); | ||||
writer.WriteByte(ServiceType); | |||||
writer.WriteByte((byte)ServiceType); | |||||
writer.Skip(1, out var serviceProviderLengthPosition); | writer.Skip(1, out var serviceProviderLengthPosition); | ||||
writer.WriteString(ServiceProvider); | writer.WriteString(ServiceProvider); | ||||
writer.WriteByteReturn((byte)(writer.GetCurrentPosition() - serviceProviderLengthPosition), serviceProviderLengthPosition); | |||||
writer.WriteByteReturn((byte)(writer.GetCurrentPosition() - serviceProviderLengthPosition-1), serviceProviderLengthPosition); | |||||
writer.Skip(1, out int SeviceNameLengthPosition); | writer.Skip(1, out int SeviceNameLengthPosition); | ||||
writer.WriteString(ServiceName); | writer.WriteString(ServiceName); | ||||
writer.WriteByteReturn((byte)(writer.GetCurrentPosition() - SeviceNameLengthPosition), SeviceNameLengthPosition); | |||||
writer.WriteByteReturn((byte)(writer.GetCurrentPosition() - position), position); | |||||
writer.WriteByteReturn((byte)(writer.GetCurrentPosition() - SeviceNameLengthPosition-1), SeviceNameLengthPosition); | |||||
writer.WriteByteReturn((byte)(writer.GetCurrentPosition() - position-1), position); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -11,5 +11,6 @@ namespace JT1078.Hls.Enums | |||||
Data_Start=3, | Data_Start=3, | ||||
Data_Segment = 4, | Data_Segment = 4, | ||||
Data_End = 5, | Data_End = 5, | ||||
SDT=6 | |||||
} | } | ||||
} | } |
@@ -0,0 +1,26 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace JT1078.Hls.Enums | |||||
{ | |||||
/// <summary> | |||||
/// 服务描述类型 | |||||
/// </summary> | |||||
public enum TS_SDT_Service_Descriptor_ServiceType:byte | |||||
{ | |||||
保留以后使用=0x00, | |||||
数字电视业务 = 0x01, | |||||
数字无线声音业务 = 0x02, | |||||
图文电视业务 = 0x03, | |||||
NVOD参考业务 = 0x04, | |||||
NVOD时间平移业务 = 0x05, | |||||
镶嵌业务 = 0x06, | |||||
PAL编码信号 = 0x07, | |||||
SECAM编码信号 = 0x08, | |||||
D_D2_MAC = 0x09, | |||||
FM无线 = 0x0A, | |||||
NTSC编码信号 = 0x0B, | |||||
数据广播业务 = 0x0C, | |||||
} | |||||
} |
@@ -7,7 +7,7 @@ namespace JT1078.Hls.Enums | |||||
/// <summary> | /// <summary> | ||||
/// 运行状态 | /// 运行状态 | ||||
/// </summary> | /// </summary> | ||||
public enum RunningStatus | |||||
public enum TS_SDT_Service_RunningStatus | |||||
{ | { | ||||
未定义=0, | 未定义=0, | ||||
未运行=1, | 未运行=1, |
@@ -32,7 +32,7 @@ namespace JT1078.Hls | |||||
/// pid值 | /// pid值 | ||||
/// 13bit | /// 13bit | ||||
/// </summary> | /// </summary> | ||||
public ushort PID { get; set; } | |||||
public ushort PID { get; set; } = 0x0011; | |||||
/// <summary> | /// <summary> | ||||
/// 传输加扰控制 | /// 传输加扰控制 | ||||
/// 2bit | /// 2bit | ||||
@@ -69,7 +69,8 @@ namespace JT1078.Hls | |||||
if(PackageType== PackageType.PAT || | if(PackageType== PackageType.PAT || | ||||
PackageType == PackageType.PMT || | PackageType == PackageType.PMT || | ||||
PackageType == PackageType.Data_Start || | PackageType == PackageType.Data_Start || | ||||
PackageType == PackageType.Data_End) | |||||
PackageType == PackageType.Data_End || | |||||
PackageType == PackageType.SDT) | |||||
{ | { | ||||
if (Adaptation != null) | if (Adaptation != null) | ||||
{ | { | ||||
@@ -16,70 +16,81 @@ namespace JT1078.Hls | |||||
{ | { | ||||
public TS_Header Header { get; set; } | public TS_Header Header { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// | |||||
/// 表标识符 | |||||
/// 可以是0x42,表示描述的是当前流的信息,也可以是0x46,表示是其他流的信息 | |||||
/// 8bit | /// 8bit | ||||
/// </summary> | /// </summary> | ||||
public byte TableId { get; set; } = 0x42; | public byte TableId { get; set; } = 0x42; | ||||
/// <summary> | /// <summary> | ||||
/// | |||||
/// 段语法指示符 | |||||
/// 1bit | /// 1bit | ||||
/// </summary> | /// </summary> | ||||
internal byte SectionSyntaxIndicator { get; set; } | |||||
internal byte SectionSyntaxIndicator { get; set; } = 0x01; | |||||
/// <summary> | /// <summary> | ||||
/// | |||||
/// 保留未来使用 | |||||
/// 1bit | /// 1bit | ||||
/// </summary> | /// </summary> | ||||
internal byte ReservedFutureUse1 { get; set; } | |||||
internal byte ReservedFutureUse1 { get; set; } = 0x01; | |||||
/// <summary> | /// <summary> | ||||
/// | |||||
/// 保留位,防止控制字冲突,一般是''0'',也有可能是''1'' | |||||
/// 2bit | /// 2bit | ||||
/// </summary> | /// </summary> | ||||
internal byte Reserved1 { get; set; } | |||||
internal byte Reserved1 { get; set; } = 0x03; | |||||
/// <summary> | /// <summary> | ||||
/// 后面数据的长度 | |||||
/// 段长度 从transport_stream_id开始,到CRC_32结束(包含) | |||||
/// 12bit | /// 12bit | ||||
/// </summary> | /// </summary> | ||||
public ushort SectionLength { get; set; } | public ushort SectionLength { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// 传输流ID | |||||
/// 传输流标识符 | |||||
/// 同 PAT表中的 TransportStreamId 和PMT表中 ProgramNumber | |||||
/// 16bit | /// 16bit | ||||
/// </summary> | /// </summary> | ||||
internal ushort TransportStreamId { get; set; } | |||||
internal ushort TransportStreamId { get; set; } | |||||
/// <summary> | /// <summary> | ||||
/// | |||||
/// 保留位 | |||||
/// 2bit | /// 2bit | ||||
/// </summary> | /// </summary> | ||||
internal byte Reserved2 { get; set; } | |||||
internal byte Reserved2 { get; set; }= 0x03; | |||||
/// <summary> | /// <summary> | ||||
/// | |||||
/// 版本号 | |||||
/// 标识子表的版本号。当子表包含的信息发生变化时, version_number 加 1。当值增至 31 时,复位为 0。 | |||||
/// 当 current_next_indicator 置“1”时,则 version_number 为当前使用的子表的版本号。 | |||||
/// 当 current_next_indicator 置“0”时,则 version_number 为下一个使用的子表的版本号。 | |||||
/// 5bit | /// 5bit | ||||
/// </summary> | /// </summary> | ||||
public byte VersionNumber { get; set; } | |||||
public byte VersionNumber { get; set; } = 0x00; | |||||
/// <summary> | /// <summary> | ||||
/// | |||||
/// 当前后续指示符 | |||||
/// 当被置“1”时,表示当前子表 正被使用。 | |||||
/// 当其置“0”时,表示所传子表尚未被使用,它是下一个将被使用的子表。 | |||||
/// 1bit | /// 1bit | ||||
/// </summary> | /// </summary> | ||||
public byte CurrentNextIndicator { get; set; } | |||||
public byte CurrentNextIndicator { get; set; } = 0x00; | |||||
/// <summary> | /// <summary> | ||||
/// | |||||
/// 段号 | |||||
/// 子表中的第一个段的 section_number 标 为 “ 0x00 ”。 | |||||
/// 每增加一个具有相同的 table_id 、 transport_stream_id 和original_network_id 的段,section_number 就加 1。 | |||||
/// bit8 | /// bit8 | ||||
/// </summary> | /// </summary> | ||||
internal byte SectionNumber { get; set; } | |||||
internal byte SectionNumber { get; set; }=0x00; | |||||
/// <summary> | /// <summary> | ||||
/// | |||||
/// 最后段号 | |||||
/// 表示所属的子表的最后一个段(即段号最大的段)的段号。 | |||||
/// bit8 | /// bit8 | ||||
/// </summary> | /// </summary> | ||||
internal byte LastSectionNumber { get; set; } | |||||
internal byte LastSectionNumber { get; set; } = 0x00; | |||||
/// <summary> | /// <summary> | ||||
/// | |||||
/// bit8 | |||||
/// 原始网络标识符 | |||||
/// 原始传输系统的 network_id | |||||
/// bit16 | |||||
/// </summary> | /// </summary> | ||||
internal ushort OriginalNetworkId { get; set; } | |||||
internal ushort OriginalNetworkId { get; set; } | |||||
/// <summary> | /// <summary> | ||||
/// | |||||
/// 1Byte | |||||
/// 保留未来使用位 | |||||
/// bit8 | |||||
/// </summary> | /// </summary> | ||||
internal byte ReservedFutureUse2 { get; set; } | |||||
internal byte ReservedFutureUse2 { get; set; } = 0xFF; | |||||
public List<TS_SDT_Service> Services { get; set; } | public List<TS_SDT_Service> Services { get; set; } | ||||
/// <summary> | /// <summary> | ||||
@@ -89,6 +100,8 @@ namespace JT1078.Hls | |||||
public void ToBuffer(ref TSMessagePackWriter writer) | public void ToBuffer(ref TSMessagePackWriter writer) | ||||
{ | { | ||||
Header.PackageType = PackageType.SDT; | |||||
Header.ToBuffer(ref writer); | |||||
writer.WriteByte(TableId); | writer.WriteByte(TableId); | ||||
writer.Skip(2, out int SectionLengthPosition); | writer.Skip(2, out int SectionLengthPosition); | ||||
writer.WriteUInt16(TransportStreamId); | writer.WriteUInt16(TransportStreamId); | ||||
@@ -101,9 +114,9 @@ namespace JT1078.Hls | |||||
{ | { | ||||
service.ToBuffer(ref writer); | service.ToBuffer(ref writer); | ||||
} | } | ||||
ushort servicesLength =(ushort)( writer.GetCurrentPosition() - SectionLengthPosition); | |||||
ushort servicesLength =(ushort)( writer.GetCurrentPosition() - SectionLengthPosition-2); | |||||
const int crcLength = 4; | const int crcLength = 4; | ||||
writer.WriteUInt16Return((ushort)(SectionSyntaxIndicator<<15 | ReservedFutureUse1<<14 | servicesLength+ crcLength), SectionLengthPosition); | |||||
writer.WriteUInt16Return((ushort)(SectionSyntaxIndicator<<15 | ReservedFutureUse1<<14| Reserved1<<12 | servicesLength+ crcLength), SectionLengthPosition); | |||||
writer.WriteCRC32(5); | writer.WriteCRC32(5); | ||||
var size = TSConstants.FiexdPackageLength - writer.GetCurrentPosition(); | var size = TSConstants.FiexdPackageLength - writer.GetCurrentPosition(); | ||||
writer.WriteArray(Enumerable.Range(0, size).Select(s => (byte)0xFF).ToArray()); | writer.WriteArray(Enumerable.Range(0, size).Select(s => (byte)0xFF).ToArray()); | ||||
@@ -1,4 +1,5 @@ | |||||
using JT1078.Hls.Enums; | |||||
using JT1078.Hls.Descriptors; | |||||
using JT1078.Hls.Enums; | |||||
using JT1078.Hls.Interfaces; | using JT1078.Hls.Interfaces; | ||||
using JT1078.Hls.MessagePack; | using JT1078.Hls.MessagePack; | ||||
using System; | using System; | ||||
@@ -20,37 +21,37 @@ namespace JT1078.Hls | |||||
/// </summary> | /// </summary> | ||||
internal ushort ServiceId { get; set; } | internal ushort ServiceId { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// | |||||
/// 保留将来使用 | |||||
/// 6bit | /// 6bit | ||||
/// </summary> | /// </summary> | ||||
internal byte ReservedFutureUse { get; set; } | |||||
internal byte ReservedFutureUse { get; set; } = 0x3F; | |||||
/// <summary> | /// <summary> | ||||
/// EIT 时间表标志 | /// EIT 时间表标志 | ||||
/// 置“1”时,表示业务的 EIT 时间表信息存在于当前 TS 中(一个 EIT 时间表子表两次出现的最大时间间隔信息见 ETR 211)。 | /// 置“1”时,表示业务的 EIT 时间表信息存在于当前 TS 中(一个 EIT 时间表子表两次出现的最大时间间隔信息见 ETR 211)。 | ||||
/// 置“0”时,表示业务的 EIT 时间表信息不在当前 TS 中 | /// 置“0”时,表示业务的 EIT 时间表信息不在当前 TS 中 | ||||
/// 1bit | /// 1bit | ||||
/// </summary> | /// </summary> | ||||
internal byte EITScheduleFlag { get; set; } | |||||
internal byte EITScheduleFlag { get; set; } = 0x00; | |||||
/// <summary> | /// <summary> | ||||
/// EIT 当前后续标志 | /// EIT 当前后续标志 | ||||
/// 置“1”时,表示业务的 EIT 当前后续信息存在于当前 TS 中(一个 EIT 当前后续子表两次出现的最大时间间隔信息见ETR 211) | /// 置“1”时,表示业务的 EIT 当前后续信息存在于当前 TS 中(一个 EIT 当前后续子表两次出现的最大时间间隔信息见ETR 211) | ||||
/// 置“0”时,表示业务的 EIT 当前后续信息不在当前 TS 中。 | /// 置“0”时,表示业务的 EIT 当前后续信息不在当前 TS 中。 | ||||
/// 1bit | /// 1bit | ||||
/// </summary> | /// </summary> | ||||
public byte EITPresentFollowingFlag { get; set; } | |||||
public byte EITPresentFollowingFlag { get; set; } = 0x00; | |||||
/// <summary> | /// <summary> | ||||
/// 运行状态 | /// 运行状态 | ||||
/// 对于一个 NVOD 业务,running_status 的值都置“0” | /// 对于一个 NVOD 业务,running_status 的值都置“0” | ||||
/// 3bit | /// 3bit | ||||
/// </summary> | /// </summary> | ||||
internal RunningStatus RunningStatus { get; set; } | |||||
internal TS_SDT_Service_RunningStatus RunningStatus { get; set; } | |||||
/// <summary> | /// <summary> | ||||
/// 自由条件接收模式 | /// 自由条件接收模式 | ||||
/// 置“0”时,表示业务的所有组件都未被加扰 | /// 置“0”时,表示业务的所有组件都未被加扰 | ||||
/// 置“1”时,表示一路或多路码流的接收由 CA 系统控制。 | /// 置“1”时,表示一路或多路码流的接收由 CA 系统控制。 | ||||
/// 1bit | /// 1bit | ||||
/// </summary> | /// </summary> | ||||
internal byte FreeCAMode { get; set; } | |||||
internal byte FreeCAMode { get; set; } = 0x00; | |||||
/// <summary> | /// <summary> | ||||
/// 描述符循环长度 | /// 描述符循环长度 | ||||
/// 指出从本字段的下一个字节开始的描述符的总字节长度。 | /// 指出从本字段的下一个字节开始的描述符的总字节长度。 | ||||
@@ -69,7 +70,7 @@ namespace JT1078.Hls | |||||
{ | { | ||||
descriptor.ToBuffer(ref writer); | descriptor.ToBuffer(ref writer); | ||||
} | } | ||||
DescriptorsLoopLength = (ushort)(writer.GetCurrentPosition() - position); | |||||
DescriptorsLoopLength = (ushort)(writer.GetCurrentPosition() - position-2); | |||||
writer.WriteUInt16Return((ushort)((ushort)RunningStatus << 13 | (ushort)FreeCAMode << 12 | DescriptorsLoopLength), position); | writer.WriteUInt16Return((ushort)((ushort)RunningStatus << 13 | (ushort)FreeCAMode << 12 | DescriptorsLoopLength), position); | ||||
} | } | ||||
} | } | ||||