支持通过网页增加、删除、修改摄像头配置信息

支持摄像头配置信息中句柄的设置,并实测有效
This commit is contained in:
2025-12-28 08:07:55 +08:00
parent 3718465463
commit 2ee25a4f7c
25 changed files with 2298 additions and 75 deletions

View File

@@ -8,11 +8,15 @@ public class CamerasController : ControllerBase
{
private readonly CameraManager _manager;
// 1. 新增:我们需要配置管理器
private readonly ProcessingConfigManager _configManager;
// 构造函数注入管理器
public CamerasController(CameraManager manager, DisplayWindowManager displayManager)
public CamerasController(CameraManager manager, DisplayWindowManager displayManager, ProcessingConfigManager configManager)
{
_manager = manager;
_displayManager = displayManager;
_configManager = configManager;
}
// ==========================================================================
@@ -191,7 +195,10 @@ public class CamerasController : ControllerBase
Password = dto.Password,
ChannelIndex = dto.ChannelIndex,
StreamType = dto.StreamType,
RtspPath = dto.RtspPath
RtspPath = dto.RtspPath,
MainboardPort = dto.MainboardPort,
MainboardIp = dto.MainboardIp,
RenderHandle =dto.RenderHandle,
};
}
@@ -212,8 +219,7 @@ public class CamerasController : ControllerBase
ChannelIndex = dto.ChannelIndex,
Brand = dto.Brand,
RtspPath = dto.RtspPath,
MainboardIp = dto.MainboardIp,
MainboardPort = dto.MainboardPort,
// ==========================================
// 2. 热更新参数 (运行时属性)
@@ -222,6 +228,9 @@ public class CamerasController : ControllerBase
Location = dto.Location,
StreamType = dto.StreamType,
MainboardIp = dto.MainboardIp,
MainboardPort = dto.MainboardPort,
RenderHandle = dto.RenderHandle,
// 注意:通常句柄是通过 bind-handle 接口单独绑定的,
// 但如果 ConfigDto 里包含了上次保存的句柄,也可以映射
// RenderHandle = dto.RenderHandle,
@@ -281,7 +290,7 @@ public class CamerasController : ControllerBase
}
// 5. 将需求注册到流控控制器
controller.Register(dto.AppId, dto.DisplayFps);
controller.Register(new FrameRequirement(dto));
// 6. 路由显示逻辑 (核心整合点)
if (dto.Type == SubscriptionType.LocalWindow)
@@ -333,4 +342,61 @@ public class CamerasController : ControllerBase
// var bytes = await cam.CaptureCurrentFrameAsync();
// return File(bytes, "image/jpeg");
//}
// =============================================================
// 3. 新增:更新图像处理/分辨率参数的接口
// URL 示例: POST /api/cameras/1001/processing
// =============================================================
[HttpPost("{id}/processing")]
public IActionResult UpdateProcessingOptions(long id, [FromBody] ProcessingOptions options)
{
// A. 检查相机是否存在
var camera = _manager.GetDevice(id);
if (camera == null)
{
return NotFound(new { error = $"Camera {id} not found." });
}
// B. 参数校验 (防止宽高为0导致报错)
if (options.TargetWidth <= 0 || options.TargetHeight <= 0)
{
return BadRequest(new { error = "Target dimensions must be greater than 0." });
}
// C. 执行更新 (热更,立即生效)
// ScaleWorker 下一帧处理时会自动读取这个新配置
_configManager.UpdateOptions(id, options);
return Ok(new
{
success = true,
message = "Image processing options updated.",
currentConfig = options
});
}
// 在 CamerasController 类中添加
// =============================================================
// 新增:获取/回显图像处理参数的接口
// URL: GET /api/cameras/{id}/processing
// =============================================================
[HttpGet("{id}/processing")]
public IActionResult GetProcessingOptions(long id)
{
// 1. 检查相机是否存在
var camera = _manager.GetDevice(id);
if (camera == null)
{
return NotFound(new { error = $"Camera {id} not found." });
}
// 2. 从配置管理器中获取当前配置
// 注意ProcessingConfigManager 内部应该处理好逻辑:
// 如果该设备还没配过,它会自动返回 new ProcessingOptions() (默认值)
var options = _configManager.GetOptions(id);
// 3. 返回 JSON 给前端
return Ok(options);
}
}

View File

@@ -61,6 +61,8 @@ public class CameraConfigDto
[MaxLength(64, ErrorMessage = "密码长度不能超过64个字符")]
public string Password { get; set; } = string.Empty;
public long RenderHandle { get; set; }
/// <summary>
/// 通道号 (通常为1)
/// </summary>

View File

@@ -41,16 +41,18 @@ public class DeviceUpdateDto
/// <summary>RTSP流地址 (非SDK模式下使用)</summary>
[MaxLength(256, ErrorMessage = "RTSP地址长度不能超过 256 个字符")]
public string? RtspPath { get; set; }
public string RtspPath { get; set; }
= string.Empty;
/// <summary>关联的主板IP (用于联动控制)</summary>
[RegularExpression(@"^((25[0-5]|2[0-4]\d|[01]?\d\d?)\.){3}(25[0-5]|2[0-4]\d|[01]?\d\d?)?$",
ErrorMessage = "IPv4地址")]
public string? MainboardIp { get; set; }
public string MainboardIp { get; set; }
= string.Empty;
/// <summary>关联的主板端口</summary>
[Range(1, 65535, ErrorMessage = "主板端口号必须在 1-65535 范围内")]
public int? MainboardPort { get; set; }
public int MainboardPort { get; set; }
// ==============================================================================
// 2. 热更新参数 (Hot Update)
@@ -71,7 +73,7 @@ public class DeviceUpdateDto
/// <summary>渲染句柄 (IntPtr 的 Long 形式)</summary>
[Range(0, long.MaxValue, ErrorMessage = "渲染句柄必须是非负整数")]
public long? RenderHandle { get; set; }
public long RenderHandle { get; set; }
// ==============================================================================
// 3. 图像处理参数 (Image Processing - Hot Update)

View File

@@ -1,10 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace SHH.CameraSdk
namespace SHH.CameraSdk
{
public class UpdateProcessingRequest
{
@@ -13,7 +7,7 @@ namespace SHH.CameraSdk
public bool EnableExpand { get; set; }
public int TargetWidth { get; set; }
public int TargetHeight { get; set; }
public bool EnableEnhance { get; set; }
public double BrightnessLevel { get; set; }
public bool EnableBrightness { get; set; }
public int Brightness { get; set; }
}
}
}

View File

@@ -43,6 +43,8 @@ public class MonitorController : ControllerBase
Status = c.Status.ToString(),
c.IsPhysicalOnline,
c.RealFps,
c.Width,
c.Height,
c.TotalFrames,
c.Config.Name,
c.Config.IpAddress,
@@ -69,23 +71,34 @@ public class MonitorController : ControllerBase
[HttpGet("{id}")]
public IActionResult GetDeviceDetail(long id)
{
var device = _cameraManager.GetDevice(id);
if (device == null) return NotFound($"设备 ID: {id} 不存在");
var d = _cameraManager.GetDevice(id);
if (d == null) return NotFound($"设备 ID: {id} 不存在");
return Ok(new
{
device.Id,
Status = device.Status.ToString(),
device.IsOnline,
device.RealFps,
device.TotalFrames,
device.Config.Name,
device.Config.IpAddress,
d.Id,
Status = d.Status.ToString(),
d.IsOnline,
d.IsPhysicalOnline,
d.RealFps,
d.Width,
d.Height,
d.TotalFrames,
d.Config.Name,
d.Config.IpAddress,
// --- 新增:将内存中的订阅需求列表传给前端 ---
Requirements = device.Controller.GetCurrentRequirements().Select(r => new {
Requirements = d.Controller.GetCurrentRequirements().Select(r => new {
r.AppId,
r.TargetFps,
r.LastActive
r.LastActive,
r.RealFps,
r.Memo,
r.SavePath,
r.Handle,
r.TargetIp,
r.TargetPort,
r.Protocol,
r.Type,
})
});
}
@@ -171,8 +184,8 @@ public class MonitorController : ControllerBase
EnableExpand = request.EnableExpand,
TargetWidth = request.TargetWidth,
TargetHeight = request.TargetHeight,
EnableEnhance = request.EnableEnhance,
BrightnessLevel = request.BrightnessLevel
EnableBrightness = request.EnableBrightness,
Brightness = request.Brightness
};
// 3. 提交给配置管理器 (实时生效)