@@ -22,20 +22,20 @@ namespace JT1078.Hls.Test | |||||
if (!File.Exists(hls_file_directory)) Directory.CreateDirectory(hls_file_directory); | if (!File.Exists(hls_file_directory)) Directory.CreateDirectory(hls_file_directory); | ||||
var m3u8_filepath = Path.Combine(hls_file_directory, "live.m3u8"); | 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 }) ); | //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")); | //var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_3.txt")); | ||||
foreach (var line in lines) | //foreach (var line in lines) | ||||
{ | //{ | ||||
var data = line.Split(','); | // var data = line.Split(','); | ||||
var bytes = data[6].ToHexBytes(); | // var bytes = data[6].ToHexBytes(); | ||||
JT1078Package package = JT1078Serializer.Deserialize(bytes); | // JT1078Package package = JT1078Serializer.Deserialize(bytes); | ||||
JT1078Package fullpackage = JT1078Serializer.Merge(package); | // JT1078Package fullpackage = JT1078Serializer.Merge(package); | ||||
if (fullpackage != null) | // if (fullpackage != null) | ||||
{ | // { | ||||
tSEncoder.CreateM3U8File(fullpackage); | // tSEncoder.CreateM3U8File(fullpackage); | ||||
} | // } | ||||
} | //} | ||||
tSEncoder.AppendM3U8End(); | //tSEncoder.AppendM3U8End(); | ||||
} | } | ||||
catch (Exception ex) | catch (Exception ex) | ||||
{ | { | ||||
@@ -81,7 +81,7 @@ namespace JT1078.Hls.Test | |||||
File.Delete(filepath); | File.Delete(filepath); | ||||
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_1.txt")); | var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_1.txt")); | ||||
fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write); | 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) | foreach (var line in lines) | ||||
{ | { | ||||
var data = line.Split(','); | 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")); | var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_3.txt")); | ||||
fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write); | fileStream = new FileStream(filepath, FileMode.OpenOrCreate, FileAccess.Write); | ||||
bool isNeedFirstHeadler = true; | bool isNeedFirstHeadler = true; | ||||
TSEncoder tSEncoder = new TSEncoder(new M3U8FileManage(new Options.M3U8Option { })); | TSEncoder tSEncoder = new TSEncoder(); | ||||
foreach (var line in lines) | foreach (var line in lines) | ||||
{ | { | ||||
var data = line.Split(','); | var data = line.Split(','); | ||||
@@ -1,8 +1,10 @@ | |||||
using System; | using System; | ||||
using System.Buffers; | using System.Buffers; | ||||
using System.Collections.Concurrent; | |||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.IO; | using System.IO; | ||||
using System.Text; | using System.Text; | ||||
using JT1078.Hls.MessagePack; | |||||
using JT1078.Hls.Options; | using JT1078.Hls.Options; | ||||
using JT1078.Protocol; | using JT1078.Protocol; | ||||
using JT1078.Protocol.Extensions; | using JT1078.Protocol.Extensions; | ||||
@@ -14,13 +16,62 @@ namespace JT1078.Hls | |||||
/// </summary> | /// </summary> | ||||
public class M3U8FileManage | public class M3U8FileManage | ||||
{ | { | ||||
private TSEncoder tSEncoder; | |||||
public readonly M3U8Option m3U8Option; | 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; | this.m3U8Option = m3U8Option; | ||||
fileData = arrayPool.Rent(2500000); | |||||
//AppendM3U8Start(m3U8Option.TsFileMaxSecond, m3U8Option.TsFileCount); | //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) | public void CreateM3U8File(JT1078Package fullpackage,byte[] data) | ||||
{ | { | ||||
@@ -35,84 +35,12 @@ namespace JT1078.Hls | |||||
private Dictionary<string, byte> VideoCounter; | private Dictionary<string, byte> VideoCounter; | ||||
//todo:音频同步 | //todo:音频同步 | ||||
//private Dictionary<string, byte> AudioCounter = new Dictionary<string, byte>(); | //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> | public TSEncoder() | ||||
/// 创建m3u8文件 和 ts文件 | |||||
/// </summary> | |||||
/// <param name="jt1078Package"></param> | |||||
public void CreateM3U8File(JT1078Package jt1078Package) | |||||
{ | { | ||||
CombinedTSData(jt1078Package); | VideoCounter = new Dictionary<string, byte>(StringComparer.OrdinalIgnoreCase); | ||||
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(); | |||||
} | } | ||||
/// <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) | public byte[] CreateSDT(JT1078Package jt1078Package, int minBufferSize = 188) | ||||
{ | { | ||||
byte[] buffer = TSArrayPool.Rent(minBufferSize); | byte[] buffer = TSArrayPool.Rent(minBufferSize); | ||||