Przeglądaj źródła

修改m3u8的管理

tags/v1.1.0
SmallChi(Koike) 4 lat temu
rodzic
commit
b65e3d5ece
5 zmienionych plików z 95 dodań i 81 usunięć
  1. +1
    -7
      src/JT1078.Flv.Test/JT1078.Flv.Test.csproj
  2. BIN
      src/JT1078.Flv.Test/Libs/libfaac.dll
  3. +1
    -1
      src/JT1078.Flv/FlvEncoder.cs
  4. +1
    -1
      src/JT1078.Flv/JT1078.Flv.csproj
  5. +92
    -72
      src/JT1078.Hls/M3U8FileManage.cs

+ 1
- 7
src/JT1078.Flv.Test/JT1078.Flv.Test.csproj Wyświetl plik

@@ -5,6 +5,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="JT1078.Flv" Version="1.0.0-preview7" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.2">
@@ -16,10 +17,6 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\JT1078.Flv\JT1078.Flv.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="H264\" />
<None Include="..\..\doc\video\jt1078_3.txt" Link="H264\jt1078_3.txt">
@@ -51,9 +48,6 @@
<None Update="H264\JT1078_3.txt">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<None Update="Libs\libfaac.dll">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>

</Project>

BIN
src/JT1078.Flv.Test/Libs/libfaac.dll Wyświetl plik


+ 1
- 1
src/JT1078.Flv/FlvEncoder.cs Wyświetl plik

@@ -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);
}

/// <summary>


+ 1
- 1
src/JT1078.Flv/JT1078.Flv.csproj Wyświetl plik

@@ -14,7 +14,7 @@
<licenseUrl>https://github.com/SmallChi/JT1078/blob/master/LICENSE</licenseUrl>
<license>https://github.com/SmallChi/JT1078/blob/master/LICENSE</license>
<GeneratePackageOnBuild>false</GeneratePackageOnBuild>
<Version>1.0.0-preview6</Version>
<Version>1.0.0-preview7</Version>
<SignAssembly>false</SignAssembly>
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
<PackageLicenseFile>LICENSE</PackageLicenseFile>


+ 92
- 72
src/JT1078.Hls/M3U8FileManage.cs Wyświetl plik

@@ -22,7 +22,6 @@ namespace JT1078.Hls
public readonly M3U8Option m3U8Option;
ConcurrentDictionary<string, TsFileInfo> curTsFileInfoDic = new ConcurrentDictionary<string, TsFileInfo>();//当前文件信息
ConcurrentDictionary<string, Queue<TsFileInfo>> tsFileInfoQueueDic = new ConcurrentDictionary<string, Queue<TsFileInfo>>();
ConcurrentDictionary<string, ulong> TsFirst1078PackageDic = new ConcurrentDictionary<string, ulong>();

public M3U8FileManage(M3U8Option m3U8Option, TSEncoder tSEncoder)
{
@@ -33,46 +32,51 @@ namespace JT1078.Hls
/// 生成ts和m3u8文件
/// </summary>
/// <param name="jt1078Package"></param>
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);
}
}
/// <summary>
@@ -81,7 +85,8 @@ namespace JT1078.Hls
/// <param name="key"></param>
/// <param name="curTsFileInfo"></param>
/// <returns></returns>
private Queue<TsFileInfo> ManageTsFileInfo(string key, TsFileInfo curTsFileInfo) {
private Queue<TsFileInfo> ManageTsFileInfo(string key, TsFileInfo curTsFileInfo)
{
if (tsFileInfoQueueDic.TryGetValue(key, out var tsFileInfoQueue))
{
if (tsFileInfoQueue.Count >= m3U8Option.TsFileCapacity)
@@ -103,12 +108,10 @@ namespace JT1078.Hls
/// <summary>
/// 创建M3U8文件
/// </summary>
/// <param name="key"></param>
/// <param name="curTsFileInfo"></param>
private void CreateM3U8File(string key,TsFileInfo curTsFileInfo, Queue<TsFileInfo> tsFileInfoQueue)
private void CreateM3U8File(TsFileInfo curTsFileInfo, Queue<TsFileInfo> 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文件信息
/// </summary>
/// <param name="key"></param>
/// <param name="jt1078Package"></param>
/// <returns></returns>
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
}
}

///// <summary>
///// 添加结束标识
///// 直播流用不到
///// </summary>
///// <param name="filepath"></param>
////public void AppendM3U8End()
////{
//// StringBuilder sb = new StringBuilder();
//// sb.AppendLine("#EXT-X-ENDLIST"); //m3u8文件结束符 表示视频已经结束 有这个标志同时也说明当前流是一个非直播流
//// //#EXT-X-PLAYLIST-TYPE:VOD/Live //VOD表示当前视频流不是一个直播流,而是点播流(也就是视频的全部ts文件已经生成)
////}

/// <summary>
/// 添加结束标识
/// 直播流用不到
/// </summary>
/// <param name="filepath"></param>
//public void AppendM3U8End()
//{
// StringBuilder sb = new StringBuilder();
// sb.AppendLine("#EXT-X-ENDLIST"); //m3u8文件结束符 表示视频已经结束 有这个标志同时也说明当前流是一个非直播流
// //#EXT-X-PLAYLIST-TYPE:VOD/Live //VOD表示当前视频流不是一个直播流,而是点播流(也就是视频的全部ts文件已经生成)
//}
}
/// <summary>
/// TS文件信息
/// </summary>
public class TsFileInfo {
/// <summary>
/// ts文件名
/// </summary>
public string FileName { get; set; } = "0.ts";
/// <summary>
/// 持续时间
/// </summary>
public double Duration { get; set; } = 0;
/// <summary>
/// 当前ts文件序号
/// </summary>
public int TsFileSerialNo { get; set; } = 0;
/// <summary>
/// 是否创建ts文件
/// 停止观看直播时清零数据
/// </summary>
public bool IsCreateTsFile { get; set; } = true;
/// <param name="sim"></param>
/// <param name="channelNo"></param>
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);
}

/// <summary>
/// ts文件第一个jt1078包的时间戳
/// TS文件信息
/// </summary>
public ulong TsFirst1078PackageTimeStamp { get; set; } = 0;
internal class TsFileInfo
{
/// <summary>
/// ts文件名
/// </summary>
public string FileName { get; set; } = "0.ts";
/// <summary>
/// 持续时间
/// </summary>
public double Duration { get; set; } = 0;
/// <summary>
/// 当前ts文件序号
/// </summary>
public int TsFileSerialNo { get; set; } = 0;
/// <summary>
/// 是否创建ts文件
/// </summary>
public bool IsCreateTsFile { get; set; } = true;
/// <summary>
/// ts文件第一个jt1078包的时间戳
/// </summary>
public ulong TsFirst1078PackageTimeStamp { get; set; } = 0;
}
}

}

Ładowanie…
Anuluj
Zapisz