Browse Source

完善PES包的编码

tags/v1.1.0
SmallChi(Koike) 5 years ago
parent
commit
c6c6b86c18
14 changed files with 258 additions and 46 deletions
  1. +4
    -10
      src/JT1078.Hls.Test/TS_Package_Test.cs
  2. +1
    -1
      src/JT1078.Hls/Descriptors/DescriptorBase.cs
  3. +1
    -1
      src/JT1078.Hls/ES_Package.cs
  4. +1
    -1
      src/JT1078.Hls/Interfaces/ITSMessagePackFormatter.cs
  5. +2
    -2
      src/JT1078.Hls/PES_Package.cs
  6. +222
    -24
      src/JT1078.Hls/TSEncoder.cs
  7. +2
    -1
      src/JT1078.Hls/TS_AdaptationInfo.cs
  8. +1
    -1
      src/JT1078.Hls/TS_Header.cs
  9. +1
    -1
      src/JT1078.Hls/TS_PAT_Package.cs
  10. +1
    -1
      src/JT1078.Hls/TS_PAT_Program.cs
  11. +1
    -1
      src/JT1078.Hls/TS_PMT_Component.cs
  12. +1
    -1
      src/JT1078.Hls/TS_PMT_Package.cs
  13. +1
    -1
      src/JT1078.Hls/TS_Package.cs
  14. +19
    -0
      src/JT1078.Hls/TS_Segment_Package.cs

+ 4
- 10
src/JT1078.Hls.Test/TS_Package_Test.cs View File

@@ -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();
}
}
}
}

+ 1
- 1
src/JT1078.Hls/Descriptors/DescriptorBase.cs View File

@@ -1,4 +1,4 @@
using JT1078.Hls.Formatters;
using JT1078.Hls.Interfaces;
using JT1078.Hls.MessagePack;
using System;
using System.Collections.Generic;


+ 1
- 1
src/JT1078.Hls/ES_Package.cs View File

@@ -1,4 +1,4 @@
using JT1078.Hls.Formatters;
using JT1078.Hls.Interfaces;
using JT1078.Hls.MessagePack;
using System;
using System.Collections.Generic;


+ 1
- 1
src/JT1078.Hls/Interfaces/ITSMessagePackFormatter.cs View File

@@ -1,7 +1,7 @@
using JT1078.Hls.MessagePack;
using System;

namespace JT1078.Hls.Formatters
namespace JT1078.Hls.Interfaces
{
public interface ITSMessagePackFormatter
{


+ 2
- 2
src/JT1078.Hls/PES_Package.cs View File

@@ -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
/// </summary>
public byte StreamId { get; set; }
public byte StreamId { get; set; } = 0xe0;
/// <summary>
/// 后面pes数据的长度,0表示长度不限制,只有视频数据长度会超过0xffff
/// </summary>


+ 222
- 24
src/JT1078.Hls/TSEncoder.cs View File

@@ -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
{
/// <summary>
/// 1.PAT
/// 2.PMT
/// 3.PES
/// </summary>
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<string, byte> PATCounter = new ConcurrentDictionary<string, byte>();
private ConcurrentDictionary<string, byte> PMTCounter = new ConcurrentDictionary<string, byte>();
private ConcurrentDictionary<string, byte> VideoCounter = new ConcurrentDictionary<string, byte>();
//private ConcurrentDictionary<string, byte> AudioCounter = new ConcurrentDictionary<string, byte>();
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<TS_PMT_Component>();
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<byte[]>() { 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<byte[]>() { jt1078Package.Bodies };
package.ToBuffer(ref messagePackReader);
}
else
{
//这个很重要,需要控制
package.Header.AdaptationFieldControl = AdaptationFieldControl.同时带有自适应域和有效负载;
//太多了,需要拆分
package.Header.Adaptation.FillSize = 0;
package.Payload.Payload.NALUs = new List<byte[]>();
ReadOnlySpan<byte> 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);
}
}
}

+ 2
- 1
src/JT1078.Hls/TS_AdaptationInfo.cs View File

@@ -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
/// </summary>
public PCRInclude PCRIncluded { get; set; }
/// <summary>
/// 第一包的数据、关键帧
/// Program Clock Reference,节目时钟参考,用于恢复出与编码端一致的系统时序时钟STC(System Time Clock)
/// 5B
/// </summary>


+ 1
- 1
src/JT1078.Hls/TS_Header.cs View File

@@ -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;


+ 1
- 1
src/JT1078.Hls/TS_PAT_Package.cs View File

@@ -1,4 +1,4 @@
using JT1078.Hls.Formatters;
using JT1078.Hls.Interfaces;
using JT1078.Hls.MessagePack;
using System;
using System.Collections.Generic;


+ 1
- 1
src/JT1078.Hls/TS_PAT_Program.cs View File

@@ -1,4 +1,4 @@
using JT1078.Hls.Formatters;
using JT1078.Hls.Interfaces;
using JT1078.Hls.MessagePack;
using System;
using System.Collections.Generic;


+ 1
- 1
src/JT1078.Hls/TS_PMT_Component.cs View File

@@ -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;


+ 1
- 1
src/JT1078.Hls/TS_PMT_Package.cs View File

@@ -1,4 +1,4 @@
using JT1078.Hls.Formatters;
using JT1078.Hls.Interfaces;
using JT1078.Hls.MessagePack;
using System;
using System.Collections.Generic;


+ 1
- 1
src/JT1078.Hls/TS_Package.cs View File

@@ -1,4 +1,4 @@
using JT1078.Hls.Formatters;
using JT1078.Hls.Interfaces;
using JT1078.Hls.MessagePack;
using JT1078.Protocol.H264;
using System;


+ 19
- 0
src/JT1078.Hls/TS_Segment_Package.cs View File

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

Loading…
Cancel
Save