@@ -2,7 +2,7 @@ | |||
<PropertyGroup> | |||
<OutputType>Exe</OutputType> | |||
<TargetFramework>net5.0</TargetFramework> | |||
<TargetFramework>net6.0</TargetFramework> | |||
</PropertyGroup> | |||
<ItemGroup> | |||
@@ -27,6 +27,7 @@ namespace JT1078.Gateway.TestNormalHosting.Services | |||
private MessageDispatchDataService messageDispatchDataService; | |||
private ConcurrentDictionary<string, List<H264NALU>> avFrameDict; | |||
private H264Decoder H264Decoder; | |||
List<JT1078Package> SegmentPackages = new List<JT1078Package>();// 一段包 以I帧为界 IPPPP , IPPPP 一组 | |||
public JT1078FMp4NormalMsgHostedService( | |||
MessageDispatchDataService messageDispatchDataService, | |||
IMemoryCache memoryCache, | |||
@@ -56,90 +57,56 @@ namespace JT1078.Gateway.TestNormalHosting.Services | |||
Logger.LogDebug(JsonSerializer.Serialize(HttpSessionManager.GetAll())); | |||
Logger.LogDebug($"{data.SIM},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}"); | |||
} | |||
var nalus = H264Decoder.ParseNALU(data); | |||
string key = $"{data.GetKey()}_{ikey}"; | |||
if (data.Label3.DataType == Protocol.Enums.JT1078DataType.视频I帧) | |||
{ | |||
var moovBuffer = FM4Encoder.VideoMoovBox( | |||
nalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.SPS), | |||
nalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.PPS)); | |||
memoryCache.Set(key, moovBuffer); | |||
} | |||
//查找第一帧为I帧,否则不推送 | |||
if (memoryCache.TryGetValue(key, out byte[] moov)) | |||
{ | |||
var httpSessions = HttpSessionManager.GetAllBySimAndChannelNo(data.SIM.TrimStart('0'), data.LogicChannelNumber); | |||
var firstHttpSessions = httpSessions.Where(w => !w.FirstSend && (w.RTPVideoType == Metadata.RTPVideoType.Http_FMp4 || w.RTPVideoType == Metadata.RTPVideoType.Ws_FMp4)).ToList(); | |||
if (firstHttpSessions.Count > 0) | |||
if (SegmentPackages.Count>0) | |||
{ | |||
try | |||
//判断是否首帧 | |||
//Logger.LogDebug($"时间1:{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss ffff")}"); | |||
var httpSessions = HttpSessionManager.GetAllBySimAndChannelNo(data.SIM.TrimStart('0'), data.LogicChannelNumber); | |||
var firstHttpSessions = httpSessions.Where(w => !w.FirstSend && (w.RTPVideoType == Metadata.RTPVideoType.Http_FMp4 || w.RTPVideoType == Metadata.RTPVideoType.Ws_FMp4)).ToList(); | |||
var otherHttpSessions = httpSessions.Where(w => w.FirstSend && (w.RTPVideoType == Metadata.RTPVideoType.Http_FMp4 || w.RTPVideoType == Metadata.RTPVideoType.Ws_FMp4)).ToList(); | |||
if (firstHttpSessions.Count > 0) | |||
{ | |||
try | |||
{ | |||
var ftyp = FM4Encoder.FtypBox(); | |||
foreach (var session in firstHttpSessions) | |||
{ | |||
HttpSessionManager.SendAVData(session, ftyp.Concat(moov).ToArray(), true); | |||
} | |||
} | |||
catch (Exception ex) | |||
//唯一 | |||
var ftyp = FM4Encoder.FtypBox(); | |||
var package1 = SegmentPackages[0]; | |||
var nalus1 = H264Decoder.ParseNALU(package1); | |||
var moov = FM4Encoder.MoovBox( | |||
nalus1.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.SPS), | |||
nalus1.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.PPS)); | |||
//首帧 | |||
var styp = FM4Encoder.StypBox(); | |||
var firstVideo = FM4Encoder.OtherVideoBox(SegmentPackages); | |||
foreach (var session in firstHttpSessions) | |||
{ | |||
Logger.LogError(ex, $"{data.SIM},{true},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}"); | |||
HttpSessionManager.SendAVData(session, ftyp.Concat(moov).Concat(styp).Concat(firstVideo).ToArray(), true); | |||
SegmentPackages.Clear();//发送完成后清理 | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
Logger.LogError(ex, $"{data.SIM},{true},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}"); | |||
} | |||
} | |||
var otherHttpSessions = httpSessions.Where(w => w.FirstSend && (w.RTPVideoType == Metadata.RTPVideoType.Http_FMp4 || w.RTPVideoType == Metadata.RTPVideoType.Ws_FMp4)).ToList(); | |||
if (otherHttpSessions.Count > 0) | |||
{ | |||
try | |||
if (otherHttpSessions.Count > 0) | |||
{ | |||
//foreach (var session in otherHttpSessions) | |||
//{ | |||
// var fmp4VideoBuffer = FM4Encoder.OtherVideoBox(nalus); | |||
// HttpSessionManager.SendAVData(session, FM4Encoder.StypBox().Concat(fmp4VideoBuffer).ToArray(), false); | |||
//} | |||
var firstNALU = nalus.FirstOrDefault(); | |||
if (firstNALU == null) | |||
//非首帧 | |||
var styp = FM4Encoder.StypBox(); | |||
var otherVideo = FM4Encoder.OtherVideoBox(SegmentPackages); | |||
foreach (var session in otherHttpSessions) | |||
{ | |||
continue; | |||
HttpSessionManager.SendAVData(session, styp.Concat(otherVideo).ToArray(), false); | |||
SegmentPackages.Clear();//发送完成后清理 | |||
} | |||
if (!avFrameDict.TryGetValue(firstNALU.GetKey(), out List<H264NALU> cacheNALU)) | |||
{ | |||
cacheNALU = new List<H264NALU>(); | |||
avFrameDict.TryAdd(firstNALU.GetKey(), cacheNALU); | |||
} | |||
foreach (var nalu in nalus) | |||
{ | |||
if (nalu.Slice) | |||
{ | |||
//H264 NALU slice first_mb_in_slice | |||
cacheNALU.Add(nalu); | |||
} | |||
else | |||
{ | |||
if (cacheNALU.Count > 0) | |||
{ | |||
foreach (var session in otherHttpSessions) | |||
{ | |||
var fmp4VideoBuffer = FM4Encoder.OtherVideoBox(cacheNALU); | |||
HttpSessionManager.SendAVData(session, FM4Encoder.StypBox().Concat(fmp4VideoBuffer).ToArray(), false); | |||
} | |||
cacheNALU.Clear(); | |||
} | |||
cacheNALU.Add(nalu); | |||
} | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
Logger.LogError(ex, $"{data.SIM},{false},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}"); | |||
} | |||
} | |||
if (SegmentPackages.Count==0) | |||
SegmentPackages.Add(data); | |||
} | |||
else { | |||
if (SegmentPackages.Count!=0) { | |||
SegmentPackages.Add(data); | |||
} | |||
} | |||
} | |||
catch (Exception ex) | |||
{ | |||
@@ -54,45 +54,28 @@ namespace JT1078.Gateway.TestNormalHosting.Services | |||
Logger.LogDebug(JsonSerializer.Serialize(HttpSessionManager.GetAll())); | |||
Logger.LogDebug($"{data.SIM},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}"); | |||
} | |||
string key = $"{data.GetKey()}_{ikey}"; | |||
if (data.Label3.DataType == Protocol.Enums.JT1078DataType.视频I帧) | |||
{ | |||
memoryCache.Set(key, data); | |||
} | |||
var httpSessions = HttpSessionManager.GetAllBySimAndChannelNo(data.SIM.TrimStart('0'), data.LogicChannelNumber); | |||
var firstHttpSessions = httpSessions.Where(w => !w.FirstSend && (w.RTPVideoType== Metadata.RTPVideoType.Http_Flv || w.RTPVideoType == Metadata.RTPVideoType.Ws_Flv)).ToList(); | |||
var otherHttpSessions = httpSessions.Where(w => w.FirstSend && (w.RTPVideoType == Metadata.RTPVideoType.Http_Flv || w.RTPVideoType == Metadata.RTPVideoType.Ws_Flv)).ToList(); | |||
if (firstHttpSessions.Count > 0) | |||
{ | |||
if (memoryCache.TryGetValue(key, out JT1078Package idata)) | |||
if (data.Label3.DataType == Protocol.Enums.JT1078DataType.视频I帧) | |||
{ | |||
try | |||
{ | |||
var flvVideoBuffer = FlvEncoder.EncoderVideoTag(idata, true); | |||
foreach (var session in firstHttpSessions) | |||
{ | |||
HttpSessionManager.SendAVData(session, flvVideoBuffer, true); | |||
} | |||
} | |||
catch (Exception ex) | |||
var flvVideoBuffer = FlvEncoder.EncoderVideoTag(data, true); | |||
foreach (var session in firstHttpSessions) | |||
{ | |||
Logger.LogError(ex, $"{data.SIM},{true},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}"); | |||
HttpSessionManager.SendAVData(session, flvVideoBuffer, true); | |||
} | |||
} | |||
} | |||
var otherHttpSessions = httpSessions.Where(w => w.FirstSend && (w.RTPVideoType == Metadata.RTPVideoType.Http_Flv || w.RTPVideoType == Metadata.RTPVideoType.Ws_Flv)).ToList(); | |||
if (otherHttpSessions.Count > 0) | |||
{ | |||
try | |||
{ | |||
var flvVideoBuffer = FlvEncoder.EncoderVideoTag(data, false); | |||
foreach (var session in otherHttpSessions) | |||
{ | |||
HttpSessionManager.SendAVData(session, flvVideoBuffer, false); | |||
} | |||
} | |||
catch (Exception ex) | |||
var flvVideoBuffer = FlvEncoder.EncoderVideoTag(data, false); | |||
foreach (var session in otherHttpSessions) | |||
{ | |||
Logger.LogError(ex, $"{data.SIM},{false},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}"); | |||
HttpSessionManager.SendAVData(session, flvVideoBuffer, false); | |||
} | |||
} | |||
} | |||
@@ -33,9 +33,16 @@ namespace JT1078.Gateway.TestNormalHosting.Services | |||
var merge = JT1078.Protocol.JT1078Serializer.Merge(package); | |||
if (merge != null) | |||
{ | |||
await messageDispatchDataService.HlsChannel.Writer.WriteAsync(merge, stoppingToken); | |||
await messageDispatchDataService.FlvChannel.Writer.WriteAsync(merge, stoppingToken); | |||
await messageDispatchDataService.FMp4Channel.Writer.WriteAsync(merge, stoppingToken); | |||
Parallel.Invoke( | |||
async() => { | |||
await messageDispatchDataService.FMp4Channel.Writer.WriteAsync(merge, stoppingToken); | |||
}, | |||
async () => { | |||
await messageDispatchDataService.FlvChannel.Writer.WriteAsync(merge, stoppingToken); | |||
}, | |||
async () => { | |||
await messageDispatchDataService.HlsChannel.Writer.WriteAsync(merge, stoppingToken); | |||
}); | |||
} | |||
}); | |||
return Task.CompletedTask; | |||
@@ -14,7 +14,7 @@ | |||
}, | |||
"JT1078Configuration": { | |||
"HttpPort": 15555, | |||
"TcpPort": 10888 | |||
"TcpPort": 1078 | |||
}, | |||
"M3U8Option": { | |||
"TsPathSimParamName": "sim", | |||
@@ -0,0 +1,3 @@ | |||
{ | |||
"liveServer.settings.port": 5501 | |||
} |
@@ -15,7 +15,7 @@ | |||
var flvPlayer = flvjs.createPlayer({ | |||
type: 'flv', | |||
isLive: true, | |||
url: "http://127.0.0.1:15555/live.flv?sim=19019000001&channel=3&token=123456" | |||
url: "http://49.235.89.102:15555/live.flv?sim=40281815788&channel=1&token=123456" | |||
}); | |||
flvPlayer.attachMediaElement(player); | |||
flvPlayer.load(); | |||
@@ -166,9 +166,9 @@ | |||
source_buffer.mode = 'sequence'; | |||
// source_buffer.mode = 'segments'; | |||
source_buffer.addEventListener("updateend", loadPacket); | |||
//ws = new WebSocket("ws://49.235.89.102:15555/live.mp4?sim=19019000001&channel=3&token=123456"); | |||
ws = new WebSocket("ws://49.235.89.102:15555/live.mp4?sim=40281815788&channel=1&token=123456"); | |||
ws = new WebSocket("ws://49.235.89.102:15555/live.mp4?sim=1901305037&channel=2&token=123456"); | |||
//ws = new WebSocket("ws://49.235.89.102:15555/live.mp4?sim=1901305037&channel=2&token=123456"); | |||
//ws = new WebSocket("ws://127.0.0.1:81/live/JT1078_8.live.mp4"); //创建WebSocket连接 | |||
ws.binaryType = 'arraybuffer'; | |||
ws.onmessage = function (e) { | |||
@@ -1,7 +1,7 @@ | |||
<Project Sdk="Microsoft.NET.Sdk"> | |||
<Import Project="..\Version.props" /> | |||
<PropertyGroup> | |||
<TargetFrameworks>netstandard2.1;net5.0;</TargetFrameworks> | |||
<TargetFrameworks>net6.0;</TargetFrameworks> | |||
<LangVersion>9.0</LangVersion> | |||
<Copyright>Copyright 2019.</Copyright> | |||
<Authors>SmallChi(Koike)</Authors> | |||
@@ -39,11 +39,11 @@ | |||
</ItemGroup> | |||
<ItemGroup> | |||
<PackageReference Include="JT1078.Hls" Version="1.1.0-preview4" /> | |||
<PackageReference Include="JT1078.FMp4" Version="1.0.0-preview5" /> | |||
<PackageReference Include="JT1078.Flv" Version="1.1.1-preview1" /> | |||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="5.0.0" /> | |||
<PackageReference Include="System.IO.Pipelines" Version="5.0.1" /> | |||
<PackageReference Include="JT1078.Hls" Version="1.2.0-preview1" /> | |||
<PackageReference Include="JT1078.FMp4" Version="1.2.0-preview1" /> | |||
<PackageReference Include="JT1078.Flv" Version="1.2.0-preview1" /> | |||
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="6.0.0" /> | |||
<PackageReference Include="System.IO.Pipelines" Version="6.0.1" /> | |||
</ItemGroup> | |||
<ItemGroup> | |||