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.
305 lines
9.9 KiB
305 lines
9.9 KiB
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;
|
|
|
|
/// <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 RedisClient _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();
|
|
|
|
/// <summary>
|
|
/// MarkSearcherDict 中 MarkLabel 原子操作锁
|
|
/// </summary>
|
|
private ReaderWriterLockSlim MsMlRWLock { get; } = new();
|
|
|
|
#endregion Attr
|
|
|
|
public MarkSearcherServer(
|
|
RedisClient 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.TryEnterWriteLock(2000);
|
|
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.IsExists(cbCamera.Ip);
|
|
if (!ret)
|
|
{
|
|
CameraInfo cameraInfo = CameraInfo.New(cbCameraParams.Manufactor, 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 = ((CameraManufactor)cbCameraParams.Manufactor).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.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();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// DeactivateSearcher 原子操作
|
|
/// </summary>
|
|
/// <param name="cameraId"></param>
|
|
/// <returns></returns>
|
|
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();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// ActivateMarkLabel 原子操作
|
|
/// </summary>
|
|
/// <param name="cameraId"></param>
|
|
/// <param name="markLabelId"></param>
|
|
/// <returns></returns>
|
|
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();
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// DeactivateMarkLabel 原子操作
|
|
/// </summary>
|
|
/// <param name="cameraId"></param>
|
|
/// <param name="markLabelId"></param>
|
|
/// <returns></returns>
|
|
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<MarkLabelCalcResult> GetMarkLabelCalcResultList(long cameraId)
|
|
{
|
|
bool ret = MarkSearcherDict.TryGetValue(cameraId, out MarkSearcherBase markSearcher);
|
|
return ret ? markSearcher.GetMarkLabelCalcResultList() : new List<MarkLabelCalcResult>();
|
|
}
|
|
|
|
#endregion Base Method
|
|
|
|
#region Base Method Async
|
|
|
|
public async Task<bool> ActivateSearcherAsync(long cameraId)
|
|
{
|
|
return await Task.Run(() => ActivateSearcher(cameraId));
|
|
}
|
|
|
|
public async Task<bool> DeactivateSearcherAsync(long cameraId)
|
|
{
|
|
return await Task.Run(() => DeactivateSearcher(cameraId));
|
|
}
|
|
|
|
public async Task<bool> IsExistsSearcherAsync(long cameraId)
|
|
{
|
|
return await Task.Run(() => IsExistsSearcher(cameraId));
|
|
}
|
|
|
|
public async Task<MarkSearcherBase> GetSearcherAsync(long cameraId)
|
|
{
|
|
return await Task.Run(() => GetSearcher(cameraId));
|
|
}
|
|
|
|
public async Task<bool> ActivateMarkLabelAsync(long cameraId, long markLabelId)
|
|
{
|
|
return await Task.Run(() => ActivateMarkLabel(cameraId, markLabelId));
|
|
}
|
|
|
|
public async Task<bool> DeactivateMarkLabelAsync(long cameraId, long markLabelId)
|
|
{
|
|
return await Task.Run(() => DeactivateMarkLabel(cameraId, markLabelId));
|
|
}
|
|
|
|
public async Task<bool> IsExistsMarkLabelAsync(long cameraId, long markLabelId)
|
|
{
|
|
return await Task.Run(() => IsExistsMarkLabel(cameraId, markLabelId));
|
|
}
|
|
|
|
public async Task<List<MarkLabelCalcResult>> GetMarkLabelCalcResultListAsync(long cameraId)
|
|
{
|
|
return await Task.Run(() => GetMarkLabelCalcResultList(cameraId));
|
|
}
|
|
|
|
#endregion Base Method Async
|
|
}
|