diff --git a/doc/video/demo.264 b/doc/video/demo.264 new file mode 100644 index 0000000..e289d5e Binary files /dev/null and b/doc/video/demo.264 differ diff --git a/src/JT1078.Hls.Test/JT1078.Hls.Test.csproj b/src/JT1078.Hls.Test/JT1078.Hls.Test.csproj index ed587fa..09ae7e2 100644 --- a/src/JT1078.Hls.Test/JT1078.Hls.Test.csproj +++ b/src/JT1078.Hls.Test/JT1078.Hls.Test.csproj @@ -17,4 +17,10 @@ + + + Always + + + diff --git a/src/JT1078.Hls.Test/TS_PAT_Package_Test.cs b/src/JT1078.Hls.Test/TS_PAT_Package_Test.cs new file mode 100644 index 0000000..6745d86 --- /dev/null +++ b/src/JT1078.Hls.Test/TS_PAT_Package_Test.cs @@ -0,0 +1,53 @@ +using JT1078.Hls.Enums; +using JT1078.Hls.MessagePack; +using JT1078.Protocol.Extensions; +using System; +using System.Collections.Generic; +using Xunit; + +namespace JT1078.Hls.Test +{ + /// + /// ʹdemo0.ts + /// + public class TS_PAT_Package_Test + { + [Fact] + public void ToBufferTest() + { + //47 40 00 10 00 00 B0 0D 00 01 C1 00 00 00 01 F0 00 2A B1 04 B2 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 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF + //----------PAT + //47 + //40 00 + //10 + //00 + //00 + //B0 0D + //00 01 + //C1 + //00 + //00 + //00 01 + //F0 00 + //2A B1 04 B2 + TS_PAT_Package package = new TS_PAT_Package(); + package.Header = new TS_Header(); + package.Header.PID = 0; + package.Header.AdaptationFieldControl = AdaptationFieldControl.Ӧ_Ч; + package.Header.ContinuityCounter = 0; + package.TableId = 0; + package.TransportStreamId = 0x0001; + package.VersionNumber = 0; + package.Programs = new List(); + package.Programs.Add(new TS_PAT_Program() + { + ProgramNumber = 0x0001, + PID = 0x1000, + }); + TSMessagePackWriter writer = new TSMessagePackWriter(new byte[188]); + package.ToBuffer(ref writer); + var patData=writer.FlushAndGetArray().ToHexString(); + Assert.Equal("47 40 00 10 00 00 B0 0D 00 01 C1 00 00 00 01 F0 00 2A B1 04 B2 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 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); + } + } +} diff --git a/src/JT1078.Hls.Test/TS_PMT_Package_Test.cs b/src/JT1078.Hls.Test/TS_PMT_Package_Test.cs new file mode 100644 index 0000000..ee00d04 --- /dev/null +++ b/src/JT1078.Hls.Test/TS_PMT_Package_Test.cs @@ -0,0 +1,80 @@ +using JT1078.Hls.Descriptors; +using JT1078.Hls.Enums; +using JT1078.Hls.MessagePack; +using JT1078.Protocol.Extensions; +using System; +using System.Collections.Generic; +using Xunit; +using System.Buffers.Binary; + +namespace JT1078.Hls.Test +{ + /// + /// 使用demo0.ts + /// + public class TS_PMT_Package_Test + { + [Fact] + public void ToBufferTest() + { + //47 50 00 10 00 02 B0 1D 00 01 C1 00 00 E1 00 F0 00 1B E1 00 F0 00 0F E1 01 F0 06 0A 04 75 6E 64 00 08 7D E8 77 + //47 + //50 00 + //10 + //00 + //02 + //B0 1D + //00 01 + //C1 + //00 + //00 + //E1 00 + //F0 00 + //1B + //E1 00 + // F0 00 + //0F + //E1 01 + // F0 06 + // 0A + // 04 + // 75 6E 64 00 + //08 7D E8 77 + TS_PMT_Package package = new TS_PMT_Package(); + package.Header = new TS_Header(); + package.Header.PID = 4096; + package.Header.AdaptationFieldControl = AdaptationFieldControl.无自适应域_仅含有效负载; + package.Header.PayloadUnitStartIndicator = 1; + package.Header.ContinuityCounter = 0; + package.TableId = 0x02; + package.ProgramNumber = 0x0001; + package.PCR_PID = 256; + package.Components = new List(); + package.Components.Add(new TS_PMT_Component() + { + StreamType= StreamType.h264, + ElementaryPID= 256, + }); + package.Components.Add(new TS_PMT_Component() + { + StreamType = StreamType.aac, + ElementaryPID = 257, + Descriptor=new ISO_639_Language_Descriptor + { + ISO_639_Language_Infos=new List() + { + new ISO_639_Language_Descriptor.ISO_639_Language_Info + { + Audio_Type=0, + ISO_639_Language_Code=BinaryPrimitives.ReadUInt32BigEndian(new byte[]{ 0x75, 0x6E, 0x64, 0x00}) + } + } + } + }); + TSMessagePackWriter writer = new TSMessagePackWriter(new byte[188]); + package.ToBuffer(ref writer); + var pmtData = writer.FlushAndGetArray().ToHexString(); + Assert.Equal("47 50 00 10 00 02 B0 1D 00 01 C1 00 00 E1 00 F0 00 1B E1 00 F0 00 0F E1 01 F0 06 0A 04 75 6E 64 00 08 7D E8 77 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 FF FF FF FF FF FF FF FF ".Replace(" ",""), pmtData); + } + } +} diff --git a/src/JT1078.Hls.Test/TS_Package_Test.cs b/src/JT1078.Hls.Test/TS_Package_Test.cs new file mode 100644 index 0000000..af46635 --- /dev/null +++ b/src/JT1078.Hls.Test/TS_Package_Test.cs @@ -0,0 +1,31 @@ +using JT1078.Hls.Descriptors; +using JT1078.Hls.Enums; +using JT1078.Hls.MessagePack; +using JT1078.Protocol.Extensions; +using System; +using System.Buffers.Binary; +using System.Collections.Generic; +using Xunit; + +namespace JT1078.Hls.Test +{ + /// + /// 使用demo0.ts + /// + public class TS_Package_Test + { + [Fact] + public void ToBufferTest() + { + TS_Package package = new TS_Package(); + package.Header = new TS_Header(); + package.Header.PID = 4096; + package.Header.AdaptationFieldControl = AdaptationFieldControl.无自适应域_仅含有效负载; + package.Header.PayloadUnitStartIndicator = 1; + package.Header.ContinuityCounter = 0; + TSMessagePackWriter writer = new TSMessagePackWriter(new byte[188]); + package.ToBuffer(ref writer); + var psData = writer.FlushAndGetArray().ToHexString(); + } + } +} diff --git a/src/JT1078.Hls.Test/UnitTest1.cs b/src/JT1078.Hls.Test/UnitTest1.cs deleted file mode 100644 index 7f9854e..0000000 --- a/src/JT1078.Hls.Test/UnitTest1.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using Xunit; - -namespace JT1078.Hls.Test -{ - public class UnitTest1 - { - [Fact] - public void Test1() - { - - } - //---------PMT - //47 50 00 10 00 02 B0 1D 00 01 C1 00 00 E1 00 F0 00 1B E1 00 F0 00 0F E1 01 F0 06 0A 04 75 6E 64 00 08 7D E8 77 - //47 - //50 00 - //10 - //00 - //02 - //B0 1D - //00 01 - //C1 - //00 - //00 - //E1 00 - //F0 00 - //1B - //E1 00 - // F0 00 - //0F - //E1 01 - // F0 06 - // 0A - // 04 75 - // 6E 64 - // 00 - //08 7D E8 77 - - //----------PAT - //47 40 00 10 00 00 B0 0D 00 01 C1 00 00 00 01 F0 00 2A B1 04 B2 - //47 - //40 00 - //10 - //00 - //00 - //B0 0D - //00 01 - //C1 - //00 - //00 - //00 01 - //F0 00 - //2A B1 04 B2 - } -} diff --git a/src/JT1078.Hls.Test/file/demo.264 b/src/JT1078.Hls.Test/file/demo.264 new file mode 100644 index 0000000..e289d5e Binary files /dev/null and b/src/JT1078.Hls.Test/file/demo.264 differ diff --git a/src/JT1078.Hls/Descriptors/DescriptorBase.cs b/src/JT1078.Hls/Descriptors/DescriptorBase.cs new file mode 100644 index 0000000..8d16331 --- /dev/null +++ b/src/JT1078.Hls/Descriptors/DescriptorBase.cs @@ -0,0 +1,15 @@ +using JT1078.Hls.Formatters; +using JT1078.Hls.MessagePack; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT1078.Hls.Descriptors +{ + public abstract class DescriptorBase : ITSMessagePackFormatter + { + public abstract byte Tag { get; set; } + public abstract byte Length { get; set; } + public abstract void ToBuffer(ref TSMessagePackWriter writer); + } +} diff --git a/src/JT1078.Hls/Descriptors/ISO_639_Language_Descriptor.cs b/src/JT1078.Hls/Descriptors/ISO_639_Language_Descriptor.cs new file mode 100644 index 0000000..34cceb7 --- /dev/null +++ b/src/JT1078.Hls/Descriptors/ISO_639_Language_Descriptor.cs @@ -0,0 +1,49 @@ +using JT1078.Hls.MessagePack; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT1078.Hls.Descriptors +{ + /// + /// 2.6.18 ISO 639 language descripto + /// + public class ISO_639_Language_Descriptor : DescriptorBase + { + public override byte Tag { get; set; } = 0x0A; + public override byte Length { get; set; } + + public List ISO_639_Language_Infos { get; set; } + + public override void ToBuffer(ref TSMessagePackWriter writer) + { + writer.WriteByte(Tag); + if (ISO_639_Language_Infos != null) + { + writer.Skip(1, out int DescriptorLengthPosition); + foreach(var item in ISO_639_Language_Infos) + { + writer.WriteUInt3(item.ISO_639_Language_Code>> 8); + writer.WriteByte(item.Audio_Type); + } + writer.WriteByteReturn((byte)(writer.GetCurrentPosition()- DescriptorLengthPosition-1), DescriptorLengthPosition); + } + else + { + writer.WriteByte(0); + } + } + + public class ISO_639_Language_Info + { + /// + /// 24bit + /// + public uint ISO_639_Language_Code { get; set; } + /// + /// 8bit + /// + public byte Audio_Type { get; set; } + } + } +} diff --git a/src/JT1078.Hls/ES_Package.cs b/src/JT1078.Hls/ES_Package.cs index 6059e68..900842b 100644 --- a/src/JT1078.Hls/ES_Package.cs +++ b/src/JT1078.Hls/ES_Package.cs @@ -1,6 +1,5 @@ using JT1078.Hls.Formatters; using JT1078.Hls.MessagePack; -using JT1078.Protocol.H264; using System; using System.Collections.Generic; using System.Text; @@ -11,7 +10,7 @@ namespace JT1078.Hls { public static byte[] NALU0X09 = new byte[] { 0x00, 0x00, 0x00, 0x01, 0x09, 0xFF }; public byte[] NALU0x09 { get; set; } = NALU0X09; - public List NALUs { get; set; } + public List NALUs { get; set; } public void ToBuffer(ref TSMessagePackWriter writer) { writer.WriteArray(NALU0x09); @@ -19,8 +18,7 @@ namespace JT1078.Hls { foreach(var nalu in NALUs) { - writer.WriteArray(nalu.StartCodePrefix); - writer.WriteArray(nalu.RawData); + writer.WriteArray(nalu); } } } diff --git a/src/JT1078.Hls/Enums/AdaptationFieldControl.cs b/src/JT1078.Hls/Enums/AdaptationFieldControl.cs index b549a57..1f56ea9 100644 --- a/src/JT1078.Hls/Enums/AdaptationFieldControl.cs +++ b/src/JT1078.Hls/Enums/AdaptationFieldControl.cs @@ -4,11 +4,11 @@ using System.Text; namespace JT1078.Hls.Enums { - public enum AdaptationFieldControl + public enum AdaptationFieldControl:byte { - 保留= 0000_0000, - 无自适应域_仅含有效负载 = 0001_0000, - 仅含自适应域_无有效负载 = 0010_0000, - 同时带有自适应域和有效负载 = 0011_0000, + 保留= 0b_0000_0000, + 无自适应域_仅含有效负载 = 0b_0001_0000, + 仅含自适应域_无有效负载 = 0b_0010_0000, + 同时带有自适应域和有效负载 = 0b_0011_0000, } } diff --git a/src/JT1078.Hls/Enums/PCRInclude.cs b/src/JT1078.Hls/Enums/PCRInclude.cs index dcc21a2..4950a27 100644 --- a/src/JT1078.Hls/Enums/PCRInclude.cs +++ b/src/JT1078.Hls/Enums/PCRInclude.cs @@ -6,6 +6,7 @@ namespace JT1078.Hls.Enums { /// /// 取0x50表示包含PCR或0x40表示不包含PCR + /// 注意:关键帧需要加pcr /// public enum PCRInclude:byte { diff --git a/src/JT1078.Hls/MessagePack/TSMessagePackWriter.cs b/src/JT1078.Hls/MessagePack/TSMessagePackWriter.cs index a4c3b54..4ae781f 100644 --- a/src/JT1078.Hls/MessagePack/TSMessagePackWriter.cs +++ b/src/JT1078.Hls/MessagePack/TSMessagePackWriter.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using System.Buffers.Binary; namespace JT1078.Hls.MessagePack @@ -127,9 +129,11 @@ namespace JT1078.Hls.MessagePack } var crcSpan = writer.Written.Slice(start); uint crc = 0xFFFFFFFF; + byte j = 0; for (int i = 0; i < crcSpan.Length; i++) { - crc = (crc << 8) ^ Util.crcTable[(crc >> 24) ^ crcSpan[i]]; + j = (byte)(((crc >> 24) ^ crcSpan[i]) & 0xff); + crc = (crc << 8) ^ Util.crcTable[j]; } WriteUInt32(crc); } diff --git a/src/JT1078.Hls/TSConstants.cs b/src/JT1078.Hls/TSConstants.cs new file mode 100644 index 0000000..9f1fff9 --- /dev/null +++ b/src/JT1078.Hls/TSConstants.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT1078.Hls +{ + public static class TSConstants + { + /// + /// 固定包长度 + /// + public const int FiexdPackageLength = 188; + + } +} diff --git a/src/JT1078.Hls/TS_AdaptationInfo.cs b/src/JT1078.Hls/TS_AdaptationInfo.cs index b80df07..b70918e 100644 --- a/src/JT1078.Hls/TS_AdaptationInfo.cs +++ b/src/JT1078.Hls/TS_AdaptationInfo.cs @@ -3,6 +3,7 @@ using JT1078.Hls.Formatters; using JT1078.Hls.MessagePack; using System; using System.Collections.Generic; +using System.Linq; using System.Text; namespace JT1078.Hls @@ -19,7 +20,10 @@ namespace JT1078.Hls /// 5B /// public long PCR { get; set; } - + /// + /// 填充字节大小 + /// + public byte FillSize { get; set; } public void ToBuffer(ref TSMessagePackWriter writer) { writer.WriteByte((byte)PCRIncluded); @@ -27,6 +31,10 @@ namespace JT1078.Hls { writer.WriteInt5(PCR); } + if (FillSize > 0) + { + writer.WriteArray(Enumerable.Range(0, FillSize).Select(s => (byte)0xFF).ToArray()); + } } } } diff --git a/src/JT1078.Hls/TS_Header.cs b/src/JT1078.Hls/TS_Header.cs index c2b015c..0f41ee7 100644 --- a/src/JT1078.Hls/TS_Header.cs +++ b/src/JT1078.Hls/TS_Header.cs @@ -34,7 +34,7 @@ namespace JT1078.Hls /// public ushort PID { get; set; } /// - /// 传输优先级,0为低优先级,1为高优先级,通常取0 + /// 传输加扰控制 /// 2bit /// internal byte TransportScramblingControl { get; set; } = 0; @@ -62,8 +62,8 @@ namespace JT1078.Hls writer.WriteByte(SyncByte); //TransportErrorIndicator PayloadUnitStartIndicator TransportPriority PID //0 1 0 0000 0000 0000 0 - writer.WriteUInt16((ushort)(0100_0000_0000_0000 | PID)); - writer.WriteByte((byte)((int)AdaptationFieldControl | ContinuityCounter)); + writer.WriteUInt16((ushort)(0b_0100_0000_0000_0000 | PID)); + writer.WriteByte((byte)((byte)AdaptationFieldControl | ContinuityCounter)); if (Adaptation != null) { writer.Skip(1, out int AdaptationLengthPosition); diff --git a/src/JT1078.Hls/TS_PAT_Package.cs b/src/JT1078.Hls/TS_PAT_Package.cs index 5844524..09e7e20 100644 --- a/src/JT1078.Hls/TS_PAT_Package.cs +++ b/src/JT1078.Hls/TS_PAT_Package.cs @@ -2,6 +2,7 @@ using JT1078.Hls.MessagePack; using System; using System.Collections.Generic; +using System.Linq; using System.Text; namespace JT1078.Hls @@ -11,6 +12,7 @@ namespace JT1078.Hls /// public class TS_PAT_Package : ITSMessagePackFormatter { + public TS_Header Header { get; set; } /// /// PAT表固定为0x00 /// 8bit @@ -76,18 +78,17 @@ namespace JT1078.Hls public void ToBuffer(ref TSMessagePackWriter writer) { + Header.ToBuffer(ref writer); writer.WriteByte(TableId); //SectionSyntaxIndicator Zero Reserved1 SectionLength //1 0 11 0000 0000 0000 - //(ushort)(1011_0000_0000_0000 | SectionLength) - // todo: - //writer.WriteUInt16((ushort)(1011_0000_0000_0000 | SectionLength)); + //(ushort)(0b_1011_0000_0000_0000 | SectionLength) writer.Skip(2, out int SectionLengthPosition); writer.WriteUInt16(TransportStreamId); //Reserved2 VersionNumber CurrentNextIndicator //11 00000 1 - var a = Reserved2 & 0xC0; - var b = VersionNumber & 0x3E; + var a = 0xC0 & (Reserved2 << 6); + var b = 0x3E & (VersionNumber << 3); var c = (byte)(a | b | CurrentNextIndicator); writer.WriteByte(c); writer.WriteByte(SectionNumber); @@ -99,8 +100,13 @@ namespace JT1078.Hls program.ToBuffer(ref writer); } } - writer.WriteUInt16Return((ushort)(1011_0000_0000_0000 | (ushort)(writer.GetCurrentPosition() - SectionLengthPosition - 2)), SectionLengthPosition); - writer.WriteCRC32(SectionLengthPosition); + 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_PAT_Program.cs b/src/JT1078.Hls/TS_PAT_Program.cs index a464fe8..0eb1856 100644 --- a/src/JT1078.Hls/TS_PAT_Program.cs +++ b/src/JT1078.Hls/TS_PAT_Program.cs @@ -15,7 +15,7 @@ namespace JT1078.Hls public ushort ProgramNumber { get; set; } /// /// 固定为二进制111(7) - /// 1110_0000_0000_0000 + /// 0b_1110_0000_0000_0000 /// 3bit /// internal byte Reserved1 { get; set; } = 0x07; @@ -28,7 +28,7 @@ namespace JT1078.Hls public void ToBuffer(ref TSMessagePackWriter writer) { writer.WriteUInt16(ProgramNumber); - writer.WriteUInt16((ushort)(1110_0000_0000_0000 | PID)); + writer.WriteUInt16((ushort)(0b_1110_0000_0000_0000 | PID)); } } } diff --git a/src/JT1078.Hls/TS_PMT_Component.cs b/src/JT1078.Hls/TS_PMT_Component.cs index 63af051..09fde58 100644 --- a/src/JT1078.Hls/TS_PMT_Component.cs +++ b/src/JT1078.Hls/TS_PMT_Component.cs @@ -1,4 +1,5 @@ -using JT1078.Hls.Enums; +using JT1078.Hls.Descriptors; +using JT1078.Hls.Enums; using JT1078.Hls.Formatters; using JT1078.Hls.MessagePack; using System; @@ -16,7 +17,7 @@ namespace JT1078.Hls public StreamType StreamType { get; set; } /// /// 固定为二进制111(7) - /// 0111_0000_0000_0000 + /// 0b_1110_0000_0000_0000 /// 3bit /// internal byte Reserved1 { get; set; } = 0x07; @@ -27,7 +28,7 @@ namespace JT1078.Hls public ushort ElementaryPID { get; set; } /// /// 固定为二进制1111(15) - /// 1111_0000_0000_0000 + /// 0b_1111_0000_0000_0000 /// 4bit /// internal byte Reserved2 { get; set; } = 0x0F; @@ -36,12 +37,22 @@ namespace JT1078.Hls /// 12bit /// internal ushort ESInfoLength { get; set; } = 0x000; - + public DescriptorBase Descriptor { get; set; } public void ToBuffer(ref TSMessagePackWriter writer) { writer.WriteByte((byte)StreamType); - writer.WriteUInt16((ushort)(0111_0000_0000_0000| ElementaryPID)); - writer.WriteUInt16((ushort)(1111_0000_0000_0000| ESInfoLength)); + writer.WriteUInt16((ushort)(0b_1110_0000_0000_0000 | ElementaryPID)); + if (Descriptor == null) + { + writer.WriteUInt16((ushort)(0b_1111_0000_0000_0000 | ESInfoLength)); + } + else + { + writer.Skip(2, out int ESInfoLengthPosition); + Descriptor.ToBuffer(ref writer); + ESInfoLength = (ushort)(writer.GetCurrentPosition() - ESInfoLengthPosition - 2); + writer.WriteUInt16Return((ushort)(0b_1111_0000_0000_0000 | ESInfoLength), ESInfoLengthPosition); + } } } } diff --git a/src/JT1078.Hls/TS_PMT_Package.cs b/src/JT1078.Hls/TS_PMT_Package.cs index 7cbae8c..bb5d601 100644 --- a/src/JT1078.Hls/TS_PMT_Package.cs +++ b/src/JT1078.Hls/TS_PMT_Package.cs @@ -2,6 +2,7 @@ using JT1078.Hls.MessagePack; using System; using System.Collections.Generic; +using System.Linq; using System.Text; namespace JT1078.Hls @@ -11,6 +12,7 @@ namespace JT1078.Hls /// public class TS_PMT_Package : ITSMessagePackFormatter { + public TS_Header Header { get; set; } /// /// PMT表取值随意 /// 8bit @@ -93,28 +95,27 @@ namespace JT1078.Hls public uint CRC32 { get; set; } public void ToBuffer(ref TSMessagePackWriter writer) { + Header.ToBuffer(ref writer); writer.WriteByte(TableId); //SectionSyntaxIndicator Zero Reserved1 SectionLength //1 0 11 0000 0000 0000 - //(ushort)(1011_0000_0000_0000 | SectionLength) - // todo: - //writer.WriteUInt16((ushort)(1011_0000_0000_0000 | SectionLength)); + //(ushort)(0b_1011_0000_0000_0000 | SectionLength) writer.Skip(2, out int SectionLengthPosition); writer.WriteUInt16(ProgramNumber); //Reserved2 VersionNumber CurrentNextIndicator //11 00000 1 - var a = Reserved2 & 0xC0; - var b = VersionNumber & 0x3E; - var c=(byte)(a | b | CurrentNextIndicator); + 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); //Reserved3 PCR_PID //111 0000 0000 0000 0 - writer.WriteUInt16((ushort)(0111_0000_0000_0000 | PCR_PID)); + writer.WriteUInt16((ushort)(0b_1110_0000_0000_0000 | PCR_PID)); //Reserved4 ProgramInfoLength //1111 0000 0000 0000 - writer.WriteUInt16((ushort)(1111_0000_0000_0000 | ProgramInfoLength)); + writer.WriteUInt16((ushort)(0b_1111_0000_0000_0000 | ProgramInfoLength)); if (Components != null) { foreach(var component in Components) @@ -122,8 +123,13 @@ namespace JT1078.Hls component.ToBuffer(ref writer); } } - writer.WriteUInt16Return((ushort)(1011_0000_0000_0000 | (ushort)(writer.GetCurrentPosition() - SectionLengthPosition - 2)), SectionLengthPosition); - writer.WriteCRC32(SectionLengthPosition); + 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_Package.cs b/src/JT1078.Hls/TS_Package.cs index 7675b44..8686aa9 100644 --- a/src/JT1078.Hls/TS_Package.cs +++ b/src/JT1078.Hls/TS_Package.cs @@ -1,17 +1,21 @@ -using JT1078.Protocol.H264; +using JT1078.Hls.Formatters; +using JT1078.Hls.MessagePack; +using JT1078.Protocol.H264; using System; using System.Collections.Generic; using System.Text; namespace JT1078.Hls { - public class TS_Package + public class TS_Package : ITSMessagePackFormatter { public TS_Header Header { get; set; } public PES_Package Payload { get; set; } - /// - /// 填充字节,取值0xff - /// - public byte[] Fill { get; set; } + + public void ToBuffer(ref TSMessagePackWriter writer) + { + Header.ToBuffer(ref writer); + Payload.ToBuffer(ref writer); + } } }