新增 Mjpegplayer 用来播放 Web 流
This commit is contained in:
17
SHH.MjpegPlayer/Core/Models/CfgRtmpReply.cs
Normal file
17
SHH.MjpegPlayer/Core/Models/CfgRtmpReply.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace SHH.MjpegPlayer;
|
||||
|
||||
/// <summary>RTMP 配置响应类</summary>
|
||||
public class CfgRtmpReply
|
||||
{
|
||||
/// <summary>响应消息</summary>
|
||||
public string msg { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>响应状态码</summary>
|
||||
public int code { get; set; }
|
||||
|
||||
/// <summary>RTMP 推流地址列表</summary>
|
||||
public RtmpVo[]? rtmpVoList { get; set; }
|
||||
|
||||
/// <summary>是否成功(状态码为 200 时返回 true)</summary>
|
||||
public bool IsSuccess => code == 200;
|
||||
}
|
||||
35
SHH.MjpegPlayer/Core/Models/EIdSys.cs
Normal file
35
SHH.MjpegPlayer/Core/Models/EIdSys.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace SHH.MjpegPlayer
|
||||
{
|
||||
public enum EIdSys
|
||||
{
|
||||
/// <summary>根据PID杀掉进程成功</summary>
|
||||
[Description("根据PID杀掉进程成功")]
|
||||
KillProcByIdSucceed = 1000101,
|
||||
|
||||
/// <summary>按秒统计汇总</summary>
|
||||
[Description("按秒统计汇总")]
|
||||
TotalBySecond = 100701,
|
||||
|
||||
/// <summary>按分钟统计汇总</summary>
|
||||
[Description("按分钟统计汇总")]
|
||||
TotalByMinute = 100702,
|
||||
|
||||
/// <summary>按小时统计汇总</summary>
|
||||
[Description("按小时统计汇总")]
|
||||
TotalByHour = 100703,
|
||||
|
||||
/// <summary>查询进程名出错</summary>
|
||||
[Description("查询进程名出错")]
|
||||
SearchProcNameError = 1000901,
|
||||
|
||||
/// <summary>根据PID杀掉进程出错</summary>
|
||||
[Description("根据PID杀掉进程出错")]
|
||||
KillProcByIdError = 1000902,
|
||||
|
||||
/// <summary>启动进程出错</summary>
|
||||
[Description("启动进程出错")]
|
||||
StartProcessError = 1000903,
|
||||
}
|
||||
}
|
||||
18
SHH.MjpegPlayer/Core/Models/JsonConfigUris.cs
Normal file
18
SHH.MjpegPlayer/Core/Models/JsonConfigUris.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace SHH.MjpegPlayer
|
||||
{
|
||||
public class JsonConfigUris
|
||||
{
|
||||
public static string DispatcherConfig;
|
||||
public static string RtspRtcConfig;
|
||||
public static string RtspRtcPortsConfig;
|
||||
public static string MjpegConfig;
|
||||
public static string CloudServerConfig;
|
||||
public static string CloudServerSessionsConfig;
|
||||
public static string CloudAgentConfig;
|
||||
public static string CloudAITerminalConfig;
|
||||
public static string VirtualCameraConfig;
|
||||
public static string AIMainConfig;
|
||||
public static string AIDbConfig;
|
||||
public static string ToolLogConfig;
|
||||
}
|
||||
}
|
||||
43
SHH.MjpegPlayer/Core/Models/MjpegConfig.cs
Normal file
43
SHH.MjpegPlayer/Core/Models/MjpegConfig.cs
Normal file
@@ -0,0 +1,43 @@
|
||||
namespace SHH.MjpegPlayer;
|
||||
|
||||
/// <summary>
|
||||
/// Mjpeg 配置
|
||||
/// </summary>
|
||||
public class MjpegConfig
|
||||
{
|
||||
/// <summary>Mjpeg 服务 IP 地址</summary>
|
||||
public string SvrMjpegIp
|
||||
= "0.0.0.0";
|
||||
|
||||
/// <summary>Mjpeg 服务端口开始</summary>
|
||||
public int SvrMjpegPortBegin
|
||||
= 25031;
|
||||
|
||||
/// <summary>Mjpeg 服务端口结束</summary>
|
||||
public int SvrMjpegPortEnd
|
||||
= 25300;
|
||||
|
||||
/// <summary>帧间隔, 单位毫秒 (值为 125, 每秒 8 帧)</summary>
|
||||
public int FrameInterval { get; set; }
|
||||
= 125;
|
||||
|
||||
/// <summary>Mjpeg Wcf 接收图片接口</summary>
|
||||
public int WcfPushImagePort
|
||||
= 25030;
|
||||
|
||||
/// <summary>接收图片的服务器名称</summary>
|
||||
public string SvrNamePushImage { get; set; }
|
||||
= "ImageService.svc";
|
||||
|
||||
/// <summary>最大接收数据大小</summary>
|
||||
public int SvrPushImageMaxRecMsgSize { get; set; }
|
||||
= 2000 * 1024 * 1024;
|
||||
|
||||
/// <summary>Rtmp 服务地址</summary>
|
||||
public string RtmpServerDjhUri { get; set; }
|
||||
= "http://172.16.41.108:8889/intellect/nvr/getRtmp";
|
||||
|
||||
/// <summary>是否使用 Rtmp 服务</summary>
|
||||
public bool UseRtmpServer { get; set; }
|
||||
= false;
|
||||
}
|
||||
17
SHH.MjpegPlayer/Core/Models/RtmpVo.cs
Normal file
17
SHH.MjpegPlayer/Core/Models/RtmpVo.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
namespace SHH.MjpegPlayer;
|
||||
|
||||
/// <summary>RTMP 推流对象类</summary>
|
||||
public class RtmpVo
|
||||
{
|
||||
/// <summary>算法代码</summary>
|
||||
public string algCode { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>设备ID</summary>
|
||||
public string deviceId { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>设备IP地址</summary>
|
||||
public string deviceIp { get; set; } = string.Empty;
|
||||
|
||||
/// <summary>RTMP 推流地址</summary>
|
||||
public string rtmp { get; set; } = string.Empty;
|
||||
}
|
||||
100
SHH.MjpegPlayer/Core/Models/SessionInfo.cs
Normal file
100
SHH.MjpegPlayer/Core/Models/SessionInfo.cs
Normal file
@@ -0,0 +1,100 @@
|
||||
namespace SHH.MjpegPlayer
|
||||
{
|
||||
/// <summary>
|
||||
/// 会话信息
|
||||
/// </summary>
|
||||
public class SessionInfo
|
||||
{
|
||||
#region Key
|
||||
|
||||
/// <summary>流标识</summary>
|
||||
public string? Key => $"{DeviceId}#{TypeCode}";
|
||||
|
||||
#endregion
|
||||
|
||||
#region DeviceId
|
||||
|
||||
/// <summary>设备类型</summary>
|
||||
public string? DeviceId { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region TypeCode
|
||||
|
||||
/// <summary>类型编码</summary>
|
||||
public string? TypeCode { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ClientIp
|
||||
|
||||
/// <summary>客户端 IP</summary>
|
||||
public string? ClientIp { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ClientPort
|
||||
|
||||
/// <summary>客户端端口</summary>
|
||||
public int ClientPort { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Message
|
||||
|
||||
/// <summary>消息</summary>
|
||||
public string? Message { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region AcceptTime
|
||||
|
||||
/// <summary>接入时间</summary>
|
||||
public DateTime AcceptTime { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
#region Counter
|
||||
|
||||
/// <summary>计数器</summary>
|
||||
public SumByTime? Counter { get; init; }
|
||||
|
||||
#endregion
|
||||
|
||||
// =======================================================
|
||||
// [新增] 专门给诊断大屏用的属性,前端可直接读取数值
|
||||
// =======================================================
|
||||
|
||||
/// <summary>接收帧率 (源头健康度)</summary>
|
||||
public int RecvFps
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Counter == null || Counter.TotalSecond == null) return 0;
|
||||
|
||||
// 从字典中安全获取 "接收帧数"
|
||||
if (Counter.TotalSecond.TryGetValue("接收帧数", out uint val))
|
||||
{
|
||||
return (int)val;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>播放/发送帧率 (客户端健康度)</summary>
|
||||
public int PlayFps
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Counter == null || Counter.TotalSecond == null) return 0;
|
||||
|
||||
// 从字典中安全获取 "播放帧数"
|
||||
if (Counter.TotalSecond.TryGetValue("播放帧数", out uint val))
|
||||
{
|
||||
return (int)val;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
190
SHH.MjpegPlayer/Core/Models/SumByTime.cs
Normal file
190
SHH.MjpegPlayer/Core/Models/SumByTime.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
using System.Text;
|
||||
|
||||
namespace SHH.MjpegPlayer
|
||||
{
|
||||
/// <summary>
|
||||
/// 按时间统计
|
||||
/// </summary>
|
||||
public class SumByTime
|
||||
{
|
||||
#region Defines
|
||||
|
||||
/// <summary>最近刷新在哪一秒</summary>
|
||||
private int LastRefreshSecond = DateTime.Now.Second;
|
||||
|
||||
/// <summary>最近刷新在哪一分钟</summary>
|
||||
private int LastRefreshMinute = DateTime.Now.Minute;
|
||||
|
||||
/// <summary>最近刷新在哪一小时</summary>
|
||||
private int LastRefreshHour = DateTime.Now.Minute;
|
||||
|
||||
/// <summary>秒统计</summary>
|
||||
private Dictionary<string, uint> _second
|
||||
= new Dictionary<string, uint>();
|
||||
|
||||
/// <summary>分钟统计</summary>
|
||||
private Dictionary<string, uint> _minute
|
||||
= new Dictionary<string, uint>();
|
||||
|
||||
/// <summary>小时统计</summary>
|
||||
private Dictionary<string, uint> _hour
|
||||
= new Dictionary<string, uint>();
|
||||
|
||||
/// <summary>累计统计</summary>
|
||||
public Dictionary<string, ulong> All { get; init; }
|
||||
= new Dictionary<string, ulong>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region TotalSecond
|
||||
|
||||
/// <summary>秒统计</summary>
|
||||
public Dictionary<string, uint> TotalSecond { get; init; }
|
||||
= new Dictionary<string, uint>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region TotalMinute
|
||||
|
||||
/// <summary>分统计</summary>
|
||||
public Dictionary<string, uint> TotalMinute { get; init; }
|
||||
= new Dictionary<string, uint>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region TotalHour
|
||||
|
||||
/// <summary>小时统计</summary>
|
||||
public Dictionary<string, uint> TotalHour { get; init; }
|
||||
= new Dictionary<string, uint>();
|
||||
|
||||
#endregion
|
||||
|
||||
#region Refresh
|
||||
|
||||
/// <summary>
|
||||
/// 刷新方法调用次数
|
||||
/// </summary>
|
||||
/// <param name="logger"></param>
|
||||
/// <param name="methodName"></param>
|
||||
/// <param name="count"></param>
|
||||
public void Refresh(string methodName, uint count = 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
#region 加入集合
|
||||
|
||||
// 加入集合
|
||||
lock (_second)
|
||||
{
|
||||
if (!_second.ContainsKey(methodName))
|
||||
_second.Add(methodName, 0);
|
||||
}
|
||||
|
||||
// 加入集合
|
||||
lock (_minute)
|
||||
{
|
||||
if (!_minute.ContainsKey(methodName))
|
||||
_minute.Add(methodName, 0);
|
||||
}
|
||||
|
||||
lock (_hour)
|
||||
{
|
||||
if (!_hour.ContainsKey(methodName))
|
||||
_hour.Add(methodName, 0);
|
||||
}
|
||||
|
||||
// 加入集合
|
||||
lock (All)
|
||||
{
|
||||
if (!All.ContainsKey(methodName))
|
||||
All.Add(methodName, 0);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 时间变更统计
|
||||
|
||||
// 秒刷新
|
||||
if (!LastRefreshSecond.Equals(DateTime.Now.Second))
|
||||
{
|
||||
LastRefreshSecond = DateTime.Now.Second;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
foreach (var de in _second)
|
||||
{
|
||||
// 更新输出用统计信息
|
||||
if (!TotalSecond.ContainsKey(de.Key))
|
||||
TotalSecond.Add(de.Key, de.Value);
|
||||
else
|
||||
TotalSecond[de.Key] = de.Value;
|
||||
|
||||
sb.Append($"\r\n\t{de.Key} => 执行 {de.Value} 次");
|
||||
_second[de.Key] = 0;
|
||||
}
|
||||
var logMsg = $"统计 => SumBySecond 统计时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}{sb.ToString()}";
|
||||
//Logs.LogInformation<SumByTime>(EIdSys.TotalBySecond, logMsg);
|
||||
}
|
||||
|
||||
// 分钟刷新
|
||||
if (!LastRefreshMinute.Equals(DateTime.Now.Minute))
|
||||
{
|
||||
LastRefreshMinute = DateTime.Now.Minute;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
foreach (var de in _minute)
|
||||
{
|
||||
// 更新输出用统计信息
|
||||
if (!TotalMinute.ContainsKey(de.Key))
|
||||
TotalMinute.Add(de.Key, de.Value);
|
||||
else
|
||||
TotalMinute[de.Key] = de.Value;
|
||||
|
||||
sb.Append($"\r\n\t{de.Key} => 执行 {de.Value} 次, 平均每秒 {Math.Round((double)de.Value / 60, 2)} 次");
|
||||
_minute[de.Key] = 0;
|
||||
}
|
||||
var logMsg = $"统计 => SumByMinute 统计时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}{sb.ToString()}";
|
||||
//Logs.LogInformation<SumByTime>(EIdSys.TotalByMinute, logMsg);
|
||||
}
|
||||
|
||||
// 小时刷新
|
||||
if (!LastRefreshHour.Equals(DateTime.Now.Hour))
|
||||
{
|
||||
LastRefreshHour = DateTime.Now.Hour;
|
||||
|
||||
var sb = new StringBuilder();
|
||||
foreach (var de in _hour)
|
||||
{
|
||||
// 更新输出用统计信息
|
||||
if (!TotalHour.ContainsKey(de.Key))
|
||||
TotalHour.Add(de.Key, de.Value);
|
||||
else
|
||||
TotalHour[de.Key] = de.Value;
|
||||
|
||||
sb.Append($"\r\n\t{de.Key} => 执行 {de.Value} 次, 平均每秒 {Math.Round((double)de.Value / 60, 2)} 次");
|
||||
_hour[de.Key] = 0;
|
||||
}
|
||||
var logMsg = $"统计 => SumByHour 统计时间:{DateTime.Now.ToString("yyyy-MM-dd HH:mm")}{sb.ToString()}";
|
||||
//Logs.LogInformation<SumByTime>(EIdSys.TotalByHour, logMsg);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 数值更新
|
||||
|
||||
_second[methodName] += count;
|
||||
_minute[methodName] += count;
|
||||
_hour[methodName] += count;
|
||||
All[methodName] += count;
|
||||
|
||||
#endregion
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
//Logs.LogWarning<SumByTime>(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user