diff --git a/server/src/Controllers/TutorialController.cs b/server/src/Controllers/TutorialController.cs
index f5ffb01..d2c092a 100644
--- a/server/src/Controllers/TutorialController.cs
+++ b/server/src/Controllers/TutorialController.cs
@@ -14,6 +14,11 @@ public class TutorialController : ControllerBase
private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
private readonly IWebHostEnvironment _environment;
+ ///
+ /// [TODO:description]
+ ///
+ /// [TODO:parameter]
+ /// [TODO:return]
public TutorialController(IWebHostEnvironment environment)
{
_environment = environment;
diff --git a/server/src/Controllers/UDPController.cs b/server/src/Controllers/UDPController.cs
index ac090a0..db39d03 100644
--- a/server/src/Controllers/UDPController.cs
+++ b/server/src/Controllers/UDPController.cs
@@ -109,6 +109,7 @@ public class UDPController : ControllerBase
/// 获取指定IP地址接收的数据列表
///
/// IP地址
+ /// 任务ID
[HttpGet("GetRecvDataArray")]
[ProducesResponseType(typeof(List), StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status500InternalServerError)]
diff --git a/server/src/Controllers/VideoStreamController.cs b/server/src/Controllers/VideoStreamController.cs
index 9a70219..30e1c4c 100644
--- a/server/src/Controllers/VideoStreamController.cs
+++ b/server/src/Controllers/VideoStreamController.cs
@@ -1,6 +1,6 @@
+using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
-using System.ComponentModel.DataAnnotations;
///
/// 视频流控制器,支持动态配置摄像头连接
@@ -17,10 +17,16 @@ public class VideoStreamController : ControllerBase
///
public class CameraConfigRequest
{
+ ///
+ /// 摄像头地址
+ ///
[Required]
[RegularExpression(@"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$", ErrorMessage = "请输入有效的IP地址")]
public string Address { get; set; } = "";
+ ///
+ /// 摄像头端口
+ ///
[Required]
[Range(1, 65535, ErrorMessage = "端口必须在1-65535范围内")]
public int Port { get; set; }
@@ -54,21 +60,11 @@ public class VideoStreamController : ControllerBase
var status = _videoStreamService.GetServiceStatus();
// 转换为小写首字母的JSON属性(符合前端惯例)
- return TypedResults.Ok(new
- {
- isRunning = true, // HTTP视频流服务作为后台服务始终运行
- serverPort = _videoStreamService.ServerPort,
- streamUrl = $"http://localhost:{_videoStreamService.ServerPort}/video-feed.html",
- mjpegUrl = $"http://localhost:{_videoStreamService.ServerPort}/video-stream",
- snapshotUrl = $"http://localhost:{_videoStreamService.ServerPort}/snapshot",
- connectedClients = _videoStreamService.ConnectedClientsCount,
- clientEndpoints = _videoStreamService.GetConnectedClientEndpoints(),
- cameraStatus = _videoStreamService.GetCameraStatus()
- });
+ return TypedResults.Ok(status);
}
catch (Exception ex)
{
- logger.Error(ex, "获取 HTTP 视频流服务状态失败");
+ logger.Error(ex, "获取 HTTP 视频流服务状态失败");
return TypedResults.InternalServerError(ex.Message);
}
}
@@ -95,13 +91,11 @@ public class VideoStreamController : ControllerBase
htmlUrl = $"http://localhost:{_videoStreamService.ServerPort}/video-feed.html",
mjpegUrl = $"http://localhost:{_videoStreamService.ServerPort}/video-stream",
snapshotUrl = $"http://localhost:{_videoStreamService.ServerPort}/snapshot",
- cameraAddress = _videoStreamService.CameraAddress,
- cameraPort = _videoStreamService.CameraPort
});
}
catch (Exception ex)
{
- logger.Error(ex, "获取 HTTP 视频流信息失败");
+ logger.Error(ex, "获取 HTTP 视频流信息失败");
return TypedResults.InternalServerError(ex.Message);
}
}
@@ -123,7 +117,7 @@ public class VideoStreamController : ControllerBase
logger.Info("配置摄像头连接: {Address}:{Port}", config.Address, config.Port);
var success = await _videoStreamService.ConfigureCameraAsync(config.Address, config.Port);
-
+
if (success)
{
return TypedResults.Ok(new
@@ -166,7 +160,7 @@ public class VideoStreamController : ControllerBase
{
logger.Info("获取摄像头配置");
var cameraStatus = _videoStreamService.GetCameraStatus();
-
+
return TypedResults.Ok(new
{
address = _videoStreamService.CameraAddress,
@@ -183,35 +177,23 @@ public class VideoStreamController : ControllerBase
}
///
- /// 测试摄像头连接
+ /// 控制 HTTP 视频流服务开关
///
- /// 连接测试结果
- [HttpPost("TestCameraConnection")]
+ /// 是否启用服务
+ /// 操作结果
+ [HttpPost("SetEnabled")]
[EnableCors("Users")]
[ProducesResponseType(typeof(object), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)]
- public async Task TestCameraConnection()
+ public IResult SetEnabled([FromQuery] bool enabled)
{
- try
+ logger.Info("设置视频流服务开关: {Enabled}", enabled);
+ _videoStreamService.Enabled = enabled;
+ return TypedResults.Ok(new
{
- logger.Info("测试摄像头连接");
-
- var (isSuccess, message) = await _videoStreamService.TestCameraConnectionAsync();
-
- return TypedResults.Ok(new
- {
- success = isSuccess,
- message = message,
- cameraAddress = _videoStreamService.CameraAddress,
- cameraPort = _videoStreamService.CameraPort,
- timestamp = DateTime.Now
- });
- }
- catch (Exception ex)
- {
- logger.Error(ex, "测试摄像头连接失败");
- return TypedResults.InternalServerError(ex.Message);
- }
+ success = true,
+ enabled = _videoStreamService.Enabled
+ });
}
///
@@ -229,16 +211,29 @@ public class VideoStreamController : ControllerBase
logger.Info("测试 HTTP 视频流连接");
// 尝试通过HTTP请求检查视频流服务是否可访问
+ bool isConnected = false;
using (var httpClient = new HttpClient())
{
httpClient.Timeout = TimeSpan.FromSeconds(2); // 设置较短的超时时间
var response = await httpClient.GetAsync($"http://localhost:{_videoStreamService.ServerPort}/");
// 只要能连接上就认为成功,不管返回状态
- bool isConnected = response.IsSuccessStatusCode;
-
- return TypedResults.Ok(isConnected);
+ isConnected = response.IsSuccessStatusCode;
}
+
+ logger.Info("测试摄像头连接");
+
+ var (isSuccess, message) = await _videoStreamService.TestCameraConnectionAsync();
+
+ return TypedResults.Ok(new
+ {
+ isConnected = isConnected,
+ success = isSuccess,
+ message = message,
+ cameraAddress = _videoStreamService.CameraAddress,
+ cameraPort = _videoStreamService.CameraPort,
+ timestamp = DateTime.Now
+ });
}
catch (Exception ex)
{
diff --git a/server/src/Peripherals/CameraClient.cs b/server/src/Peripherals/CameraClient.cs
index 89bfc9b..9dffbee 100644
--- a/server/src/Peripherals/CameraClient.cs
+++ b/server/src/Peripherals/CameraClient.cs
@@ -38,7 +38,7 @@ class Camera
public async ValueTask> Init()
{
var i2c = new Peripherals.I2cClient.I2c(this.address, this.port, this.timeout);
- var ret = await i2c.WriteData(0x78, new byte[] { 0x08, 0x30, 0x02 }, Peripherals.I2cClient.I2cProtocol.I2c);
+ var ret = await i2c.WriteData(0x78, new byte[] { 0x30, 0x08, 0x02 }, Peripherals.I2cClient.I2cProtocol.I2c);
if (!ret.IsSuccessful)
{
logger.Error($"I2C write failed during camera initialization for {this.address}:{this.port}, error: {ret.Error}");
diff --git a/server/src/Services/HttpVideoStreamService.cs b/server/src/Services/HttpVideoStreamService.cs
index 803a8ee..0969e89 100644
--- a/server/src/Services/HttpVideoStreamService.cs
+++ b/server/src/Services/HttpVideoStreamService.cs
@@ -4,6 +4,73 @@ using Peripherals.CameraClient; // 添加摄像头客户端引用
namespace server.Services;
+///
+/// 表示摄像头连接状态信息
+///
+public class CameraStatus
+{
+ ///
+ /// 摄像头的IP地址
+ ///
+ public string Address { get; set; } = string.Empty;
+
+ ///
+ /// 摄像头的端口号
+ ///
+ public int Port { get; set; }
+
+ ///
+ /// 是否已配置摄像头
+ ///
+ public bool IsConfigured { get; set; }
+
+ ///
+ /// 摄像头连接字符串(IP:端口)
+ ///
+ public string ConnectionString { get; set; } = string.Empty;
+}
+
+///
+/// 表示视频流服务的运行状态
+///
+public class ServiceStatus
+{
+ ///
+ /// 服务是否正在运行
+ ///
+ public bool IsRunning { get; set; }
+
+ ///
+ /// 服务监听的端口号
+ ///
+ public int ServerPort { get; set; }
+
+ ///
+ /// 视频流的帧率(FPS)
+ ///
+ public int FrameRate { get; set; }
+
+ ///
+ /// 视频分辨率(如 640x480)
+ ///
+ public string Resolution { get; set; } = string.Empty;
+
+ ///
+ /// 当前连接的客户端数量
+ ///
+ public int ConnectedClients { get; set; }
+
+ ///
+ /// 当前连接的客户端端点列表
+ ///
+ public List ClientEndpoints { get; set; } = new();
+
+ ///
+ /// 摄像头连接状态信息
+ ///
+ public CameraStatus CameraStatus { get; set; } = new();
+}
+
///
/// HTTP 视频流服务,用于从 FPGA 获取图像数据并推送到前端网页
/// 支持动态配置摄像头地址和端口
@@ -28,6 +95,11 @@ public class HttpVideoStreamService : BackgroundService
private readonly List _activeClients = new List();
private readonly object _clientsLock = new object();
+ ///
+ /// 获取 / 设置视频流服务是否启用
+ ///
+ public bool Enabled { get; set; } = false;
+
///
/// 获取当前连接的客户端数量
///
@@ -94,7 +166,7 @@ public class HttpVideoStreamService : BackgroundService
try
{
- await Task.Run(() =>
+ await Task.Run(async () =>
{
lock (_cameraLock)
{
@@ -122,6 +194,22 @@ public class HttpVideoStreamService : BackgroundService
logger.Info("摄像头配置已更新: {Address}:{Port}", _cameraAddress, _cameraPort);
}
+
+ // Init Camera
+ {
+ var ret = await _camera.Init();
+ if (!ret.IsSuccessful)
+ {
+ logger.Error(ret.Error);
+ throw ret.Error;
+ }
+
+ if (!ret.Value)
+ {
+ logger.Error($"Camera Init Failed!");
+ throw new Exception($"Camera Init Failed!");
+ }
+ }
});
return true;
}
@@ -176,18 +264,15 @@ public class HttpVideoStreamService : BackgroundService
/// 获取摄像头连接状态
///
/// 连接状态信息
- public object GetCameraStatus()
+ public CameraStatus GetCameraStatus()
{
- lock (_cameraLock)
+ return new CameraStatus
{
- return new
- {
- Address = _cameraAddress,
- Port = _cameraPort,
- IsConfigured = _camera != null,
- ConnectionString = $"{_cameraAddress}:{_cameraPort}"
- };
- }
+ Address = _cameraAddress,
+ Port = _cameraPort,
+ IsConfigured = _camera != null,
+ ConnectionString = $"{_cameraAddress}:{_cameraPort}"
+ };
}
///
@@ -215,7 +300,17 @@ public class HttpVideoStreamService : BackgroundService
_ = Task.Run(() => AcceptClientsAsync(stoppingToken), stoppingToken);
// 开始生成视频帧
- await GenerateVideoFrames(stoppingToken);
+ while (!stoppingToken.IsCancellationRequested)
+ {
+ if (Enabled)
+ {
+ await GenerateVideoFrames(stoppingToken);
+ }
+ else
+ {
+ await Task.Delay(500, stoppingToken);
+ }
+ }
}
catch (HttpListenerException ex)
{
@@ -660,13 +755,13 @@ public class HttpVideoStreamService : BackgroundService
///
/// 获取服务状态信息
///
- public object GetServiceStatus()
+ public ServiceStatus GetServiceStatus()
{
var cameraStatus = GetCameraStatus();
- return new
+ return new ServiceStatus
{
- IsRunning = _httpListener?.IsListening ?? false,
+ IsRunning = (_httpListener?.IsListening ?? false) && Enabled,
ServerPort = _serverPort,
FrameRate = _frameRate,
Resolution = $"{_frameWidth}x{_frameHeight}",
@@ -683,6 +778,8 @@ public class HttpVideoStreamService : BackgroundService
{
logger.Info("正在停止 HTTP 视频流服务...");
+ Enabled = false;
+
if (_httpListener != null && _httpListener.IsListening)
{
_httpListener.Stop();
diff --git a/src/APIClient.ts b/src/APIClient.ts
index 4d88dbe..115b1eb 100644
--- a/src/APIClient.ts
+++ b/src/APIClient.ts
@@ -216,11 +216,16 @@ export class VideoStreamClient {
}
/**
- * 测试摄像头连接
- * @return 连接测试结果
+ * 控制 HTTP 视频流服务开关
+ * @param enabled (optional) 是否启用服务
+ * @return 操作结果
*/
- testCameraConnection(): Promise {
- let url_ = this.baseUrl + "/api/VideoStream/TestCameraConnection";
+ setEnabled(enabled: boolean | undefined): Promise {
+ let url_ = this.baseUrl + "/api/VideoStream/SetEnabled?";
+ if (enabled === null)
+ throw new Error("The parameter 'enabled' cannot be null.");
+ else if (enabled !== undefined)
+ url_ += "enabled=" + encodeURIComponent("" + enabled) + "&";
url_ = url_.replace(/[?&]$/, "");
let options_: RequestInit = {
@@ -231,11 +236,11 @@ export class VideoStreamClient {
};
return this.http.fetch(url_, options_).then((_response: Response) => {
- return this.processTestCameraConnection(_response);
+ return this.processSetEnabled(_response);
});
}
- protected processTestCameraConnection(response: Response): Promise {
+ protected processSetEnabled(response: Response): Promise {
const status = response.status;
let _headers: any = {}; if (response.headers && response.headers.forEach) { response.headers.forEach((v: any, k: any) => _headers[k] = v); };
if (status === 200) {
@@ -2541,4 +2546,4 @@ function throwException(message: string, status: number, response: string, heade
throw result;
else
throw new ApiException(message, status, response, headers, null);
-}
\ No newline at end of file
+}
diff --git a/src/views/VideoStreamView.vue b/src/views/VideoStreamView.vue
index 34f1198..c7f1192 100644
--- a/src/views/VideoStreamView.vue
+++ b/src/views/VideoStreamView.vue
@@ -149,69 +149,40 @@
摄像头配置
-
-
+
+
+
@@ -540,8 +511,15 @@