using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.OpenApi.Models; using OpenCvSharp; using SHH.CameraSdk; using System.Diagnostics; namespace SHH.CameraSdk { /// /// A 方案:标准控制台结构 (显式 Main 方法 + STAThread) /// public class Program { // [关键点 1] 显式声明 STA 线程模式,确保 OpenCV/GUI 窗口消息循环正常 [STAThread] public static async Task Main(string[] args) { // ============================================================================== // 1. 基础设施初始化 // ============================================================================== InitHardwareEnv(); using var cameraManager = new CameraManager(); // [关键点 2] 提升变量作用域 // 将渲染器(消费者)在 Main 中声明,确保它与主程序同寿命,不会被中途回收 using var remoteRenderer = new FrameConsumer("Process A Remote Preview"); remoteRenderer.Start(); // ============================================================================== // 2. 启动 Web 监控与诊断服务 // ============================================================================== var app = await StartWebMonitoring(cameraManager); // [新增] 启动网络哨兵 (它会自动在后台跑) // 就像保安一样,你不需要管它,它每3秒会把所有摄像头的 IsOnline 状态刷一遍 var sentinel = new ConnectivitySentinel(cameraManager); // ============================================================================== // 3. 业务编排:配置设备与流控策略 (8+2 演示) // ============================================================================== // [关键点 3] 将渲染器作为参数传递进去 await ConfigureBusinessLogic(cameraManager, remoteRenderer); // ============================================================================== // 4. 启动引擎与交互 // ============================================================================== Console.WriteLine("\n[系统] 正在启动全局管理引擎..."); await cameraManager.StartAsync(); Console.WriteLine(">> 系统就绪。访问 http://localhost:5000/swagger 查看诊断信息。"); Console.WriteLine(">> 按 'S' 键退出..."); // [关键点 4] 阻塞主线程 // 只要这个循环在跑,remoteRenderer 就不会被 Dispose,窗口就会一直存在 while (Console.ReadKey(true).Key != ConsoleKey.S) { Thread.Sleep(100); } Console.WriteLine("[系统] 正在停机..."); await app.StopAsync(); } // ============================================================================== // Static Methods (原 Local Functions 转换为类的静态方法) // ============================================================================== static void InitHardwareEnv() { Console.WriteLine("=== 工业级视频 SDK 架构测试 (V3.3 分层版 - STA模式) ==="); Console.WriteLine("[硬件] 海康驱动预热中..."); HikNativeMethods.NET_DVR_Init(); HikSdkManager.ForceWarmUp(); // 强制加载 PlayCtrl.dll Console.WriteLine("[硬件] 预热完成。"); } static async Task StartWebMonitoring(CameraManager manager) { var builder = WebApplication.CreateBuilder(); // [新增] 屏蔽日志配置 builder.Logging.AddFilter("Microsoft", Microsoft.Extensions.Logging.LogLevel.Warning); builder.Logging.AddFilter("System", Microsoft.Extensions.Logging.LogLevel.Warning); builder.Logging.AddFilter("Microsoft.AspNetCore.Hosting.Diagnostics", Microsoft.Extensions.Logging.LogLevel.Warning); // 注入服务 builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(c => { c.SwaggerDoc("v1", new OpenApiInfo { Title = "SHH Camera Diagnostics", Version = "v1" }); }); builder.Services.AddCors(o => o.AddPolicy("AllowAll", p => p.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader())); // 关键:注入单例 Manager builder.Services.AddSingleton(manager); var webApp = builder.Build(); // 配置管道 webApp.UseSwagger(); webApp.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Diagnostics V1")); webApp.UseCors("AllowAll"); webApp.MapControllers(); // 异步启动,不阻塞主线程 _ = webApp.RunAsync("http://0.0.0.0:5000"); Console.WriteLine("[Web] 监控API已启动: http://localhost:5000"); return webApp; } // [关键点 5] 方法签名修改:接收 FrameConsumer 参数 static async Task ConfigureBusinessLogic(CameraManager manager, FrameConsumer renderer) { // 1. 配置设备 var config = new VideoSourceConfig { Id = 101, Brand = DeviceBrand.HikVision, IpAddress = "172.16.41.206", //IpAddress = "192.168.5.9", Port = 8000, Username = "admin", Password = "abcd1234", //Password = "RRYFOA", StreamType = 0 // 主码流 }; manager.AddDevice(config); if (manager.GetDevice(101) is HikVideoSource hikCamera) { // 1. 注册差异化需求 (给每个消费者唯一的 AppId) // ---------------------------------------------------- // 1. 注册需求时,手动加上 _Display 后缀 hikCamera.Controller.Register("Process_A_Remote_Display", 20); // 2. 订阅时,也改用带后缀的名称 GlobalStreamDispatcher.Subscribe("Process_A_Remote_Display", 101, frame => { frame.AddRef(); renderer.Enqueue(frame); }); } var config2 = new VideoSourceConfig { Id = 102, Brand = DeviceBrand.HikVision, IpAddress = "172.16.41.20", Port = 8000, Username = "admin", Password = "abcd1234", StreamType = 0 // 主码流 }; manager.AddDevice(config2); //if (manager.GetDevice(102) is HikVideoSource hikCamera2) //{ //} } } }