using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using OrpaonVision.Core.Results; using OrpaonVision.SiteApp.Runtime.Contracts; using OrpaonVision.SiteApp.Runtime.Services; using System.Collections.Concurrent; using System.Runtime.InteropServices; using MvCamCtrl.NET; namespace OrpaonVision.SiteApp.Runtime.Services; /// /// 海康相机服务实现(支持真实和模拟模式)。 /// public sealed class RealHikCameraService : IHikCameraService, IDisposable { private readonly ILogger _logger; private readonly HikCameraOptions _options; private readonly object _lockObject = new(); private HikCameraDevice? _currentDevice; private bool _isConnected; private bool _isGrabbing; private Timer? _frameTimer; private readonly ConcurrentQueue _frameQueue = new(); private MyCamera? _camera; private bool _sdkInitialized; private IntPtr _deviceHandle = IntPtr.Zero; private MyCamera.MV_CC_DEVICE_INFO? _deviceInfo; private int _reconnectAttempts = 0; /// /// 构造函数。 /// public RealHikCameraService(ILogger logger, IOptions options) { _logger = logger; _options = options.Value; _logger.LogInformation("海康相机服务已初始化(模式: {RunMode})", _options.RunMode); if (_options.RunMode == "Real") { InitializeSdk(); } } /// public bool IsConnected => _isConnected; /// public HikCameraDevice? CurrentDevice => _currentDevice; /// public event Action? OnImageReceived; /// public event Action? OnConnectionStateChanged; /// /// 初始化海康SDK。 /// private void InitializeSdk() { try { if (_sdkInitialized) { return; } _logger.LogInformation("正在初始化海康SDK..."); // 初始化海康SDK var result = MyCamera.MV_CC_Initialize_NET(); if (result != MyCamera.MV_OK) { _logger.LogError("海康SDK初始化失败,错误代码: {ErrorCode}", result); return; } _camera = new MyCamera(); _sdkInitialized = true; _logger.LogInformation("海康SDK初始化成功"); } catch (Exception ex) { _logger.LogError(ex, "初始化海康SDK失败,将回退到模拟模式"); } } /// public Result> EnumerateDevices() { try { _logger.LogInformation("正在枚举海康相机设备..."); if (_options.RunMode != "Real" || !_sdkInitialized || _camera == null) { _logger.LogWarning("真实模式未启用或SDK未初始化,返回模拟设备"); return GetMockDevices(); } // 使用海康SDK枚举设备 var deviceList = new MyCamera.MV_CC_DEVICE_INFO_LIST(); var result = _camera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref deviceList); if (result != MyCamera.MV_OK) { _logger.LogError("枚举海康设备失败,错误代码: {ErrorCode}", result); return GetMockDevices(); } var devices = new List(); for (uint i = 0; i < deviceList.nDeviceNum; i++) { var deviceInfo = deviceList.MvDeviceInfo[i]; var device = new HikCameraDevice { SerialNumber = Marshal.PtrToStringAnsi(deviceInfo.SpecialInfo.stGigEInfo.chSerialNumber) ?? $"HK_DEVICE_{i}", DeviceName = Marshal.PtrToStringAnsi(deviceInfo.SpecialInfo.stGigEInfo.chUserDefinedName) ?? $"海康相机_{i}", IpAddress = Marshal.PtrToStringAnsi(deviceInfo.SpecialInfo.stGigEInfo.nCurrentIp) ?? "Unknown", MacAddress = Marshal.PtrToStringAnsi(deviceInfo.SpecialInfo.stGigEInfo.nCurrentMac) ?? "Unknown", IsConnected = true }; devices.Add(device); _logger.LogInformation("发现海康设备: {DeviceName} ({SerialNumber})", device.DeviceName, device.SerialNumber); } if (devices.Count == 0) { _logger.LogInformation("未发现海康设备,返回模拟设备"); return GetMockDevices(); } _logger.LogInformation("成功枚举到 {Count} 个海康设备", devices.Count); return Result.Success>(devices); } catch (Exception ex) { _logger.LogError(ex, "枚举海康设备失败"); return Result.Fail>("HIK_ENUM_FAILED", "枚举海康设备失败"); } } /// public Result ConnectToDevice(HikCameraDevice device) { if (device == null) { return Result.Fail("HIK_CAMERA_DEVICE_NULL", "相机设备不能为空。"); } lock (_lockObject) { try { if (_isConnected) { return Result.Fail("HIK_CAMERA_ALREADY_CONNECTED", "相机已连接,请先断开。"); } _logger.LogInformation("正在连接相机设备: {SerialNumber}", device.SerialNumber); if (_options.RunMode != "Real" || !_sdkInitialized) { _logger.LogWarning("真实模式未启用或SDK未初始化,使用模拟连接"); return MockConnect(device); } // 查找目标设备信息 MyCamera.MV_CC_DEVICE_INFO targetDeviceInfo = default; bool foundDevice = false; var deviceList = new MyCamera.MV_CC_DEVICE_INFO_LIST(); var enumResult = _camera.MV_CC_EnumDevices_NET(MyCamera.MV_GIGE_DEVICE | MyCamera.MV_USB_DEVICE, ref deviceList); if (enumResult == MyCamera.MV_OK) { for (uint i = 0; i < deviceList.nDeviceNum; i++) { var deviceInfo = deviceList.MvDeviceInfo[i]; var serialNumber = Marshal.PtrToStringAnsi(deviceInfo.SpecialInfo.stGigEInfo.chSerialNumber) ?? ""; var ipAddress = Marshal.PtrToStringAnsi(deviceInfo.SpecialInfo.stGigEInfo.nCurrentIp) ?? ""; if (serialNumber.Equals(device.SerialNumber, StringComparison.OrdinalIgnoreCase) || ipAddress.Equals(device.IpAddress, StringComparison.OrdinalIgnoreCase)) { targetDeviceInfo = deviceInfo; foundDevice = true; break; } } } if (!foundDevice) { _logger.LogError("未找到指定的相机设备: {SerialNumber}", device.SerialNumber); return Result.Fail("HIK_DEVICE_NOT_FOUND", $"未找到指定的相机设备: {device.SerialNumber}"); } // 创建设备句柄 var createResult = _camera.MV_CC_CreateHandle_NET(ref targetDeviceInfo, out _deviceHandle); if (createResult != MyCamera.MV_OK) { _logger.LogError("创建相机句柄失败,错误代码: {ErrorCode}", createResult); return Result.Fail("HIK_CREATE_HANDLE_FAILED", $"创建相机句柄失败,错误代码: {createResult}"); } // 打开设备 var openResult = _camera.MV_CC_OpenDevice_NET(_deviceHandle, MyCamera.MV_ACCESS_Exclusive, 0); if (openResult != MyCamera.MV_OK) { _logger.LogError("打开相机设备失败,错误代码: {ErrorCode}", openResult); _camera.MV_CC_DestroyHandle_NET(_deviceHandle); _deviceHandle = IntPtr.Zero; return Result.Fail("HIK_OPEN_DEVICE_FAILED", $"打开相机设备失败,错误代码: {openResult}"); } // 获取设备信息 _deviceInfo = targetDeviceInfo; var deviceInfoResult = GetDeviceInfo(); if (!deviceInfoResult.Succeeded) { _camera.MV_CC_CloseDevice_NET(_deviceHandle); _camera.MV_CC_DestroyHandle_NET(_deviceHandle); _deviceHandle = IntPtr.Zero; _deviceInfo = null; return Result.Fail(deviceInfoResult.Code, deviceInfoResult.Message, deviceInfoResult.Errors.ToArray()); } _currentDevice = new HikCameraDevice { SerialNumber = device.SerialNumber, DeviceName = device.DeviceName, IpAddress = device.IpAddress, SubnetMask = device.SubnetMask, DefaultGateway = device.DefaultGateway, MacAddress = device.MacAddress, FirmwareVersion = device.FirmwareVersion, IsConnected = true, ConnectedAt = DateTime.UtcNow }; _isConnected = true; _reconnectAttempts = 0; _logger.LogInformation("相机连接成功: {SerialNumber}", device.SerialNumber); OnConnectionStateChanged?.Invoke(true, $"已连接到 {device.DeviceName}"); return Result.Success(message: $"相机 {device.DeviceName} 连接成功。"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "连接相机失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "HIK_CAMERA_CONNECT_FAILED", "连接相机失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } } /// public Result ConnectToDevice(string serialNumberOrIp) { var devicesResult = EnumerateDevices(); if (!devicesResult.Succeeded) { return Result.Fail(devicesResult.Code, devicesResult.Message, devicesResult.Errors.ToArray()); } var targetDevice = devicesResult.Data.FirstOrDefault(d => d.SerialNumber.Equals(serialNumberOrIp, StringComparison.OrdinalIgnoreCase) || d.IpAddress.Equals(serialNumberOrIp, StringComparison.OrdinalIgnoreCase)); if (targetDevice == null) { return Result.Fail("HIK_CAMERA_NOT_FOUND", $"未找到序列号或IP为 {serialNumberOrIp} 的相机设备。"); } return ConnectToDevice(targetDevice); } /// public Result Disconnect() { lock (_lockObject) { try { if (!_isConnected) { return Result.Success(message: "相机未连接。"); } _logger.LogInformation("正在断开相机连接..."); // 停止采集 if (_isGrabbing) { StopGrabbing(); } // 实际实现需要调用海康SDK的MV_CC_CloseDevice、MV_CC_DestroyHandle等函数 if (_options.RunMode == "Real" && _deviceHandle != IntPtr.Zero && _camera != null) { // 关闭设备 var closeResult = _camera.MV_CC_CloseDevice_NET(_deviceHandle); if (closeResult != MyCamera.MV_OK) { _logger.LogWarning("关闭相机设备失败,错误代码: {ErrorCode}", closeResult); } // 销毁句柄 var destroyResult = _camera.MV_CC_DestroyHandle_NET(_deviceHandle); if (destroyResult != MyCamera.MV_OK) { _logger.LogWarning("销毁相机句柄失败,错误代码: {ErrorCode}", destroyResult); } _deviceHandle = IntPtr.Zero; _deviceInfo = null; } Thread.Sleep(100); var deviceName = _currentDevice?.DeviceName ?? "未知设备"; _currentDevice = null; _isConnected = false; _logger.LogInformation("相机断开连接成功"); OnConnectionStateChanged?.Invoke(false, $"已断开与 {deviceName} 的连接"); return Result.Success(message: "相机断开连接成功。"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "断开相机连接失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "HIK_CAMERA_DISCONNECT_FAILED", "断开相机连接失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } } /// public Result SetCameraParameters(int width, int height, string pixelFormat, int triggerMode = 0) { lock (_lockObject) { try { if (!_isConnected) { return Result.Fail("HIK_CAMERA_NOT_CONNECTED", "相机未连接。"); } _logger.LogInformation("正在设置相机参数: {Width}x{Height}, {PixelFormat}, TriggerMode: {TriggerMode}", width, height, pixelFormat, triggerMode); if (_options.RunMode != "Real" || _deviceHandle == IntPtr.Zero || _camera == null) { _logger.LogDebug("模拟模式:设置相机参数"); return Result.Success(message: "相机参数设置成功(模拟模式)。"); } // 设置图像宽度 var widthResult = _camera.MV_CC_SetIntValue_NET(_deviceHandle, "Width", width); if (widthResult != MyCamera.MV_OK) { _logger.LogWarning("设置图像宽度失败,错误代码: {ErrorCode}", widthResult); } // 设置图像高度 var heightResult = _camera.MV_CC_SetIntValue_NET(_deviceHandle, "Height", height); if (heightResult != MyCamera.MV_OK) { _logger.LogWarning("设置图像高度失败,错误代码: {ErrorCode}", heightResult); } // 设置像素格式 var pixelFormatResult = _camera.MV_CC_SetEnumValue_NET(_deviceHandle, "PixelFormat", GetPixelFormatValue(pixelFormat)); if (pixelFormatResult != MyCamera.MV_OK) { _logger.LogWarning("设置像素格式失败,错误代码: {ErrorCode}", pixelFormatResult); } // 设置触发模式 var triggerModeResult = _camera.MV_CC_SetEnumValue_NET(_deviceHandle, "TriggerMode", triggerMode); if (triggerModeResult != MyCamera.MV_OK) { _logger.LogWarning("设置触发模式失败,错误代码: {ErrorCode}", triggerModeResult); } Thread.Sleep(100); // 等待参数生效 _logger.LogInformation("相机参数设置成功"); return Result.Success(message: "相机参数设置成功。"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "设置相机参数失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "HIK_CAMERA_SET_PARAMS_FAILED", "设置相机参数失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } } /// public Result StartGrabbing() { lock (_lockObject) { try { if (!_isConnected) { return Result.Fail("HIK_CAMERA_NOT_CONNECTED", "相机未连接。"); } if (_isGrabbing) { return Result.Success(message: "相机已在采集中。"); } _logger.LogInformation("正在开始图像采集..."); if (_options.RunMode != "Real" || _deviceHandle == IntPtr.Zero || _camera == null) { _logger.LogDebug("模拟模式:开始图像采集"); _isGrabbing = true; _frameQueue.Clear(); // 启动定时器生成模拟帧 _frameTimer = new Timer(GenerateMockFrame, null, TimeSpan.Zero, TimeSpan.FromMilliseconds(33)); // 约30fps return Result.Success(message: "图像采集启动成功(模拟模式)。"); } // 开始采集 var startResult = _camera.MV_CC_StartGrabbing_NET(_deviceHandle); if (startResult != MyCamera.MV_OK) { _logger.LogError("启动图像采集失败,错误代码: {ErrorCode}", startResult); return Result.Fail("HIK_START_GRABBING_FAILED", $"启动图像采集失败,错误代码: {startResult}"); } Thread.Sleep(100); // 等待采集启动 _isGrabbing = true; _frameQueue.Clear(); // 启动定时器获取图像帧 _frameTimer = new Timer(GetFrameFromCamera, null, TimeSpan.Zero, TimeSpan.FromMilliseconds(33)); // 约30fps _logger.LogInformation("图像采集已启动"); return Result.Success(message: "图像采集启动成功。"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "启动图像采集失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "HIK_CAMERA_START_GRAB_FAILED", "启动图像采集失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } } /// public Result StopGrabbing() { lock (_lockObject) { try { if (!_isGrabbing) { return Result.Success(message: "相机未在采集状态。"); } _logger.LogInformation("正在停止图像采集..."); // 停止定时器 _frameTimer?.Dispose(); _frameTimer = null; if (_options.RunMode == "Real" && _deviceHandle != IntPtr.Zero && _camera != null) { var stopResult = _camera.MV_CC_StopGrabbing_NET(_deviceHandle); if (stopResult != MyCamera.MV_OK) { _logger.LogWarning("停止图像采集失败,错误代码: {ErrorCode}", stopResult); } } Thread.Sleep(50); // 等待采集停止 _isGrabbing = false; _frameQueue.Clear(); _logger.LogInformation("图像采集已停止"); return Result.Success(message: "图像采集停止成功。"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "停止图像采集失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "HIK_CAMERA_STOP_GRAB_FAILED", "停止图像采集失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } } /// public Result TriggerSoftware() { lock (_lockObject) { try { if (!_isConnected) { return Result.Fail("HIK_CAMERA_NOT_CONNECTED", "相机未连接。"); } if (!_isGrabbing) { return Result.Fail("HIK_CAMERA_NOT_GRABBING", "相机未在采集状态。"); } if (_options.RunMode == "Real" && _camera != null) { _logger.LogDebug("执行软件触发"); var triggerResult = _camera.MV_CC_SetCommandValue_NET(_deviceHandle, "TriggerSoftware"); if (triggerResult != MyCamera.MV_OK) { _logger.LogWarning("软件触发失败,错误代码: {ErrorCode}", triggerResult); return Result.Fail("HIK_CAMERA_TRIGGER_FAILED", $"软件触发失败,错误代码: {triggerResult}"); } } return Result.Success(message: "软件触发执行成功。"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "软件触发失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "HIK_CAMERA_TRIGGER_FAILED", "软件触发失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } } /// public Result GetLatestFrame() { try { if (!_isGrabbing) { return Result.Fail("HIK_CAMERA_NOT_GRABBING", "相机未在采集状态。"); } if (_frameQueue.TryDequeue(out var frame)) { return Result.Success(frame, message: "获取图像帧成功。"); } return Result.Fail("HIK_CAMERA_NO_FRAME", "暂无可用图像帧。"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "获取图像帧失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "HIK_CAMERA_GET_FRAME_FAILED", "获取图像帧失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// public Result GetLatestFrameWithTimestamp() { var frameResult = GetLatestFrame(); if (!frameResult.Succeeded) { return Result.Fail(frameResult.Code, frameResult.Message, frameResult.Errors.ToArray()); } var now = DateTime.UtcNow; return Result.Success(new CameraFrameDto { FrameId = Guid.NewGuid(), CapturedAtUtc = now, CameraId = _currentDevice?.SerialNumber ?? string.Empty, ImageData = frameResult.Data, Timestamp = now, Width = _options.ImageWidth, Height = _options.ImageHeight, PixelFormat = _options.PixelFormat }, message: "获取图像帧成功。"); } /// /// 从相机获取图像帧。 /// private void GetFrameFromCamera(object? state) { try { if (!_isGrabbing || _options.RunMode != "Real" || !_sdkInitialized) { return; } if (_deviceHandle == IntPtr.Zero || _camera == null) { return; } // 获取一帧图像数据 var frame = new MyCamera.MV_FRAME_OUT_INFO_EX(); var imageBuffer = IntPtr.Zero; var getFrameResult = _camera.MV_CC_GetOneFrameTimeout_NET(_deviceHandle, ref frame, 1000); if (getFrameResult == MyCamera.MV_OK) { try { // 转换图像数据为BGR格式 var convertResult = _camera.MV_CC_ConvertPixelType_NET(_deviceHandle, frame, MyCamera.MV_Gvsp_RGB8_Packed, ref imageBuffer); if (convertResult == MyCamera.MV_OK && imageBuffer != IntPtr.Zero) { var frameSize = frame.nWidth * frame.nHeight * 3; // BGR8Packed var frameData = new byte[frameSize]; Marshal.Copy(imageBuffer, frameData, 0, frameSize); var timestamp = DateTime.UtcNow; // 添加到队列 if (_frameQueue.Count < 10) // 限制队列大小防止内存溢出 { _frameQueue.Enqueue(frameData); } // 触发事件 OnImageReceived?.Invoke(frameData, timestamp); // 释放图像缓冲区 _camera.MV_CC_FreeImageBuffer_NET(_deviceHandle, ref frame); } else { // 转换失败,使用模拟数据 GenerateMockFrame(null); } } catch (Exception ex) { _logger.LogError(ex, "处理图像帧数据时发生异常"); } finally { // 确保释放缓冲区 if (imageBuffer != IntPtr.Zero) { _camera.MV_CC_FreeImageBuffer_NET(_deviceHandle, ref frame); } } } else { // 获取图像失败,使用模拟数据 GenerateMockFrame(null); } } catch (Exception ex) { _logger.LogError(ex, "从相机获取图像帧失败"); } } /// /// 生成模拟图像帧。 /// private void GenerateMockFrame(object? state) { try { var width = _options.ImageWidth; var height = _options.ImageHeight; var frameSize = width * height * 3; // BGR8Packed var frameData = new byte[frameSize]; // 填充模拟图像数据(简单的渐变图案) var random = new Random(); for (int i = 0; i < frameSize; i += 3) { frameData[i] = (byte)(i % 256); // B frameData[i + 1] = (byte)((i / 3) % 256); // G frameData[i + 2] = (byte)random.Next(256); // R } var timestamp = DateTime.UtcNow; // 添加到队列 if (_frameQueue.Count < 10) { _frameQueue.Enqueue(frameData); } // 触发事件 OnImageReceived?.Invoke(frameData, timestamp); } catch (Exception ex) { _logger.LogError(ex, "生成模拟图像帧失败"); } } /// /// 获取设备详细信息。 /// private Result GetDeviceInfo() { try { if (_deviceHandle == IntPtr.Zero || !_deviceInfo.HasValue) { return Result.Fail("HIK_DEVICE_NOT_CONNECTED", "设备未连接"); } var info = _deviceInfo.Value; // 获取设备型号名称 var modelName = Marshal.PtrToStringAnsi(info.SpecialInfo.stGigEInfo.chModelName) ?? "Unknown"; // 获取设备序列号 var serialNumber = Marshal.PtrToStringAnsi(info.SpecialInfo.stGigEInfo.chSerialNumber) ?? "Unknown"; // 获取设备用户定义名称 var userDefinedName = Marshal.PtrToStringAnsi(info.SpecialInfo.stGigEInfo.chUserDefinedName) ?? "Unknown"; // 获取固件版本 var firmwareVersion = Marshal.PtrToStringAnsi(info.SpecialInfo.stGigEInfo.chFirmwareVersion) ?? "Unknown"; // 获取IP地址 var ipAddress = Marshal.PtrToStringAnsi(info.SpecialInfo.stGigEInfo.nCurrentIp) ?? "Unknown"; // 获取子网掩码 var subnetMask = Marshal.PtrToStringAnsi(info.SpecialInfo.stGigEInfo.nCurrentSubNet) ?? "Unknown"; // 获取默认网关 var defaultGateway = Marshal.PtrToStringAnsi(info.SpecialInfo.stGigEInfo.nDefaultGate) ?? "Unknown"; // 获取MAC地址 var macAddress = Marshal.PtrToStringAnsi(info.SpecialInfo.stGigEInfo.nCurrentMac) ?? "Unknown"; // 更新当前设备信息 if (_currentDevice != null) { _currentDevice.DeviceName = userDefinedName; _currentDevice.FirmwareVersion = firmwareVersion; _currentDevice.SubnetMask = subnetMask; _currentDevice.DefaultGateway = defaultGateway; _currentDevice.MacAddress = macAddress; } _logger.LogDebug("设备信息: {ModelName}, {SerialNumber}, {IpAddress}", modelName, serialNumber, ipAddress); return Result.Success(message: "获取设备信息成功。"); } catch (Exception ex) { var traceId = Guid.NewGuid().ToString("N"); _logger.LogError(ex, "获取设备信息失败。TraceId: {TraceId}", traceId); var result = Result.FromException(ex, "HIK_GET_DEVICE_INFO_FAILED", "获取设备信息失败。", traceId); return Result.FailWithTrace(result.Code, result.Message, result.TraceId ?? traceId, result.Errors.ToArray()); } } /// /// 模拟连接。 /// private Result MockConnect(HikCameraDevice device) { _currentDevice = new HikCameraDevice { SerialNumber = device.SerialNumber, DeviceName = device.DeviceName, IpAddress = device.IpAddress, MacAddress = device.MacAddress, IsConnected = true, ConnectedAt = DateTime.UtcNow }; _isConnected = true; _logger.LogInformation("模拟连接成功: {SerialNumber}", device.SerialNumber); OnConnectionStateChanged?.Invoke(true, $"模拟连接到 {device.DeviceName}"); return Result.Success(message: $"相机 {device.DeviceName} 模拟连接成功。"); } /// /// 获取模拟设备。 /// private Result> GetMockDevices() { var mockDevices = new List { new() { SerialNumber = "MOCK_HIK_001", DeviceName = "模拟海康相机_001", IpAddress = "192.168.1.100", MacAddress = "00:11:22:33:44:55", IsConnected = true }, new() { SerialNumber = "MOCK_HIK_002", DeviceName = "模拟海康相机_002", IpAddress = "192.168.1.101", MacAddress = "00:11:22:33:44:56", IsConnected = true } }; _logger.LogInformation("返回 {Count} 个模拟设备", mockDevices.Count); return Result.Success>(mockDevices); } /// /// 获取像素格式值。 /// private uint GetPixelFormatValue(string pixelFormat) { return pixelFormat.ToUpperInvariant() switch { "BGR8PACKED" => MyCamera.MV_Gvsp_RGB8_Packed, "RGB8PACKED" => MyCamera.MV_Gvsp_RGB8_Packed, "MONO8" => MyCamera.MV_Gvsp_Mono8, "MONO16" => MyCamera.MV_Gvsp_Mono16, _ => MyCamera.MV_Gvsp_RGB8_Packed }; } /// /// 自动重连。 /// private async Task AutoReconnectAsync() { if (_reconnectAttempts >= _options.AutoReconnectCount) { _logger.LogWarning("已达到最大重连次数,停止重连"); return; } _reconnectAttempts++; _logger.LogInformation("执行第 {Attempt} 次自动重连", _reconnectAttempts); await Task.Delay(_options.AutoReconnectIntervalMs); if (_currentDevice != null) { var connectResult = ConnectToDevice(_currentDevice.SerialNumber); if (connectResult.Succeeded) { _logger.LogInformation("自动重连成功"); _reconnectAttempts = 0; } else { _logger.LogWarning("自动重连失败: {Error}", connectResult.Message); await AutoReconnectAsync(); } } } /// /// 释放资源。 /// public void Dispose() { try { // 停止定时器 _frameTimer?.Dispose(); _frameTimer = null; // 断开连接 Disconnect(); // 释放SDK if (_sdkInitialized && _options.RunMode == "Real") { _camera?.MV_CC_Finalize_NET(); _camera?.Dispose(); _camera = null; _sdkInitialized = false; } _logger.LogInformation("海康相机服务已释放"); } catch (Exception ex) { _logger.LogError(ex, "释放海康相机服务资源时发生错误"); } } }