feat: 完成jpeg后端
This commit is contained in:
parent
e5dac3e731
commit
66bc5882af
|
@ -12,7 +12,7 @@ static class HdmiInAddr
|
|||
public const UInt32 HdmiIn_READFIFO = BASE + 0x1;
|
||||
}
|
||||
|
||||
class HdmiIn
|
||||
public class HdmiIn
|
||||
{
|
||||
private static readonly NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
|
||||
|
||||
|
|
|
@ -7,14 +7,28 @@ namespace Peripherals.JpegClient;
|
|||
static class JpegAddr
|
||||
{
|
||||
const UInt32 BASE = 0x0000_0000;
|
||||
public const UInt32 ENABLE = BASE + 0x0;
|
||||
public const UInt32 FRAME_NUM = BASE + 0x1;
|
||||
public const UInt32 FRAME_INFO = BASE + 0x2;
|
||||
public const UInt32 FRAME_SAMPLE_RATE = BASE + 0x3;
|
||||
public const UInt32 FRAME_DATA_MAX_POINTER = BASE + 0x4;
|
||||
|
||||
public const UInt32 DDR_FRAME_DATA_ADDR = 0x0000_0000;
|
||||
public const UInt32 DDR_FRAME_DATA_MAX_ADDR = 0x8000_0000;
|
||||
public const UInt32 CAPTURE_RD_CTRL = BASE + 0x0;
|
||||
public const UInt32 CAPTURE_WR_CTRL = BASE + 0x1;
|
||||
|
||||
public const UInt32 START_WR_ADDR0 = BASE + 0x2;
|
||||
public const UInt32 END_WR_ADDR0 = BASE + 0x3;
|
||||
public const UInt32 START_WR_ADDR1 = BASE + 0x4;
|
||||
public const UInt32 END_WR_ADDR1 = BASE + 0x5;
|
||||
public const UInt32 START_RD_ADDR0 = BASE + 0x6;
|
||||
public const UInt32 END_RD_ADDR0 = BASE + 0x7;
|
||||
|
||||
public const UInt32 HDMI_NOT_READY = BASE + 0x8;
|
||||
public const UInt32 HDMI_HEIGHT_WIDTH = BASE + 0x9;
|
||||
|
||||
public const UInt32 JPEG_HEIGHT_WIDTH = BASE + 0xA;
|
||||
public const UInt32 JPEG_ADD_NEED_FRAME_NUM = BASE + 0xB;
|
||||
public const UInt32 JPEG_FRAME_SAVE_NUM = BASE + 0xC;
|
||||
public const UInt32 JPEG_FIFO_FRAME_INFO = BASE + 0xD;
|
||||
|
||||
public const UInt32 ADDR_HDMI_WD_START = 0x4000_0000;
|
||||
public const UInt32 ADDR_JPEG_START = 0x8000_0000;
|
||||
public const UInt32 ADDR_JPEG_END = 0xA000_0000;
|
||||
}
|
||||
|
||||
public class JpegInfo
|
||||
|
@ -79,39 +93,248 @@ public class Jpeg
|
|||
this.timeout = timeout;
|
||||
}
|
||||
|
||||
public async ValueTask<Result<bool>> Init(bool enable = true)
|
||||
{
|
||||
{
|
||||
var ret = await CheckHdmiIsReady();
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to check HDMI ready: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
if (!ret.Value)
|
||||
{
|
||||
logger.Error("HDMI not ready");
|
||||
return new(false);
|
||||
}
|
||||
}
|
||||
|
||||
int width = -1, height = -1;
|
||||
{
|
||||
var ret = await GetHdmiResolution();
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to get HDMI resolution: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
(width, height) = ret.Value;
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await ConnectJpeg2Hdmi(width, height);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to connect JPEG to HDMI: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
if (!ret.Value)
|
||||
{
|
||||
logger.Error("Failed to connect JPEG to HDMI");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (enable)
|
||||
return await SetEnable(true);
|
||||
else return true;
|
||||
}
|
||||
|
||||
public async ValueTask<bool> SetEnable(bool enable)
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, this.taskID, JpegAddr.ENABLE, Convert.ToUInt32(enable), this.timeout);
|
||||
if (enable)
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddrSeq(
|
||||
this.ep,
|
||||
this.taskID,
|
||||
[JpegAddr.CAPTURE_RD_CTRL, JpegAddr.CAPTURE_WR_CTRL],
|
||||
[0b11, 0b01],
|
||||
this.timeout
|
||||
);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set JPEG enable: {ret.Error}");
|
||||
return false;
|
||||
}
|
||||
return ret.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddrSeq(
|
||||
this.ep,
|
||||
this.taskID,
|
||||
[JpegAddr.CAPTURE_RD_CTRL, JpegAddr.CAPTURE_WR_CTRL],
|
||||
[0b00, 0b00],
|
||||
this.timeout
|
||||
);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set JPEG disable: {ret.Error}");
|
||||
return false;
|
||||
}
|
||||
return ret.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public async ValueTask<Result<bool>> CheckHdmiIsReady()
|
||||
{
|
||||
var ret = await UDPClientPool.ReadAddrWithWait(
|
||||
this.ep, this.taskID, JpegAddr.HDMI_NOT_READY, 0b01, 0b01, 100, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set JPEG enable: {ret.Error}");
|
||||
return false;
|
||||
logger.Error($"Failed to check HDMI status: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
return ret.Value;
|
||||
}
|
||||
|
||||
public async ValueTask<bool> SetSampleRate(uint rate)
|
||||
public async ValueTask<Result<(int, int)>> GetHdmiResolution()
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, this.taskID, JpegAddr.FRAME_SAMPLE_RATE, rate, this.timeout);
|
||||
var ret = await UDPClientPool.ReadAddr(
|
||||
this.ep, this.taskID, JpegAddr.HDMI_HEIGHT_WIDTH, 0, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set JPEG sample rate: {ret.Error}");
|
||||
return false;
|
||||
logger.Error($"Failed to get HDMI resolution: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
return ret.Value;
|
||||
|
||||
var data = ret.Value.Options.Data;
|
||||
if (data == null || data.Length != 4)
|
||||
{
|
||||
logger.Error($"Invalid HDMI resolution data length: {data?.Length ?? 0}");
|
||||
return new(new Exception("Invalid HDMI resolution data length"));
|
||||
}
|
||||
|
||||
var width = data[0] | (data[1] << 8);
|
||||
var height = data[2] | (data[3] << 8);
|
||||
return new((width, height));
|
||||
}
|
||||
|
||||
public async ValueTask<bool> SetSampleRate(JpegSampleRate rate)
|
||||
public async ValueTask<Result<bool>> ConnectJpeg2Hdmi(int width, int height)
|
||||
{
|
||||
return await SetSampleRate((uint)rate);
|
||||
if (width <= 0 || height <= 0)
|
||||
{
|
||||
logger.Error($"Invalid HDMI resolution: {width}x{height}");
|
||||
return new(new ArgumentException("Invalid HDMI resolution"));
|
||||
}
|
||||
|
||||
var frameSize = (UInt32)(width * height / 4);
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, this.taskID, JpegAddr.START_WR_ADDR0, JpegAddr.ADDR_HDMI_WD_START, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set HDMI output start address: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
if (!ret.Value)
|
||||
{
|
||||
logger.Error($"Failed to set HDMI output start address");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, this.taskID, JpegAddr.END_WR_ADDR0,
|
||||
JpegAddr.ADDR_HDMI_WD_START + frameSize, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set HDMI output end address: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
if (!ret.Value)
|
||||
{
|
||||
logger.Error($"Failed to set HDMI output address");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, this.taskID, JpegAddr.START_RD_ADDR0, JpegAddr.ADDR_HDMI_WD_START, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set jpeg input start address: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
if (!ret.Value)
|
||||
{
|
||||
logger.Error($"Failed to set jpeg input address");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, this.taskID, JpegAddr.END_RD_ADDR0,
|
||||
JpegAddr.ADDR_HDMI_WD_START + frameSize, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set jpeg input end address: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
if (!ret.Value)
|
||||
{
|
||||
logger.Error($"Failed to set jpeg input end address");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, this.taskID, JpegAddr.START_WR_ADDR1, JpegAddr.ADDR_JPEG_START, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set jpeg output start address: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
if (!ret.Value)
|
||||
{
|
||||
logger.Error($"Failed to set jpeg output start address");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, this.taskID, JpegAddr.END_WR_ADDR1, JpegAddr.ADDR_JPEG_END, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to set jpeg output end address: {ret.Error}");
|
||||
return new(ret.Error);
|
||||
}
|
||||
if (!ret.Value)
|
||||
{
|
||||
logger.Error($"Failed to set jpeg output end address");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// public async ValueTask<bool> SetSampleRate(uint rate)
|
||||
// {
|
||||
// var ret = await UDPClientPool.WriteAddr(
|
||||
// this.ep, this.taskID, JpegAddr.FRAME_SAMPLE_RATE, rate, this.timeout);
|
||||
// if (!ret.IsSuccessful)
|
||||
// {
|
||||
// logger.Error($"Failed to set JPEG sample rate: {ret.Error}");
|
||||
// return false;
|
||||
// }
|
||||
// return ret.Value;
|
||||
// }
|
||||
|
||||
// public async ValueTask<bool> SetSampleRate(JpegSampleRate rate)
|
||||
// {
|
||||
// return await SetSampleRate((uint)rate);
|
||||
// }
|
||||
|
||||
public async ValueTask<uint> GetFrameNumber()
|
||||
{
|
||||
var ret = await UDPClientPool.ReadAddrByte(
|
||||
this.ep, this.taskID, JpegAddr.FRAME_NUM, this.timeout);
|
||||
this.ep, this.taskID, JpegAddr.JPEG_FRAME_SAVE_NUM, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to get JPEG frame number: {ret.Error}");
|
||||
|
@ -122,7 +345,7 @@ public class Jpeg
|
|||
|
||||
public async ValueTask<Optional<List<JpegInfo>>> GetFrameInfo(int num)
|
||||
{
|
||||
var ret = await UDPClientPool.ReadAddr(this.ep, this.taskID, JpegAddr.FRAME_INFO, num, this.timeout);
|
||||
var ret = await UDPClientPool.ReadAddr(this.ep, this.taskID, JpegAddr.JPEG_FIFO_FRAME_INFO, num, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to get JPEG frame info: {ret.Error}");
|
||||
|
@ -150,10 +373,10 @@ public class Jpeg
|
|||
return new(infos);
|
||||
}
|
||||
|
||||
public async ValueTask<bool> UpdatePointer(uint cnt)
|
||||
public async ValueTask<bool> AddFrameNum2Process(uint cnt)
|
||||
{
|
||||
var ret = await UDPClientPool.WriteAddr(
|
||||
this.ep, this.taskID, JpegAddr.FRAME_DATA_MAX_POINTER, cnt, this.timeout);
|
||||
this.ep, this.taskID, JpegAddr.JPEG_ADD_NEED_FRAME_NUM, cnt, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to update pointer: {ret.Error}");
|
||||
|
@ -171,13 +394,16 @@ public class Jpeg
|
|||
}
|
||||
MsgBus.UDPServer.ClearUDPData(this.ep.Address.ToString(), this.ep.Port);
|
||||
|
||||
var firstReadLength = (int)(Math.Min(length, JpegAddr.DDR_FRAME_DATA_MAX_ADDR - offset));
|
||||
var firstReadLength = (int)(Math.Min(
|
||||
length,
|
||||
JpegAddr.ADDR_JPEG_END - JpegAddr.ADDR_JPEG_START - offset
|
||||
));
|
||||
var secondReadLength = (int)(length - firstReadLength);
|
||||
var dataBytes = new byte[length];
|
||||
|
||||
{
|
||||
var ret = await UDPClientPool.ReadAddr4Bytes(
|
||||
this.ep, this.taskID, JpegAddr.DDR_FRAME_DATA_ADDR + offset, firstReadLength, this.timeout);
|
||||
this.ep, this.taskID, JpegAddr.ADDR_JPEG_START + offset, firstReadLength, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to get JPEG frame data: {ret.Error}");
|
||||
|
@ -194,7 +420,7 @@ public class Jpeg
|
|||
if (secondReadLength > 0)
|
||||
{
|
||||
var ret = await UDPClientPool.ReadAddr4Bytes(
|
||||
this.ep, this.taskID, JpegAddr.DDR_FRAME_DATA_ADDR, secondReadLength, this.timeout);
|
||||
this.ep, this.taskID, JpegAddr.ADDR_JPEG_START, secondReadLength, this.timeout);
|
||||
if (!ret.IsSuccessful)
|
||||
{
|
||||
logger.Error($"Failed to get JPEG frame data: {ret.Error}");
|
||||
|
@ -239,7 +465,7 @@ public class Jpeg
|
|||
}
|
||||
|
||||
{
|
||||
var ret = await UpdatePointer((uint)sizes.Length);
|
||||
var ret = await AddFrameNum2Process((uint)sizes.Length);
|
||||
if (!ret) logger.Error($"Failed to update pointer");
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -331,7 +331,9 @@ public class UDPClientPool
|
|||
/// <param name="timeout">超时时间(毫秒)</param>
|
||||
/// <returns>校验结果,true表示在超时前数据匹配期望值</returns>
|
||||
public static async ValueTask<Result<bool>> ReadAddrWithWait(
|
||||
IPEndPoint endPoint, int taskID, uint devAddr, UInt32 result, UInt32 resultMask, int waittime = 100, int timeout = 1000)
|
||||
IPEndPoint endPoint, int taskID, uint devAddr,
|
||||
UInt32 result, UInt32 resultMask,
|
||||
int waittime = 100, int timeout = 1000)
|
||||
{
|
||||
var address = endPoint.Address.ToString();
|
||||
|
||||
|
|
Loading…
Reference in New Issue