2025-12-26 03:18:21 +08:00
|
|
|
|
namespace SHH.CameraSdk;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 帧需求定义模型
|
|
|
|
|
|
/// 功能:描述某个程序/模块对视频帧的消费需求,用于帧分发调度与帧率控制
|
|
|
|
|
|
/// 用途:配合 FrameController,实现按订阅者需求精准分配帧资源,避免资源浪费
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public class FrameRequirement
|
|
|
|
|
|
{
|
2025-12-28 08:07:55 +08:00
|
|
|
|
public FrameRequirement()
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public FrameRequirement(SubscriptionDto dto)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 1. 核心标识
|
|
|
|
|
|
this.AppId = dto.AppId;
|
|
|
|
|
|
this.Type = dto.Type;
|
|
|
|
|
|
|
|
|
|
|
|
// 2. 流控参数
|
|
|
|
|
|
this.TargetFps = dto.DisplayFps;
|
|
|
|
|
|
|
|
|
|
|
|
// 3. 业务动态参数
|
|
|
|
|
|
this.Memo = dto.Memo;
|
|
|
|
|
|
this.Handle = dto.Handle;
|
|
|
|
|
|
this.RecordDuration = dto.RecordDuration;
|
|
|
|
|
|
this.SavePath = dto.SavePath;
|
|
|
|
|
|
|
|
|
|
|
|
// 4. 网络转发相关参数 (补全)
|
|
|
|
|
|
this.Protocol = dto.Protocol;
|
|
|
|
|
|
this.TargetIp = dto.TargetIp;
|
|
|
|
|
|
this.TargetPort = dto.TargetPort;
|
|
|
|
|
|
|
|
|
|
|
|
// 5. 初始化内部统计状态
|
|
|
|
|
|
this.LastCaptureTick = Environment.TickCount64;
|
|
|
|
|
|
this._lastFpsCalcTick = Environment.TickCount64;
|
|
|
|
|
|
this.IsActive = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-12-26 03:18:21 +08:00
|
|
|
|
#region --- 订阅者核心标识 (Subscriber Core Identification) ---
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> 订阅者唯一ID(如 "Client_A"、"AI_Service"、"WPF_Display_Main") </summary>
|
|
|
|
|
|
/// <remarks> 用于区分不同的帧消费模块,作为帧分发路由的关键标识 </remarks>
|
|
|
|
|
|
public string AppId { get; set; } = string.Empty;
|
|
|
|
|
|
|
2025-12-27 14:16:50 +08:00
|
|
|
|
/// <summary> 订阅业务类型(描述视频流的最终去向和处理逻辑) </summary>
|
|
|
|
|
|
/// <remarks> 决定了后端流控引擎后续的资源分配(如录像机或渲染器) </remarks>
|
|
|
|
|
|
public SubscriptionType Type { get; set; } = SubscriptionType.LocalWindow;
|
|
|
|
|
|
|
2025-12-26 03:18:21 +08:00
|
|
|
|
#endregion
|
|
|
|
|
|
|
2025-12-27 14:16:50 +08:00
|
|
|
|
#region --- 帧率控制参数 (Frame Rate Control Parameters) ---
|
2025-12-26 03:18:21 +08:00
|
|
|
|
|
2025-12-27 14:16:50 +08:00
|
|
|
|
/// <summary> 目标帧率(单位:fps,订阅者期望的每秒接收帧数) </summary>
|
|
|
|
|
|
/// <remarks> 范围 1-25 fps。例如:UI 预览需 15fps,AI 分析需 5fps </remarks>
|
|
|
|
|
|
public int TargetFps { get; set; } = 15;
|
2025-12-26 03:18:21 +08:00
|
|
|
|
|
2025-12-27 14:16:50 +08:00
|
|
|
|
/// <summary> 上次成功分发帧的时间点(单位:毫秒,基于 Environment.TickCount64) </summary>
|
|
|
|
|
|
/// <remarks> 帧率控制算法的核心,用于判断当前时刻是否应向此订阅者推送帧 </remarks>
|
2025-12-26 03:18:21 +08:00
|
|
|
|
public long LastCaptureTick { get; set; } = 0;
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
2025-12-27 14:16:50 +08:00
|
|
|
|
#region --- 业务动态参数 (Business Dynamic Parameters) ---
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> 备注信息(记录订阅用途、申请人或关联业务系统) </summary>
|
|
|
|
|
|
public string Memo { get; set; } = string.Empty;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> 窗口句柄(仅在 Type 为 HandleDisplay 时有效) </summary>
|
|
|
|
|
|
/// <remarks> 格式通常为十六进制或十进制字符串,用于跨进程或底层渲染对接 </remarks>
|
|
|
|
|
|
public string Handle { get; set; } = string.Empty;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> 录像持续时长(单位:分钟,仅在 Type 为 LocalRecord 时有效) </summary>
|
|
|
|
|
|
public int RecordDuration { get; set; } = 5;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> 录像存放路径(仅在 Type 为 LocalRecord 时有效) </summary>
|
|
|
|
|
|
/// <remarks> 服务器本地磁盘的绝对路径,例如:D:\Recordings\Camera_01 </remarks>
|
|
|
|
|
|
public string SavePath { get; set; } = string.Empty;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> 通讯传输协议(仅在网络转发模式下有效) </summary>
|
|
|
|
|
|
public TransportProtocol Protocol { get; set; }
|
|
|
|
|
|
= TransportProtocol.Tcp;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> 目标接收端 IP 地址(仅在网络转发模式下有效) </summary>
|
|
|
|
|
|
public string TargetIp { get; set; } = "127.0.0.1";
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> 目标接收端端口号(仅在网络转发模式下有效) </summary>
|
|
|
|
|
|
public int TargetPort { get; set; } = 8080;
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
|
|
|
|
#region --- 运行统计与控制 (Runtime Stats & Control) ---
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary> 实时计算的输出帧率(单位:fps,实际分发给订阅者的频率) </summary>
|
|
|
|
|
|
/// <remarks> 反映系统真实运行状态,若低于 TargetFps 则说明分发链路存在瓶颈 </remarks>
|
|
|
|
|
|
public double RealFps { get; set; } = 0.0;
|
2025-12-26 03:18:21 +08:00
|
|
|
|
|
|
|
|
|
|
/// <summary> 需求是否激活(true=正常接收帧,false=暂停接收,保留配置) </summary>
|
|
|
|
|
|
public bool IsActive { get; set; } = true;
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
2025-12-27 14:16:50 +08:00
|
|
|
|
|
|
|
|
|
|
#region --- 内部逻辑控制 (Internal Logic Control) ---
|
|
|
|
|
|
|
|
|
|
|
|
private int _frameCount = 0;
|
|
|
|
|
|
private long _lastFpsCalcTick = Environment.TickCount64;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// 更新实际帧率统计
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <remarks> 每当成功分发一帧后调用,内部自动按秒计算 RealFps </remarks>
|
|
|
|
|
|
public void UpdateRealFps()
|
|
|
|
|
|
{
|
2025-12-28 08:07:55 +08:00
|
|
|
|
try
|
2025-12-27 14:16:50 +08:00
|
|
|
|
{
|
2025-12-28 08:07:55 +08:00
|
|
|
|
_frameCount++;
|
|
|
|
|
|
long currentTick = Environment.TickCount64;
|
|
|
|
|
|
long elapsed = currentTick - _lastFpsCalcTick;
|
|
|
|
|
|
|
|
|
|
|
|
if (elapsed >= 1000) // 达到 1 秒周期
|
|
|
|
|
|
{
|
|
|
|
|
|
RealFps = Math.Round(_frameCount / (elapsed / 1000.0), 1);
|
|
|
|
|
|
_frameCount = 0;
|
|
|
|
|
|
_lastFpsCalcTick = currentTick;
|
|
|
|
|
|
}
|
2025-12-27 14:16:50 +08:00
|
|
|
|
}
|
2025-12-28 08:07:55 +08:00
|
|
|
|
catch{ }
|
2025-12-27 14:16:50 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#endregion
|
2025-12-26 03:18:21 +08:00
|
|
|
|
}
|