feat: 完成jpeg后端

This commit is contained in:
2025-08-14 14:19:46 +08:00
parent e5dac3e731
commit 66bc5882af
4 changed files with 306 additions and 79 deletions

View File

@@ -1,6 +1,7 @@
using System.Net;
using System.Collections.Concurrent;
using Peripherals.HdmiInClient;
using Peripherals.JpegClient;
namespace server.Services;
@@ -12,6 +13,15 @@ public class HdmiVideoStreamEndpoint
public string SnapshotUrl { get; set; } = "";
}
public class HdmiVideoStreamClient
{
public required HdmiIn HdmiInClient { get; set; }
public required Jpeg JpegClient { get; set; }
public required CancellationTokenSource CTS { get; set; }
}
public class HttpHdmiVideoStreamService : BackgroundService
{
private readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
@@ -20,8 +30,7 @@ public class HttpHdmiVideoStreamService : BackgroundService
private HttpListener? _httpListener;
private readonly int _serverPort = 4322;
private readonly ConcurrentDictionary<string, HdmiIn> _hdmiInDict = new();
private readonly ConcurrentDictionary<string, CancellationTokenSource> _hdmiInCtsDict = new();
private readonly ConcurrentDictionary<string, HdmiVideoStreamClient> _clientDict = new();
public HttpHdmiVideoStreamService(IServiceProvider serviceProvider)
{
@@ -75,7 +84,7 @@ public class HttpHdmiVideoStreamService : BackgroundService
// 禁用所有活跃的HDMI传输
var disableTasks = new List<Task>();
foreach (var hdmiKey in _hdmiInDict.Keys)
foreach (var hdmiKey in _clientDict.Keys)
{
disableTasks.Add(DisableHdmiTransmissionAsync(hdmiKey));
}
@@ -84,8 +93,7 @@ public class HttpHdmiVideoStreamService : BackgroundService
await Task.WhenAll(disableTasks);
// 清空字典
_hdmiInDict.Clear();
_hdmiInCtsDict.Clear();
_clientDict.Clear();
_httpListener?.Close(); // 立即关闭监听器,唤醒阻塞
await base.StopAsync(cancellationToken);
@@ -95,11 +103,10 @@ public class HttpHdmiVideoStreamService : BackgroundService
{
try
{
var cts = _hdmiInCtsDict[key];
cts.Cancel();
var client = _clientDict[key];
client.CTS.Cancel();
var hdmiIn = _hdmiInDict[key];
var disableResult = await hdmiIn.EnableTrans(false);
var disableResult = await client.HdmiInClient.EnableTrans(false);
if (disableResult.IsSuccessful)
{
logger.Info("Successfully disabled HDMI transmission");
@@ -115,31 +122,9 @@ public class HttpHdmiVideoStreamService : BackgroundService
}
}
// 获取/创建 HdmiIn 实例
private async Task<HdmiIn?> GetOrCreateHdmiInAsync(string boardId)
private async Task<HdmiVideoStreamClient?> GetOrCreateClientAsync(string boardId)
{
if (_hdmiInDict.TryGetValue(boardId, out var hdmiIn))
{
try
{
var enableResult = await hdmiIn.EnableTrans(true);
if (!enableResult.IsSuccessful)
{
logger.Error($"Failed to enable HDMI transmission for board {boardId}: {enableResult.Error}");
return null;
}
logger.Info($"Successfully enabled HDMI transmission for board {boardId}");
}
catch (Exception ex)
{
logger.Error(ex, $"Exception occurred while enabling HDMI transmission for board {boardId}");
return null;
}
_hdmiInDict[boardId] = hdmiIn;
_hdmiInCtsDict[boardId] = new CancellationTokenSource();
return hdmiIn;
}
if (_clientDict.TryGetValue(boardId, out var client)) return client;
using var scope = _serviceProvider.CreateScope();
var userManager = scope.ServiceProvider.GetRequiredService<Database.UserManager>();
@@ -153,18 +138,31 @@ public class HttpHdmiVideoStreamService : BackgroundService
var board = boardRet.Value.Value;
hdmiIn = new HdmiIn(board.IpAddr, board.Port, 0); // taskID 可根据实际需求调整
client = new HdmiVideoStreamClient()
{
HdmiInClient = new HdmiIn(board.IpAddr, board.Port, 1),
JpegClient = new Jpeg(board.IpAddr, board.Port, 1),
CTS = new CancellationTokenSource()
};
// 启用HDMI传输
try
{
var enableResult = await hdmiIn.EnableTrans(true);
if (!enableResult.IsSuccessful)
var hdmiEnableRet = await client.HdmiInClient.EnableTrans(true);
if (!hdmiEnableRet.IsSuccessful)
{
logger.Error($"Failed to enable HDMI transmission for board {boardId}: {enableResult.Error}");
logger.Error($"Failed to enable HDMI transmission for board {boardId}: {hdmiEnableRet.Error}");
return null;
}
logger.Info($"Successfully enabled HDMI transmission for board {boardId}");
var jpegEnableRet = await client.JpegClient.Init(true);
if (!jpegEnableRet.IsSuccessful)
{
logger.Error($"Failed to enable JPEG transmission for board {boardId}: {jpegEnableRet.Error}");
return null;
}
logger.Info($"Successfully enabled JPEG transmission for board {boardId}");
}
catch (Exception ex)
{
@@ -172,9 +170,8 @@ public class HttpHdmiVideoStreamService : BackgroundService
return null;
}
_hdmiInDict[boardId] = hdmiIn;
_hdmiInCtsDict[boardId] = new CancellationTokenSource();
return hdmiIn;
_clientDict[boardId] = client;
return client;
}
private async Task HandleRequestAsync(HttpListenerContext context, CancellationToken cancellationToken)
@@ -187,14 +184,14 @@ public class HttpHdmiVideoStreamService : BackgroundService
return;
}
var hdmiIn = await GetOrCreateHdmiInAsync(boardId);
if (hdmiIn == null)
var client = await GetOrCreateClientAsync(boardId);
if (client == null)
{
await SendErrorAsync(context.Response, "Invalid boardId or board not available");
return;
}
var hdmiInToken = _hdmiInCtsDict[boardId].Token;
var hdmiInToken = _clientDict[boardId].CTS.Token;
if (hdmiInToken == null)
{
await SendErrorAsync(context.Response, "HDMI input is not available");
@@ -203,11 +200,11 @@ public class HttpHdmiVideoStreamService : BackgroundService
if (path == "/snapshot")
{
await HandleSnapshotRequestAsync(context.Response, hdmiIn, hdmiInToken);
await HandleSnapshotRequestAsync(context.Response, client, hdmiInToken);
}
else if (path == "/mjpeg")
{
await HandleMjpegStreamAsync(context.Response, hdmiIn, hdmiInToken);
await HandleMjpegStreamAsync(context.Response, client, hdmiInToken);
}
else if (path == "/video")
{
@@ -219,14 +216,15 @@ public class HttpHdmiVideoStreamService : BackgroundService
}
}
private async Task HandleSnapshotRequestAsync(HttpListenerResponse response, HdmiIn hdmiIn, CancellationToken cancellationToken)
private async Task HandleSnapshotRequestAsync(
HttpListenerResponse response, HdmiVideoStreamClient client, CancellationToken cancellationToken)
{
try
{
logger.Debug("处理HDMI快照请求");
// 从HDMI读取RGB565数据
var frameResult = await hdmiIn.ReadFrame();
var frameResult = await client.HdmiInClient.ReadFrame();
if (!frameResult.IsSuccessful || frameResult.Value == null)
{
logger.Error("HDMI快照获取失败");
@@ -260,7 +258,8 @@ public class HttpHdmiVideoStreamService : BackgroundService
}
}
private async Task HandleMjpegStreamAsync(HttpListenerResponse response, HdmiIn hdmiIn, CancellationToken cancellationToken)
private async Task HandleMjpegStreamAsync(
HttpListenerResponse response, HdmiVideoStreamClient client, CancellationToken cancellationToken)
{
try
{
@@ -280,7 +279,7 @@ public class HttpHdmiVideoStreamService : BackgroundService
{
var frameStartTime = DateTime.UtcNow;
var ret = await hdmiIn.GetMJpegFrame();
var ret = await client.HdmiInClient.GetMJpegFrame();
if (ret == null) continue;
var frame = ret.Value;
@@ -315,7 +314,7 @@ public class HttpHdmiVideoStreamService : BackgroundService
try
{
// 停止传输时禁用HDMI传输
await hdmiIn.EnableTrans(false);
await client.HdmiInClient.EnableTrans(false);
logger.Info("已禁用HDMI传输");
}
catch (Exception ex)