feat: 细化OV配置
This commit is contained in:
parent
15c6eefe30
commit
229e6e70ed
File diff suppressed because it is too large
Load Diff
|
@ -82,8 +82,8 @@ public class HttpVideoStreamService : BackgroundService
|
||||||
private HttpListener? _httpListener;
|
private HttpListener? _httpListener;
|
||||||
private readonly int _serverPort = 8080;
|
private readonly int _serverPort = 8080;
|
||||||
private readonly int _frameRate = 30; // 30 FPS
|
private readonly int _frameRate = 30; // 30 FPS
|
||||||
private readonly int _frameWidth = 640;
|
private readonly int _frameWidth = 1280;
|
||||||
private readonly int _frameHeight = 480;
|
private readonly int _frameHeight = 720;
|
||||||
|
|
||||||
// 摄像头客户端
|
// 摄像头客户端
|
||||||
private Camera? _camera;
|
private Camera? _camera;
|
||||||
|
@ -559,21 +559,59 @@ public class HttpVideoStreamService : BackgroundService
|
||||||
private async Task GenerateVideoFrames(CancellationToken cancellationToken)
|
private async Task GenerateVideoFrames(CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
var frameInterval = TimeSpan.FromMilliseconds(1000.0 / _frameRate);
|
var frameInterval = TimeSpan.FromMilliseconds(1000.0 / _frameRate);
|
||||||
|
var lastFrameTime = DateTime.UtcNow;
|
||||||
|
|
||||||
while (!cancellationToken.IsCancellationRequested && _cameraEnable)
|
while (!cancellationToken.IsCancellationRequested && _cameraEnable)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 从 FPGA 获取图像数据(模拟)
|
var frameStartTime = DateTime.UtcNow;
|
||||||
|
|
||||||
|
// 从 FPGA 获取图像数据
|
||||||
var imageData = await GetFPGAImageData();
|
var imageData = await GetFPGAImageData();
|
||||||
|
|
||||||
// 向所有连接的客户端发送帧
|
var imageAcquireTime = DateTime.UtcNow;
|
||||||
|
|
||||||
|
// 如果有图像数据,立即开始广播(不等待)
|
||||||
|
if (imageData != null && imageData.Length > 0)
|
||||||
|
{
|
||||||
|
// 异步广播帧,不阻塞下一帧的获取
|
||||||
|
_ = Task.Run(async () =>
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
await BroadcastFrameAsync(imageData, cancellationToken);
|
await BroadcastFrameAsync(imageData, cancellationToken);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
logger.Error(ex, "异步广播帧时发生错误");
|
||||||
|
}
|
||||||
|
}, cancellationToken);
|
||||||
|
|
||||||
_frameCounter++;
|
_frameCounter++;
|
||||||
|
|
||||||
// 等待下一帧
|
var frameEndTime = DateTime.UtcNow;
|
||||||
await Task.Delay(frameInterval, cancellationToken);
|
var frameProcessingTime = (frameEndTime - frameStartTime).TotalMilliseconds;
|
||||||
|
var imageAcquireElapsed = (imageAcquireTime - frameStartTime).TotalMilliseconds;
|
||||||
|
|
||||||
|
if (_frameCounter % 30 == 0) // 每秒记录一次性能信息
|
||||||
|
{
|
||||||
|
logger.Debug("帧 {FrameNumber} 性能统计 - 图像获取: {AcquireTime:F1}ms, 总处理: {ProcessTime:F1}ms",
|
||||||
|
_frameCounter, imageAcquireElapsed, frameProcessingTime);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 动态调整延迟 - 基于实际处理时间
|
||||||
|
var elapsed = (DateTime.UtcNow - lastFrameTime).TotalMilliseconds;
|
||||||
|
var targetInterval = frameInterval.TotalMilliseconds;
|
||||||
|
var remainingDelay = Math.Max(0, targetInterval - elapsed);
|
||||||
|
|
||||||
|
if (remainingDelay > 0)
|
||||||
|
{
|
||||||
|
await Task.Delay(TimeSpan.FromMilliseconds(remainingDelay), cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
lastFrameTime = DateTime.UtcNow;
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
|
@ -582,7 +620,7 @@ public class HttpVideoStreamService : BackgroundService
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.Error(ex, "生成视频帧时发生错误");
|
logger.Error(ex, "生成视频帧时发生错误");
|
||||||
await Task.Delay(1000, cancellationToken); // 错误恢复延迟
|
await Task.Delay(100, cancellationToken); // 减少错误恢复延迟
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -593,6 +631,7 @@ public class HttpVideoStreamService : BackgroundService
|
||||||
/// </summary>
|
/// </summary>
|
||||||
private async Task<byte[]> GetFPGAImageData()
|
private async Task<byte[]> GetFPGAImageData()
|
||||||
{
|
{
|
||||||
|
var startTime = DateTime.UtcNow;
|
||||||
Camera? currentCamera = null;
|
Camera? currentCamera = null;
|
||||||
|
|
||||||
lock (_cameraLock)
|
lock (_cameraLock)
|
||||||
|
@ -609,7 +648,10 @@ public class HttpVideoStreamService : BackgroundService
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// 从摄像头读取帧数据
|
// 从摄像头读取帧数据
|
||||||
|
var readStartTime = DateTime.UtcNow;
|
||||||
var result = await currentCamera.ReadFrame();
|
var result = await currentCamera.ReadFrame();
|
||||||
|
var readEndTime = DateTime.UtcNow;
|
||||||
|
var readTime = (readEndTime - readStartTime).TotalMilliseconds;
|
||||||
|
|
||||||
if (!result.IsSuccessful)
|
if (!result.IsSuccessful)
|
||||||
{
|
{
|
||||||
|
@ -627,17 +669,23 @@ public class HttpVideoStreamService : BackgroundService
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将 RGB565 转换为 RGB24
|
// 将 RGB565 转换为 RGB24
|
||||||
|
var convertStartTime = DateTime.UtcNow;
|
||||||
var rgb24Result = Common.Image.ConvertRGB565ToRGB24(rgb565Data, _frameWidth, _frameHeight, isLittleEndian: false);
|
var rgb24Result = Common.Image.ConvertRGB565ToRGB24(rgb565Data, _frameWidth, _frameHeight, isLittleEndian: false);
|
||||||
|
var convertEndTime = DateTime.UtcNow;
|
||||||
|
var convertTime = (convertEndTime - convertStartTime).TotalMilliseconds;
|
||||||
|
|
||||||
if (!rgb24Result.IsSuccessful)
|
if (!rgb24Result.IsSuccessful)
|
||||||
{
|
{
|
||||||
logger.Error("RGB565转RGB24失败: {Error}", rgb24Result.Error);
|
logger.Error("RGB565转RGB24失败: {Error}", rgb24Result.Error);
|
||||||
return new byte[0];
|
return new byte[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var totalTime = (DateTime.UtcNow - startTime).TotalMilliseconds;
|
||||||
|
|
||||||
if (_frameCounter % 30 == 0) // 每秒更新一次日志
|
if (_frameCounter % 30 == 0) // 每秒更新一次日志
|
||||||
{
|
{
|
||||||
logger.Debug("成功获取第 {FrameNumber} 帧,RGB565大小: {RGB565Size} 字节, RGB24大小: {RGB24Size} 字节",
|
logger.Debug("帧 {FrameNumber} 数据获取性能 - 读取: {ReadTime:F1}ms, 转换: {ConvertTime:F1}ms, 总计: {TotalTime:F1}ms, RGB565: {RGB565Size} 字节, RGB24: {RGB24Size} 字节",
|
||||||
_frameCounter, rgb565Data.Length, rgb24Result.Value.Length);
|
_frameCounter, readTime, convertTime, totalTime, rgb565Data.Length, rgb24Result.Value.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rgb24Result.Value;
|
return rgb24Result.Value;
|
||||||
|
@ -688,8 +736,8 @@ public class HttpVideoStreamService : BackgroundService
|
||||||
return; // 没有活跃客户端
|
return; // 没有活跃客户端
|
||||||
}
|
}
|
||||||
|
|
||||||
// 向每个活跃的客户端发送帧
|
// 向每个活跃的客户端并行发送帧
|
||||||
foreach (var client in clientsToProcess)
|
var sendTasks = clientsToProcess.Select(async client =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -705,19 +753,33 @@ public class HttpVideoStreamService : BackgroundService
|
||||||
// 确保数据立即发送
|
// 确保数据立即发送
|
||||||
await client.OutputStream.FlushAsync(cancellationToken);
|
await client.OutputStream.FlushAsync(cancellationToken);
|
||||||
|
|
||||||
if (_frameCounter % 30 == 0) // 每秒记录一次日志
|
return (client, success: true, error: (Exception?)null);
|
||||||
{
|
|
||||||
logger.Debug("已向客户端 {ClientId} 发送第 {FrameNumber} 帧,大小:{Size} 字节",
|
|
||||||
client.OutputStream.GetHashCode(), _frameCounter, jpegData.Length);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
logger.Debug("发送帧数据时出错: {Error}", ex.Message);
|
return (client, success: false, error: ex);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 等待所有发送任务完成
|
||||||
|
var results = await Task.WhenAll(sendTasks);
|
||||||
|
|
||||||
|
// 处理发送结果
|
||||||
|
foreach (var (client, success, error) in results)
|
||||||
|
{
|
||||||
|
if (!success)
|
||||||
|
{
|
||||||
|
logger.Debug("发送帧数据时出错: {Error}", error?.Message ?? "未知错误");
|
||||||
clientsToRemove.Add(client);
|
clientsToRemove.Add(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_frameCounter % 30 == 0 && clientsToProcess.Count > 0) // 每秒记录一次日志
|
||||||
|
{
|
||||||
|
logger.Debug("已向 {ClientCount} 个客户端发送第 {FrameNumber} 帧,大小:{Size} 字节",
|
||||||
|
clientsToProcess.Count, _frameCounter, jpegData.Length);
|
||||||
|
}
|
||||||
|
|
||||||
// 移除断开连接的客户端
|
// 移除断开连接的客户端
|
||||||
if (clientsToRemove.Count > 0)
|
if (clientsToRemove.Count > 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -60,8 +60,8 @@ public class UDPClientPool
|
||||||
var sendLen = socket.SendTo(buf, endPoint);
|
var sendLen = socket.SendTo(buf, endPoint);
|
||||||
socket.Close();
|
socket.Close();
|
||||||
|
|
||||||
logger.Debug($"UDP socket send bytes to device {endPoint.Address.ToString()}:{endPoint.Port.ToString()}:");
|
// logger.Debug($"UDP socket send bytes to device {endPoint.Address.ToString()}:{endPoint.Port.ToString()}:");
|
||||||
logger.Debug($" Original Data: {BitConverter.ToString(buf).Replace("-", " ")}");
|
// logger.Debug($" Original Data: {BitConverter.ToString(buf).Replace("-", " ")}");
|
||||||
|
|
||||||
if (sendLen == buf.Length) { return true; }
|
if (sendLen == buf.Length) { return true; }
|
||||||
else { return false; }
|
else { return false; }
|
||||||
|
@ -91,9 +91,9 @@ public class UDPClientPool
|
||||||
var sendLen = socket.SendTo(sendBytes, endPoint);
|
var sendLen = socket.SendTo(sendBytes, endPoint);
|
||||||
socket.Close();
|
socket.Close();
|
||||||
|
|
||||||
logger.Debug($"UDP socket send address package to device {endPoint.Address.ToString()}:{endPoint.Port.ToString()}:");
|
// logger.Debug($"UDP socket send address package to device {endPoint.Address.ToString()}:{endPoint.Port.ToString()}:");
|
||||||
logger.Debug($" Original Data: {BitConverter.ToString(pkg.ToBytes()).Replace("-", " ")}");
|
// logger.Debug($" Original Data: {BitConverter.ToString(pkg.ToBytes()).Replace("-", " ")}");
|
||||||
logger.Debug($" Decoded Data: {pkg.ToString()}");
|
// logger.Debug($" Decoded Data: {pkg.ToString()}");
|
||||||
|
|
||||||
if (sendLen == sendBytes.Length) { return true; }
|
if (sendLen == sendBytes.Length) { return true; }
|
||||||
else { return false; }
|
else { return false; }
|
||||||
|
@ -124,8 +124,8 @@ public class UDPClientPool
|
||||||
var sendLen = socket.SendTo(sendBytes, endPoint);
|
var sendLen = socket.SendTo(sendBytes, endPoint);
|
||||||
socket.Close();
|
socket.Close();
|
||||||
|
|
||||||
logger.Debug($"UDP socket send data package to device {endPoint.Address.ToString()}:{endPoint.Port.ToString()}:");
|
// logger.Debug($"UDP socket send data package to device {endPoint.Address.ToString()}:{endPoint.Port.ToString()}:");
|
||||||
logger.Debug($" Original Data: {BitConverter.ToString(pkg.ToBytes()).Replace("-", " ")}");
|
// logger.Debug($" Original Data: {BitConverter.ToString(pkg.ToBytes()).Replace("-", " ")}");
|
||||||
|
|
||||||
if (sendLen == sendBytes.Length) { return true; }
|
if (sendLen == sendBytes.Length) { return true; }
|
||||||
else { return false; }
|
else { return false; }
|
||||||
|
|
|
@ -145,7 +145,7 @@ public class UDPServer
|
||||||
{
|
{
|
||||||
UDPData? data = null;
|
UDPData? data = null;
|
||||||
|
|
||||||
logger.Debug($"Caller \"{callerName}|{callerLineNum}\": Try to find {ipAddr}-{taskID} UDP Data");
|
// logger.Debug($"Caller \"{callerName}|{callerLineNum}\": Try to find {ipAddr}-{taskID} UDP Data");
|
||||||
|
|
||||||
var startTime = DateTime.Now;
|
var startTime = DateTime.Now;
|
||||||
var isTimeout = false;
|
var isTimeout = false;
|
||||||
|
@ -164,7 +164,7 @@ public class UDPServer
|
||||||
dataQueue.Count > 0)
|
dataQueue.Count > 0)
|
||||||
{
|
{
|
||||||
data = dataQueue.Dequeue();
|
data = dataQueue.Dequeue();
|
||||||
logger.Debug($"Find UDP Data: {data.ToString()}");
|
// logger.Debug($"Find UDP Data: {data.ToString()}");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -212,7 +212,7 @@ public class UDPServer
|
||||||
dataQueue.Count > 0)
|
dataQueue.Count > 0)
|
||||||
{
|
{
|
||||||
data = dataQueue.ToList();
|
data = dataQueue.ToList();
|
||||||
logger.Debug($"Find UDP Data Array: {JsonConvert.SerializeObject(data)}");
|
// logger.Debug($"Find UDP Data Array: {JsonConvert.SerializeObject(data)}");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -290,8 +290,8 @@ public class UDPServer
|
||||||
// Handle RemoteEP
|
// Handle RemoteEP
|
||||||
if (remoteEP is null)
|
if (remoteEP is null)
|
||||||
{
|
{
|
||||||
logger.Debug($"Receive Data from Unknown at {DateTime.Now.ToString()}:");
|
// logger.Debug($"Receive Data from Unknown at {DateTime.Now.ToString()}:");
|
||||||
logger.Debug($" Original Data : {BitConverter.ToString(bytes).Replace("-", " ")}");
|
// logger.Debug($" Original Data : {BitConverter.ToString(bytes).Replace("-", " ")}");
|
||||||
goto BEGIN_RECEIVE;
|
goto BEGIN_RECEIVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -395,9 +395,9 @@ public class UDPServer
|
||||||
recvData = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
|
recvData = Encoding.ASCII.GetString(bytes, 0, bytes.Length);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.Debug($"Receive Data from {data.Address}:{data.Port} at {data.DateTime.ToString()}:");
|
// logger.Debug($"Receive Data from {data.Address}:{data.Port} at {data.DateTime.ToString()}:");
|
||||||
logger.Debug($" Original Data : {BitConverter.ToString(bytes).Replace("-", " ")}");
|
// logger.Debug($" Original Data : {BitConverter.ToString(bytes).Replace("-", " ")}");
|
||||||
if (recvData.Length != 0) logger.Debug($" Decoded Data : {recvData}");
|
// if (recvData.Length != 0) logger.Debug($" Decoded Data : {recvData}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -408,13 +408,13 @@ public class UDPServer
|
||||||
{
|
{
|
||||||
using (udpData.AcquireReadLock())
|
using (udpData.AcquireReadLock())
|
||||||
{
|
{
|
||||||
logger.Debug("Ready Data:");
|
// logger.Debug("Ready Data:");
|
||||||
|
|
||||||
foreach (var ip in udpData)
|
foreach (var ip in udpData)
|
||||||
{
|
{
|
||||||
foreach (var data in ip.Value)
|
foreach (var data in ip.Value)
|
||||||
{
|
{
|
||||||
logger.Debug(data.ToString());
|
// logger.Debug(data.ToString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue