@@ -24,7 +24,7 @@ namespace JT1078.Hls.Test | |||
//47 41 00 30 07 50 00 00 7B 0C 7E 00 00 00 01 E0 00 00 80 C0 0A 31 00 09 08 97 11 00 07 D8 61 00 00 00 01 09 F0 00 00 00 01 67 64 00 1F AC D9 40 88 1E 68 40 00 00 03 01 80 00 00 57 83 C6 0C 65 80 00 00 00 01 68 EB E3 CB 22 C0 00 00 01 06 05 FF FF AB DC 45 E9 BD E6 D9 48 B7 96 2C D8 20 D9 23 EE EF 78 32 36 34 20 2D 20 63 6F 72 65 20 31 35 38 20 72 32 39 38 34 20 33 37 35 39 66 63 62 20 2D 20 48 2E 32 36 34 2F 4D 50 45 47 2D 34 20 41 56 43 20 63 6F 64 65 63 20 2D 20 43 6F 70 79 6C 65 66 74 20 32 30 30 33 2D 32 30 31 39 20 2D 20 68 74 74 70 3A 2F 2F 77 77 77 2E | |||
//47 41 00 30 07 50 00 00 7B 0C 7E 00 00 00 01 E0 00 00 80 C0 0A 31 00 09 08 97 11 00 07 D8 61 00 00 00 01 09 F0 00 00 00 01 67 64 00 1F AC D9 40 88 1E 68 40 00 00 03 01 80 00 00 57 83 C6 0C 65 80 00 00 00 01 68 EB E3 CB 22 C0 00 00 01 06 05 FF FF AB DC 45 E9 BD E6 D9 48 B7 96 2C D8 20 D9 23 EE EF 78 32 36 34 20 2D 20 63 6F 72 65 20 31 35 38 20 72 32 39 38 34 20 33 37 35 39 66 63 62 20 2D 20 48 2E 32 36 34 2F 4D 50 45 47 2D 34 20 41 56 43 20 63 6F 64 65 63 20 2D 20 43 6F 70 79 6C 65 66 74 20 32 30 30 33 2D 32 30 31 39 20 2D 20 68 74 74 70 3A 2F 2F 77 77 77 2E | |||
//47 41 00 30 07 50 00 90 32 10 7E 00 00 00 01 E0 00 00 80 C0 0A 00 00 02 04 4B 00 00 01EC300000000109FF000000016764001FACD940881E6840000003018000005783C60C65800000000168EBE3CB22C00000010605FFFFABDC45E9BDE6D948B7962CD820D923EEEF78323634202D20636F7265203135382072323938342033373539666362202D20482E3236342F4D5045472D342041564320636F646563202D20436F70796C65667420323030332D32303139202D20687474703A2F2F7777772E | |||
//47 41 00 30 07 50 00 00 7B 0C 7E 00 00 00 01 E0 00 00 80 C0 0A 00 00 02 04 4B 00 00 01 EC 30 00 00 00 01 09 FF 000000016764001FACD940881E6840000003018000005783C60C65800000000168EBE3CB22C00000010605FFFFABDC45E9BDE6D948B7962CD820D923EEEF78323634202D20636F7265203135382072323938342033373539666362202D20482E3236342F4D5045472D342041564320636F646563202D20436F70796C65667420323030332D32303139202D20687474703A2F2F7777772E | |||
//47 | |||
//41 00 | |||
@@ -54,7 +54,7 @@ namespace JT1078.Hls.Test | |||
package.Header.PackageType = PackageType.Data_Start; | |||
package.Header.PayloadUnitStartIndicator = 1; | |||
package.Header.Adaptation = new TS_AdaptationInfo(); | |||
package.Header.Adaptation.PCR = 18900000; | |||
package.Header.Adaptation.Timestamp = 18900000; | |||
package.Header.Adaptation.PCRIncluded = PCRInclude.包含; | |||
package.Payload = new PES_Package(); | |||
package.Payload.PTS = 132171; | |||
@@ -133,14 +133,21 @@ namespace JT1078.Hls.Test | |||
{ | |||
if (isNeedFirstHeadler) | |||
{ | |||
fileStream.Write(tSEncoder.CreatePAT(fullpackage)); | |||
fileStream.Write(tSEncoder.CreatePMT(fullpackage)); | |||
fileStream.Write(tSEncoder.CreatePES(fullpackage,1888)); | |||
var sdt = tSEncoder.CreateSDT(fullpackage); | |||
string sdtHEX = sdt.ToHexString(); | |||
fileStream.Write(sdt); | |||
var pat = tSEncoder.CreatePAT(fullpackage); | |||
string patHEX = pat.ToHexString(); | |||
fileStream.Write(pat); | |||
var pmt = tSEncoder.CreatePMT(fullpackage); | |||
fileStream.Write(pmt); | |||
var pes = tSEncoder.CreatePES(fullpackage, 18888); | |||
fileStream.Write(pes); | |||
isNeedFirstHeadler = false; | |||
} | |||
else | |||
{ | |||
fileStream.Write(tSEncoder.CreatePES(fullpackage, 1888)); | |||
fileStream.Write(tSEncoder.CreatePES(fullpackage, 18888)); | |||
} | |||
} | |||
} | |||
@@ -65,15 +65,6 @@ namespace JT1078.Hls.MessagePack | |||
writer.Free[4] = (byte)(value); | |||
writer.Advance(5); | |||
} | |||
public void WritePCR(long value) | |||
{ | |||
writer.Free[0] = (byte)(value >> 25); | |||
writer.Free[1] = (byte)((value >> 17) & 0xff); | |||
writer.Free[2] = (byte)((value >> 9) & 0xff); | |||
writer.Free[3] = (byte)((value >> 1) & 0xff); | |||
writer.Free[4] = (byte)(((value & 0x1) << 7) | 0x7e); | |||
writer.Advance(5); | |||
} | |||
public void WriteInt6(long value) | |||
{ | |||
writer.Free[0] = (byte)(value >> 40); | |||
@@ -16,6 +16,10 @@ namespace JT1078.Hls | |||
/// 固定包长度 | |||
/// </summary> | |||
public const int FiexdPackageLength = 188; | |||
/// <summary> | |||
/// 固定ES包头的长度 | |||
/// </summary> | |||
public const int FiexdESPackageHeaderLength = 6; | |||
} | |||
} |
@@ -26,8 +26,12 @@ namespace JT1078.Hls | |||
private const int FiexdSegmentPESLength = 184; | |||
private const int FiexdTSLength = 188; | |||
private const string ServiceProvider = "JTT1078"; | |||
private const string ServiceName = "Koike&TK"; | |||
private ConcurrentDictionary<string, byte> VideoCounter = new ConcurrentDictionary<string, byte>(); | |||
private const string ServiceName = "Koike&TK"; | |||
public TSEncoder() | |||
{ | |||
VideoCounter = new ConcurrentDictionary<string, byte>(StringComparer.OrdinalIgnoreCase); | |||
} | |||
private ConcurrentDictionary<string, byte> VideoCounter; | |||
//private ConcurrentDictionary<string, byte> AudioCounter = new ConcurrentDictionary<string, byte>(); | |||
public byte[] CreateSDT(JT1078Package jt1078Package, int minBufferSize = 188) | |||
{ | |||
@@ -143,38 +147,41 @@ namespace JT1078.Hls | |||
//ts header 4 | |||
totalLength += 4; | |||
package.Header.PID = 256; | |||
package.Header.PackageType = PackageType.Data_Start; | |||
string key = jt1078Package.GetKey(); | |||
if (VideoCounter.TryGetValue(key, out byte counter)) | |||
//if (jt1078Package.Label3.DataType == JT1078DataType.视频P帧) | |||
//{ | |||
//} | |||
byte counter = VideoCounter.AddOrUpdate(key, 0, (a, b) => | |||
{ | |||
if (counter > 0xf) | |||
if (b > 0xf) | |||
{ | |||
counter = 0; | |||
return 0; | |||
} | |||
package.Header.ContinuityCounter = counter++; | |||
VideoCounter.TryUpdate(key, counter, counter); | |||
} | |||
else | |||
{ | |||
package.Header.ContinuityCounter = counter++; | |||
VideoCounter.TryAdd(key, counter); | |||
} | |||
else | |||
{ | |||
return b; | |||
} | |||
}); | |||
package.Header.ContinuityCounter = 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); | |||
//PESStartCode + StreamId+ Flag1 + PTS_DTS_Flag + PESPacketLength | |||
//3 + 1 + 1 + 1 + 2 | |||
totalLength += (3+1+1+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); | |||
//PCRIncluded + Timestamp | |||
//1 + 6 | |||
totalLength += (1 + 6); | |||
package.Header.Adaptation.PCRIncluded = PCRInclude.包含; | |||
package.Header.Adaptation.PCR = (long)jt1078Package.Timestamp; | |||
package.Header.Adaptation.Timestamp = (long)jt1078Package.Timestamp; | |||
package.Payload.DTS = jt1078Package.LastIFrameInterval; | |||
package.Payload.PTS = jt1078Package.LastIFrameInterval; | |||
} | |||
@@ -189,8 +196,9 @@ namespace JT1078.Hls | |||
package.Payload.PTS = jt1078Package.LastFrameInterval; | |||
} | |||
//Flag1 + PTS_DTS_Flag + DTS + PTS | |||
//1 + 1 + 5 + 5 | |||
//1 + 1 + 5 + 5 = 12 | |||
totalLength += 12; | |||
totalLength += TSConstants.FiexdESPackageHeaderLength; | |||
//根据计算剩余的长度进行是否需要填充第一包 | |||
var remainingLength = FiexdTSLength - totalLength; | |||
int index = 0; | |||
@@ -202,6 +210,7 @@ namespace JT1078.Hls | |||
package.Payload.Payload = new ES_Package(); | |||
if (fullSize < 0) | |||
{ | |||
counter++; | |||
//这个很重要,需要控制 | |||
package.Header.AdaptationFieldControl = AdaptationFieldControl.同时带有自适应域和有效负载; | |||
//还差一点 | |||
@@ -212,6 +221,7 @@ namespace JT1078.Hls | |||
} | |||
else if(fullSize==0) | |||
{ | |||
counter++; | |||
//这个很重要,需要控制 | |||
package.Header.AdaptationFieldControl = AdaptationFieldControl.无自适应域_仅含有效负载; | |||
//刚刚好 | |||
@@ -230,7 +240,7 @@ namespace JT1078.Hls | |||
package.Payload.Payload.NALUs.Add(dataReader.Slice(index, remainingLength).ToArray()); | |||
index += remainingLength; | |||
package.ToBuffer(ref messagePackReader); | |||
while(index!= jt1078Package.Bodies.Length) | |||
while (index!= jt1078Package.Bodies.Length) | |||
{ | |||
if (counter > 0xf) | |||
{ | |||
@@ -248,8 +258,18 @@ namespace JT1078.Hls | |||
index += segmentFullSize; | |||
} | |||
} | |||
VideoCounter.TryUpdate(key, counter, counter); | |||
} | |||
VideoCounter.AddOrUpdate(key, counter, (a, b) => | |||
{ | |||
if (b > 0xf) | |||
{ | |||
return 0; | |||
} | |||
else | |||
{ | |||
return b; | |||
} | |||
}); | |||
return messagePackReader.FlushAndGetArray(); | |||
} | |||
finally | |||
@@ -274,7 +294,9 @@ namespace JT1078.Hls | |||
package.Header.PackageType = PackageType.Data_End; | |||
package.Header.Adaptation = new TS_AdaptationInfo(); | |||
package.Header.Adaptation.PCRIncluded = PCRInclude.不包含; | |||
package.Header.Adaptation.FillSize = (byte)(FiexdSegmentPESLength - nalu.Length); | |||
//AdaptationLengthPosition + PCRIncluded | |||
//1 + 1 | |||
package.Header.Adaptation.FillSize = (byte)(FiexdSegmentPESLength - 1 - 1 - nalu.Length); | |||
package.Header.AdaptationFieldControl = AdaptationFieldControl.同时带有自适应域和有效负载; | |||
} | |||
else | |||
@@ -16,11 +16,12 @@ namespace JT1078.Hls | |||
/// </summary> | |||
public PCRInclude PCRIncluded { get; set; } | |||
/// <summary> | |||
/// JT1078时间戳 | |||
/// 第一包的数据、关键帧 | |||
/// Program Clock Reference,节目时钟参考,用于恢复出与编码端一致的系统时序时钟STC(System Time Clock) | |||
/// 5B | |||
/// </summary> | |||
public long PCR { get; set; } | |||
public long Timestamp { get; set; } | |||
/// <summary> | |||
/// 填充字节大小 | |||
/// </summary> | |||
@@ -28,16 +29,27 @@ namespace JT1078.Hls | |||
public void ToBuffer(ref TSMessagePackWriter writer) | |||
{ | |||
writer.WriteByte((byte)PCRIncluded); | |||
if (PCRIncluded== PCRInclude.包含) | |||
if (PCRIncluded == PCRInclude.包含) | |||
{ | |||
writer.WritePCR(PCR); | |||
#warning PCR 0???? | |||
writer.WriteByte(0); | |||
writer.WriteInt6(ToPCR()); | |||
} | |||
if (FillSize > 0) | |||
{ | |||
writer.WriteArray(Enumerable.Range(0, FillSize).Select(s => (byte)0xFF).ToArray()); | |||
} | |||
} | |||
/// <summary> | |||
/// if(PCR_flag == '1'){ | |||
/// program_clock_reference_base 33 uimsbf | |||
/// Reserved 6 bslbf | |||
/// program_clock_reference_extension 9 uimsbf | |||
/// } | |||
/// </summary> | |||
/// <returns></returns> | |||
private long ToPCR() | |||
{ | |||
return (Timestamp / 300 << 15 | 0x7E00); | |||
} | |||
} | |||
} |
@@ -64,7 +64,8 @@ namespace JT1078.Hls | |||
writer.WriteByte(SyncByte); | |||
//TransportErrorIndicator PayloadUnitStartIndicator TransportPriority PID | |||
//0 1 0 0000 0000 0000 0 | |||
writer.WriteUInt16((ushort)(0b_0100_0000_0000_0000 | PID)); | |||
//writer.WriteUInt16((ushort)((0b_0100_0000_0000_0000 & (PayloadUnitStartIndicator<<14)) | PID)); | |||
writer.WriteUInt16((ushort)((PayloadUnitStartIndicator<<14) | PID)); | |||
writer.WriteByte((byte)((byte)AdaptationFieldControl | ContinuityCounter)); | |||
if(PackageType== PackageType.PAT || | |||
PackageType == PackageType.PMT || | |||