From c6c6b86c18319d4bc4af9a2a3d88212fc1ac9afe Mon Sep 17 00:00:00 2001 From: "SmallChi(Koike)" <564952747@qq.com> Date: Tue, 5 May 2020 21:49:19 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84PES=E5=8C=85=E7=9A=84?= =?UTF-8?q?=E7=BC=96=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/JT1078.Hls.Test/TS_Package_Test.cs | 14 +- src/JT1078.Hls/Descriptors/DescriptorBase.cs | 2 +- src/JT1078.Hls/ES_Package.cs | 2 +- .../Interfaces/ITSMessagePackFormatter.cs | 2 +- src/JT1078.Hls/PES_Package.cs | 4 +- src/JT1078.Hls/TSEncoder.cs | 246 ++++++++++++++++-- src/JT1078.Hls/TS_AdaptationInfo.cs | 3 +- src/JT1078.Hls/TS_Header.cs | 2 +- src/JT1078.Hls/TS_PAT_Package.cs | 2 +- src/JT1078.Hls/TS_PAT_Program.cs | 2 +- src/JT1078.Hls/TS_PMT_Component.cs | 2 +- src/JT1078.Hls/TS_PMT_Package.cs | 2 +- src/JT1078.Hls/TS_Package.cs | 2 +- src/JT1078.Hls/TS_Segment_Package.cs | 19 ++ 14 files changed, 258 insertions(+), 46 deletions(-) create mode 100644 src/JT1078.Hls/TS_Segment_Package.cs diff --git a/src/JT1078.Hls.Test/TS_Package_Test.cs b/src/JT1078.Hls.Test/TS_Package_Test.cs index af46635..cb24095 100644 --- a/src/JT1078.Hls.Test/TS_Package_Test.cs +++ b/src/JT1078.Hls.Test/TS_Package_Test.cs @@ -5,6 +5,8 @@ using JT1078.Protocol.Extensions; using System; using System.Buffers.Binary; using System.Collections.Generic; +using System.Security.Cryptography; +using System.Text; using Xunit; namespace JT1078.Hls.Test @@ -17,15 +19,7 @@ namespace JT1078.Hls.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/Descriptors/DescriptorBase.cs b/src/JT1078.Hls/Descriptors/DescriptorBase.cs index 8d16331..4bb4d85 100644 --- a/src/JT1078.Hls/Descriptors/DescriptorBase.cs +++ b/src/JT1078.Hls/Descriptors/DescriptorBase.cs @@ -1,4 +1,4 @@ -using JT1078.Hls.Formatters; +using JT1078.Hls.Interfaces; using JT1078.Hls.MessagePack; using System; using System.Collections.Generic; diff --git a/src/JT1078.Hls/ES_Package.cs b/src/JT1078.Hls/ES_Package.cs index 900842b..da47943 100644 --- a/src/JT1078.Hls/ES_Package.cs +++ b/src/JT1078.Hls/ES_Package.cs @@ -1,4 +1,4 @@ -using JT1078.Hls.Formatters; +using JT1078.Hls.Interfaces; using JT1078.Hls.MessagePack; using System; using System.Collections.Generic; diff --git a/src/JT1078.Hls/Interfaces/ITSMessagePackFormatter.cs b/src/JT1078.Hls/Interfaces/ITSMessagePackFormatter.cs index 2ad3854..2a6b4e7 100644 --- a/src/JT1078.Hls/Interfaces/ITSMessagePackFormatter.cs +++ b/src/JT1078.Hls/Interfaces/ITSMessagePackFormatter.cs @@ -1,7 +1,7 @@ using JT1078.Hls.MessagePack; using System; -namespace JT1078.Hls.Formatters +namespace JT1078.Hls.Interfaces { public interface ITSMessagePackFormatter { diff --git a/src/JT1078.Hls/PES_Package.cs b/src/JT1078.Hls/PES_Package.cs index a0f8468..e3facf3 100644 --- a/src/JT1078.Hls/PES_Package.cs +++ b/src/JT1078.Hls/PES_Package.cs @@ -1,5 +1,5 @@ using JT1078.Hls.Enums; -using JT1078.Hls.Formatters; +using JT1078.Hls.Interfaces; using JT1078.Hls.MessagePack; using System; using System.Collections.Generic; @@ -18,7 +18,7 @@ namespace JT1078.Hls /// 音频取值(0xc0-0xdf),通常为0xc0 /// 视频取值(0xe0-0xef),通常为0xe0 /// - public byte StreamId { get; set; } + public byte StreamId { get; set; } = 0xe0; /// /// 后面pes数据的长度,0表示长度不限制,只有视频数据长度会超过0xffff /// diff --git a/src/JT1078.Hls/TSEncoder.cs b/src/JT1078.Hls/TSEncoder.cs index f01b016..495f93b 100644 --- a/src/JT1078.Hls/TSEncoder.cs +++ b/src/JT1078.Hls/TSEncoder.cs @@ -7,46 +7,218 @@ using System.Linq; using System.Runtime.CompilerServices; using JT1078.Protocol; using JT1078.Hls.MessagePack; +using JT1078.Hls.Enums; +using System.Collections.Concurrent; +using System.Security.Cryptography; [assembly: InternalsVisibleTo("JT1078.Hls.Test")] namespace JT1078.Hls { + /// + /// 1.PAT + /// 2.PMT + /// 3.PES + /// public class TSEncoder { - readonly H264Decoder h264Decoder = new H264Decoder(); - - public byte[] Create(JT1078Package package, int minBufferSize = 65535) + private const int FiexdSegmentPESLength = 184; + private const int FiexdTSLength = 188; + private ConcurrentDictionary PATCounter = new ConcurrentDictionary(); + private ConcurrentDictionary PMTCounter = new ConcurrentDictionary(); + private ConcurrentDictionary VideoCounter = new ConcurrentDictionary(); + //private ConcurrentDictionary AudioCounter = new ConcurrentDictionary(); + public byte[] CreatePAT(JT1078Package jt1078Package, int minBufferSize = 188) { byte[] buffer = TSArrayPool.Rent(minBufferSize); try { - TS_Package tS_Package = new TS_Package(); - tS_Package.Header = new TS_Header(); - tS_Package.Header.PID = (ushort)package.GetKey().GetHashCode(); - tS_Package.Header.ContinuityCounter = (byte)package.SN; - tS_Package.Header.PayloadUnitStartIndicator = 1; - tS_Package.Header.Adaptation = new TS_AdaptationInfo(); - tS_Package.Payload = new PES_Package(); - + TS_PAT_Package package = new TS_PAT_Package(); + package.Header = new TS_Header(); + package.Header.ContinuityCounter = PATCounter.AddOrUpdate(jt1078Package.GetKey(), 0, (a, b) => + { + if (b > 0xf) + { + return 0; + } + else + { + return (byte)(b +1); + } + }); + package.Header.AdaptationFieldControl = AdaptationFieldControl.无自适应域_仅含有效负载; + package.Header.PayloadUnitStartIndicator = 1; + package.Header.PID = 0; TSMessagePackWriter messagePackReader = new TSMessagePackWriter(buffer); - var nalus = h264Decoder.ParseNALU(package); - if (nalus != null && nalus.Count > 0) - { - var sei = nalus.FirstOrDefault(x => x.NALUHeader.NalUnitType == 6); - var sps = nalus.FirstOrDefault(x => x.NALUHeader.NalUnitType == 7); - var pps = nalus.FirstOrDefault(x => x.NALUHeader.NalUnitType == 8); - nalus.Remove(sps); - nalus.Remove(pps); - nalus.Remove(sei); - - foreach (var naln in nalus) + package.ToBuffer(ref messagePackReader); + return messagePackReader.FlushAndGetArray(); + } + finally + { + TSArrayPool.Return(buffer); + } + } + public byte[] CreatePMT(JT1078Package jt1078Package, int minBufferSize = 188) + { + byte[] buffer = TSArrayPool.Rent(minBufferSize); + try + { + TS_PMT_Package package = new TS_PMT_Package(); + package.Header = new TS_Header(); + package.Header.ContinuityCounter = PMTCounter.AddOrUpdate(jt1078Package.GetKey(), 0, (a, b) => + { + if (b > 0xf) + { + return 0; + } + else + { + return (byte)(b + 1); + } + }); + package.Header.AdaptationFieldControl = AdaptationFieldControl.无自适应域_仅含有效负载; + package.Header.PayloadUnitStartIndicator = 1; + package.Header.PID = 4096; + package.TableId = 0x02; + package.Components = new List(); + package.Components.Add(new TS_PMT_Component + { + StreamType= StreamType.h264, + ElementaryPID = 256, + ESInfoLength=0 + }); + TSMessagePackWriter messagePackReader = new TSMessagePackWriter(buffer); + package.ToBuffer(ref messagePackReader); + return messagePackReader.FlushAndGetArray(); + } + finally + { + TSArrayPool.Return(buffer); + } + } + public byte[] CreatePES(JT1078Package jt1078Package, int minBufferSize = 188) + { + //将1078一帧的数据拆分成一小段一小段的PES包 + byte[] buffer = TSArrayPool.Rent(jt1078Package.Bodies.Length + minBufferSize); + TSMessagePackWriter messagePackReader = new TSMessagePackWriter(buffer); + //TSHeader + Adaptation + PES1 + //TSHeader + PES2 + //TSHeader + Adaptation + PESN + try + { + int totalLength = 0; + TS_Package package = new TS_Package(); + package.Header = new TS_Header(); + //ts header 4 + totalLength += 4; + package.Header.PID = 256; + string key = jt1078Package.GetKey(); + if (VideoCounter.TryGetValue(key, out byte counter)) + { + if (counter > 0xf) { - + counter = 0; } + package.Header.ContinuityCounter = counter++; + VideoCounter.TryUpdate(key, counter, counter); } + else + { + package.Header.ContinuityCounter = counter++; + VideoCounter.TryAdd(key, counter); + } + package.Header.PayloadUnitStartIndicator = 1; + package.Header.Adaptation = new TS_AdaptationInfo(); + package.Payload = new PES_Package(); + package.Payload.StreamId = 0xe0; + package.Payload.PESPacketLength = 0; + //PESStartCode + StreamId + PESPacketLength + //3 + 1 + 2 + totalLength += (3+1+2); + package.Payload.PTS_DTS_Flag = PTS_DTS_Flags.all; + if (jt1078Package.Label3.DataType== JT1078DataType.视频I帧) + { + //ts header adaptation + //PCRIncluded + PCR + //1 + 5 + totalLength += (1 + 5); + package.Header.Adaptation.PCRIncluded = PCRInclude.包含; + package.Header.Adaptation.PCR = jt1078Package.LastIFrameInterval; + package.Payload.DTS = jt1078Package.LastIFrameInterval; + package.Payload.PTS = jt1078Package.LastIFrameInterval; + } + else + { + //ts header adaptation + //PCRIncluded + //1 + totalLength += 1; + package.Header.Adaptation.PCRIncluded = PCRInclude.不包含; + package.Payload.DTS = jt1078Package.LastFrameInterval; + package.Payload.PTS = jt1078Package.LastFrameInterval; + } + //Flag1 + PTS_DTS_Flag + DTS + PTS + //1 + 1 + 5 + 5 + totalLength += 12; + //根据计算剩余的长度进行是否需要填充第一包 + var remainingLength = FiexdTSLength - totalLength; + int index = 0; + //情况1:1078的第一包不够剩余(remainingLength)字节 + //情况2:1078的第一包比剩余(remainingLength)字节多 + //情况3: 1078的第一包等于剩余(remainingLength)字节 + //填充大小 + int fullSize = jt1078Package.Bodies.Length - remainingLength; + package.Payload.Payload = new ES_Package(); + if (fullSize < 0) + { + //这个很重要,需要控制 + package.Header.AdaptationFieldControl = AdaptationFieldControl.同时带有自适应域和有效负载; + //还差一点 + fullSize = Math.Abs(fullSize); + package.Header.Adaptation.FillSize = (byte)fullSize; + package.Payload.Payload.NALUs = new List() { jt1078Package.Bodies }; + package.ToBuffer(ref messagePackReader); + } + else if(fullSize==0) + { + //这个很重要,需要控制 + package.Header.AdaptationFieldControl = AdaptationFieldControl.无自适应域_仅含有效负载; + //刚刚好 + package.Header.Adaptation.FillSize = 0; + package.Payload.Payload.NALUs = new List() { jt1078Package.Bodies }; + package.ToBuffer(ref messagePackReader); + } + else + { + //这个很重要,需要控制 + package.Header.AdaptationFieldControl = AdaptationFieldControl.同时带有自适应域和有效负载; + //太多了,需要拆分 + package.Header.Adaptation.FillSize = 0; + package.Payload.Payload.NALUs = new List(); + ReadOnlySpan dataReader = jt1078Package.Bodies; + package.Payload.Payload.NALUs.Add(dataReader.Slice(index, remainingLength).ToArray()); + index += remainingLength; + package.ToBuffer(ref messagePackReader); - + while(index!= jt1078Package.Bodies.Length) + { + if (counter > 0xf) + { + counter = 0; + } + int segmentFullSize = jt1078Package.Bodies.Length - index; + if(segmentFullSize >= FiexdSegmentPESLength) + { + CreateSegmentPES(ref messagePackReader, dataReader.Slice(index, FiexdSegmentPESLength).ToArray(), counter++); + } + else + { + CreateSegmentPES(ref messagePackReader, dataReader.Slice(index, segmentFullSize).ToArray(), counter++); + index += segmentFullSize; + } + } + VideoCounter.TryUpdate(key, counter, counter); + } return messagePackReader.FlushAndGetArray(); } finally @@ -54,5 +226,31 @@ namespace JT1078.Hls TSArrayPool.Return(buffer); } } + internal void CreateSegmentPES(ref TSMessagePackWriter writer,byte[] nalu, byte counter) + { + TS_Segment_Package package = new TS_Segment_Package(); + package.Header = new TS_Header(); + package.Header.PID = 256; + package.Header.ContinuityCounter = counter; + package.Header.PayloadUnitStartIndicator = 0; + package.Payload = nalu; + //这个很重要,需要控制 + //package.Header.AdaptationFieldControl= AdaptationFieldControl.同时带有自适应域和有效负载 + //这个很重要,填充大小 + //package.Header.Adaptation.FillSize + if (nalu.Length < FiexdSegmentPESLength) + { + package.Header.Adaptation = new TS_AdaptationInfo(); + package.Header.Adaptation.PCRIncluded = PCRInclude.不包含; + package.Header.Adaptation.FillSize = (byte)(FiexdSegmentPESLength - nalu.Length); + package.Header.AdaptationFieldControl = AdaptationFieldControl.同时带有自适应域和有效负载; + } + else + { + package.Header.AdaptationFieldControl = AdaptationFieldControl.无自适应域_仅含有效负载; + } + package.Payload = nalu; + package.ToBuffer(ref writer); + } } } diff --git a/src/JT1078.Hls/TS_AdaptationInfo.cs b/src/JT1078.Hls/TS_AdaptationInfo.cs index b70918e..6e84c79 100644 --- a/src/JT1078.Hls/TS_AdaptationInfo.cs +++ b/src/JT1078.Hls/TS_AdaptationInfo.cs @@ -1,5 +1,5 @@ using JT1078.Hls.Enums; -using JT1078.Hls.Formatters; +using JT1078.Hls.Interfaces; using JT1078.Hls.MessagePack; using System; using System.Collections.Generic; @@ -16,6 +16,7 @@ namespace JT1078.Hls /// public PCRInclude PCRIncluded { get; set; } /// + /// 第一包的数据、关键帧 /// Program Clock Reference,节目时钟参考,用于恢复出与编码端一致的系统时序时钟STC(System Time Clock) /// 5B /// diff --git a/src/JT1078.Hls/TS_Header.cs b/src/JT1078.Hls/TS_Header.cs index 0f41ee7..31c7c95 100644 --- a/src/JT1078.Hls/TS_Header.cs +++ b/src/JT1078.Hls/TS_Header.cs @@ -1,5 +1,5 @@ using JT1078.Hls.Enums; -using JT1078.Hls.Formatters; +using JT1078.Hls.Interfaces; using JT1078.Hls.MessagePack; using System; using System.Collections.Generic; diff --git a/src/JT1078.Hls/TS_PAT_Package.cs b/src/JT1078.Hls/TS_PAT_Package.cs index 09e7e20..f221bc3 100644 --- a/src/JT1078.Hls/TS_PAT_Package.cs +++ b/src/JT1078.Hls/TS_PAT_Package.cs @@ -1,4 +1,4 @@ -using JT1078.Hls.Formatters; +using JT1078.Hls.Interfaces; using JT1078.Hls.MessagePack; using System; using System.Collections.Generic; diff --git a/src/JT1078.Hls/TS_PAT_Program.cs b/src/JT1078.Hls/TS_PAT_Program.cs index 0eb1856..f82ede7 100644 --- a/src/JT1078.Hls/TS_PAT_Program.cs +++ b/src/JT1078.Hls/TS_PAT_Program.cs @@ -1,4 +1,4 @@ -using JT1078.Hls.Formatters; +using JT1078.Hls.Interfaces; using JT1078.Hls.MessagePack; using System; using System.Collections.Generic; diff --git a/src/JT1078.Hls/TS_PMT_Component.cs b/src/JT1078.Hls/TS_PMT_Component.cs index 09fde58..96a0ed5 100644 --- a/src/JT1078.Hls/TS_PMT_Component.cs +++ b/src/JT1078.Hls/TS_PMT_Component.cs @@ -1,6 +1,6 @@ using JT1078.Hls.Descriptors; using JT1078.Hls.Enums; -using JT1078.Hls.Formatters; +using JT1078.Hls.Interfaces; using JT1078.Hls.MessagePack; using System; using System.Collections.Generic; diff --git a/src/JT1078.Hls/TS_PMT_Package.cs b/src/JT1078.Hls/TS_PMT_Package.cs index bb5d601..1564b58 100644 --- a/src/JT1078.Hls/TS_PMT_Package.cs +++ b/src/JT1078.Hls/TS_PMT_Package.cs @@ -1,4 +1,4 @@ -using JT1078.Hls.Formatters; +using JT1078.Hls.Interfaces; using JT1078.Hls.MessagePack; using System; using System.Collections.Generic; diff --git a/src/JT1078.Hls/TS_Package.cs b/src/JT1078.Hls/TS_Package.cs index 8686aa9..aaa1a2e 100644 --- a/src/JT1078.Hls/TS_Package.cs +++ b/src/JT1078.Hls/TS_Package.cs @@ -1,4 +1,4 @@ -using JT1078.Hls.Formatters; +using JT1078.Hls.Interfaces; using JT1078.Hls.MessagePack; using JT1078.Protocol.H264; using System; diff --git a/src/JT1078.Hls/TS_Segment_Package.cs b/src/JT1078.Hls/TS_Segment_Package.cs new file mode 100644 index 0000000..71bd027 --- /dev/null +++ b/src/JT1078.Hls/TS_Segment_Package.cs @@ -0,0 +1,19 @@ +using JT1078.Hls.Interfaces; +using JT1078.Hls.MessagePack; +using System; +using System.Collections.Generic; +using System.Text; + +namespace JT1078.Hls +{ + public class TS_Segment_Package : ITSMessagePackFormatter + { + public TS_Header Header { get; set; } + public byte[] Payload { get; set; } + public void ToBuffer(ref TSMessagePackWriter writer) + { + Header.ToBuffer(ref writer); + writer.WriteArray(Payload); + } + } +}