@@ -22,20 +22,20 @@ namespace JT1078.Hls.Test | |||
if (!File.Exists(hls_file_directory)) Directory.CreateDirectory(hls_file_directory); | |||
var m3u8_filepath = Path.Combine(hls_file_directory, "live.m3u8"); | |||
TSEncoder tSEncoder = new TSEncoder(new M3U8FileManage (new Options.M3U8Option { HlsFileDirectory = hls_file_directory, M3U8Filepath = m3u8_filepath }) ); | |||
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_3.txt")); | |||
foreach (var line in lines) | |||
{ | |||
var data = line.Split(','); | |||
var bytes = data[6].ToHexBytes(); | |||
JT1078Package package = JT1078Serializer.Deserialize(bytes); | |||
JT1078Package fullpackage = JT1078Serializer.Merge(package); | |||
if (fullpackage != null) | |||
{ | |||
tSEncoder.CreateM3U8File(fullpackage); | |||
} | |||
} | |||
tSEncoder.AppendM3U8End(); | |||
//TSEncoder tSEncoder = new TSEncoder(new M3U8FileManage (new Options.M3U8Option { HlsFileDirectory = hls_file_directory, M3U8Filepath = m3u8_filepath }) ); | |||
//var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_3.txt")); | |||
//foreach (var line in lines) | |||
//{ | |||
// var data = line.Split(','); | |||
// var bytes = data[6].ToHexBytes(); | |||
// JT1078Package package = JT1078Serializer.Deserialize(bytes); | |||
// JT1078Package fullpackage = JT1078Serializer.Merge(package); | |||
// if (fullpackage != null) | |||
// { | |||
// tSEncoder.CreateM3U8File(fullpackage); | |||
// } | |||
//} | |||
//tSEncoder.AppendM3U8End(); | |||
} | |||
catch (Exception ex) | |||
{ | |||
@@ -81,7 +81,7 @@ namespace JT1078.Hls.Test | |||
File.Delete(filepath); | |||
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_1.txt")); | |||
fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write); | |||
TSEncoder tSEncoder = new TSEncoder(new M3U8FileManage(new Options.M3U8Option { })); | |||
TSEncoder tSEncoder = new TSEncoder(); | |||
foreach (var line in lines) | |||
{ | |||
var data = line.Split(','); | |||
@@ -128,7 +128,7 @@ namespace JT1078.Hls.Test | |||
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_3.txt")); | |||
fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write); | |||
bool isNeedFirstHeadler = true; | |||
TSEncoder tSEncoder = new TSEncoder(new M3U8FileManage(new Options.M3U8Option { })); | |||
TSEncoder tSEncoder = new TSEncoder(); | |||
foreach (var line in lines) | |||
{ | |||
var data = line.Split(','); | |||
@@ -1,8 +1,10 @@ | |||
using System; | |||
using System.Buffers; | |||
using System.Collections.Concurrent; | |||
using System.Collections.Generic; | |||
using System.IO; | |||
using System.Text; | |||
using JT1078.Hls.MessagePack; | |||
using JT1078.Hls.Options; | |||
using JT1078.Protocol; | |||
using JT1078.Protocol.Extensions; | |||
@@ -14,13 +16,62 @@ namespace JT1078.Hls | |||
/// </summary> | |||
public class M3U8FileManage | |||
{ | |||
private TSEncoder tSEncoder; | |||
public readonly M3U8Option m3U8Option; | |||
ArrayPool<byte> arrayPool = ArrayPool<byte>.Create(); | |||
byte[] fileData; | |||
int fileIndex = 0; | |||
public M3U8FileManage(M3U8Option m3U8Option) | |||
ConcurrentDictionary<string, ulong> TsFirst1078PackageDic = new ConcurrentDictionary<string, ulong>(); | |||
public M3U8FileManage(M3U8Option m3U8Option, TSEncoder tSEncoder) | |||
{ | |||
this.tSEncoder = tSEncoder; | |||
this.m3U8Option = m3U8Option; | |||
fileData = arrayPool.Rent(2500000); | |||
//AppendM3U8Start(m3U8Option.TsFileMaxSecond, m3U8Option.TsFileCount); | |||
} | |||
/// <summary> | |||
/// 创建m3u8文件 和 ts文件 | |||
/// </summary> | |||
/// <param name="jt1078Package"></param> | |||
public void CreateM3U8File(JT1078Package jt1078Package) | |||
{ | |||
//CombinedTSData(jt1078Package); | |||
//if (m3U8FileManage.m3U8Option.AccumulateSeconds >= m3U8FileManage.m3U8Option.TsFileMaxSecond) | |||
//{ | |||
// m3U8FileManage.CreateM3U8File(jt1078Package, fileData.AsSpan().Slice(0, fileIndex).ToArray()); | |||
// arrayPool.Return(fileData); | |||
// fileData = arrayPool.Rent(2500000); | |||
// fileIndex = 0; | |||
//} | |||
} | |||
private byte[] CreateTsData(JT1078Package jt1078Package, bool isNeedHeader,Span<byte> span) { | |||
var buff = TSArrayPool.Rent(jt1078Package.Bodies.Length + 2048); | |||
TSMessagePackWriter tSMessagePackWriter = new TSMessagePackWriter(buff); | |||
if (TsFirst1078PackageDic.TryGetValue(jt1078Package.SIM, out var firstTimespan)) | |||
{ | |||
if ((jt1078Package.Timestamp - firstTimespan) > 10 * 1000) | |||
{ | |||
//按设定的时间(默认为10秒)切分ts文件 | |||
} | |||
var pes = tSEncoder.CreatePES(jt1078Package, 188); | |||
tSMessagePackWriter.WriteArray(pes); | |||
} | |||
else { | |||
var sdt = tSEncoder.CreateSDT(jt1078Package); | |||
tSMessagePackWriter.WriteArray(sdt); | |||
var pat = tSEncoder.CreatePAT(jt1078Package); | |||
tSMessagePackWriter.WriteArray(pat); | |||
var pmt = tSEncoder.CreatePMT(jt1078Package); | |||
tSMessagePackWriter.WriteArray(pmt); | |||
var pes = tSEncoder.CreatePES(jt1078Package, 188); | |||
tSMessagePackWriter.WriteArray(pes); | |||
} | |||
return buff; | |||
} | |||
public void CreateM3U8File(JT1078Package fullpackage,byte[] data) | |||
{ | |||
@@ -35,84 +35,12 @@ namespace JT1078.Hls | |||
private Dictionary<string, byte> VideoCounter; | |||
//todo:音频同步 | |||
//private Dictionary<string, byte> AudioCounter = new Dictionary<string, byte>(); | |||
ArrayPool<byte> arrayPool = ArrayPool<byte>.Create(); | |||
byte[] fileData; | |||
int fileIndex = 0; | |||
private M3U8FileManage m3U8FileManage; | |||
public TSEncoder(M3U8FileManage m3U8FileManage) | |||
{ | |||
VideoCounter = new Dictionary<string, byte>(StringComparer.OrdinalIgnoreCase); | |||
this.m3U8FileManage = m3U8FileManage; | |||
fileData = arrayPool.Rent(2500000); | |||
} | |||
/// <summary> | |||
/// 创建m3u8文件 和 ts文件 | |||
/// </summary> | |||
/// <param name="jt1078Package"></param> | |||
public void CreateM3U8File(JT1078Package jt1078Package) | |||
public TSEncoder() | |||
{ | |||
CombinedTSData(jt1078Package); | |||
if (m3U8FileManage.m3U8Option.AccumulateSeconds >= m3U8FileManage.m3U8Option.TsFileMaxSecond) | |||
{ | |||
m3U8FileManage.CreateM3U8File(jt1078Package, fileData.AsSpan().Slice(0,fileIndex).ToArray()); | |||
arrayPool.Return(fileData); | |||
fileData = arrayPool.Rent(2500000); | |||
fileIndex = 0; | |||
} | |||
} | |||
/// <summary> | |||
/// m3u8文件 追加结束标识 | |||
/// </summary> | |||
public void AppendM3U8End() | |||
{ | |||
m3U8FileManage.AppendM3U8End(); | |||
VideoCounter = new Dictionary<string, byte>(StringComparer.OrdinalIgnoreCase); | |||
} | |||
/// <summary> | |||
/// 按设定的时间(默认为10秒)切分ts文件 | |||
/// </summary> | |||
/// <param name="jt1078Package"></param> | |||
private void CombinedTSData(JT1078Package jt1078Package) | |||
{ | |||
if (m3U8FileManage.m3U8Option.TimestampMilliSecond == 0) | |||
{ | |||
m3U8FileManage.m3U8Option.TimestampMilliSecond = jt1078Package.Timestamp; | |||
} | |||
else | |||
{ | |||
int duration = (int)(jt1078Package.Timestamp - m3U8FileManage.m3U8Option.TimestampMilliSecond); | |||
m3U8FileManage.m3U8Option.TimestampMilliSecond = jt1078Package.Timestamp; | |||
m3U8FileManage.m3U8Option.AccumulateSeconds = m3U8FileManage.m3U8Option.AccumulateSeconds + duration / 1000.0; | |||
} | |||
if (m3U8FileManage.m3U8Option.IsNeedFirstHeadler) | |||
{ | |||
var sdt = CreateSDT(jt1078Package); | |||
sdt.CopyTo(fileData, fileIndex); | |||
fileIndex = sdt.Length; | |||
var pat = CreatePAT(jt1078Package); | |||
pat.CopyTo(fileData, fileIndex); | |||
fileIndex = fileIndex + pat.Length; | |||
var pmt = CreatePMT(jt1078Package); | |||
pmt.CopyTo(fileData, fileIndex); | |||
fileIndex = fileIndex + pmt.Length; | |||
var pes = CreatePES(jt1078Package, 18888); | |||
pes.CopyTo(fileData, fileIndex); | |||
fileIndex = fileIndex + pes.Length; | |||
m3U8FileManage.m3U8Option.IsNeedFirstHeadler = false; | |||
} | |||
else | |||
{ | |||
var pes = CreatePES(jt1078Package, 18888); | |||
pes.CopyTo(fileData, fileIndex); | |||
fileIndex = fileIndex + pes.Length; | |||
} | |||
} | |||
public byte[] CreateSDT(JT1078Package jt1078Package, int minBufferSize = 188) | |||
{ | |||
byte[] buffer = TSArrayPool.Rent(minBufferSize); | |||