You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

150 line
7.4 KiB

  1. using JT1078.Gateway.Sessions;
  2. using Microsoft.Extensions.Hosting;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Threading;
  6. using System.Threading.Tasks;
  7. using System.Linq;
  8. using Microsoft.Extensions.Logging;
  9. using Microsoft.Extensions.Caching.Memory;
  10. using JT1078.Protocol;
  11. using System.Text.Json;
  12. using JT1078.Protocol.H264;
  13. using System.Collections.Concurrent;
  14. using JT1078.FMp4;
  15. using JT1078.Protocol.Extensions;
  16. using System.IO;
  17. namespace JT1078.Gateway.TestNormalHosting.Services
  18. {
  19. public class JT1078FMp4NormalMsgHostedService : BackgroundService
  20. {
  21. private JT1078HttpSessionManager HttpSessionManager;
  22. private FMp4Encoder FM4Encoder;
  23. private ILogger Logger;
  24. private IMemoryCache memoryCache;
  25. private const string ikey = "IFMp4KEY";
  26. private MessageDispatchDataService messageDispatchDataService;
  27. private ConcurrentDictionary<string, List<H264NALU>> avFrameDict;
  28. private H264Decoder H264Decoder;
  29. public JT1078FMp4NormalMsgHostedService(
  30. MessageDispatchDataService messageDispatchDataService,
  31. IMemoryCache memoryCache,
  32. ILoggerFactory loggerFactory,
  33. FMp4Encoder fM4Encoder,
  34. H264Decoder h264Decoder,
  35. JT1078HttpSessionManager httpSessionManager)
  36. {
  37. Logger = loggerFactory.CreateLogger<JT1078FMp4NormalMsgHostedService>();
  38. HttpSessionManager = httpSessionManager;
  39. FM4Encoder = fM4Encoder;
  40. H264Decoder= h264Decoder;
  41. this.memoryCache = memoryCache;
  42. this.messageDispatchDataService = messageDispatchDataService;
  43. //todo:定时清理
  44. avFrameDict = new ConcurrentDictionary<string, List<H264NALU>>();
  45. }
  46. protected async override Task ExecuteAsync(CancellationToken stoppingToken)
  47. {
  48. while (!stoppingToken.IsCancellationRequested)
  49. {
  50. var data = await messageDispatchDataService.FMp4Channel.Reader.ReadAsync();
  51. try
  52. {
  53. if (Logger.IsEnabled(LogLevel.Debug))
  54. {
  55. Logger.LogDebug(JsonSerializer.Serialize(HttpSessionManager.GetAll()));
  56. Logger.LogDebug($"{data.SIM},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}");
  57. }
  58. var nalus = H264Decoder.ParseNALU(data);
  59. string key = $"{data.GetKey()}_{ikey}";
  60. if (data.Label3.DataType == Protocol.Enums.JT1078DataType.视频I帧)
  61. {
  62. var moovBuffer = FM4Encoder.EncoderMoovBox(
  63. nalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.SPS),
  64. nalus.FirstOrDefault(f => f.NALUHeader.NalUnitType == NalUnitType.PPS));
  65. memoryCache.Set(key, moovBuffer);
  66. }
  67. //查找第一帧为I帧,否则不推送
  68. if (memoryCache.TryGetValue(key, out byte[] moov))
  69. {
  70. var httpSessions = HttpSessionManager.GetAllBySimAndChannelNo(data.SIM.TrimStart('0'), data.LogicChannelNumber);
  71. var firstHttpSessions = httpSessions.Where(w => !w.FirstSend).ToList();
  72. if (firstHttpSessions.Count > 0)
  73. {
  74. try
  75. {
  76. try
  77. {
  78. var ftyp = FM4Encoder.EncoderFtypBox();
  79. foreach (var session in firstHttpSessions)
  80. {
  81. HttpSessionManager.SendAVData(session, ftyp, true);
  82. HttpSessionManager.SendAVData(session, moov, false);
  83. }
  84. }
  85. catch (Exception ex)
  86. {
  87. Logger.LogError(ex, $"{data.SIM},{true},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}");
  88. }
  89. }
  90. catch (Exception ex)
  91. {
  92. Logger.LogError(ex, $"{data.SIM},{true},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}");
  93. }
  94. }
  95. var otherHttpSessions = httpSessions.Where(w => w.FirstSend).ToList();
  96. if (otherHttpSessions.Count > 0)
  97. {
  98. try
  99. {
  100. var firstNALU = nalus.FirstOrDefault();
  101. if (firstNALU == null)
  102. {
  103. continue;
  104. }
  105. if(!avFrameDict.TryGetValue(firstNALU.GetKey(),out List<H264NALU> cacheNALU))
  106. {
  107. cacheNALU = new List<H264NALU>();
  108. avFrameDict.TryAdd(firstNALU.GetKey(), cacheNALU);
  109. }
  110. foreach (var nalu in nalus)
  111. {
  112. if (nalu.Slice)
  113. {
  114. //H264 NALU slice first_mb_in_slice
  115. cacheNALU.Add(nalu);
  116. }
  117. else
  118. {
  119. if (cacheNALU.Count > 0)
  120. {
  121. foreach (var session in otherHttpSessions)
  122. {
  123. var fmp4VideoBuffer = FM4Encoder.EncoderOtherVideoBox(cacheNALU);
  124. HttpSessionManager.SendAVData(session, fmp4VideoBuffer, false);
  125. }
  126. cacheNALU.Clear();
  127. }
  128. cacheNALU.Add(nalu);
  129. }
  130. }
  131. }
  132. catch (Exception ex)
  133. {
  134. Logger.LogError(ex, $"{data.SIM},{false},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}");
  135. }
  136. }
  137. }
  138. }
  139. catch (Exception ex)
  140. {
  141. Logger.LogError(ex, $"{data.SIM},{data.SN},{data.LogicChannelNumber},{data.Label3.DataType.ToString()},{data.Label3.SubpackageType.ToString()},{data.Bodies.ToHexString()}");
  142. }
  143. }
  144. await Task.CompletedTask;
  145. }
  146. }
  147. }