Camera Information System
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

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
}