From 01e8ebac237cf0543c0e5c18ff3137b54d380587 Mon Sep 17 00:00:00 2001 From: waterliu99 Date: Thu, 20 Aug 2020 23:54:13 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=B8=80=E4=B8=8Bm3u8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/JT1078.Flv/FlvEncoder.cs | 2 +- src/JT1078.Hls.Test/M3U8_Test.cs | 5 +- src/JT1078.Hls/M3U8FileManage.cs | 109 ++++++++++++--------------- src/JT1078.Hls/Options/M3U8Option.cs | 6 +- src/JT1078.Hls/TSEncoder.cs | 2 +- 5 files changed, 56 insertions(+), 68 deletions(-) diff --git a/src/JT1078.Flv/FlvEncoder.cs b/src/JT1078.Flv/FlvEncoder.cs index 2328dfe..ab933db 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.Hls.Test/M3U8_Test.cs b/src/JT1078.Hls.Test/M3U8_Test.cs index 8d12acf..502be21 100644 --- a/src/JT1078.Hls.Test/M3U8_Test.cs +++ b/src/JT1078.Hls.Test/M3U8_Test.cs @@ -20,9 +20,9 @@ namespace JT1078.Hls.Test { var hls_file_directory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "terminalno"); if (!File.Exists(hls_file_directory)) Directory.CreateDirectory(hls_file_directory); - var m3u8_filepath = Path.Combine(hls_file_directory, "live.m3u8"); + var m3u8_filename = Path.Combine(hls_file_directory, "live.m3u8"); TSEncoder tSEncoder = new TSEncoder(); - var m3u8Manage = new M3U8FileManage(new Options.M3U8Option { HlsFileDirectory = hls_file_directory, M3U8Filepath = m3u8_filepath }, tSEncoder); + var m3u8Manage = new M3U8FileManage(new Options.M3U8Option { HlsFileDirectory = hls_file_directory, M3U8FileName = m3u8_filename }, tSEncoder); var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "JT1078_3.txt")); foreach (var line in lines) @@ -34,7 +34,6 @@ namespace JT1078.Hls.Test if (fullpackage != null) { m3u8Manage.CreateTsData(fullpackage); - m3u8Manage.CreateM3U8File(); } } } diff --git a/src/JT1078.Hls/M3U8FileManage.cs b/src/JT1078.Hls/M3U8FileManage.cs index e0d3552..97e8336 100644 --- a/src/JT1078.Hls/M3U8FileManage.cs +++ b/src/JT1078.Hls/M3U8FileManage.cs @@ -33,25 +33,28 @@ namespace JT1078.Hls } public void CreateTsData(JT1078Package jt1078Package) { + if (!File.Exists(m3U8Option.M3U8FileName)) File.Create(m3U8Option.M3U8FileName);//创建m3u8文件 string tsFileDirectory = m3U8Option.HlsFileDirectory; - string tsNewFileName = $"{m3U8Option.TsFileCount}.ts"; - string fileName= Path.Combine(tsFileDirectory, tsNewFileName); - var buff = TSArrayPool.Rent(jt1078Package.Bodies.Length + 2048); + string tsNewFileName = $"{m3U8Option.TsFileSerialNo}.ts"; + string tsFileName= Path.Combine(tsFileDirectory, tsNewFileName); + var buff = TSArrayPool.Rent(jt1078Package.Bodies.Length + 1024); TSMessagePackWriter tSMessagePackWriter = new TSMessagePackWriter(buff); - if (TsFirst1078PackageDic.TryGetValue(jt1078Package.SIM, out var firstTimespan)) + if (TsFirst1078PackageDic.TryGetValue($"{jt1078Package.SIM}_{jt1078Package.LogicChannelNumber}" , out var firstTimespan)) { - var pes = tSEncoder.CreatePES(jt1078Package, 188); + var pes = tSEncoder.CreatePES(jt1078Package); tSMessagePackWriter.WriteArray(pes); - CreateTsFile(fileName, tSMessagePackWriter.FlushAndGetArray()); + CreateTsFile(tsFileName, tSMessagePackWriter.FlushAndGetArray()); if ((jt1078Package.Timestamp - firstTimespan) > 10 * 1000) { //按设定的时间(默认为10秒)切分ts文件 - TsFirst1078PackageDic.TryRemove(jt1078Package.SIM, out var _); - tsFileInfoQueue.Enqueue(new TsFileInfo { FileName= tsNewFileName, Duration= (jt1078Package.Timestamp - firstTimespan)/1000.0 }); - m3U8Option.TsFileCount++; + TsFirst1078PackageDic.TryRemove($"{jt1078Package.SIM}_{jt1078Package.LogicChannelNumber}", out var _); + var tsFileInfo = new TsFileInfo { FileName = tsNewFileName, Duration = (jt1078Package.Timestamp - firstTimespan) / 1000.0 }; + CreateM3U8File(tsFileInfo); + m3U8Option.TsFileSerialNo++; } } else { + if (File.Exists(tsFileName)) File.Delete(tsFileName); var sdt = tSEncoder.CreateSDT(jt1078Package); tSMessagePackWriter.WriteArray(sdt); var pat = tSEncoder.CreatePAT(jt1078Package); @@ -60,68 +63,54 @@ namespace JT1078.Hls tSMessagePackWriter.WriteArray(pmt); var pes = tSEncoder.CreatePES(jt1078Package); tSMessagePackWriter.WriteArray(pes); - CreateTsFile(fileName, tSMessagePackWriter.FlushAndGetArray()); - TsFirst1078PackageDic.TryAdd(jt1078Package.SIM, jt1078Package.Timestamp); + CreateTsFile(tsFileName, tSMessagePackWriter.FlushAndGetArray()); + TsFirst1078PackageDic.TryAdd($"{jt1078Package.SIM}_{jt1078Package.LogicChannelNumber}", jt1078Package.Timestamp); } } - public void CreateM3U8File() + private void CreateM3U8File(TsFileInfo tsFileInfo) { //ecode_slice_header error 以非关键帧开始的报错信息 - if (tsFileInfoQueue.TryDequeue(out var tsFileInfo)) + string tsFileSerialNo = string.Empty; + StringBuilder sb = new StringBuilder(); + sb.AppendLine("#EXTM3U");//开始 + sb.AppendLine("#EXT-X-VERSION:3");//版本号 + sb.AppendLine("#EXT-X-ALLOW-CACHE:NO");//是否允许cache + sb.AppendLine($"#EXT-X-TARGETDURATION:{m3U8Option.TsFileMaxSecond}");//第一个TS分片的序列号 + sb.AppendLine($"#EXT-X-MEDIA-SEQUENCE:{(m3U8Option.TsFileSerialNo - m3U8Option.TsFileCapacity > 0 ? (m3U8Option.TsFileSerialNo - m3U8Option.TsFileCapacity) : 0)}"); //默认第一个文件为0 + Queue fileBody = new Queue(); + using (FileStream fs = new FileStream(m3U8Option.M3U8FileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + using (StreamReader sr = new StreamReader(fs)) { - string firstTsIndex = string.Empty; - StringBuilder sb = new StringBuilder(); - List fileHeader = new List() { - "#EXTM3U",//开始 - "#EXT-X-VERSION:3",//版本号 - "#EXT-X-ALLOW-CACHE:NO",//是否允许cache - $"#EXT-X-TARGETDURATION:{m3U8Option.TsFileMaxSecond}",//第一个TS分片的序列号 - $"#EXT-X-MEDIA-SEQUENCE:firstTsIndex" - }; - Queue fileBody = new Queue(); - if (!File.Exists(m3U8Option.M3U8Filepath)) File.Create(m3U8Option.M3U8Filepath); - using(FileStream fs=new FileStream(m3U8Option.M3U8Filepath,FileMode.Open,FileAccess.Read,FileShare.ReadWrite)) - using (StreamReader sr = new StreamReader(fs)) + while (!sr.EndOfStream) { - while (!sr.EndOfStream) - { - var text = sr.ReadLine(); - if (text.Length == 0) continue; - if (fileHeader.Contains(text)) continue; - if (text.StartsWith("#EXT-X-MEDIA-SEQUENCE")) continue; - fileBody.Enqueue(text); - } - if (fileBody.Count >= m3U8Option.TsFileCapacity * 2) - { - var deleteTsFileName_extraInfo = fileBody.Dequeue(); - var deleteTsFileName = fileBody.Dequeue(); - tsDelFileNameQueue.Enqueue(deleteTsFileName); - - fileBody.Enqueue($"#EXTINF:{tsFileInfo.Duration},"); - fileBody.Enqueue(tsFileInfo.FileName); - - firstTsIndex = fileBody.ElementAt(1).Replace(".ts", ""); - } - else { - fileBody.Enqueue($"#EXTINF:{tsFileInfo.Duration},"); - fileBody.Enqueue(tsFileInfo.FileName); + var text = sr.ReadLine(); + if (text.Length == 0) continue; + if (sb.ToString().Contains(text.Split(':')[0])) continue; + fileBody.Enqueue(text); + } + if (fileBody.Count >= m3U8Option.TsFileCapacity * 2) + { + var deleteTsFileName_extraInfo = fileBody.Dequeue(); + var deleteTsFileName = fileBody.Dequeue(); + tsDelFileNameQueue.Enqueue(deleteTsFileName); - firstTsIndex = fileBody.ElementAt(1).Replace(".ts", ""); - } - fileHeader.ForEach((m) => { - if (m.Contains("firstTsIndex")) m = m.Replace("firstTsIndex", firstTsIndex); - sb.AppendLine(m); - }); - fileBody.ToList().ForEach(m => { - sb.AppendLine(m); - }); + fileBody.Enqueue($"#EXTINF:{tsFileInfo.Duration},"); + fileBody.Enqueue(tsFileInfo.FileName); } - using (FileStream fs = new FileStream(m3U8Option.M3U8Filepath, FileMode.Create,FileAccess.Write, FileShare.ReadWrite)) - using (StreamWriter sw = new StreamWriter(fs)) + else { - sw.Write(sb.ToString()); + fileBody.Enqueue($"#EXTINF:{tsFileInfo.Duration},"); + fileBody.Enqueue(tsFileInfo.FileName); } + fileBody.ToList().ForEach(m => { + sb.AppendLine(m); + }); + } + using (FileStream fs = new FileStream(m3U8Option.M3U8FileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) + using (StreamWriter sw = new StreamWriter(fs)) + { + sw.Write(sb.ToString()); } } diff --git a/src/JT1078.Hls/Options/M3U8Option.cs b/src/JT1078.Hls/Options/M3U8Option.cs index 131edb7..3d67e51 100644 --- a/src/JT1078.Hls/Options/M3U8Option.cs +++ b/src/JT1078.Hls/Options/M3U8Option.cs @@ -18,13 +18,13 @@ namespace JT1078.Hls.Options /// public int TsFileMaxSecond { get; set; } = 10; /// - /// ts文件个数 + /// 当前ts文件序号 /// - public int TsFileCount { get; set; } = 0; + public int TsFileSerialNo { get; set; } = 0; /// /// m3u8文件 /// - public string M3U8Filepath { get; set; } + public string M3U8FileName { get; set; } /// /// hls文件路径 /// diff --git a/src/JT1078.Hls/TSEncoder.cs b/src/JT1078.Hls/TSEncoder.cs index 8104cb0..5c73e4a 100644 --- a/src/JT1078.Hls/TSEncoder.cs +++ b/src/JT1078.Hls/TSEncoder.cs @@ -139,7 +139,7 @@ namespace JT1078.Hls TSArrayPool.Return(buffer); } } - public byte[] CreatePES(JT1078Package jt1078Package, int minBufferSize = 188) + public byte[] CreatePES(JT1078Package jt1078Package, int minBufferSize = 1024) { //将1078一帧的数据拆分成一小段一小段的PES包 byte[] buffer = TSArrayPool.Rent(jt1078Package.Bodies.Length + minBufferSize);