diff --git a/src/JT1078.Flv.Test/JT1078.Flv.Test.csproj b/src/JT1078.Flv.Test/JT1078.Flv.Test.csproj index 938f334..dfff8a5 100644 --- a/src/JT1078.Flv.Test/JT1078.Flv.Test.csproj +++ b/src/JT1078.Flv.Test/JT1078.Flv.Test.csproj @@ -5,6 +5,7 @@ + @@ -16,10 +17,6 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - - - - @@ -51,9 +48,6 @@ Always - - Always - diff --git a/src/JT1078.Flv.Test/Libs/libfaac.dll b/src/JT1078.Flv.Test/Libs/libfaac.dll deleted file mode 100644 index a67c71f..0000000 Binary files a/src/JT1078.Flv.Test/Libs/libfaac.dll and /dev/null differ diff --git a/src/JT1078.Flv/FlvEncoder.cs b/src/JT1078.Flv/FlvEncoder.cs index ab933db..2328dfe 100644 --- a/src/JT1078.Flv/FlvEncoder.cs +++ b/src/JT1078.Flv/FlvEncoder.cs @@ -41,7 +41,7 @@ namespace JT1078.Flv readonly H264Decoder h264Decoder = new H264Decoder(); public FlvEncoder(int sampleRate = 8000, int channels = 1, int sampleBit = 16, bool adts = false) { - //faacEncoder = new FaacEncoder(sampleRate, channels, sampleBit, adts); + faacEncoder = new FaacEncoder(sampleRate, channels, sampleBit, adts); } /// diff --git a/src/JT1078.Flv/JT1078.Flv.csproj b/src/JT1078.Flv/JT1078.Flv.csproj index 2003d3f..2442c56 100644 --- a/src/JT1078.Flv/JT1078.Flv.csproj +++ b/src/JT1078.Flv/JT1078.Flv.csproj @@ -14,7 +14,7 @@ https://github.com/SmallChi/JT1078/blob/master/LICENSE https://github.com/SmallChi/JT1078/blob/master/LICENSE false - 1.0.0-preview6 + 1.0.0-preview7 false true LICENSE diff --git a/src/JT1078.Hls/M3U8FileManage.cs b/src/JT1078.Hls/M3U8FileManage.cs index 909edf3..260bb6c 100644 --- a/src/JT1078.Hls/M3U8FileManage.cs +++ b/src/JT1078.Hls/M3U8FileManage.cs @@ -22,7 +22,6 @@ namespace JT1078.Hls public readonly M3U8Option m3U8Option; ConcurrentDictionary curTsFileInfoDic = new ConcurrentDictionary();//当前文件信息 ConcurrentDictionary> tsFileInfoQueueDic = new ConcurrentDictionary>(); - ConcurrentDictionary TsFirst1078PackageDic = new ConcurrentDictionary(); public M3U8FileManage(M3U8Option m3U8Option, TSEncoder tSEncoder) { @@ -33,46 +32,51 @@ namespace JT1078.Hls /// 生成ts和m3u8文件 /// /// - public void CreateTsData(JT1078Package jt1078Package) { - string key = $"{jt1078Package.SIM}_{jt1078Package.LogicChannelNumber}"; + public void CreateTsData(JT1078Package jt1078Package) + { + string key = jt1078Package.GetKey(); string hlsFileDirectory = m3U8Option.HlsFileDirectory; string m3u8FileName = Path.Combine(hlsFileDirectory, m3U8Option.M3U8FileName); if (!File.Exists(m3u8FileName)) File.Create(m3u8FileName);//创建m3u8文件 - var buff = TSArrayPool.Rent(jt1078Package.Bodies.Length + 1024); TSMessagePackWriter tSMessagePackWriter = new TSMessagePackWriter(buff); - - var curTsFileInfo = CreateTsFileInfo(key, jt1078Package); - if (!curTsFileInfo.IsCreateTsFile) + try { - var pes = tSEncoder.CreatePES(jt1078Package); - tSMessagePackWriter.WriteArray(pes); - CreateTsFile(curTsFileInfo.FileName, tSMessagePackWriter.FlushAndGetArray()); - - curTsFileInfo.Duration = (jt1078Package.Timestamp - curTsFileInfo.TsFirst1078PackageTimeStamp) / 1000.0; - //按设定的时间(默认为10秒)切分ts文件 - if (curTsFileInfo.Duration > m3U8Option.TsFileMaxSecond) + var curTsFileInfo = CreateTsFileInfo(key); + if (!curTsFileInfo.IsCreateTsFile) + { + var pes = tSEncoder.CreatePES(jt1078Package); + tSMessagePackWriter.WriteArray(pes); + CreateTsFile(curTsFileInfo.FileName, tSMessagePackWriter.FlushAndGetArray()); + curTsFileInfo.Duration = (jt1078Package.Timestamp - curTsFileInfo.TsFirst1078PackageTimeStamp) / 1000.0; + //按设定的时间(默认为10秒)切分ts文件 + if (curTsFileInfo.Duration > m3U8Option.TsFileMaxSecond) + { + var tsFileInfoQueue = ManageTsFileInfo(key, curTsFileInfo); + CreateM3U8File(curTsFileInfo, tsFileInfoQueue); + var newTsFileInfo = new TsFileInfo { IsCreateTsFile = true, Duration = 0, TsFileSerialNo = ++curTsFileInfo.TsFileSerialNo }; + curTsFileInfoDic.TryUpdate(key, newTsFileInfo, curTsFileInfo); + } + } + else { - var tsFileInfoQueue = ManageTsFileInfo(key, curTsFileInfo); - CreateM3U8File(key, curTsFileInfo, tsFileInfoQueue); - var newTsFileInfo = new TsFileInfo { IsCreateTsFile = true, Duration = 0, TsFileSerialNo = ++curTsFileInfo.TsFileSerialNo }; - curTsFileInfoDic.TryUpdate(key, newTsFileInfo, curTsFileInfo); + curTsFileInfo.IsCreateTsFile = false; + curTsFileInfo.TsFirst1078PackageTimeStamp = jt1078Package.Timestamp; + curTsFileInfo.FileName = $"{curTsFileInfo.TsFileSerialNo}.ts"; + 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); + tSMessagePackWriter.WriteArray(pes); + CreateTsFile(curTsFileInfo.FileName, tSMessagePackWriter.FlushAndGetArray()); } } - else { - curTsFileInfo.IsCreateTsFile = false; - curTsFileInfo.TsFirst1078PackageTimeStamp = jt1078Package.Timestamp; - curTsFileInfo.FileName = $"{curTsFileInfo.TsFileSerialNo}.ts"; - - 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); - tSMessagePackWriter.WriteArray(pes); - CreateTsFile(curTsFileInfo.FileName, tSMessagePackWriter.FlushAndGetArray()); + finally + { + TSArrayPool.Return(buff); } } /// @@ -81,7 +85,8 @@ namespace JT1078.Hls /// /// /// - private Queue ManageTsFileInfo(string key, TsFileInfo curTsFileInfo) { + private Queue ManageTsFileInfo(string key, TsFileInfo curTsFileInfo) + { if (tsFileInfoQueueDic.TryGetValue(key, out var tsFileInfoQueue)) { if (tsFileInfoQueue.Count >= m3U8Option.TsFileCapacity) @@ -103,12 +108,10 @@ namespace JT1078.Hls /// /// 创建M3U8文件 /// - /// /// - private void CreateM3U8File(string key,TsFileInfo curTsFileInfo, Queue tsFileInfoQueue) + private void CreateM3U8File(TsFileInfo curTsFileInfo, Queue tsFileInfoQueue) { //ecode_slice_header error 以非关键帧开始生成的ts,通过ffplay播放会出现报错信息 - string tsFileSerialNo = string.Empty; StringBuilder sb = new StringBuilder(); sb.AppendLine("#EXTM3U");//开始 sb.AppendLine("#EXT-X-VERSION:3");//版本号 @@ -123,9 +126,9 @@ namespace JT1078.Hls sb.AppendLine(tsFileInfo.FileName); } using (FileStream fs = new FileStream(m3U8Option.M3U8FileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) - using (StreamWriter sw = new StreamWriter(fs)) { - sw.Write(sb.ToString()); + var buffer = Encoding.UTF8.GetBytes(sb.ToString()); + fs.Write(buffer,0, buffer.Length); } } @@ -133,9 +136,9 @@ namespace JT1078.Hls /// 创建TS文件信息 /// /// - /// /// - private TsFileInfo CreateTsFileInfo(string key,JT1078Package jt1078Package) { + private TsFileInfo CreateTsFileInfo(string key) + { if (!curTsFileInfoDic.TryGetValue(key, out var curTsFileInfo)) { curTsFileInfo = new TsFileInfo(); @@ -157,41 +160,58 @@ namespace JT1078.Hls } } + ///// + ///// 添加结束标识 + ///// 直播流用不到 + ///// + ///// + ////public void AppendM3U8End() + ////{ + //// StringBuilder sb = new StringBuilder(); + //// sb.AppendLine("#EXT-X-ENDLIST"); //m3u8文件结束符 表示视频已经结束 有这个标志同时也说明当前流是一个非直播流 + //// //#EXT-X-PLAYLIST-TYPE:VOD/Live //VOD表示当前视频流不是一个直播流,而是点播流(也就是视频的全部ts文件已经生成) + ////} + /// - /// 添加结束标识 - /// 直播流用不到 - /// - /// - //public void AppendM3U8End() - //{ - // StringBuilder sb = new StringBuilder(); - // sb.AppendLine("#EXT-X-ENDLIST"); //m3u8文件结束符 表示视频已经结束 有这个标志同时也说明当前流是一个非直播流 - // //#EXT-X-PLAYLIST-TYPE:VOD/Live //VOD表示当前视频流不是一个直播流,而是点播流(也就是视频的全部ts文件已经生成) - //} - } - /// - /// TS文件信息 - /// - public class TsFileInfo { - /// - /// ts文件名 - /// - public string FileName { get; set; } = "0.ts"; - /// - /// 持续时间 - /// - public double Duration { get; set; } = 0; - /// - /// 当前ts文件序号 - /// - public int TsFileSerialNo { get; set; } = 0; - /// - /// 是否创建ts文件 + /// 停止观看直播时清零数据 /// - public bool IsCreateTsFile { get; set; } = true; + /// + /// + public void Clear(string sim,int channelNo) + { + var key = $"{sim}_{channelNo}"; + curTsFileInfoDic.TryRemove(key, out _); + tsFileInfoQueueDic.TryRemove(key, out _); + var directory = Path.Combine(m3U8Option.HlsFileDirectory, key); + if (Directory.Exists(directory)) Directory.Delete(directory); + } + /// - /// ts文件第一个jt1078包的时间戳 + /// TS文件信息 /// - public ulong TsFirst1078PackageTimeStamp { get; set; } = 0; + internal class TsFileInfo + { + /// + /// ts文件名 + /// + public string FileName { get; set; } = "0.ts"; + /// + /// 持续时间 + /// + public double Duration { get; set; } = 0; + /// + /// 当前ts文件序号 + /// + public int TsFileSerialNo { get; set; } = 0; + /// + /// 是否创建ts文件 + /// + public bool IsCreateTsFile { get; set; } = true; + /// + /// ts文件第一个jt1078包的时间戳 + /// + public ulong TsFirst1078PackageTimeStamp { get; set; } = 0; + } } + }