@@ -2,7 +2,7 @@ | |||||
<PropertyGroup> | <PropertyGroup> | ||||
<OutputType>Exe</OutputType> | <OutputType>Exe</OutputType> | ||||
<TargetFramework>net5.0</TargetFramework> | |||||
<TargetFramework>net6.0</TargetFramework> | |||||
</PropertyGroup> | </PropertyGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
@@ -27,6 +27,7 @@ namespace JT1078.Gateway.TestNormalHosting.Services | |||||
private MessageDispatchDataService messageDispatchDataService; | private MessageDispatchDataService messageDispatchDataService; | ||||
private ConcurrentDictionary<string, List<H264NALU>> avFrameDict; | private ConcurrentDictionary<string, List<H264NALU>> avFrameDict; | ||||
private H264Decoder H264Decoder; | private H264Decoder H264Decoder; | ||||
List<JT1078Package> SegmentPackages = new List<JT1078Package>();// 一段包 以I帧为界 IPPPP , IPPPP 一组 | |||||
public JT1078FMp4NormalMsgHostedService( | public JT1078FMp4NormalMsgHostedService( | ||||
MessageDispatchDataService messageDispatchDataService, | MessageDispatchDataService messageDispatchDataService, | ||||
IMemoryCache memoryCache, | IMemoryCache memoryCache, | ||||
@@ -56,90 +57,56 @@ namespace JT1078.Gateway.TestNormalHosting.Services | |||||
Logger.LogDebug(JsonSerializer.Serialize(HttpSessionManager.GetAll())); | 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()}"); | 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帧) | 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) | catch (Exception ex) | ||||
{ | { | ||||
@@ -54,45 +54,28 @@ namespace JT1078.Gateway.TestNormalHosting.Services | |||||
Logger.LogDebug(JsonSerializer.Serialize(HttpSessionManager.GetAll())); | 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()}"); | 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 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 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 (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) | 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); | var merge = JT1078.Protocol.JT1078Serializer.Merge(package); | ||||
if (merge != null) | 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; | return Task.CompletedTask; | ||||
@@ -14,7 +14,7 @@ | |||||
}, | }, | ||||
"JT1078Configuration": { | "JT1078Configuration": { | ||||
"HttpPort": 15555, | "HttpPort": 15555, | ||||
"TcpPort": 10888 | |||||
"TcpPort": 1078 | |||||
}, | }, | ||||
"M3U8Option": { | "M3U8Option": { | ||||
"TsPathSimParamName": "sim", | "TsPathSimParamName": "sim", | ||||
@@ -0,0 +1,3 @@ | |||||
{ | |||||
"liveServer.settings.port": 5501 | |||||
} |
@@ -15,7 +15,7 @@ | |||||
var flvPlayer = flvjs.createPlayer({ | var flvPlayer = flvjs.createPlayer({ | ||||
type: 'flv', | type: 'flv', | ||||
isLive: true, | 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.attachMediaElement(player); | ||||
flvPlayer.load(); | flvPlayer.load(); | ||||
@@ -166,9 +166,9 @@ | |||||
source_buffer.mode = 'sequence'; | source_buffer.mode = 'sequence'; | ||||
// source_buffer.mode = 'segments'; | // source_buffer.mode = 'segments'; | ||||
source_buffer.addEventListener("updateend", loadPacket); | 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 = new WebSocket("ws://127.0.0.1:81/live/JT1078_8.live.mp4"); //创建WebSocket连接 | ||||
ws.binaryType = 'arraybuffer'; | ws.binaryType = 'arraybuffer'; | ||||
ws.onmessage = function (e) { | ws.onmessage = function (e) { | ||||
@@ -1,7 +1,7 @@ | |||||
<Project Sdk="Microsoft.NET.Sdk"> | <Project Sdk="Microsoft.NET.Sdk"> | ||||
<Import Project="..\Version.props" /> | <Import Project="..\Version.props" /> | ||||
<PropertyGroup> | <PropertyGroup> | ||||
<TargetFrameworks>netstandard2.1;net5.0;</TargetFrameworks> | |||||
<TargetFrameworks>net6.0;</TargetFrameworks> | |||||
<LangVersion>9.0</LangVersion> | <LangVersion>9.0</LangVersion> | ||||
<Copyright>Copyright 2019.</Copyright> | <Copyright>Copyright 2019.</Copyright> | ||||
<Authors>SmallChi(Koike)</Authors> | <Authors>SmallChi(Koike)</Authors> | ||||
@@ -39,11 +39,11 @@ | |||||
</ItemGroup> | </ItemGroup> | ||||
<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> | ||||
<ItemGroup> | <ItemGroup> | ||||