SDK核心 Bug 修复
This commit is contained in:
@@ -515,9 +515,18 @@ public class HikVideoSource : BaseVideoSource,
|
||||
{
|
||||
//Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 帧抵达.");
|
||||
|
||||
// Optimized: [原因] 增加前置防御性检查,若回调入参异常立即退出,防止后续 OpenCV 封装崩溃
|
||||
if (pBuf == IntPtr.Zero || nSize <= 0
|
||||
|| pFrameInfo.nWidth <= 0 || pFrameInfo.nHeight <= 0) return;
|
||||
// 1. 基础指针检查
|
||||
if (pBuf == IntPtr.Zero || nSize <= 0) return;
|
||||
|
||||
// 2. 视频有效性检查
|
||||
// 如果不是音频,但宽高依然为 0,说明是异常数据或非图像私有头
|
||||
if (pFrameInfo.nWidth <= 0 || pFrameInfo.nHeight <= 0)
|
||||
{
|
||||
// 如果你想调试音频,可以在这里处理 pBuf
|
||||
// 但对于视频分析业务,这里直接 return,不要写 Log,否则磁盘会爆
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// [优化] 维持心跳,防止被哨兵误杀
|
||||
MarkFrameReceived(0);
|
||||
@@ -584,59 +593,23 @@ public class HikVideoSource : BaseVideoSource,
|
||||
|
||||
//Console.WriteLine($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 帧抵处理.");
|
||||
|
||||
int width = pFrameInfo.nWidth;
|
||||
int height = pFrameInfo.nHeight;
|
||||
|
||||
// 2. 初始化帧池
|
||||
if (!_isPoolReady)
|
||||
{
|
||||
// ====================================================================================
|
||||
// 【修改点 Start】: 使用 Monitor.TryEnter 替换 lock
|
||||
// 原因:防止死锁。如果主线程 CleanupSync 持有 _initLock 正在 Stop,
|
||||
// 这里如果用 lock 会死等,导致 StopRealPlay 无法返回。
|
||||
// 改用 TryEnter,如果拿不到锁(说明正在停止),直接放弃这一帧并退出。
|
||||
// ====================================================================================
|
||||
bool lockTaken = false;
|
||||
try
|
||||
{
|
||||
// 尝试获取锁,超时时间 20ms (拿不到立即返回 false)
|
||||
Monitor.TryEnter(_initLock, 20, ref lockTaken);
|
||||
|
||||
if (lockTaken)
|
||||
{
|
||||
// 拿到锁了,执行原有的初始化逻辑 (Double Check)
|
||||
if (!_isPoolReady)
|
||||
{
|
||||
_framePool?.Dispose();
|
||||
_framePool = new FramePool(width, height, MatType.CV_8UC3, initialSize: 3, maxSize: 5);
|
||||
_isPoolReady = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 【关键逻辑】如果 20ms 没拿到锁,说明主线程正在操作 (通常是正在 Stop)
|
||||
// 既然都要停止了,这一帧直接丢弃,立即返回,防止死锁
|
||||
return;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (lockTaken) Monitor.Exit(_initLock);
|
||||
}
|
||||
}
|
||||
|
||||
if (_framePool == null) return;
|
||||
|
||||
// Optimized: [原因] 将 smartFrame 定义在 try 外部,确保 finally 块能够可靠执行 Dispose 归还逻辑
|
||||
SmartFrame? smartFrame = null;
|
||||
|
||||
try
|
||||
{ // 3. 转换与分发
|
||||
{
|
||||
if (_framePool == null)
|
||||
{
|
||||
_sdkLog.Warning($"[SDK] Hik framePool 为空, 丢弃. 设备ID: {Config.Id} IP:{Config.IpAddress} Name:{Config.Name}");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 转换与分发
|
||||
smartFrame = _framePool.Get();
|
||||
if (smartFrame == null) return; // 池满丢帧
|
||||
|
||||
// Optimized: [原因] 使用局部作用域封装 YUV 转换,确保原生指针尽快脱离
|
||||
using (var rawYuvWrapper = Mat.FromPixelData(height + height / 2, width, MatType.CV_8UC1, pBuf))
|
||||
using (var rawYuvWrapper = Mat.FromPixelData(currentHeight + currentHeight / 2, currentWidth, MatType.CV_8UC1, pBuf))
|
||||
{
|
||||
Cv2.CvtColor(rawYuvWrapper, smartFrame.InternalMat, ColorConversionCodes.YUV2BGR_YV12);
|
||||
}
|
||||
@@ -647,7 +620,7 @@ public class HikVideoSource : BaseVideoSource,
|
||||
// =========================================================
|
||||
if (smartFrame.InternalMat.Empty())
|
||||
{
|
||||
_sdkLog.Warning($"[SDK] Dahua 解码帧无效 (Empty Mat), 丢弃. 设备ID: {Config.Id} IP:{Config.IpAddress} Name:{Config.Name}");
|
||||
_sdkLog.Warning($"[SDK] Hik 解码帧无效 (Empty Mat), 丢弃. 设备ID: {Config.Id} IP:{Config.IpAddress} Name:{Config.Name}");
|
||||
// finally 会负责 Dispose,这里直接返回
|
||||
return;
|
||||
}
|
||||
@@ -669,7 +642,7 @@ public class HikVideoSource : BaseVideoSource,
|
||||
catch (Exception ex)
|
||||
{
|
||||
// 这里为了性能不频繁写日志,仅在调试时开启
|
||||
_sdkLog.Debug($"[SDK] Hik SafeOnDecodingCallBack 异常. => ID:{_config.Id} IP:{_config.IpAddress} Port:{_config.Port} Name:{_config.Name}, UserID: {_userId}" + "Exception: {Exp}", ex);
|
||||
_sdkLog.Warning($"[SDK] Hik SafeOnDecodingCallBack 异常. => ID:{_config.Id} IP:{_config.IpAddress} Port:{_config.Port} Name:{_config.Name}, UserID: {_userId}" + "Exception: {Exp}", ex);
|
||||
AddAuditLog($"[SDK] Hik SafeOnDecodingCallBack 异常. => ID:{_config.Id} IP:{_config.IpAddress} Port:{_config.Port} Name:{_config.Name}, UserID: {_userId} Exception: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
|
||||
Reference in New Issue
Block a user