|
|
@@ -26,19 +26,22 @@ namespace JT1078.Gateway.TestNormalHosting.Services |
|
|
|
private const string ikey = "IFMp4KEY"; |
|
|
|
private MessageDispatchDataService messageDispatchDataService; |
|
|
|
private ConcurrentDictionary<string, List<H264NALU>> avFrameDict; |
|
|
|
|
|
|
|
private H264Decoder H264Decoder; |
|
|
|
public JT1078FMp4NormalMsgHostedService( |
|
|
|
MessageDispatchDataService messageDispatchDataService, |
|
|
|
IMemoryCache memoryCache, |
|
|
|
ILoggerFactory loggerFactory, |
|
|
|
FMp4Encoder fM4Encoder, |
|
|
|
H264Decoder h264Decoder, |
|
|
|
JT1078HttpSessionManager httpSessionManager) |
|
|
|
{ |
|
|
|
Logger = loggerFactory.CreateLogger<JT1078FMp4NormalMsgHostedService>(); |
|
|
|
HttpSessionManager = httpSessionManager; |
|
|
|
FM4Encoder = fM4Encoder; |
|
|
|
H264Decoder= h264Decoder; |
|
|
|
this.memoryCache = memoryCache; |
|
|
|
this.messageDispatchDataService = messageDispatchDataService; |
|
|
|
//todo:定时清理 |
|
|
|
avFrameDict = new ConcurrentDictionary<string, List<H264NALU>>(); |
|
|
|
} |
|
|
|
protected async override Task ExecuteAsync(CancellationToken stoppingToken) |
|
|
@@ -46,7 +49,6 @@ namespace JT1078.Gateway.TestNormalHosting.Services |
|
|
|
while (!stoppingToken.IsCancellationRequested) |
|
|
|
{ |
|
|
|
var data = await messageDispatchDataService.FMp4Channel.Reader.ReadAsync(); |
|
|
|
|
|
|
|
try |
|
|
|
{ |
|
|
|
if (Logger.IsEnabled(LogLevel.Debug)) |
|
|
@@ -54,25 +56,31 @@ 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帧) |
|
|
|
{ |
|
|
|
memoryCache.Set(key, data); |
|
|
|
var moovBuffer = FM4Encoder.EncoderMoovBox( |
|
|
|
nalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.SPS), |
|
|
|
nalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.PPS)); |
|
|
|
memoryCache.Set(key, moovBuffer); |
|
|
|
} |
|
|
|
var httpSessions = HttpSessionManager.GetAllBySimAndChannelNo(data.SIM.TrimStart('0'), data.LogicChannelNumber); |
|
|
|
var firstHttpSessions = httpSessions.Where(w => !w.FirstSend).ToList(); |
|
|
|
if (firstHttpSessions.Count > 0) |
|
|
|
//查找第一帧为I帧,否则不推送 |
|
|
|
if (memoryCache.TryGetValue(key, out byte[] moov)) |
|
|
|
{ |
|
|
|
try |
|
|
|
var httpSessions = HttpSessionManager.GetAllBySimAndChannelNo(data.SIM.TrimStart('0'), data.LogicChannelNumber); |
|
|
|
var firstHttpSessions = httpSessions.Where(w => !w.FirstSend).ToList(); |
|
|
|
if (firstHttpSessions.Count > 0) |
|
|
|
{ |
|
|
|
if (memoryCache.TryGetValue(key, out JT1078Package idata)) |
|
|
|
try |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
var ftyp = FM4Encoder.EncoderFtypBox(); |
|
|
|
foreach (var session in firstHttpSessions) |
|
|
|
{ |
|
|
|
var fmp4VideoBuffer = FM4Encoder.EncoderVideo(idata, session.FMp4EncoderInfo, true); |
|
|
|
HttpSessionManager.SendAVData(session, fmp4VideoBuffer, true); |
|
|
|
HttpSessionManager.SendAVData(session, ftyp, true); |
|
|
|
HttpSessionManager.SendAVData(session, moov, false); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Exception ex) |
|
|
@@ -80,26 +88,52 @@ namespace JT1078.Gateway.TestNormalHosting.Services |
|
|
|
Logger.LogError(ex, $"{data.SIM},{true},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
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).ToList(); |
|
|
|
if (otherHttpSessions.Count > 0) |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
foreach (var session in otherHttpSessions) |
|
|
|
catch (Exception ex) |
|
|
|
{ |
|
|
|
var fmp4VideoBuffer = FM4Encoder.EncoderVideo(data, session.FMp4EncoderInfo, false); |
|
|
|
HttpSessionManager.SendAVData(session, fmp4VideoBuffer, false); |
|
|
|
Logger.LogError(ex, $"{data.SIM},{true},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}"); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Exception ex) |
|
|
|
var otherHttpSessions = httpSessions.Where(w => w.FirstSend).ToList(); |
|
|
|
if (otherHttpSessions.Count > 0) |
|
|
|
{ |
|
|
|
Logger.LogError(ex, $"{data.SIM},{false},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}"); |
|
|
|
try |
|
|
|
{ |
|
|
|
var firstNALU = nalus.FirstOrDefault(); |
|
|
|
if (firstNALU == null) |
|
|
|
{ |
|
|
|
continue; |
|
|
|
} |
|
|
|
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.EncoderOtherVideoBox(cacheNALU); |
|
|
|
HttpSessionManager.SendAVData(session, fmp4VideoBuffer, 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()}"); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|