using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; using TeamAAS.Camera.Attributes; using TeamAAS.Camera.Enums; using TeamAAS.Camera.Interfaces; using TeamAAS.Camera.Models; namespace TeamAAS.Camera { /// /// 相机生命周期和配置管理器。 /// 负责相机实例的创建、注册、连接、采集控制、移除、JSON 配置持久化以及品牌/设备发现。 /// 同时作为懒汉单例使用:CameraManager.Instance。 /// public class CameraManager : ICameraManager { #region 单例 private static readonly Lazy _instance = new Lazy(() => new CameraManager(), isThreadSafe: true); /// /// 懒汉单例入口。首次访问时初始化,线程安全。 /// public static CameraManager Instance => _instance.Value; #endregion #region 字段 private readonly Dictionary _cameras; private readonly object _sync = new object(); // 设备发现 provider 缓存 private List _providers; private readonly object _providerLock = new object(); // 反射扫描结果缓存 private List _scannedTypes; private readonly object _scanLock = new object(); #endregion #region 构造 /// /// 默认构造(供单例和 DI 容器使用)。 /// 外部不应直接 new,请使用 或通过 DI 注入 。 /// public CameraManager() { _cameras = new Dictionary(); } #endregion #region 相机生命周期 public bool CreateCamera(Guid id, CameraInfo cameraInfo) { if (cameraInfo == null) throw new ArgumentNullException(nameof(cameraInfo)); var camera = CreateCameraInstance(id, cameraInfo); ICamera existing = null; lock (_sync) { _cameras.TryGetValue(id, out existing); _cameras[id] = camera; } if (existing != null && !ReferenceEquals(existing, camera)) { try { if (existing.IsGrabbing) existing.StopGrabbing(); } catch { } try { existing.CloseDevice(); } catch { } } return true; } public Task CreateCameraAsync(Guid id, CameraInfo cameraInfo) { return Task.Run(() => CreateCamera(id, cameraInfo)); } public ICamera GetCamera(Guid id) { lock (_sync) { return _cameras.TryGetValue(id, out var cam) ? cam : null; } } public Task GetCameraAsync(Guid id) { return Task.Run(() => GetCamera(id)); } public IReadOnlyCollection GetAllCameras() { lock (_sync) { return _cameras.Values.ToList().AsReadOnly(); } } public Task> GetAllCamerasAsync() { return Task.Run(() => GetAllCameras()); } public bool TryGetCamera(Guid id, out ICamera camera) { lock (_sync) { return _cameras.TryGetValue(id, out camera); } } public IReadOnlyList Devices { get { lock (_sync) { return _cameras.Values.ToList().AsReadOnly(); } } } public bool ContainsCamera(Guid id) { lock (_sync) { return _cameras.ContainsKey(id); } } public bool ContainsSN(string serialNumber) { lock (_sync) { return _cameras?.Values.Any(c => c.SerialNumber == serialNumber) ?? false; } } public bool RemoveCamera(Guid id) { ICamera camera = null; lock (_sync) { if (_cameras.TryGetValue(id, out camera)) { _cameras.Remove(id); } } if (camera != null) { try { if (camera.IsGrabbing) camera.StopGrabbing(); } catch { } try { camera.CloseDevice(); } catch { } return true; } return false; } public Task RemoveCameraAsync(Guid id) { return Task.Run(() => RemoveCamera(id)); } public void UnRegisterCamera(Guid id) { RemoveCamera(id); } /// /// 停止采集并关闭所有相机(程序退出前调用)。 /// 幂等:已关闭的设备再调一次不会抛异常。 /// public void CloseAll() { List list; lock (_sync) { list = _cameras.Values.ToList(); _cameras.Clear(); } foreach (var camera in list) { try { if (camera.IsGrabbing) camera.StopGrabbing(); } catch { } try { camera.CloseDevice(); } catch { } } } public Task UnRegisterCameraAsync(Guid id) { return Task.Run(() => RemoveCamera(id)); } public ICamera GetCameraByNumber(int number) { lock (_sync) { foreach (var kvp in _cameras) { if (kvp.Value != null && kvp.Value.Index == number) return kvp.Value; } } return null; } public void RemoveAllCameras() { List ids; lock (_sync) { ids = _cameras.Keys.ToList(); } foreach (var id in ids) { RemoveCamera(id); } } public (bool IsSucceed, string Message) InitializeAllCameras(CameraInfo[] cameras) { RemoveAllCameras(); foreach (var info in cameras) { var camera = CreateCameraInstance(info.Id, info); lock (_sync) { _cameras[info.Id] = camera; } } bool allConnected = true; StringBuilder errors = new StringBuilder(); foreach (var info in cameras) { if (TryGetCamera(info.Id, out var camera)) { bool opened = camera.OpenDevice(); if (!opened) { allConnected = false; errors.AppendLine($"相机 {info.CameraName}(编号: {info.CameraNo})打开失败: {camera.ErrorMessage}"); } else { // 应用配置里持久化的参数快照(曝光/增益/Gamma),null 表示沿用硬件默认值 ApplySavedParameters(camera, info); } } else { allConnected = false; errors.AppendLine($"未找到相机 {info.CameraName}(编号: {info.CameraNo})的实例。"); } } return allConnected ? (true, "所有相机均已成功初始化并连接。") : (false, errors.ToString()); } public Task<(bool IsSucceed, string Message)> InitializeAllCamerasAsync(CameraInfo[] cameras) { return Task.Run(() => InitializeAllCameras(cameras)); } public void UpdateCameraNumber(Guid id, int newNumber) { if (TryGetCamera(id, out var camera)) { camera.Index = newNumber; } } #endregion #region 配置持久化 public static string DefaultConfigPath { get { return Path.Combine(TeamAAS.PathHelper.ConfigDirectory, "Cameras.json"); } } public bool SaveConfig(string path = null) { path = path ?? DefaultConfigPath; var infos = new List(); lock (_sync) { foreach (var cam in _cameras.Values) { infos.Add(new CameraInfo { Id = cam.ID, CameraNo = cam.Index, CameraName = cam.Name, CameraBrand = cam.CameraBrand, CameraType = cam.CameraType, CameraIp = cam.CameraIp, IsFindByIp = cam.IsFindByIp, SerialNumber = cam.SerialNumber, Model = cam.ModelName, ManufacturerName = cam.ManufacturerName, ExposureTime = cam.ExposureTime, Gain = cam.Gain, Gamma = cam.Gamma, }); } } return TeamAAS.JsonFileStore.Save(path, infos); } public IReadOnlyList GetAllCameraInfos() { var infos = new List(); lock (_sync) { foreach (var cam in _cameras.Values) { infos.Add(new CameraInfo { Id = cam.ID, CameraNo = cam.Index, CameraName = cam.Name, CameraBrand = cam.CameraBrand, CameraType = cam.CameraType, CameraIp = cam.CameraIp, IsFindByIp = cam.IsFindByIp, SerialNumber = cam.SerialNumber, Model = cam.ModelName, ManufacturerName = cam.ManufacturerName, ExposureTime = cam.ExposureTime, Gain = cam.Gain, Gamma = cam.Gamma, }); } } return infos.AsReadOnly(); } public void LoadConfig(string path = null) { path = path ?? DefaultConfigPath; if (!File.Exists(path)) return; var infos = TeamAAS.JsonFileStore.Load>(path); if (infos == null || infos.Count == 0) return; InitializeAllCameras(infos.ToArray()); } #endregion #region 品牌/设备发现(原 CameraFactory 职责) /// /// 获取所有已注册的相机品牌 provider(首次访问时反射扫描并缓存)。 /// private List GetProviders() { if (_providers != null) return _providers; lock (_providerLock) { if (_providers != null) return _providers; _providers = ScanProviders(); return _providers; } } private List ScanProviders() { var result = new List(); // 通用模块扫描:收集全部 ICamera 实现(含 Runtime\Plugins 里的插件 DLL) foreach (var type in TeamAAS.Modularity.AssemblyScanner.FindImplementations()) { var attr = type.GetCustomAttribute(); if (attr == null) continue; var getDevicesMethod = type.GetMethod("GetDevices", BindingFlags.Public | BindingFlags.Static); var checkInstalledMethod = type.GetMethod("CheckSoftwareInstalled", BindingFlags.Public | BindingFlags.Static); if (getDevicesMethod == null) continue; result.Add(new CameraProviderInfo { CameraType = type, Brand = attr.Brand, DisplayName = attr.DisplayName, GetDevicesDelegate = () => { try { var r = getDevicesMethod.Invoke(null, null); if (r is CameraInfo[] arr) return arr.ToList(); if (r is IEnumerable list) return list.ToList(); return new List(); } catch { return new List(); } }, CheckInstalledDelegate = () => { if (checkInstalledMethod == null) return (false, ""); try { var r = checkInstalledMethod.Invoke(null, null); if (r is ValueTuple tuple) return tuple; if (r is Tuple t2) return (t2.Item1, t2.Item2); return (false, ""); } catch { return (false, ""); } } }); } return result .GroupBy(p => p.CameraType.FullName) .Select(g => g.First()) .OrderBy(p => p.DisplayName) .ToList(); } /// /// 搜索所有品牌的可用相机设备 /// public List DiscoverAllDevices() { var allDevices = new List(); int index = 1; foreach (var provider in GetProviders()) { try { var devices = provider.GetDevicesDelegate(); foreach (var d in devices) { d.CameraNo = index++; allDevices.Add(d); } } catch { } } return allDevices; } /// /// 按品牌搜索可用相机设备 /// public List DiscoverByBrand(string brand) { var provider = GetProviders().FirstOrDefault(p => p.Brand == brand); if (provider == null) throw new NotSupportedException($"品牌 {brand} 暂未实现设备发现功能"); try { return provider.GetDevicesDelegate(); } catch { return new List(); } } /// /// 获取已安装的相机品牌列表(用于弹窗选择) /// public List<(string Brand, string DisplayName, bool Installed)> GetAvailableBrands() { var list = new List<(string, string, bool)>(); foreach (var provider in GetProviders()) { try { var (installed, _) = provider.CheckInstalledDelegate(); list.Add((provider.Brand, provider.DisplayName, installed)); } catch { list.Add((provider.Brand, provider.DisplayName, false)); } } return list; } /// /// 获取相机品牌的显示名称 /// public string GetBrandDisplayName(string brand) { var provider = GetProviders().FirstOrDefault(p => p.Brand == brand); return provider?.DisplayName ?? brand; } /// /// 获取已安装的相机SDK列表 /// public List<(string Name, bool Installed, string Version)> GetSdkStatus() { var list = new List<(string, bool, string)>(); foreach (var provider in GetProviders()) { try { var (installed, version) = provider.CheckInstalledDelegate(); list.Add((provider.DisplayName, installed, version)); } catch { list.Add((provider.DisplayName, false, "")); } } return list; } #endregion #region 反射扫描(类型信息) /// /// 获取所有可用的相机类型信息(通过 [Camera] 特性自动发现)。 /// public IReadOnlyList GetAvailableTypes() { if (_scannedTypes != null) return _scannedTypes.AsReadOnly(); lock (_scanLock) { if (_scannedTypes != null) return _scannedTypes.AsReadOnly(); _scannedTypes = ScanTypes(); return _scannedTypes.AsReadOnly(); } } private List ScanTypes() { var result = new List(); // 通用模块扫描:收集全部 ICamera 实现(含 Runtime\Plugins 里的插件 DLL) foreach (var type in TeamAAS.Modularity.AssemblyScanner.FindImplementations()) { var attr = type.GetCustomAttribute(); if (attr == null) continue; result.Add(new CameraTypeInfo { TypeKey = type.FullName, DisplayName = attr.DisplayName, Brand = attr.Brand, Description = attr.Description, Type = type }); } return result .GroupBy(t => t.TypeKey) .Select(g => g.First()) .OrderBy(t => t.DisplayName) .ToList(); } #endregion #region IDisposable public void Dispose() { RemoveAllCameras(); GC.SuppressFinalize(this); } #endregion #region 私有辅助 private ICamera CreateCameraInstance(Guid id, CameraInfo info) { var types = GetAvailableTypes(); var match = types.FirstOrDefault(t => t.Brand == info.CameraBrand); if (match == null) throw new NotSupportedException("Unsupported camera brand: " + info.CameraBrand); return (ICamera)Activator.CreateInstance( match.Type, id, info.CameraNo, info.CameraName, info.SerialNumber, info.CameraIp, info.IsFindByIp); } /// /// 相机打开成功后,把 Cameras.json 中持久化的参数快照下发到硬件。 /// 属性 setter 内部已做异常兜底(失败写入 ErrorMessage),此处再整体兜底保证初始化流程不被打断。 /// private static void ApplySavedParameters(ICamera camera, CameraInfo info) { if (camera == null || info == null) return; try { // 自动曝光是相机品牌特有(UVC)的运行时开关,不在这层恢复; // 恢复手动参数即可——UVC 处于自动曝光时会自行忽略手动写入。 if (info.ExposureTime.HasValue) camera.ExposureTime = info.ExposureTime.Value; if (info.Gain.HasValue) camera.Gain = info.Gain.Value; if (info.Gamma.HasValue) camera.Gamma = info.Gamma.Value; } catch { } } private class CameraProviderInfo { public Type CameraType { get; set; } public string Brand { get; set; } public string DisplayName { get; set; } public Func> GetDevicesDelegate { get; set; } public Func<(bool isInstalled, string version)> CheckInstalledDelegate { get; set; } } #endregion } public class CameraTypeInfo { public string TypeKey { get; set; } public string DisplayName { get; set; } public string Brand { get; set; } public string Description { get; set; } public Type Type { get; set; } } }