海康摄像头取流示例初始签入
This commit is contained in:
140
SHH.CameraSdk/Core/Memory/FramePool.cs
Normal file
140
SHH.CameraSdk/Core/Memory/FramePool.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using OpenCvSharp;
|
||||
|
||||
namespace SHH.CameraSdk;
|
||||
|
||||
/// <summary>
|
||||
/// [零延迟核心] 智能帧对象池
|
||||
/// 功能:预分配并复用 SmartFrame 实例,杜绝频繁 new Mat() 与 GC 回收,消除内存分配停顿
|
||||
/// 核心策略:
|
||||
/// <para>1. 预热分配:启动时创建初始数量帧,避免运行时内存申请</para>
|
||||
/// <para>2. 上限控制:最大池大小限制内存占用,防止内存溢出</para>
|
||||
/// <para>3. 背压丢帧:池空时返回 null,强制丢帧保证实时性,不阻塞生产端</para>
|
||||
/// </summary>
|
||||
public class FramePool : IDisposable
|
||||
{
|
||||
#region --- 私有资源与配置 (Private Resources & Configurations) ---
|
||||
|
||||
/// <summary> 可用帧队列(线程安全):存储待借出的空闲智能帧 </summary>
|
||||
private readonly ConcurrentQueue<SmartFrame> _availableFrames = new();
|
||||
|
||||
/// <summary> 所有已分配帧列表:用于统一销毁释放内存 </summary>
|
||||
private readonly List<SmartFrame> _allAllocatedFrames = new();
|
||||
|
||||
/// <summary> 创建新帧锁:确保多线程下创建新帧的线程安全 </summary>
|
||||
private readonly object _lock = new();
|
||||
|
||||
/// <summary> 帧宽度(与相机输出分辨率一致) </summary>
|
||||
private readonly int _width;
|
||||
|
||||
/// <summary> 帧高度(与相机输出分辨率一致) </summary>
|
||||
private readonly int _height;
|
||||
|
||||
/// <summary> 帧数据类型(如 CV_8UC3 对应 RGB 彩色图像) </summary>
|
||||
private readonly MatType _type;
|
||||
|
||||
/// <summary> 池最大容量:限制最大分配帧数,防止内存占用过高 </summary>
|
||||
private readonly int _maxPoolSize;
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- 构造与预热 (Constructor & Warm-Up) ---
|
||||
|
||||
/// <summary>
|
||||
/// 初始化智能帧对象池
|
||||
/// </summary>
|
||||
/// <param name="width">帧宽度</param>
|
||||
/// <param name="height">帧高度</param>
|
||||
/// <param name="type">帧数据类型</param>
|
||||
/// <param name="initialSize">初始预热帧数(默认5)</param>
|
||||
/// <param name="maxSize">池最大容量(默认10)</param>
|
||||
public FramePool(int width, int height, MatType type, int initialSize = 5, int maxSize = 10)
|
||||
{
|
||||
_width = width;
|
||||
_height = height;
|
||||
_type = type;
|
||||
_maxPoolSize = maxSize;
|
||||
|
||||
// 预热:启动时预分配初始数量帧,避免运行时动态申请内存
|
||||
for (int i = 0; i < initialSize; i++)
|
||||
{
|
||||
CreateNewFrame();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建新智能帧并加入池(内部调用,加锁保护)
|
||||
/// </summary>
|
||||
private void CreateNewFrame()
|
||||
{
|
||||
var frame = new SmartFrame(this, _width, _height, _type);
|
||||
_allAllocatedFrames.Add(frame);
|
||||
_availableFrames.Enqueue(frame);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- 帧借出与归还 (Frame Borrow & Return) ---
|
||||
|
||||
/// <summary>
|
||||
/// 从池借出一个智能帧(O(1) 时间复杂度)
|
||||
/// </summary>
|
||||
/// <returns>可用智能帧 / 池空且达上限时返回 null(触发背压丢帧)</returns>
|
||||
public SmartFrame Get()
|
||||
{
|
||||
// 1. 优先从可用队列取帧,无锁快速路径
|
||||
if (_availableFrames.TryDequeue(out var frame))
|
||||
{
|
||||
frame.Activate();
|
||||
return frame;
|
||||
}
|
||||
|
||||
// 2. 可用队列为空,检查是否达最大容量
|
||||
if (_allAllocatedFrames.Count < _maxPoolSize)
|
||||
{
|
||||
// 加锁创建新帧,避免多线程重复创建
|
||||
lock (_lock)
|
||||
{
|
||||
// 双重检查:防止等待锁期间其他线程已创建新帧
|
||||
if (_allAllocatedFrames.Count < _maxPoolSize)
|
||||
{
|
||||
CreateNewFrame();
|
||||
}
|
||||
}
|
||||
// 递归重试取帧
|
||||
return Get();
|
||||
}
|
||||
|
||||
// 3. 背压策略:池空且达上限,返回 null 强制丢帧,保证生产端不阻塞
|
||||
// 适用场景:消费端处理过慢导致帧堆积,丢帧保实时性
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [系统内部调用] 将帧归还至池(由 SmartFrame.Dispose 自动触发)
|
||||
/// </summary>
|
||||
/// <param name="frame">待归还的智能帧</param>
|
||||
public void Return(SmartFrame frame)
|
||||
{
|
||||
_availableFrames.Enqueue(frame);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- 资源释放 (Resource Disposal) ---
|
||||
|
||||
/// <summary>
|
||||
/// 释放帧池所有资源,销毁所有 Mat 内存
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
// 遍历所有已分配帧,释放 OpenCV Mat 底层内存
|
||||
foreach (var frame in _allAllocatedFrames)
|
||||
{
|
||||
frame.InternalMat.Dispose();
|
||||
}
|
||||
_allAllocatedFrames.Clear();
|
||||
_availableFrames.Clear();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
95
SHH.CameraSdk/Core/Memory/SmartFrame.cs
Normal file
95
SHH.CameraSdk/Core/Memory/SmartFrame.cs
Normal file
@@ -0,0 +1,95 @@
|
||||
using OpenCvSharp;
|
||||
|
||||
namespace SHH.CameraSdk;
|
||||
|
||||
/// <summary>
|
||||
/// [零延迟核心] 智能帧(内存复用+引用计数)
|
||||
/// 功能:封装 OpenCV Mat 实现物理内存复用,通过引用计数管理生命周期,避免 GC 频繁回收导致的性能抖动
|
||||
/// 特性:引用归零自动回池,全程无内存分配/释放开销,支撑高帧率实时流处理
|
||||
/// </summary>
|
||||
public class SmartFrame : IDisposable
|
||||
{
|
||||
#region --- 私有资源与状态 (Private Resources & States) ---
|
||||
|
||||
/// <summary> 所属帧池:用于引用归零后自动回收复用 </summary>
|
||||
private readonly FramePool _pool;
|
||||
|
||||
/// <summary> 引用计数器:线程安全,控制帧的生命周期 </summary>
|
||||
/// <remarks> 初始值 0,激活后设为 1;引用归零则自动回池 </remarks>
|
||||
private int _refCount = 0;
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- 公共属性 (Public Properties) ---
|
||||
|
||||
/// <summary> 帧数据物理内存载体(OpenCV Mat 对象) </summary>
|
||||
/// <remarks> 内存由帧池预分配,全程复用,不触发 GC </remarks>
|
||||
public Mat InternalMat { get; private set; }
|
||||
|
||||
/// <summary> 帧激活时间戳(记录帧被取出池的时刻) </summary>
|
||||
public DateTime Timestamp { get; private set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- 构造与激活 (Constructor & Activation) ---
|
||||
|
||||
/// <summary>
|
||||
/// 初始化智能帧(由帧池调用,外部禁止直接实例化)
|
||||
/// </summary>
|
||||
/// <param name="pool">所属帧池实例</param>
|
||||
/// <param name="width">帧宽度</param>
|
||||
/// <param name="height">帧高度</param>
|
||||
/// <param name="type">帧数据类型(如 MatType.CV_8UC3)</param>
|
||||
internal SmartFrame(FramePool pool, int width, int height, MatType type)
|
||||
{
|
||||
_pool = pool;
|
||||
// 预分配物理内存:内存块在帧池生命周期内复用,避免频繁申请/释放
|
||||
InternalMat = new Mat(height, width, type);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [生产者调用] 从帧池取出时激活帧
|
||||
/// 功能:初始化引用计数,标记激活时间戳
|
||||
/// </summary>
|
||||
public void Activate()
|
||||
{
|
||||
// 激活后引用计数设为 1,代表生产者(驱动/管道)持有该帧
|
||||
_refCount = 1;
|
||||
// 记录帧被取出池的时间,用于后续延迟计算
|
||||
Timestamp = DateTime.Now;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- 引用计数管理 (Reference Count Management) ---
|
||||
|
||||
/// <summary>
|
||||
/// [消费者调用] 增加引用计数
|
||||
/// 适用场景:帧需要被多模块同时持有(如同时分发到 UI 和 AI 分析)
|
||||
/// </summary>
|
||||
public void AddRef()
|
||||
{
|
||||
// 原子递增:线程安全,避免多线程竞争导致计数错误
|
||||
Interlocked.Increment(ref _refCount);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region --- 释放与回池 (Disposal & Pool Return) ---
|
||||
|
||||
/// <summary>
|
||||
/// [消费者调用] 释放引用计数
|
||||
/// 核心逻辑:引用归零后自动将帧归还至帧池,实现内存复用
|
||||
/// </summary>
|
||||
public void Dispose()
|
||||
{
|
||||
// 原子递减:线程安全,确保计数准确
|
||||
if (Interlocked.Decrement(ref _refCount) <= 0)
|
||||
{
|
||||
// 引用归零:所有消费者均已释放,将帧归还池复用
|
||||
_pool.Return(this);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
Reference in New Issue
Block a user