using Cis.Application.Cb; using Cis.Application.Cm; using Cis.Application.Core.Component.PtzServer; using EC.Helper.CameraSDK; using EC.Helper.RabbitFunc; using EC.Helper.RabbitFunc.Expressions; using FreeRedis; using System.Collections.Concurrent; namespace Cis.Application.Core.Component.MarkSeacher; /// /// 追踪标签服务类 /// public class MarkSearcherServer : IMarkSearcherServer, ISingleton { #region Attr private readonly SqlSugarRepository _cbCameraRep; private readonly SqlSugarRepository _cbCameraParamsRep; private readonly SqlSugarRepository _cmMarkLableRep; private readonly RedisClient _cache; private readonly ICameraSdkServer _cameraSdkServer; /// /// {cbCameraId, MarkSearcherBase} /// private ConcurrentDictionary MarkSearcherDict { get; set; } = new(); /// /// MarkSearcherDict 原子操作锁 /// private ReaderWriterLockSlim MsDictRWLock { get; } = new(); /// /// MarkSearcherDict 中 MarkLabel 原子操作锁 /// private ReaderWriterLockSlim MsMlRWLock { get; } = new(); #endregion Attr public MarkSearcherServer( RedisClient cache, ICameraSdkServer cameraSdkServer ) { _cbCameraRep = App.GetService>(); _cbCameraParamsRep = App.GetService>(); _cmMarkLableRep = App.GetService>(); _cache = cache; _cameraSdkServer = cameraSdkServer; } #region Base Method public bool ActivateSearcher(long cameraId) { try { MsDictRWLock.TryEnterWriteLock(2000); return ActivateSearcherAtom(cameraId); } finally { MsDictRWLock.ExitWriteLock(); } } /// /// ActivateSearcher 原子操作 /// /// /// private bool ActivateSearcherAtom(long cameraId) { bool ret = MarkSearcherDict.ContainsKey(cameraId); if (ret) return false; // 获取相机 CbCamera cbCamera = _cbCameraRep.GetById(cameraId); if (cbCamera == null) return false; // 获取相机参数 CbCameraParams cbCameraParams = _cbCameraParamsRep.GetById(cbCamera.CbCameraParamsId); if (cbCameraParams == null) return false; // 注册并获取 ptz ret = _cameraSdkServer.IsExists(cbCamera.Ip); if (!ret) { CameraInfo cameraInfo = CameraInfo.New(cbCameraParams.CameraType, cbCamera.Ip, cbCamera.UserName, cbCamera.Password); ret = _cameraSdkServer.Register(cameraInfo); if (!ret) { // double check ret = _cameraSdkServer.IsExists(cbCamera.Ip); if (!ret) return false; } } ret = _cameraSdkServer.TryGetPtzInfoByIp(cbCamera.Ip, out PtzInfo ptzInfo); if (!ret) return false; // 解析 ZoomVaryFunc LambdaExpression zoomVaryExpr = RabbitFuncUtil.CompileFromSource(cbCameraParams.ZoomVaryFunc); // 创建相机计算参数 CameraCalcParams cameraCalcParams = CameraCalcParams.New(cbCamera.Id, ptzInfo, cbCameraParams.FocusX, cbCameraParams.FocusY, zoomVaryExpr); // 创建 markSearcher MarkSearcherBase markSearcher = ((CameraType)cbCameraParams.CameraType).CreateMarkSearcher(cameraCalcParams); if (markSearcher == null) return false; // 获取标签列表 List cmMarkLabelList = _cmMarkLableRep.GetList(u => u.CbCameraId == cameraId); // 将标签添加到 markSearcher foreach (CmMarkLabel item in cmMarkLabelList) { // 创建标签计算参数 MarkLabelCalcParams labelCalcParams = MarkLabelCalcParams.New( item.Id, PtzInfo.New(item.PanPosition, item.TiltPosition, item.ZoomPosition), item.VideoWidth, item.VideoHeight, item.CanvasLeftRatio, item.CanvasTopRatio ); markSearcher.AddMarkLabelCalcParams(labelCalcParams); } // 存放 markSearcher ret = MarkSearcherDict.TryAdd(cameraId, markSearcher); if (!ret) return false; // 记录缓存 _cache.HSet(CacheInfo.CameraId2Ip, cbCamera.Id.ToString(), cbCamera.Ip); _cache.HIncrBy(CacheInfo.CameraIpCounts, cbCamera.Ip, 1); return true; } public bool DeactivateSearcher(long cameraId) { try { MsDictRWLock.TryEnterWriteLock(2000); return DeactivateSearcherAtom(cameraId); } finally { MsDictRWLock.ExitWriteLock(); } } /// /// DeactivateSearcher 原子操作 /// /// /// private bool DeactivateSearcherAtom(long cameraId) { bool ret = MarkSearcherDict.TryRemove(cameraId, out _); if (!ret) return false; string cameraIp = _cache.HGet(CacheInfo.CameraId2Ip, cameraId.ToString()); if (string.IsNullOrEmpty(cameraIp)) return false; _cache.HDel(CacheInfo.CameraId2Ip, cameraId.ToString()); _cache.HIncrBy(CacheInfo.CameraIpCounts, cameraIp, -1); //int ipCount = (int)_cache.HashGet(CacheInfo.CameraIpCounts, cameraIp); //if (ipCount <= 0) //{ // // 直接删除 or 设置过期 // _cache.HashDelete(CacheInfo.CameraIpCounts, cameraIp); // _cameraSdkServer.DeleteCamera(cameraIp); //} return true; } public bool IsExistsSearcher(long cameraId) { return MarkSearcherDict.ContainsKey(cameraId); } public MarkSearcherBase GetSearcher(long cameraId) { MarkSearcherDict.TryGetValue(cameraId, out MarkSearcherBase searcher); return searcher; } public bool ActivateMarkLabel(long cameraId, long markLabelId) { try { MsMlRWLock.TryEnterWriteLock(2000); return ActivateMarkLabelAtom(cameraId, markLabelId); } finally { MsMlRWLock.ExitWriteLock(); } } /// /// ActivateMarkLabel 原子操作 /// /// /// /// private bool ActivateMarkLabelAtom(long cameraId, long markLabelId) { bool ret = MarkSearcherDict.TryGetValue(cameraId, out MarkSearcherBase markSearcher); if (!ret) return false; ret = markSearcher.IsExistsMarkLabelCalcParams(markLabelId); if (ret) return false; CmMarkLabel label = _cmMarkLableRep.GetById(markLabelId); if (label == null) return false; MarkLabelCalcParams labelCalcParams = MarkLabelCalcParams.New( label.Id, PtzInfo.New(label.PanPosition, label.TiltPosition, label.ZoomPosition), label.VideoWidth, label.VideoHeight, label.CanvasLeftRatio, label.CanvasTopRatio ); ret = markSearcher.AddMarkLabelCalcParams(labelCalcParams); return ret; } public bool DeactivateMarkLabel(long cameraId, long markLabelId) { try { MsMlRWLock.TryEnterWriteLock(2000); return DeactivateMarkLabelAtom(cameraId, markLabelId); } finally { MsMlRWLock.ExitWriteLock(); } } /// /// DeactivateMarkLabel 原子操作 /// /// /// /// private bool DeactivateMarkLabelAtom(long cameraId, long markLabelId) { bool ret = MarkSearcherDict.TryGetValue(cameraId, out MarkSearcherBase markSearcher); if (!ret) return false; ret = markSearcher.DeleteMarkLabelCalcParams(markLabelId); return ret; } public bool IsExistsMarkLabel(long cameraId, long markLabelId) { return MarkSearcherDict.TryGetValue(cameraId, out MarkSearcherBase searcher) && searcher.IsExistsMarkLabelCalcParams(markLabelId); } public List GetMarkLabelCalcResultList(long cameraId) { bool ret = MarkSearcherDict.TryGetValue(cameraId, out MarkSearcherBase markSearcher); return ret ? markSearcher.GetMarkLabelCalcResultList() : new List(); } #endregion Base Method #region Base Method Async public async Task ActivateSearcherAsync(long cameraId) { return await Task.Run(() => ActivateSearcher(cameraId)); } public async Task DeactivateSearcherAsync(long cameraId) { return await Task.Run(() => DeactivateSearcher(cameraId)); } public async Task IsExistsSearcherAsync(long cameraId) { return await Task.Run(() => IsExistsSearcher(cameraId)); } public async Task GetSearcherAsync(long cameraId) { return await Task.Run(() => GetSearcher(cameraId)); } public async Task ActivateMarkLabelAsync(long cameraId, long markLabelId) { return await Task.Run(() => ActivateMarkLabel(cameraId, markLabelId)); } public async Task DeactivateMarkLabelAsync(long cameraId, long markLabelId) { return await Task.Run(() => DeactivateMarkLabel(cameraId, markLabelId)); } public async Task IsExistsMarkLabelAsync(long cameraId, long markLabelId) { return await Task.Run(() => IsExistsMarkLabel(cameraId, markLabelId)); } public async Task> GetMarkLabelCalcResultListAsync(long cameraId) { return await Task.Run(() => GetMarkLabelCalcResultList(cameraId)); } #endregion Base Method Async }