Bladeren bron

添加ts的编码

tags/v1.1.0
SmallChi(Koike) 5 jaren geleden
bovenliggende
commit
8055e90a4a
24 gewijzigde bestanden met toevoegingen van 1024 en 0 verwijderingen
  1. +7
    -0
      doc/video/demo.m3u8
  2. BIN
      doc/video/demo0.ts
  3. +20
    -0
      src/JT1078.Hls.Test/JT1078.Hls.Test.csproj
  4. +55
    -0
      src/JT1078.Hls.Test/UnitTest1.cs
  5. +24
    -0
      src/JT1078.Hls/Buffers/TSBufferWriter.cs
  6. +28
    -0
      src/JT1078.Hls/ES_Package.cs
  7. +14
    -0
      src/JT1078.Hls/Enums/AdaptationFieldControl.cs
  8. +15
    -0
      src/JT1078.Hls/Enums/PCRInclude.cs
  9. +16
    -0
      src/JT1078.Hls/Enums/PTS_DTS_Flags.cs
  10. +13
    -0
      src/JT1078.Hls/Enums/StreamType.cs
  11. +10
    -0
      src/JT1078.Hls/Interfaces/ITSMessagePackFormatter.cs
  12. +163
    -0
      src/JT1078.Hls/MessagePack/TSMessagePackWriter.cs
  13. +81
    -0
      src/JT1078.Hls/PES_Package.cs
  14. +24
    -0
      src/JT1078.Hls/TSArrayPool.cs
  15. +58
    -0
      src/JT1078.Hls/TSEncoder.cs
  16. +32
    -0
      src/JT1078.Hls/TS_AdaptationInfo.cs
  17. +79
    -0
      src/JT1078.Hls/TS_Header.cs
  18. +106
    -0
      src/JT1078.Hls/TS_PAT_Package.cs
  19. +34
    -0
      src/JT1078.Hls/TS_PAT_Program.cs
  20. +47
    -0
      src/JT1078.Hls/TS_PMT_Component.cs
  21. +129
    -0
      src/JT1078.Hls/TS_PMT_Package.cs
  22. +17
    -0
      src/JT1078.Hls/TS_Package.cs
  23. +45
    -0
      src/JT1078.Hls/Util.cs
  24. +7
    -0
      src/JT1078.sln

+ 7
- 0
doc/video/demo.m3u8 Bestand weergeven

@@ -0,0 +1,7 @@
#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:7
#EXT-X-MEDIA-SEQUENCE:0
#EXTINF:7.200667,
demo0.ts
#EXT-X-ENDLIST

BIN
doc/video/demo0.ts Bestand weergeven


+ 20
- 0
src/JT1078.Hls.Test/JT1078.Hls.Test.csproj Bestand weergeven

@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<PackageReference Include="coverlet.collector" Version="1.2.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\JT1078.Hls\JT1078.Hls.csproj" />
</ItemGroup>

</Project>

+ 55
- 0
src/JT1078.Hls.Test/UnitTest1.cs Bestand weergeven

@@ -0,0 +1,55 @@
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
}
}

+ 24
- 0
src/JT1078.Hls/Buffers/TSBufferWriter.cs Bestand weergeven

@@ -0,0 +1,24 @@
using System;

namespace JT1078.Hls
{
/// <summary>
/// <see cref="System.Buffers.Writer"/>
/// </summary>
ref partial struct TSBufferWriter
{
private Span<byte> _buffer;
public TSBufferWriter(Span<byte> buffer)
{
_buffer = buffer;
WrittenCount = 0;
}
public Span<byte> Free => _buffer.Slice(WrittenCount);
public Span<byte> Written => _buffer.Slice(0, WrittenCount);
public int WrittenCount { get; private set; }
public void Advance(int count)
{
WrittenCount += count;
}
}
}

+ 28
- 0
src/JT1078.Hls/ES_Package.cs Bestand weergeven

@@ -0,0 +1,28 @@
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 ES_Package: ITSMessagePackFormatter
{
public static byte[] NALU0X09 = new byte[] { 0x00, 0x00, 0x00, 0x01, 0x09, 0xFF };
public byte[] NALU0x09 { get; set; } = NALU0X09;
public List<H264NALU> NALUs { get; set; }
public void ToBuffer(ref TSMessagePackWriter writer)
{
writer.WriteArray(NALU0x09);
if(NALUs!=null)
{
foreach(var nalu in NALUs)
{
writer.WriteArray(nalu.StartCodePrefix);
writer.WriteArray(nalu.RawData);
}
}
}
}
}

+ 14
- 0
src/JT1078.Hls/Enums/AdaptationFieldControl.cs Bestand weergeven

@@ -0,0 +1,14 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.Hls.Enums
{
public enum AdaptationFieldControl
{
保留= 0000_0000,
无自适应域_仅含有效负载 = 0001_0000,
仅含自适应域_无有效负载 = 0010_0000,
同时带有自适应域和有效负载 = 0011_0000,
}
}

+ 15
- 0
src/JT1078.Hls/Enums/PCRInclude.cs Bestand weergeven

@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.Hls.Enums
{
/// <summary>
/// 取0x50表示包含PCR或0x40表示不包含PCR
/// </summary>
public enum PCRInclude:byte
{
包含= 0x50,
不包含= 0x40
}
}

+ 16
- 0
src/JT1078.Hls/Enums/PTS_DTS_Flags.cs Bestand weergeven

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.Hls.Enums
{
/// <summary>
///
/// </summary>
public enum PTS_DTS_Flags:byte
{
all = 0xc0,
pts = 0x80,
dts = 0x40
}
}

+ 13
- 0
src/JT1078.Hls/Enums/StreamType.cs Bestand weergeven

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.Hls.Enums
{
public enum StreamType:byte
{
h264 = 0x1B,
aac = 0x0f,
mp3 = 0x03
}
}

+ 10
- 0
src/JT1078.Hls/Interfaces/ITSMessagePackFormatter.cs Bestand weergeven

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

namespace JT1078.Hls.Formatters
{
public interface ITSMessagePackFormatter
{
void ToBuffer(ref TSMessagePackWriter writer);
}
}

+ 163
- 0
src/JT1078.Hls/MessagePack/TSMessagePackWriter.cs Bestand weergeven

@@ -0,0 +1,163 @@
using System;
using System.Buffers.Binary;

namespace JT1078.Hls.MessagePack
{
public ref partial struct TSMessagePackWriter
{
private TSBufferWriter writer;
public TSMessagePackWriter(Span<byte> buffer)
{
this.writer = new TSBufferWriter(buffer);
}
public byte[] FlushAndGetArray()
{
return writer.Written.ToArray();
}
public void WriteByte(byte value)
{
var span = writer.Free;
span[0] = value;
writer.Advance(1);
}
public void WriteUInt16(ushort value)
{
BinaryPrimitives.WriteUInt16BigEndian(writer.Free, value);
writer.Advance(2);
}
public void WriteInt32(int value)
{
BinaryPrimitives.WriteInt32BigEndian(writer.Free, value);
writer.Advance(4);
}
public void WriteUInt64(ulong value)
{
BinaryPrimitives.WriteUInt64BigEndian(writer.Free, value);
writer.Advance(8);
}
public void WriteUInt5(ulong value)
{
writer.Free[0] = (byte)(value >> 32);
writer.Free[1] = (byte)(value >> 24);
writer.Free[2] = (byte)(value >> 16);
writer.Free[3] = (byte)(value >> 8);
writer.Free[4] = (byte)(value);
writer.Advance(5);
}
public void WriteUInt6(ulong value)
{
writer.Free[0] = (byte)(value >> 40);
writer.Free[1] = (byte)(value >> 32);
writer.Free[2] = (byte)(value >> 24);
writer.Free[3] = (byte)(value >> 16);
writer.Free[4] = (byte)(value >> 8);
writer.Free[5] = (byte)(value);
writer.Advance(6);
}
public void WriteInt5(long value)
{
writer.Free[0] = (byte)(value >> 32);
writer.Free[1] = (byte)(value >> 24);
writer.Free[2] = (byte)(value >> 16);
writer.Free[3] = (byte)(value >> 8);
writer.Free[4] = (byte)(value);
writer.Advance(5);
}
public void WriteInt6(long value)
{
writer.Free[0] = (byte)(value >> 40);
writer.Free[1] = (byte)(value >> 32);
writer.Free[2] = (byte)(value >> 24);
writer.Free[3] = (byte)(value >> 16);
writer.Free[4] = (byte)(value >> 8);
writer.Free[5] = (byte)(value);
writer.Advance(6);
}
public void WriteUInt3(uint value)
{
writer.Free[0] = (byte)(value >> 16);
writer.Free[1] = (byte)(value >> 8);
writer.Free[2] = (byte)(value);
writer.Advance(3);
}
public void WriteInt3(int value)
{
writer.Free[0] = (byte)(value >> 16);
writer.Free[1] = (byte)(value >> 8);
writer.Free[2] = (byte)(value);
writer.Advance(3);
}
public void WriteUInt32(uint value)
{
BinaryPrimitives.WriteUInt32BigEndian(writer.Free, value);
writer.Advance(4);
}
public void WriteArray(ReadOnlySpan<byte> src)
{
src.CopyTo(writer.Free);
writer.Advance(src.Length);
}
public void Skip(int count, out int position)
{
position = writer.WrittenCount;
byte[] tmp = new byte[count];
tmp.CopyTo(writer.Free);
writer.Advance(count);
}
public void WriteCRC32()
{
if (writer.WrittenCount < 1)
{
throw new ArgumentOutOfRangeException($"Written<start:{writer.WrittenCount}>{1}");
}
//从第1位开始
var crcSpan = writer.Written.Slice(1);
uint crc = 0xFFFFFFFF;
for (int i = 0; i < crcSpan.Length; i++)
{
crc = (crc << 8) ^ Util.crcTable[(crc >> 24) ^ crcSpan[i]];
}
WriteUInt32(crc);
}
public void WriteCRC32(int start)
{
if (writer.WrittenCount < start)
{
throw new ArgumentOutOfRangeException($"Written<start:{writer.WrittenCount}>{1}");
}
var crcSpan = writer.Written.Slice(start);
uint crc = 0xFFFFFFFF;
for (int i = 0; i < crcSpan.Length; i++)
{
crc = (crc << 8) ^ Util.crcTable[(crc >> 24) ^ crcSpan[i]];
}
WriteUInt32(crc);
}
public void WriteCRC32(int start, int end)
{
if (start > end)
{
throw new ArgumentOutOfRangeException($"start>end:{start}>{end}");
}
var crcSpan = writer.Written.Slice(start, end);
uint crc = 0xFFFFFFFF;
for (int i = 0; i < crcSpan.Length; i++)
{
crc = ((crc << 8) ^ Util.crcTable[(crc >> 8) ^ crcSpan[i]]);
}
WriteUInt32(crc);
}
public void WriteUInt16Return(ushort value, int position)
{
BinaryPrimitives.WriteUInt16BigEndian(writer.Written.Slice(position, 2), value);
}
public void WriteByteReturn(byte value, int position)
{
writer.Written[position] = value;
}
public int GetCurrentPosition()
{
return writer.WrittenCount;
}
}
}

+ 81
- 0
src/JT1078.Hls/PES_Package.cs Bestand weergeven

@@ -0,0 +1,81 @@
using JT1078.Hls.Enums;
using JT1078.Hls.Formatters;
using JT1078.Hls.MessagePack;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.Hls
{
public class PES_Package: ITSMessagePackFormatter
{
public static byte[] PESSTARCODE = new byte[] { 0x00, 0x00, 0x01 };
/// <summary>
/// 开始码,固定为0x000001
/// </summary>
public byte[] PESStartCode { get; set; } = PESSTARCODE;
/// <summary>
/// 音频取值(0xc0-0xdf),通常为0xc0
/// 视频取值(0xe0-0xef),通常为0xe0
/// </summary>
public byte StreamId { get; set; }
/// <summary>
/// 后面pes数据的长度,0表示长度不限制,只有视频数据长度会超过0xffff
/// </summary>
public ushort PESPacketLength { get; set; }
/// <summary>
/// 通常取值0x80,表示数据不加密、无优先级、备份的数据
/// ISOIEC13818-1 120页 Table E-1 -- PES packet header example
/// </summary>
internal byte Flag1 { get; set; } = 0x80;
/// <summary>
/// 取值0x80表示只含有pts,取值0xc0表示含有pts和dts
/// ISOIEC13818-1 120页 Table E-1 -- PES packet header example
/// </summary>
public PTS_DTS_Flags PTS_DTS_Flag { get; set; }
/// <summary>
/// 根据PTS_DTS_Flag来判断后续长度
/// 后面数据的长度,取值5或10
/// </summary>
internal byte PESDataLength { get; set; }
/// <summary>
/// 5B
/// 33bit值
/// </summary>
public long PTS { get; set; }
/// <summary>
/// 5B
/// 33bit值
/// </summary>
public long DTS { get; set; }
/// <summary>
/// 音视频数据
/// </summary>
public ES_Package Payload { get; set; }
public void ToBuffer(ref TSMessagePackWriter writer)
{
writer.WriteArray(PESStartCode);
writer.WriteByte(StreamId);
writer.WriteUInt16(PESPacketLength);
writer.WriteByte(Flag1);
writer.WriteByte((byte)PTS_DTS_Flag);
if(PTS_DTS_Flag== PTS_DTS_Flags.all)
{
writer.WriteByte(10);
writer.WriteInt5(PTS);
writer.WriteInt5(DTS);
}
else if(PTS_DTS_Flag == PTS_DTS_Flags.pts)
{
writer.WriteByte(5);
writer.WriteInt5(PTS);
}
else if (PTS_DTS_Flag == PTS_DTS_Flags.dts)
{
writer.WriteByte(5);
writer.WriteInt5(DTS);
}
Payload.ToBuffer(ref writer);
}
}
}

+ 24
- 0
src/JT1078.Hls/TSArrayPool.cs Bestand weergeven

@@ -0,0 +1,24 @@
using System.Buffers;

namespace JT1078.Hls
{
internal static class TSArrayPool
{
private readonly static ArrayPool<byte> ArrayPool;

static TSArrayPool()
{
ArrayPool = ArrayPool<byte>.Create();
}

public static byte[] Rent(int minimumLength)
{
return ArrayPool.Rent(minimumLength);
}

public static void Return(byte[] array, bool clearArray = false)
{
ArrayPool.Return(array, clearArray);
}
}
}

+ 58
- 0
src/JT1078.Hls/TSEncoder.cs Bestand weergeven

@@ -0,0 +1,58 @@
using JT1078.Protocol.Enums;
using JT1078.Protocol.H264;
using JT1078.Protocol.MessagePack;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using JT1078.Protocol;
using JT1078.Hls.MessagePack;

[assembly: InternalsVisibleTo("JT1078.Hls.Test")]

namespace JT1078.Hls
{
public class TSEncoder
{
readonly H264Decoder h264Decoder = new H264Decoder();

public byte[] Create(JT1078Package package, int minBufferSize = 65535)
{
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();

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)
{
}
}


return messagePackReader.FlushAndGetArray();
}
finally
{
TSArrayPool.Return(buffer);
}
}
}
}

+ 32
- 0
src/JT1078.Hls/TS_AdaptationInfo.cs Bestand weergeven

@@ -0,0 +1,32 @@
using JT1078.Hls.Enums;
using JT1078.Hls.Formatters;
using JT1078.Hls.MessagePack;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.Hls
{
public class TS_AdaptationInfo : ITSMessagePackFormatter
{
/// <summary>
/// 取0x50表示包含PCR或0x40表示不包含PCR
/// 1B
/// </summary>
public PCRInclude PCRIncluded { get; set; }
/// <summary>
/// Program Clock Reference,节目时钟参考,用于恢复出与编码端一致的系统时序时钟STC(System Time Clock)
/// 5B
/// </summary>
public long PCR { get; set; }

public void ToBuffer(ref TSMessagePackWriter writer)
{
writer.WriteByte((byte)PCRIncluded);
if (PCRIncluded== PCRInclude.包含)
{
writer.WriteInt5(PCR);
}
}
}
}

+ 79
- 0
src/JT1078.Hls/TS_Header.cs Bestand weergeven

@@ -0,0 +1,79 @@
using JT1078.Hls.Enums;
using JT1078.Hls.Formatters;
using JT1078.Hls.MessagePack;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.Hls
{
public class TS_Header : ITSMessagePackFormatter
{
/// <summary>
/// 同步字节,固定为0x47
/// </summary>
internal byte SyncByte { get; set; } = 0x47;
/// <summary>
/// 传输错误指示符,表明在ts头的adapt域后由一个无用字节,通常都为0,这个字节算在adapt域长度内
/// 1bit
/// </summary>
internal byte TransportErrorIndicator { get; set; } = 0;
/// <summary>
/// 负载单元起始标示符,一个完整的数据包开始时标记为1
/// 1bit
/// </summary>
public byte PayloadUnitStartIndicator { get; set; } = 1;
/// <summary>
/// 传输优先级,0为低优先级,1为高优先级,通常取0
/// 1bit
/// </summary>
internal byte TransportPriority { get; set; } = 0;
/// <summary>
/// pid值
/// 13bit
/// </summary>
public ushort PID { get; set; }
/// <summary>
/// 传输优先级,0为低优先级,1为高优先级,通常取0
/// 2bit
/// </summary>
internal byte TransportScramblingControl { get; set; } = 0;
/// <summary>
/// 是否包含自适应区,‘00’保留;‘01’为无自适应域,仅含有效负载;‘10’为仅含自适应域,无有效负载;‘11’为同时带有自适应域和有效负载。
/// 2bit
/// </summary>
public AdaptationFieldControl AdaptationFieldControl { get; set; }
/// <summary>
/// 递增计数器,从0-f,起始值不一定取0,但必须是连续的
/// 4bit
/// </summary>
public byte ContinuityCounter { get; set; } = 0;
/// <summary>
/// 自适应域长度,后面的字节数
/// </summary>
public byte AdaptationLength { get; set; }
/// <summary>
/// 附加字段
/// </summary>
public TS_AdaptationInfo Adaptation { get; set; }

public void ToBuffer(ref TSMessagePackWriter writer)
{
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));
if (Adaptation != null)
{
writer.Skip(1, out int AdaptationLengthPosition);
Adaptation.ToBuffer(ref writer);
writer.WriteByteReturn((byte)(writer.GetCurrentPosition() - AdaptationLengthPosition - 1), AdaptationLengthPosition);
}
else
{
writer.WriteByte(0);
}
}
}
}

+ 106
- 0
src/JT1078.Hls/TS_PAT_Package.cs Bestand weergeven

@@ -0,0 +1,106 @@
using JT1078.Hls.Formatters;
using JT1078.Hls.MessagePack;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.Hls
{
/// <summary>
/// 格式节目关联表
/// </summary>
public class TS_PAT_Package : ITSMessagePackFormatter
{
/// <summary>
/// PAT表固定为0x00
/// 8bit
/// </summary>
public byte TableId { get; set; } = 0x00;
/// <summary>
/// 固定为二进制1
/// 1bit
/// </summary>
internal byte SectionSyntaxIndicator { get; set; } = 0x01;
/// <summary>
/// 固定为二进制0
/// 1bit
/// </summary>
internal byte Zero { get; set; } = 0x00;
/// <summary>
/// 固定为二进制3
/// 2bit
/// </summary>
internal byte Reserved1 { get; set; } = 0x03;
/// <summary>
/// 后面数据的长度
/// 12bit
/// </summary>
public ushort SectionLength { get; set; }
/// <summary>
/// 传输流ID
/// 16bit
/// </summary>
internal ushort TransportStreamId { get; set; } = 0x0001;
/// <summary>
/// 固定为二进制3
/// 2bit
/// </summary>
internal byte Reserved2 { get; set; } = 0x03;
/// <summary>
/// 版本号,固定为二进制00000,如果PAT有变化则版本号加1
/// 5bit
/// </summary>
public byte VersionNumber { get; set; } = 0x00;
/// <summary>
/// 固定为二进制1,表示这个PAT表可以用,如果为0则要等待下一个PAT表
/// 1bit
/// </summary>
public byte CurrentNextIndicator { get; set; } = 1;
/// <summary>
/// 固定为0x00
/// bit8
/// </summary>
internal byte SectionNumber { get; set; } = 0x00;
/// <summary>
/// 固定为0x00
/// bit8
/// </summary>
internal byte LastSectionNumber { get; set; } = 0x00;

public List<TS_PAT_Program> Programs { get; set; }

/// <summary>
/// 前面数据的CRC32校验码
/// </summary>
public uint CRC32 { get; set; }

public void ToBuffer(ref TSMessagePackWriter 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));
writer.Skip(2, out int SectionLengthPosition);
writer.WriteUInt16(TransportStreamId);
//Reserved2 VersionNumber CurrentNextIndicator
//11 00000 1
var a = Reserved2 & 0xC0;
var b = VersionNumber & 0x3E;
var c = (byte)(a | b | CurrentNextIndicator);
writer.WriteByte(c);
writer.WriteByte(SectionNumber);
writer.WriteByte(LastSectionNumber);
if (Programs != null)
{
foreach (var program in Programs)
{
program.ToBuffer(ref writer);
}
}
writer.WriteUInt16Return((ushort)(1011_0000_0000_0000 | (ushort)(writer.GetCurrentPosition() - SectionLengthPosition - 2)), SectionLengthPosition);
writer.WriteCRC32(SectionLengthPosition);
}
}
}

+ 34
- 0
src/JT1078.Hls/TS_PAT_Program.cs Bestand weergeven

@@ -0,0 +1,34 @@
using JT1078.Hls.Formatters;
using JT1078.Hls.MessagePack;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.Hls
{
public class TS_PAT_Program : ITSMessagePackFormatter
{
/// <summary>
/// 节目号为0x0000时表示这是NIT,节目号为0x0001时,表示这是PMT
/// 16bit
/// </summary>
public ushort ProgramNumber { get; set; }
/// <summary>
/// 固定为二进制111(7)
/// 1110_0000_0000_0000
/// 3bit
/// </summary>
internal byte Reserved1 { get; set; } = 0x07;
/// <summary>
/// 节目号对应内容的PID值
/// 13bit
/// </summary>
public ushort PID { get; set; }

public void ToBuffer(ref TSMessagePackWriter writer)
{
writer.WriteUInt16(ProgramNumber);
writer.WriteUInt16((ushort)(1110_0000_0000_0000 | PID));
}
}
}

+ 47
- 0
src/JT1078.Hls/TS_PMT_Component.cs Bestand weergeven

@@ -0,0 +1,47 @@
using JT1078.Hls.Enums;
using JT1078.Hls.Formatters;
using JT1078.Hls.MessagePack;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.Hls
{
public class TS_PMT_Component: ITSMessagePackFormatter
{
/// <summary>
/// 流类型,标志是Video还是Audio还是其他数据,h.264编码对应0x1b,aac编码对应0x0f,mp3编码对应0x03
/// 8bit
/// </summary>
public StreamType StreamType { get; set; }
/// <summary>
/// 固定为二进制111(7)
/// 0111_0000_0000_0000
/// 3bit
/// </summary>
internal byte Reserved1 { get; set; } = 0x07;
/// <summary>
/// 与StreamType对应的PID
/// 13bit
/// </summary>
public ushort ElementaryPID { get; set; }
/// <summary>
/// 固定为二进制1111(15)
/// 1111_0000_0000_0000
/// 4bit
/// </summary>
internal byte Reserved2 { get; set; } = 0x0F;
/// <summary>
/// 描述信息,指定为0x000表示没有
/// 12bit
/// </summary>
internal ushort ESInfoLength { get; set; } = 0x000;

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

+ 129
- 0
src/JT1078.Hls/TS_PMT_Package.cs Bestand weergeven

@@ -0,0 +1,129 @@
using JT1078.Hls.Formatters;
using JT1078.Hls.MessagePack;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.Hls
{
/// <summary>
/// 格式节目映射表
/// </summary>
public class TS_PMT_Package : ITSMessagePackFormatter
{
/// <summary>
/// PMT表取值随意
/// 8bit
/// </summary>
public byte TableId { get; set; } = 0xFF;
/// <summary>
/// 固定为二进制1
/// 1bit
/// </summary>
internal byte SectionSyntaxIndicator { get; set; } = 0x01;
/// <summary>
/// 固定为二进制0
/// 1bit
/// </summary>
internal byte Zero { get; set; } = 0x00;
/// <summary>
/// 固定为二进制3
/// 2bit
/// </summary>
internal byte Reserved1 { get; set; } = 0x03;
/// <summary>
/// 后面数据的长度
/// 12bit
/// </summary>
public ushort SectionLength { get; set; }
/// <summary>
/// 频道号码,表示当前的PMT关联到的频道,取值0x0001
/// 16bit
/// </summary>
public ushort ProgramNumber { get; set; } = 0x0001;
/// <summary>
/// 固定为二进制3
/// 2bit
/// </summary>
internal byte Reserved2 { get; set; } = 0x03;
/// <summary>
/// 版本号,固定为二进制00000,如果PAT有变化则版本号加1
/// 5bit
/// </summary>
public byte VersionNumber { get; set; } = 0x00;
/// <summary>
/// 固定为二进制1,表示这个PAT表可以用,如果为0则要等待下一个PAT表
/// 1bit
/// </summary>
public byte CurrentNextIndicator { get; set; } = 1;
/// <summary>
/// 固定为0x00
/// bit8
/// </summary>
internal byte SectionNumber { get; set; } = 0x00;
/// <summary>
/// 固定为0x00
/// bit8
/// </summary>
internal byte LastSectionNumber { get; set; } = 0x00;
/// <summary>
/// 固定为二进制111(7)
/// 2bit
/// </summary>
internal byte Reserved3 { get; set; } = 0x07;
/// <summary>
/// PCR(节目参考时钟)所在TS分组的PID,指定为视频PID
/// 13bit
/// </summary>
public ushort PCR_PID { get; set; }
/// <summary>
/// 固定为二进制1111(F)
/// 4bit
/// </summary>
internal byte Reserved4 { get; set; } = 0x0F;
/// <summary>
/// 节目描述信息,指定为0x000表示没有
/// 12bit
/// </summary>
public ushort ProgramInfoLength { get; set; }
public List<TS_PMT_Component> Components { get; set; }
/// <summary>
/// 前面数据的CRC32校验码
/// </summary>
public uint CRC32 { get; set; }
public void ToBuffer(ref TSMessagePackWriter 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));
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);
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));
//Reserved4 ProgramInfoLength
//1111 0000 0000 0000
writer.WriteUInt16((ushort)(1111_0000_0000_0000 | ProgramInfoLength));
if (Components != null)
{
foreach(var component in Components)
{
component.ToBuffer(ref writer);
}
}
writer.WriteUInt16Return((ushort)(1011_0000_0000_0000 | (ushort)(writer.GetCurrentPosition() - SectionLengthPosition - 2)), SectionLengthPosition);
writer.WriteCRC32(SectionLengthPosition);
}
}
}

+ 17
- 0
src/JT1078.Hls/TS_Package.cs Bestand weergeven

@@ -0,0 +1,17 @@
using JT1078.Protocol.H264;
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.Hls
{
public class TS_Package
{
public TS_Header Header { get; set; }
public PES_Package Payload { get; set; }
/// <summary>
/// 填充字节,取值0xff
/// </summary>
public byte[] Fill { get; set; }
}
}

+ 45
- 0
src/JT1078.Hls/Util.cs Bestand weergeven

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Text;

namespace JT1078.Hls
{
class Util
{
public static uint[] crcTable =
{
0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
};
}
}

+ 7
- 0
src/JT1078.sln Bestand weergeven

@@ -34,6 +34,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT1078.Flv.Benchmark", "JT1
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT1078.Hls", "JT1078.Hls\JT1078.Hls.csproj", "{C98AD4CE-D7F5-4F7F-BAB5-D1AD50DDF14F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JT1078.Hls.Test", "JT1078.Hls.Test\JT1078.Hls.Test.csproj", "{5564C20B-BFF4-4A2A-BDF2-C7427E93E993}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -88,6 +90,10 @@ Global
{C98AD4CE-D7F5-4F7F-BAB5-D1AD50DDF14F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C98AD4CE-D7F5-4F7F-BAB5-D1AD50DDF14F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C98AD4CE-D7F5-4F7F-BAB5-D1AD50DDF14F}.Release|Any CPU.Build.0 = Release|Any CPU
{5564C20B-BFF4-4A2A-BDF2-C7427E93E993}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5564C20B-BFF4-4A2A-BDF2-C7427E93E993}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5564C20B-BFF4-4A2A-BDF2-C7427E93E993}.Release|Any CPU.ActiveCfg = Release|Any CPU
{5564C20B-BFF4-4A2A-BDF2-C7427E93E993}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -98,6 +104,7 @@ Global
{9ADD82F9-E0B2-4263-8573-151F673BB33F} = {0655AF84-E578-409F-AB0E-B47E0D2F6814}
{9DB37370-AC73-434B-9CE2-6659321858C8} = {0655AF84-E578-409F-AB0E-B47E0D2F6814}
{D13FE092-1D11-4545-A322-9F06BCDAC0FD} = {0655AF84-E578-409F-AB0E-B47E0D2F6814}
{5564C20B-BFF4-4A2A-BDF2-C7427E93E993} = {0655AF84-E578-409F-AB0E-B47E0D2F6814}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {FAE1656D-226F-4B4B-8C33-615D7E632B26}


Laden…
Annuleren
Opslaan