diff --git a/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/Program.cs b/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/Program.cs index 0399646..61fd6fb 100644 --- a/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/Program.cs +++ b/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/Program.cs @@ -41,6 +41,8 @@ namespace JT1078.Gateway.TestNormalHosting services.AddSingleton(); //hls视频解码器 services.AddSingleton(); + //h264 + services.AddSingleton(); services.AddSingleton(); //添加hls依赖项 services.AddHlsGateway(hostContext.Configuration); diff --git a/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/Services/JT1078FMp4NormalMsgHostedService.cs b/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/Services/JT1078FMp4NormalMsgHostedService.cs index 9ad8395..93921b9 100644 --- a/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/Services/JT1078FMp4NormalMsgHostedService.cs +++ b/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/Services/JT1078FMp4NormalMsgHostedService.cs @@ -26,19 +26,22 @@ namespace JT1078.Gateway.TestNormalHosting.Services private const string ikey = "IFMp4KEY"; private MessageDispatchDataService messageDispatchDataService; private ConcurrentDictionary> avFrameDict; - + private H264Decoder H264Decoder; public JT1078FMp4NormalMsgHostedService( MessageDispatchDataService messageDispatchDataService, IMemoryCache memoryCache, ILoggerFactory loggerFactory, FMp4Encoder fM4Encoder, + H264Decoder h264Decoder, JT1078HttpSessionManager httpSessionManager) { Logger = loggerFactory.CreateLogger(); HttpSessionManager = httpSessionManager; FM4Encoder = fM4Encoder; + H264Decoder= h264Decoder; this.memoryCache = memoryCache; this.messageDispatchDataService = messageDispatchDataService; + //todo:定时清理 avFrameDict = new ConcurrentDictionary>(); } 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 cacheNALU)) + { + cacheNALU = new List(); + 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()}"); + } } } } diff --git a/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/Services/MessageDispatchHostedService.cs b/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/Services/MessageDispatchHostedService.cs index 96acf3c..01cd2fd 100644 --- a/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/Services/MessageDispatchHostedService.cs +++ b/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/Services/MessageDispatchHostedService.cs @@ -33,8 +33,8 @@ 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.HlsChannel.Writer.WriteAsync(merge, stoppingToken); + //await messageDispatchDataService.FlvChannel.Writer.WriteAsync(merge, stoppingToken); await messageDispatchDataService.FMp4Channel.Writer.WriteAsync(merge, stoppingToken); } }); diff --git a/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/appsettings.json b/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/appsettings.json index b2125e2..8b0f2a9 100644 --- a/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/appsettings.json +++ b/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/appsettings.json @@ -13,7 +13,8 @@ } }, "JT1078Configuration": { - "HttpPort": 15555 + "HttpPort": 15555, + "TcpPort": 10888 }, "M3U8Option": { "TsPathSimParamName": "sim", diff --git a/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/wwwroot/fmp4_demo/index.html b/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/wwwroot/fmp4_demo/index.html index 1b65ae8..5ee0609 100644 --- a/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/wwwroot/fmp4_demo/index.html +++ b/src/JT1078.Gateway.Tests/JT1078.Gateway.TestNormalHosting/wwwroot/fmp4_demo/index.html @@ -172,8 +172,9 @@ ws.binaryType = 'arraybuffer'; ws.onmessage = function (e) { //当客户端收到服务端发来的消息时,触发onmessage事件,参数e.data包含server传递过来的数据 - console.log(e.data); - putPacket(e.data); + //console.log(e.data); + //putPacket(e.data); + source_buffer.appendBuffer(e.data); } } diff --git a/src/JT1078.Gateway/JT1078.Gateway.csproj b/src/JT1078.Gateway/JT1078.Gateway.csproj index 68dc127..0f16094 100644 --- a/src/JT1078.Gateway/JT1078.Gateway.csproj +++ b/src/JT1078.Gateway/JT1078.Gateway.csproj @@ -39,8 +39,8 @@ - + diff --git a/src/JT1078.Gateway/JT1078.Gateway.xml b/src/JT1078.Gateway/JT1078.Gateway.xml index fcc5020..611ad76 100644 --- a/src/JT1078.Gateway/JT1078.Gateway.xml +++ b/src/JT1078.Gateway/JT1078.Gateway.xml @@ -195,11 +195,6 @@ 会话Id - - - FMp4编码信息 - - http上下文 diff --git a/src/JT1078.Gateway/Metadata/JT1078HttpContext.cs b/src/JT1078.Gateway/Metadata/JT1078HttpContext.cs index eb4d597..729e9ad 100644 --- a/src/JT1078.Gateway/Metadata/JT1078HttpContext.cs +++ b/src/JT1078.Gateway/Metadata/JT1078HttpContext.cs @@ -19,10 +19,6 @@ namespace JT1078.Gateway.Metadata /// public string SessionId { get; } /// - /// FMp4编码信息 - /// - public FMp4EncoderInfo FMp4EncoderInfo { get; set; } = new FMp4EncoderInfo(); - /// /// http上下文 /// [JsonIgnore]