@@ -17,4 +17,10 @@ | |||||
<ProjectReference Include="..\JT1078.Hls\JT1078.Hls.csproj" /> | <ProjectReference Include="..\JT1078.Hls\JT1078.Hls.csproj" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | |||||
<None Update="file\demo.264"> | |||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | |||||
</None> | |||||
</ItemGroup> | |||||
</Project> | </Project> |
@@ -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 | |||||
{ | |||||
/// <summary> | |||||
/// 使用demo0.ts | |||||
/// </summary> | |||||
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<TS_PAT_Program>(); | |||||
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); | |||||
} | |||||
} | |||||
} |
@@ -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 | |||||
{ | |||||
/// <summary> | |||||
/// 使用demo0.ts | |||||
/// </summary> | |||||
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<TS_PMT_Component>(); | |||||
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<ISO_639_Language_Descriptor.ISO_639_Language_Info>() | |||||
{ | |||||
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); | |||||
} | |||||
} | |||||
} |
@@ -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 | |||||
{ | |||||
/// <summary> | |||||
/// 使用demo0.ts | |||||
/// </summary> | |||||
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(); | |||||
} | |||||
} | |||||
} |
@@ -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 | |||||
} | |||||
} |
@@ -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); | |||||
} | |||||
} |
@@ -0,0 +1,49 @@ | |||||
using JT1078.Hls.MessagePack; | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace JT1078.Hls.Descriptors | |||||
{ | |||||
/// <summary> | |||||
/// 2.6.18 ISO 639 language descripto | |||||
/// </summary> | |||||
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_Info> 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 | |||||
{ | |||||
/// <summary> | |||||
/// 24bit | |||||
/// </summary> | |||||
public uint ISO_639_Language_Code { get; set; } | |||||
/// <summary> | |||||
/// 8bit | |||||
/// </summary> | |||||
public byte Audio_Type { get; set; } | |||||
} | |||||
} | |||||
} |
@@ -1,6 +1,5 @@ | |||||
using JT1078.Hls.Formatters; | using JT1078.Hls.Formatters; | ||||
using JT1078.Hls.MessagePack; | using JT1078.Hls.MessagePack; | ||||
using JT1078.Protocol.H264; | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Text; | using System.Text; | ||||
@@ -11,7 +10,7 @@ namespace JT1078.Hls | |||||
{ | { | ||||
public static byte[] NALU0X09 = new byte[] { 0x00, 0x00, 0x00, 0x01, 0x09, 0xFF }; | public static byte[] NALU0X09 = new byte[] { 0x00, 0x00, 0x00, 0x01, 0x09, 0xFF }; | ||||
public byte[] NALU0x09 { get; set; } = NALU0X09; | public byte[] NALU0x09 { get; set; } = NALU0X09; | ||||
public List<H264NALU> NALUs { get; set; } | |||||
public List<byte[]> NALUs { get; set; } | |||||
public void ToBuffer(ref TSMessagePackWriter writer) | public void ToBuffer(ref TSMessagePackWriter writer) | ||||
{ | { | ||||
writer.WriteArray(NALU0x09); | writer.WriteArray(NALU0x09); | ||||
@@ -19,8 +18,7 @@ namespace JT1078.Hls | |||||
{ | { | ||||
foreach(var nalu in NALUs) | foreach(var nalu in NALUs) | ||||
{ | { | ||||
writer.WriteArray(nalu.StartCodePrefix); | |||||
writer.WriteArray(nalu.RawData); | |||||
writer.WriteArray(nalu); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -4,11 +4,11 @@ using System.Text; | |||||
namespace JT1078.Hls.Enums | 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, | |||||
} | } | ||||
} | } |
@@ -6,6 +6,7 @@ namespace JT1078.Hls.Enums | |||||
{ | { | ||||
/// <summary> | /// <summary> | ||||
/// 取0x50表示包含PCR或0x40表示不包含PCR | /// 取0x50表示包含PCR或0x40表示不包含PCR | ||||
/// 注意:关键帧需要加pcr | |||||
/// </summary> | /// </summary> | ||||
public enum PCRInclude:byte | public enum PCRInclude:byte | ||||
{ | { | ||||
@@ -1,4 +1,6 @@ | |||||
using System; | using System; | ||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using System.Buffers.Binary; | using System.Buffers.Binary; | ||||
namespace JT1078.Hls.MessagePack | namespace JT1078.Hls.MessagePack | ||||
@@ -127,9 +129,11 @@ namespace JT1078.Hls.MessagePack | |||||
} | } | ||||
var crcSpan = writer.Written.Slice(start); | var crcSpan = writer.Written.Slice(start); | ||||
uint crc = 0xFFFFFFFF; | uint crc = 0xFFFFFFFF; | ||||
byte j = 0; | |||||
for (int i = 0; i < crcSpan.Length; i++) | 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); | WriteUInt32(crc); | ||||
} | } | ||||
@@ -0,0 +1,15 @@ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using System.Text; | |||||
namespace JT1078.Hls | |||||
{ | |||||
public static class TSConstants | |||||
{ | |||||
/// <summary> | |||||
/// 固定包长度 | |||||
/// </summary> | |||||
public const int FiexdPackageLength = 188; | |||||
} | |||||
} |
@@ -3,6 +3,7 @@ using JT1078.Hls.Formatters; | |||||
using JT1078.Hls.MessagePack; | using JT1078.Hls.MessagePack; | ||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Linq; | |||||
using System.Text; | using System.Text; | ||||
namespace JT1078.Hls | namespace JT1078.Hls | ||||
@@ -19,7 +20,10 @@ namespace JT1078.Hls | |||||
/// 5B | /// 5B | ||||
/// </summary> | /// </summary> | ||||
public long PCR { get; set; } | public long PCR { get; set; } | ||||
/// <summary> | |||||
/// 填充字节大小 | |||||
/// </summary> | |||||
public byte FillSize { get; set; } | |||||
public void ToBuffer(ref TSMessagePackWriter writer) | public void ToBuffer(ref TSMessagePackWriter writer) | ||||
{ | { | ||||
writer.WriteByte((byte)PCRIncluded); | writer.WriteByte((byte)PCRIncluded); | ||||
@@ -27,6 +31,10 @@ namespace JT1078.Hls | |||||
{ | { | ||||
writer.WriteInt5(PCR); | writer.WriteInt5(PCR); | ||||
} | } | ||||
if (FillSize > 0) | |||||
{ | |||||
writer.WriteArray(Enumerable.Range(0, FillSize).Select(s => (byte)0xFF).ToArray()); | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -34,7 +34,7 @@ namespace JT1078.Hls | |||||
/// </summary> | /// </summary> | ||||
public ushort PID { get; set; } | public ushort PID { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// 传输优先级,0为低优先级,1为高优先级,通常取0 | |||||
/// 传输加扰控制 | |||||
/// 2bit | /// 2bit | ||||
/// </summary> | /// </summary> | ||||
internal byte TransportScramblingControl { get; set; } = 0; | internal byte TransportScramblingControl { get; set; } = 0; | ||||
@@ -62,8 +62,8 @@ namespace JT1078.Hls | |||||
writer.WriteByte(SyncByte); | writer.WriteByte(SyncByte); | ||||
//TransportErrorIndicator PayloadUnitStartIndicator TransportPriority PID | //TransportErrorIndicator PayloadUnitStartIndicator TransportPriority PID | ||||
//0 1 0 0000 0000 0000 0 | //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) | if (Adaptation != null) | ||||
{ | { | ||||
writer.Skip(1, out int AdaptationLengthPosition); | writer.Skip(1, out int AdaptationLengthPosition); | ||||
@@ -2,6 +2,7 @@ | |||||
using JT1078.Hls.MessagePack; | using JT1078.Hls.MessagePack; | ||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Linq; | |||||
using System.Text; | using System.Text; | ||||
namespace JT1078.Hls | namespace JT1078.Hls | ||||
@@ -11,6 +12,7 @@ namespace JT1078.Hls | |||||
/// </summary> | /// </summary> | ||||
public class TS_PAT_Package : ITSMessagePackFormatter | public class TS_PAT_Package : ITSMessagePackFormatter | ||||
{ | { | ||||
public TS_Header Header { get; set; } | |||||
/// <summary> | /// <summary> | ||||
/// PAT表固定为0x00 | /// PAT表固定为0x00 | ||||
/// 8bit | /// 8bit | ||||
@@ -76,18 +78,17 @@ namespace JT1078.Hls | |||||
public void ToBuffer(ref TSMessagePackWriter writer) | public void ToBuffer(ref TSMessagePackWriter writer) | ||||
{ | { | ||||
Header.ToBuffer(ref writer); | |||||
writer.WriteByte(TableId); | writer.WriteByte(TableId); | ||||
//SectionSyntaxIndicator Zero Reserved1 SectionLength | //SectionSyntaxIndicator Zero Reserved1 SectionLength | ||||
//1 0 11 0000 0000 0000 | //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.Skip(2, out int SectionLengthPosition); | ||||
writer.WriteUInt16(TransportStreamId); | writer.WriteUInt16(TransportStreamId); | ||||
//Reserved2 VersionNumber CurrentNextIndicator | //Reserved2 VersionNumber CurrentNextIndicator | ||||
//11 00000 1 | //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); | var c = (byte)(a | b | CurrentNextIndicator); | ||||
writer.WriteByte(c); | writer.WriteByte(c); | ||||
writer.WriteByte(SectionNumber); | writer.WriteByte(SectionNumber); | ||||
@@ -99,8 +100,13 @@ namespace JT1078.Hls | |||||
program.ToBuffer(ref writer); | 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()); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -15,7 +15,7 @@ namespace JT1078.Hls | |||||
public ushort ProgramNumber { get; set; } | public ushort ProgramNumber { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// 固定为二进制111(7) | /// 固定为二进制111(7) | ||||
/// 1110_0000_0000_0000 | |||||
/// 0b_1110_0000_0000_0000 | |||||
/// 3bit | /// 3bit | ||||
/// </summary> | /// </summary> | ||||
internal byte Reserved1 { get; set; } = 0x07; | internal byte Reserved1 { get; set; } = 0x07; | ||||
@@ -28,7 +28,7 @@ namespace JT1078.Hls | |||||
public void ToBuffer(ref TSMessagePackWriter writer) | public void ToBuffer(ref TSMessagePackWriter writer) | ||||
{ | { | ||||
writer.WriteUInt16(ProgramNumber); | writer.WriteUInt16(ProgramNumber); | ||||
writer.WriteUInt16((ushort)(1110_0000_0000_0000 | PID)); | |||||
writer.WriteUInt16((ushort)(0b_1110_0000_0000_0000 | PID)); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -1,4 +1,5 @@ | |||||
using JT1078.Hls.Enums; | |||||
using JT1078.Hls.Descriptors; | |||||
using JT1078.Hls.Enums; | |||||
using JT1078.Hls.Formatters; | using JT1078.Hls.Formatters; | ||||
using JT1078.Hls.MessagePack; | using JT1078.Hls.MessagePack; | ||||
using System; | using System; | ||||
@@ -16,7 +17,7 @@ namespace JT1078.Hls | |||||
public StreamType StreamType { get; set; } | public StreamType StreamType { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// 固定为二进制111(7) | /// 固定为二进制111(7) | ||||
/// 0111_0000_0000_0000 | |||||
/// 0b_1110_0000_0000_0000 | |||||
/// 3bit | /// 3bit | ||||
/// </summary> | /// </summary> | ||||
internal byte Reserved1 { get; set; } = 0x07; | internal byte Reserved1 { get; set; } = 0x07; | ||||
@@ -27,7 +28,7 @@ namespace JT1078.Hls | |||||
public ushort ElementaryPID { get; set; } | public ushort ElementaryPID { get; set; } | ||||
/// <summary> | /// <summary> | ||||
/// 固定为二进制1111(15) | /// 固定为二进制1111(15) | ||||
/// 1111_0000_0000_0000 | |||||
/// 0b_1111_0000_0000_0000 | |||||
/// 4bit | /// 4bit | ||||
/// </summary> | /// </summary> | ||||
internal byte Reserved2 { get; set; } = 0x0F; | internal byte Reserved2 { get; set; } = 0x0F; | ||||
@@ -36,12 +37,22 @@ namespace JT1078.Hls | |||||
/// 12bit | /// 12bit | ||||
/// </summary> | /// </summary> | ||||
internal ushort ESInfoLength { get; set; } = 0x000; | internal ushort ESInfoLength { get; set; } = 0x000; | ||||
public DescriptorBase Descriptor { get; set; } | |||||
public void ToBuffer(ref TSMessagePackWriter writer) | public void ToBuffer(ref TSMessagePackWriter writer) | ||||
{ | { | ||||
writer.WriteByte((byte)StreamType); | 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); | |||||
} | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -2,6 +2,7 @@ | |||||
using JT1078.Hls.MessagePack; | using JT1078.Hls.MessagePack; | ||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Linq; | |||||
using System.Text; | using System.Text; | ||||
namespace JT1078.Hls | namespace JT1078.Hls | ||||
@@ -11,6 +12,7 @@ namespace JT1078.Hls | |||||
/// </summary> | /// </summary> | ||||
public class TS_PMT_Package : ITSMessagePackFormatter | public class TS_PMT_Package : ITSMessagePackFormatter | ||||
{ | { | ||||
public TS_Header Header { get; set; } | |||||
/// <summary> | /// <summary> | ||||
/// PMT表取值随意 | /// PMT表取值随意 | ||||
/// 8bit | /// 8bit | ||||
@@ -93,28 +95,27 @@ namespace JT1078.Hls | |||||
public uint CRC32 { get; set; } | public uint CRC32 { get; set; } | ||||
public void ToBuffer(ref TSMessagePackWriter writer) | public void ToBuffer(ref TSMessagePackWriter writer) | ||||
{ | { | ||||
Header.ToBuffer(ref writer); | |||||
writer.WriteByte(TableId); | writer.WriteByte(TableId); | ||||
//SectionSyntaxIndicator Zero Reserved1 SectionLength | //SectionSyntaxIndicator Zero Reserved1 SectionLength | ||||
//1 0 11 0000 0000 0000 | //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.Skip(2, out int SectionLengthPosition); | ||||
writer.WriteUInt16(ProgramNumber); | writer.WriteUInt16(ProgramNumber); | ||||
//Reserved2 VersionNumber CurrentNextIndicator | //Reserved2 VersionNumber CurrentNextIndicator | ||||
//11 00000 1 | //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(c); | ||||
writer.WriteByte(SectionNumber); | writer.WriteByte(SectionNumber); | ||||
writer.WriteByte(LastSectionNumber); | writer.WriteByte(LastSectionNumber); | ||||
//Reserved3 PCR_PID | //Reserved3 PCR_PID | ||||
//111 0000 0000 0000 0 | //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 | //Reserved4 ProgramInfoLength | ||||
//1111 0000 0000 0000 | //1111 0000 0000 0000 | ||||
writer.WriteUInt16((ushort)(1111_0000_0000_0000 | ProgramInfoLength)); | |||||
writer.WriteUInt16((ushort)(0b_1111_0000_0000_0000 | ProgramInfoLength)); | |||||
if (Components != null) | if (Components != null) | ||||
{ | { | ||||
foreach(var component in Components) | foreach(var component in Components) | ||||
@@ -122,8 +123,13 @@ namespace JT1078.Hls | |||||
component.ToBuffer(ref writer); | 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()); | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -1,17 +1,21 @@ | |||||
using JT1078.Protocol.H264; | |||||
using JT1078.Hls.Formatters; | |||||
using JT1078.Hls.MessagePack; | |||||
using JT1078.Protocol.H264; | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Text; | using System.Text; | ||||
namespace JT1078.Hls | namespace JT1078.Hls | ||||
{ | { | ||||
public class TS_Package | |||||
public class TS_Package : ITSMessagePackFormatter | |||||
{ | { | ||||
public TS_Header Header { get; set; } | public TS_Header Header { get; set; } | ||||
public PES_Package Payload { get; set; } | public PES_Package Payload { get; set; } | ||||
/// <summary> | |||||
/// 填充字节,取值0xff | |||||
/// </summary> | |||||
public byte[] Fill { get; set; } | |||||
public void ToBuffer(ref TSMessagePackWriter writer) | |||||
{ | |||||
Header.ToBuffer(ref writer); | |||||
Payload.ToBuffer(ref writer); | |||||
} | |||||
} | } | ||||
} | } |