@@ -0,0 +1,2 @@ | |||||
[Settings] | |||||
language=Chinese |
@@ -43,4 +43,10 @@ | |||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | <CopyToOutputDirectory>Always</CopyToOutputDirectory> | ||||
</None> | </None> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | |||||
<None Update="H264\1078视频数据.txt"> | |||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory> | |||||
</None> | |||||
</ItemGroup> | |||||
</Project> | </Project> |
@@ -5,11 +5,45 @@ using System.IO; | |||||
using System.Text; | using System.Text; | ||||
using Xunit; | using Xunit; | ||||
using JT1078.Protocol.Extensions; | using JT1078.Protocol.Extensions; | ||||
using Microsoft.VisualStudio.TestPlatform.CommunicationUtilities; | |||||
using System.Net.Sockets; | |||||
using System.Threading; | |||||
namespace JT1078.Hls.Test | namespace JT1078.Hls.Test | ||||
{ | { | ||||
public class M3U8_Test | public class M3U8_Test | ||||
{ | { | ||||
/// <summary> | |||||
/// 模拟发送视频数据 | |||||
/// </summary> | |||||
[Fact] | |||||
public void Test1() | |||||
{ | |||||
try | |||||
{ | |||||
var lines = File.ReadAllLines(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "H264", "1078视频数据.txt")); | |||||
Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); | |||||
clientSocket.Connect("127.0.0.1",1078); | |||||
long lasttime = 0; | |||||
foreach (var line in lines) | |||||
{ | |||||
var temp = line.Split(','); | |||||
if (lasttime == 0) | |||||
{ | |||||
lasttime = long.Parse(temp[0]); | |||||
} | |||||
else { | |||||
Thread.Sleep(TimeSpan.FromSeconds(long.Parse(temp[0]) - lasttime)); | |||||
lasttime = long.Parse(temp[0]); | |||||
} | |||||
var data= temp[1].ToHexBytes(); | |||||
clientSocket.Send(data); | |||||
} | |||||
} | |||||
catch (Exception ex) | |||||
{ | |||||
//Assert.Throws<Exception>(() => { }); | |||||
} | |||||
} | |||||
/// <summary> | /// <summary> | ||||
/// 生成m3u8索引文件 | /// 生成m3u8索引文件 | ||||
/// </summary> | /// </summary> | ||||
@@ -14,7 +14,7 @@ | |||||
<licenseUrl>https://github.com/SmallChi/JT1078/blob/master/LICENSE</licenseUrl> | <licenseUrl>https://github.com/SmallChi/JT1078/blob/master/LICENSE</licenseUrl> | ||||
<license>https://github.com/SmallChi/JT1078/blob/master/LICENSE</license> | <license>https://github.com/SmallChi/JT1078/blob/master/LICENSE</license> | ||||
<GeneratePackageOnBuild>false</GeneratePackageOnBuild> | <GeneratePackageOnBuild>false</GeneratePackageOnBuild> | ||||
<Version>1.1.0-preview1</Version> | |||||
<Version>1.1.0.0</Version> | |||||
<SignAssembly>false</SignAssembly> | <SignAssembly>false</SignAssembly> | ||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> | <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> | ||||
<PackageLicenseFile>LICENSE</PackageLicenseFile> | <PackageLicenseFile>LICENSE</PackageLicenseFile> | ||||
@@ -24,10 +24,6 @@ | |||||
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' "> | <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' "> | ||||
<PackageReference Include="System.Memory" Version="4.5.4" /> | <PackageReference Include="System.Memory" Version="4.5.4" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | |||||
<ProjectReference Include="..\JT1078.Protocol\JT1078.Protocol.csproj" /> | |||||
</ItemGroup> | |||||
<ItemGroup> | <ItemGroup> | ||||
<None Include="..\..\LICENSE"> | <None Include="..\..\LICENSE"> | ||||
<Pack>True</Pack> | <Pack>True</Pack> | ||||
@@ -37,4 +33,7 @@ | |||||
<ItemGroup> | <ItemGroup> | ||||
<PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" /> | <PackageReference Include="System.Text.Encoding.CodePages" Version="5.0.0" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | |||||
<ProjectReference Include="..\JT1078.Protocol\JT1078.Protocol.csproj" /> | |||||
</ItemGroup> | |||||
</Project> | </Project> |
@@ -144,6 +144,16 @@ | |||||
TS文件信息 | TS文件信息 | ||||
</summary> | </summary> | ||||
</member> | </member> | ||||
<member name="P:JT1078.Hls.M3U8FileManage.TsFileInfo.Sim"> | |||||
<summary> | |||||
设备手机号 | |||||
</summary> | |||||
</member> | |||||
<member name="P:JT1078.Hls.M3U8FileManage.TsFileInfo.ChannelNo"> | |||||
<summary> | |||||
设备逻辑通道号 | |||||
</summary> | |||||
</member> | |||||
<member name="P:JT1078.Hls.M3U8FileManage.TsFileInfo.FileName"> | <member name="P:JT1078.Hls.M3U8FileManage.TsFileInfo.FileName"> | ||||
<summary> | <summary> | ||||
ts文件名 | ts文件名 | ||||
@@ -37,7 +37,6 @@ namespace JT1078.Hls | |||||
string key = jt1078Package.GetKey(); | string key = jt1078Package.GetKey(); | ||||
string hlsFileDirectory = m3U8Option.HlsFileDirectory; | string hlsFileDirectory = m3U8Option.HlsFileDirectory; | ||||
string m3u8FileName = Path.Combine(hlsFileDirectory, key, m3U8Option.M3U8FileName); | string m3u8FileName = Path.Combine(hlsFileDirectory, key, m3U8Option.M3U8FileName); | ||||
if (!File.Exists(m3u8FileName)) File.Create(m3u8FileName);//创建m3u8文件 | |||||
var buff = TSArrayPool.Rent(jt1078Package.Bodies.Length + 1024); | var buff = TSArrayPool.Rent(jt1078Package.Bodies.Length + 1024); | ||||
TSMessagePackWriter tSMessagePackWriter = new TSMessagePackWriter(buff); | TSMessagePackWriter tSMessagePackWriter = new TSMessagePackWriter(buff); | ||||
try | try | ||||
@@ -50,7 +49,7 @@ namespace JT1078.Hls | |||||
CreateTsFile(curTsFileInfo.FileName,key, tSMessagePackWriter.FlushAndGetArray()); | CreateTsFile(curTsFileInfo.FileName,key, tSMessagePackWriter.FlushAndGetArray()); | ||||
curTsFileInfo.Duration = (jt1078Package.Timestamp - curTsFileInfo.TsFirst1078PackageTimeStamp) / 1000.0; | curTsFileInfo.Duration = (jt1078Package.Timestamp - curTsFileInfo.TsFirst1078PackageTimeStamp) / 1000.0; | ||||
//按设定的时间(默认为10秒)切分ts文件 | //按设定的时间(默认为10秒)切分ts文件 | ||||
if (curTsFileInfo.Duration > m3U8Option.TsFileMaxSecond) | |||||
if (curTsFileInfo.Duration > (m3U8Option.TsFileMaxSecond-1)) | |||||
{ | { | ||||
var tsFileInfoQueue = ManageTsFileInfo(key, curTsFileInfo); | var tsFileInfoQueue = ManageTsFileInfo(key, curTsFileInfo); | ||||
CreateM3U8File(curTsFileInfo, tsFileInfoQueue); | CreateM3U8File(curTsFileInfo, tsFileInfoQueue); | ||||
@@ -92,7 +91,7 @@ namespace JT1078.Hls | |||||
if (tsFileInfoQueue.Count >= m3U8Option.TsFileCapacity) | if (tsFileInfoQueue.Count >= m3U8Option.TsFileCapacity) | ||||
{ | { | ||||
var deleteTsFileInfo = tsFileInfoQueue.Dequeue(); | var deleteTsFileInfo = tsFileInfoQueue.Dequeue(); | ||||
var deleteTsFileName = Path.Combine(m3U8Option.HlsFileDirectory, deleteTsFileInfo.FileName); | |||||
var deleteTsFileName = Path.Combine(m3U8Option.HlsFileDirectory, key, deleteTsFileInfo.FileName); | |||||
if (File.Exists(deleteTsFileName)) File.Delete(deleteTsFileName); | if (File.Exists(deleteTsFileName)) File.Delete(deleteTsFileName); | ||||
} | } | ||||
tsFileInfoQueue.Enqueue(curTsFileInfo); | tsFileInfoQueue.Enqueue(curTsFileInfo); | ||||
@@ -124,9 +123,10 @@ namespace JT1078.Hls | |||||
{ | { | ||||
var tsFileInfo = tsFileInfoQueue.ElementAt(i); | var tsFileInfo = tsFileInfoQueue.ElementAt(i); | ||||
sb.AppendLine($"#EXTINF:{tsFileInfo.Duration},"); | sb.AppendLine($"#EXTINF:{tsFileInfo.Duration},"); | ||||
sb.AppendLine(tsFileInfo.FileName); | |||||
sb.AppendLine($"{tsFileInfo.FileName}?sim={tsFileInfo.Sim}&channelNo={tsFileInfo.ChannelNo}"); | |||||
} | } | ||||
using (FileStream fs = new FileStream(m3U8Option.M3U8FileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) | |||||
string m3u8FileName = Path.Combine(m3U8Option.HlsFileDirectory,$"{curTsFileInfo.Sim}_{curTsFileInfo.ChannelNo}", m3U8Option.M3U8FileName); | |||||
using (FileStream fs = new FileStream(m3u8FileName, FileMode.Create, FileAccess.Write, FileShare.ReadWrite)) | |||||
{ | { | ||||
var buffer = Encoding.UTF8.GetBytes(sb.ToString()); | var buffer = Encoding.UTF8.GetBytes(sb.ToString()); | ||||
fs.Write(buffer,0, buffer.Length); | fs.Write(buffer,0, buffer.Length); | ||||
@@ -142,9 +142,17 @@ namespace JT1078.Hls | |||||
{ | { | ||||
if (!curTsFileInfoDic.TryGetValue(key, out var curTsFileInfo)) | if (!curTsFileInfoDic.TryGetValue(key, out var curTsFileInfo)) | ||||
{ | { | ||||
curTsFileInfo = new TsFileInfo(); | |||||
curTsFileInfo = new TsFileInfo() | |||||
{ | |||||
Sim = key.Split('_')[0], | |||||
ChannelNo = key.Split('_')[1] | |||||
}; | |||||
curTsFileInfoDic.TryAdd(key, curTsFileInfo); | curTsFileInfoDic.TryAdd(key, curTsFileInfo); | ||||
} | } | ||||
else { | |||||
curTsFileInfo.Sim = key.Split('_')[0]; | |||||
curTsFileInfo.ChannelNo = key.Split('_')[1]; | |||||
} | |||||
return curTsFileInfo; | return curTsFileInfo; | ||||
} | } | ||||
/// <summary> | /// <summary> | ||||
@@ -193,6 +201,14 @@ namespace JT1078.Hls | |||||
/// </summary> | /// </summary> | ||||
internal class TsFileInfo | internal class TsFileInfo | ||||
{ | { | ||||
/// <summary> | |||||
/// 设备手机号 | |||||
/// </summary> | |||||
public string Sim { get; set; } | |||||
/// <summary> | |||||
/// 设备逻辑通道号 | |||||
/// </summary> | |||||
public string ChannelNo { get; set; } | |||||
/// <summary> | /// <summary> | ||||
/// ts文件名 | /// ts文件名 | ||||
/// </summary> | /// </summary> | ||||
@@ -24,6 +24,6 @@ namespace JT1078.Hls.Options | |||||
/// <summary> | /// <summary> | ||||
/// hls文件路径(包括m3u8路径,ts路径) | /// hls文件路径(包括m3u8路径,ts路径) | ||||
/// </summary> | /// </summary> | ||||
public string HlsFileDirectory { get; set; } | |||||
public string HlsFileDirectory { get; set; } = "wwwroot"; | |||||
} | } | ||||
} | } |