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