@@ -15,6 +15,47 @@ namespace JT1078.Hls.Test | |||
[Fact] | |||
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.Text; | |||
namespace JT1078.Hls | |||
namespace JT1078.Hls.Descriptors | |||
{ | |||
/// <summary> | |||
/// 业务描述服务描述 | |||
@@ -14,7 +14,7 @@ namespace JT1078.Hls | |||
public class TS_SDT_Service_Descriptor : ITSMessagePackFormatter | |||
{ | |||
/// <summary> | |||
/// | |||
/// 业务描述符 | |||
/// 8bit | |||
/// </summary> | |||
public byte DescriptorTag { get; set; } = 0x48; | |||
@@ -22,12 +22,12 @@ namespace JT1078.Hls | |||
/// | |||
/// 8bit | |||
/// </summary> | |||
internal byte DescriptorLength { get; set; } = 0x12; | |||
internal byte DescriptorLength { get; set; } | |||
/// <summary> | |||
/// | |||
/// 8bit | |||
/// </summary> | |||
internal byte ServiceType { get; set; } = 0x01; | |||
internal TS_SDT_Service_Descriptor_ServiceType ServiceType { get; set; } = TS_SDT_Service_Descriptor_ServiceType.数字电视业务; | |||
/// <summary> | |||
/// | |||
/// 8bit | |||
@@ -52,14 +52,14 @@ namespace JT1078.Hls | |||
{ | |||
writer.WriteByte(DescriptorTag); | |||
writer.Skip(1,out var position); | |||
writer.WriteByte(ServiceType); | |||
writer.WriteByte((byte)ServiceType); | |||
writer.Skip(1, out var serviceProviderLengthPosition); | |||
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.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_Segment = 4, | |||
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> | |||
public enum RunningStatus | |||
public enum TS_SDT_Service_RunningStatus | |||
{ | |||
未定义=0, | |||
未运行=1, |
@@ -32,7 +32,7 @@ namespace JT1078.Hls | |||
/// pid值 | |||
/// 13bit | |||
/// </summary> | |||
public ushort PID { get; set; } | |||
public ushort PID { get; set; } = 0x0011; | |||
/// <summary> | |||
/// 传输加扰控制 | |||
/// 2bit | |||
@@ -69,7 +69,8 @@ namespace JT1078.Hls | |||
if(PackageType== PackageType.PAT || | |||
PackageType == PackageType.PMT || | |||
PackageType == PackageType.Data_Start || | |||
PackageType == PackageType.Data_End) | |||
PackageType == PackageType.Data_End || | |||
PackageType == PackageType.SDT) | |||
{ | |||
if (Adaptation != null) | |||
{ | |||
@@ -16,70 +16,81 @@ namespace JT1078.Hls | |||
{ | |||
public TS_Header Header { get; set; } | |||
/// <summary> | |||
/// | |||
/// 表标识符 | |||
/// 可以是0x42,表示描述的是当前流的信息,也可以是0x46,表示是其他流的信息 | |||
/// 8bit | |||
/// </summary> | |||
public byte TableId { get; set; } = 0x42; | |||
/// <summary> | |||
/// | |||
/// 段语法指示符 | |||
/// 1bit | |||
/// </summary> | |||
internal byte SectionSyntaxIndicator { get; set; } | |||
internal byte SectionSyntaxIndicator { get; set; } = 0x01; | |||
/// <summary> | |||
/// | |||
/// 保留未来使用 | |||
/// 1bit | |||
/// </summary> | |||
internal byte ReservedFutureUse1 { get; set; } | |||
internal byte ReservedFutureUse1 { get; set; } = 0x01; | |||
/// <summary> | |||
/// | |||
/// 保留位,防止控制字冲突,一般是''0'',也有可能是''1'' | |||
/// 2bit | |||
/// </summary> | |||
internal byte Reserved1 { get; set; } | |||
internal byte Reserved1 { get; set; } = 0x03; | |||
/// <summary> | |||
/// 后面数据的长度 | |||
/// 段长度 从transport_stream_id开始,到CRC_32结束(包含) | |||
/// 12bit | |||
/// </summary> | |||
public ushort SectionLength { get; set; } | |||
/// <summary> | |||
/// 传输流ID | |||
/// 传输流标识符 | |||
/// 同 PAT表中的 TransportStreamId 和PMT表中 ProgramNumber | |||
/// 16bit | |||
/// </summary> | |||
internal ushort TransportStreamId { get; set; } | |||
internal ushort TransportStreamId { get; set; } | |||
/// <summary> | |||
/// | |||
/// 保留位 | |||
/// 2bit | |||
/// </summary> | |||
internal byte Reserved2 { get; set; } | |||
internal byte Reserved2 { get; set; }= 0x03; | |||
/// <summary> | |||
/// | |||
/// 版本号 | |||
/// 标识子表的版本号。当子表包含的信息发生变化时, version_number 加 1。当值增至 31 时,复位为 0。 | |||
/// 当 current_next_indicator 置“1”时,则 version_number 为当前使用的子表的版本号。 | |||
/// 当 current_next_indicator 置“0”时,则 version_number 为下一个使用的子表的版本号。 | |||
/// 5bit | |||
/// </summary> | |||
public byte VersionNumber { get; set; } | |||
public byte VersionNumber { get; set; } = 0x00; | |||
/// <summary> | |||
/// | |||
/// 当前后续指示符 | |||
/// 当被置“1”时,表示当前子表 正被使用。 | |||
/// 当其置“0”时,表示所传子表尚未被使用,它是下一个将被使用的子表。 | |||
/// 1bit | |||
/// </summary> | |||
public byte CurrentNextIndicator { get; set; } | |||
public byte CurrentNextIndicator { get; set; } = 0x00; | |||
/// <summary> | |||
/// | |||
/// 段号 | |||
/// 子表中的第一个段的 section_number 标 为 “ 0x00 ”。 | |||
/// 每增加一个具有相同的 table_id 、 transport_stream_id 和original_network_id 的段,section_number 就加 1。 | |||
/// bit8 | |||
/// </summary> | |||
internal byte SectionNumber { get; set; } | |||
internal byte SectionNumber { get; set; }=0x00; | |||
/// <summary> | |||
/// | |||
/// 最后段号 | |||
/// 表示所属的子表的最后一个段(即段号最大的段)的段号。 | |||
/// bit8 | |||
/// </summary> | |||
internal byte LastSectionNumber { get; set; } | |||
internal byte LastSectionNumber { get; set; } = 0x00; | |||
/// <summary> | |||
/// | |||
/// bit8 | |||
/// 原始网络标识符 | |||
/// 原始传输系统的 network_id | |||
/// bit16 | |||
/// </summary> | |||
internal ushort OriginalNetworkId { get; set; } | |||
internal ushort OriginalNetworkId { get; set; } | |||
/// <summary> | |||
/// | |||
/// 1Byte | |||
/// 保留未来使用位 | |||
/// bit8 | |||
/// </summary> | |||
internal byte ReservedFutureUse2 { get; set; } | |||
internal byte ReservedFutureUse2 { get; set; } = 0xFF; | |||
public List<TS_SDT_Service> Services { get; set; } | |||
/// <summary> | |||
@@ -89,6 +100,8 @@ namespace JT1078.Hls | |||
public void ToBuffer(ref TSMessagePackWriter writer) | |||
{ | |||
Header.PackageType = PackageType.SDT; | |||
Header.ToBuffer(ref writer); | |||
writer.WriteByte(TableId); | |||
writer.Skip(2, out int SectionLengthPosition); | |||
writer.WriteUInt16(TransportStreamId); | |||
@@ -101,9 +114,9 @@ namespace JT1078.Hls | |||
{ | |||
service.ToBuffer(ref writer); | |||
} | |||
ushort servicesLength =(ushort)( writer.GetCurrentPosition() - SectionLengthPosition); | |||
ushort servicesLength =(ushort)( writer.GetCurrentPosition() - SectionLengthPosition-2); | |||
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); | |||
var size = TSConstants.FiexdPackageLength - writer.GetCurrentPosition(); | |||
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.MessagePack; | |||
using System; | |||
@@ -20,37 +21,37 @@ namespace JT1078.Hls | |||
/// </summary> | |||
internal ushort ServiceId { get; set; } | |||
/// <summary> | |||
/// | |||
/// 保留将来使用 | |||
/// 6bit | |||
/// </summary> | |||
internal byte ReservedFutureUse { get; set; } | |||
internal byte ReservedFutureUse { get; set; } = 0x3F; | |||
/// <summary> | |||
/// EIT 时间表标志 | |||
/// 置“1”时,表示业务的 EIT 时间表信息存在于当前 TS 中(一个 EIT 时间表子表两次出现的最大时间间隔信息见 ETR 211)。 | |||
/// 置“0”时,表示业务的 EIT 时间表信息不在当前 TS 中 | |||
/// 1bit | |||
/// </summary> | |||
internal byte EITScheduleFlag { get; set; } | |||
internal byte EITScheduleFlag { get; set; } = 0x00; | |||
/// <summary> | |||
/// EIT 当前后续标志 | |||
/// 置“1”时,表示业务的 EIT 当前后续信息存在于当前 TS 中(一个 EIT 当前后续子表两次出现的最大时间间隔信息见ETR 211) | |||
/// 置“0”时,表示业务的 EIT 当前后续信息不在当前 TS 中。 | |||
/// 1bit | |||
/// </summary> | |||
public byte EITPresentFollowingFlag { get; set; } | |||
public byte EITPresentFollowingFlag { get; set; } = 0x00; | |||
/// <summary> | |||
/// 运行状态 | |||
/// 对于一个 NVOD 业务,running_status 的值都置“0” | |||
/// 3bit | |||
/// </summary> | |||
internal RunningStatus RunningStatus { get; set; } | |||
internal TS_SDT_Service_RunningStatus RunningStatus { get; set; } | |||
/// <summary> | |||
/// 自由条件接收模式 | |||
/// 置“0”时,表示业务的所有组件都未被加扰 | |||
/// 置“1”时,表示一路或多路码流的接收由 CA 系统控制。 | |||
/// 1bit | |||
/// </summary> | |||
internal byte FreeCAMode { get; set; } | |||
internal byte FreeCAMode { get; set; } = 0x00; | |||
/// <summary> | |||
/// 描述符循环长度 | |||
/// 指出从本字段的下一个字节开始的描述符的总字节长度。 | |||
@@ -69,7 +70,7 @@ namespace JT1078.Hls | |||
{ | |||
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); | |||
} | |||
} | |||