You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
268 lines
8.4 KiB
268 lines
8.4 KiB
using Cis.Application.Cb;
|
|
using Cis.Application.Cm;
|
|
using Cis.Application.Core.Component.PtzServer;
|
|
using EC.Helper.CameraSDK;
|
|
using StackExchange.Redis;
|
|
using System.Collections.Concurrent;
|
|
|
|
namespace Cis.Application.Core.Component.MarkSeacher;
|
|
|
|
/// <summary>
|
|
/// 追踪标签服务类
|
|
/// </summary>
|
|
public class MarkSearcherServer : IMarkSearcherServer, ISingleton
|
|
{
|
|
#region Attr
|
|
|
|
private readonly SqlSugarRepository<CbCamera> _cbCameraRep;
|
|
private readonly SqlSugarRepository<CbCameraParams> _cbCameraParamsRep;
|
|
private readonly SqlSugarRepository<CmMarkLabel> _cmMarkLableRep;
|
|
private readonly IDatabase _cache;
|
|
|
|
private readonly ICameraSdkServer _cameraSdkServer;
|
|
|
|
/// <summary>
|
|
/// {cbCameraId, MarkSearcherBase}
|
|
/// </summary>
|
|
private ConcurrentDictionary<long, MarkSearcherBase> MarkSearcherDict { get; set; } = new();
|
|
|
|
/// <summary>
|
|
/// MarkSearcherDict 原子操作锁
|
|
/// </summary>
|
|
private ReaderWriterLockSlim MsDictRWLock { get; } = new();
|
|
|
|
#endregion Attr
|
|
|
|
public MarkSearcherServer(
|
|
IDatabase cache,
|
|
ICameraSdkServer cameraSdkServer
|
|
)
|
|
{
|
|
_cbCameraRep = App.GetService<SqlSugarRepository<CbCamera>>();
|
|
_cbCameraParamsRep = App.GetService<SqlSugarRepository<CbCameraParams>>();
|
|
_cmMarkLableRep = App.GetService<SqlSugarRepository<CmMarkLabel>>();
|
|
_cache = cache;
|
|
_cameraSdkServer = cameraSdkServer;
|
|
}
|
|
|
|
#region Base Method
|
|
|
|
public bool ActivateSearcher(long cameraId)
|
|
{
|
|
try
|
|
{
|
|
MsDictRWLock.EnterWriteLock();
|
|
return ActivateSearcherAtom(cameraId);
|
|
}
|
|
finally
|
|
{
|
|
MsDictRWLock.ExitWriteLock();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// ActivateSearcher 原子操作
|
|
/// </summary>
|
|
/// <param name="cameraId"></param>
|
|
/// <returns></returns>
|
|
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.IsExistsCamera(cbCamera.Ip);
|
|
if (!ret)
|
|
{
|
|
CameraInfo cameraInfo = CameraInfo.New(cbCameraParams.CameraType, cbCamera.Ip, cbCamera.UserName, cbCamera.Password);
|
|
ret = _cameraSdkServer.RegisterCamera(cameraInfo);
|
|
if (!ret)
|
|
{
|
|
// double check
|
|
ret = _cameraSdkServer.IsExistsCamera(cbCamera.Ip);
|
|
if (!ret) return false;
|
|
}
|
|
}
|
|
ret = _cameraSdkServer.GetPtzInfoByIp(cbCamera.Ip, out PtzInfo ptzInfo);
|
|
if (!ret) return false;
|
|
|
|
// 创建相机计算参数
|
|
CameraCalcParams cameraCalcParams = CameraCalcParams.New(cbCamera.Id, ptzInfo, cbCameraParams.FocusX, cbCameraParams.FocusY);
|
|
// 创建 markSearcher
|
|
MarkSearcherBase markSearcher = ((CameraType)cbCameraParams.CameraType).CreateMarkSearcher(cameraCalcParams);
|
|
if (markSearcher == null) return false;
|
|
// 获取标签列表
|
|
List<CmMarkLabel> 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.HashSet(CacheInfo.CameraId2Ip, cbCamera.Id, cbCamera.Ip);
|
|
_cache.HashIncrement(CacheInfo.CameraIpCounts, cbCamera.Ip);
|
|
return true;
|
|
}
|
|
|
|
public bool DeactivateSearcher(long cameraId)
|
|
{
|
|
try
|
|
{
|
|
MsDictRWLock.EnterWriteLock();
|
|
return DeactivateSearcherAtom(cameraId);
|
|
}
|
|
finally
|
|
{
|
|
MsDictRWLock.ExitWriteLock();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// DeactivateSearcher 原子操作
|
|
/// </summary>
|
|
/// <param name="cameraId"></param>
|
|
/// <returns></returns>
|
|
private bool DeactivateSearcherAtom(long cameraId)
|
|
{
|
|
bool ret = MarkSearcherDict.TryRemove(cameraId, out _);
|
|
if (!ret) return false;
|
|
RedisValue value = _cache.HashGet(CacheInfo.CameraId2Ip, cameraId);
|
|
if (!value.HasValue) return false;
|
|
string cameraIp = (string)value;
|
|
_cache.HashDelete(CacheInfo.CameraId2Ip, cameraId);
|
|
_cache.HashDecrement(CacheInfo.CameraIpCounts, cameraIp);
|
|
//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)
|
|
{
|
|
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)
|
|
{
|
|
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);
|
|
}
|
|
|
|
#endregion Base Method
|
|
|
|
#region Base Method Async
|
|
|
|
public async Task<bool> ActivateSearcherAsync(long cameraId)
|
|
{
|
|
return await Task.Run(() =>
|
|
{
|
|
return ActivateSearcher(cameraId);
|
|
});
|
|
}
|
|
|
|
public async Task<bool> DeactivateSearcherAsync(long cameraId)
|
|
{
|
|
return await Task.Run(() =>
|
|
{
|
|
return DeactivateSearcher(cameraId);
|
|
});
|
|
}
|
|
|
|
public async Task<bool> IsExistsSearcherAsync(long cameraId)
|
|
{
|
|
return await Task.Run(() =>
|
|
{
|
|
return IsExistsSearcher(cameraId);
|
|
});
|
|
}
|
|
|
|
public async Task<MarkSearcherBase> GetSearcherAsync(long cameraId)
|
|
{
|
|
return await Task.Run(() =>
|
|
{
|
|
return GetSearcher(cameraId);
|
|
});
|
|
}
|
|
|
|
public async Task<bool> ActivateMarkLabelAsync(long cameraId, long markLabelId)
|
|
{
|
|
return await Task.Run(() =>
|
|
{
|
|
return ActivateMarkLabel(cameraId, markLabelId);
|
|
});
|
|
}
|
|
|
|
public async Task<bool> DeactivateMarkLabelAsync(long cameraId, long markLabelId)
|
|
{
|
|
return await Task.Run(() =>
|
|
{
|
|
return DeactivateMarkLabel(cameraId, markLabelId);
|
|
});
|
|
}
|
|
|
|
public async Task<bool> IsExistsMarkLabelAsync(long cameraId, long markLabelId)
|
|
{
|
|
return await Task.Run(() =>
|
|
{
|
|
return IsExistsMarkLabel(cameraId, markLabelId);
|
|
});
|
|
}
|
|
|
|
#endregion Base Method Async
|
|
}
|