using System.ComponentModel.DataAnnotations; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Authorization; using System.Security.Claims; using Database; using DotNext; /// /// 视频流控制器,支持动态配置摄像头连接 /// [ApiController] [Authorize] [Route("api/[controller]")] public class VideoStreamController : ControllerBase { private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); private readonly server.Services.HttpVideoStreamService _videoStreamService; /// /// 分辨率配置请求模型 /// public class ResolutionConfigRequest { /// /// 宽度 /// [Required] [Range(640, 1920, ErrorMessage = "宽度必须在640-1920范围内")] public int Width { get; set; } /// /// 高度 /// [Required] [Range(480, 1080, ErrorMessage = "高度必须在480-1080范围内")] public int Height { get; set; } } public class AvailableResolutionsResponse { public int Width { get; set; } public int Height { get; set; } public string Name { get; set; } = string.Empty; public string Value => $"{Width}x{Height}"; } /// /// 初始化HTTP视频流控制器 /// /// HTTP视频流服务 public VideoStreamController(server.Services.HttpVideoStreamService videoStreamService) { logger.Info("创建VideoStreamController,命名空间:{Namespace}", this.GetType().Namespace); _videoStreamService = videoStreamService; } private Optional TryGetBoardId() { var userName = User.FindFirstValue(ClaimTypes.Name); if (string.IsNullOrEmpty(userName)) { logger.Error("User name not found in claims."); return Optional.None; } var db = new AppDataConnection(); if (db == null) { logger.Error("Database connection failed."); return Optional.None; } var userRet = db.GetUserByName(userName); if (!userRet.IsSuccessful || !userRet.Value.HasValue) { logger.Error("User not found."); return Optional.None; } var user = userRet.Value.Value; var boardId = user.BoardID; if (boardId == Guid.Empty) { logger.Error("No board bound to this user."); return Optional.None; } return boardId.ToString(); } /// /// 获取 HTTP 视频流服务状态 /// /// 服务状态信息 [HttpGet("Status")] [EnableCors("Users")] [ProducesResponseType(typeof(object), StatusCodes.Status200OK)] [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] public IResult GetStatus() { try { // 使用HttpVideoStreamService提供的状态信息 var status = _videoStreamService.GetServiceStatus(); // 转换为小写首字母的JSON属性(符合前端惯例) return TypedResults.Ok(status); } catch (Exception ex) { logger.Error(ex, "获取 HTTP 视频流服务状态失败"); return TypedResults.InternalServerError(ex.Message); } } [HttpGet("MyEndpoint")] [EnableCors("Users")] [ProducesResponseType(typeof(object), StatusCodes.Status200OK)] [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] public IResult MyEndpoint() { try { var boardId = TryGetBoardId().OrThrow(() => new Exception("Board ID not found")); var endpoint = _videoStreamService.GetVideoEndpoint(boardId); return TypedResults.Ok(endpoint); } catch (Exception ex) { logger.Error(ex, "获取摄像头配置失败"); return TypedResults.InternalServerError(ex.Message); } } /// /// 测试 HTTP 视频流连接 /// /// 连接测试结果 [HttpPost("TestConnection")] [EnableCors("Users")] [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)] [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] public async Task TestConnection() { try { var boardId = TryGetBoardId().OrThrow(() => new Exception("Board ID not found")); var endpoint = _videoStreamService.GetVideoEndpoint(boardId); // 尝试通过HTTP请求检查视频流服务是否可访问 bool isConnected = false; using (var httpClient = new HttpClient()) { httpClient.Timeout = TimeSpan.FromSeconds(2); // 设置较短的超时时间 var response = await httpClient.GetAsync(endpoint.MjpegUrl); // 只要能连接上就认为成功,不管返回状态 isConnected = response.IsSuccessStatusCode; } var ret = await _videoStreamService.TestCameraConnection(boardId); return TypedResults.Ok(ret); } catch (Exception ex) { logger.Error(ex, "HTTP 视频流连接测试失败"); // 连接失败但不抛出异常,而是返回连接失败的结果 return TypedResults.Ok(false); } } [HttpPost("DisableTransmission")] public async Task DisableHdmiTransmission() { try { var boardId = TryGetBoardId().OrThrow(() => new ArgumentException("Board ID is required")); await _videoStreamService.DisableHdmiTransmissionAsync(boardId.ToString()); return Ok($"HDMI transmission for board {boardId} disabled."); } catch (Exception ex) { logger.Error(ex, $"Failed to disable HDMI transmission for board"); return StatusCode(500, $"Error disabling HDMI transmission: {ex.Message}"); } } /// /// 设置视频流分辨率 /// /// 分辨率配置请求 /// 设置结果 [HttpPost("Resolution")] [EnableCors("Users")] [ProducesResponseType(typeof(object), StatusCodes.Status200OK)] [ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)] public async Task SetResolution([FromBody] ResolutionConfigRequest request) { try { var boardId = TryGetBoardId().OrThrow(() => new Exception("Board ID not found")); var ret = await _videoStreamService.SetResolutionAsync(boardId, request.Width, request.Height); if (ret.IsSuccessful && ret.Value) { return TypedResults.Ok(new { success = true, message = $"成功设置分辨率为 {request.Width}x{request.Height}", width = request.Width, height = request.Height, timestamp = DateTime.Now }); } else { return TypedResults.BadRequest(new { success = false, message = ret.Error?.ToString() ?? "未知错误", timestamp = DateTime.Now }); } } catch (Exception ex) { logger.Error(ex, $"设置分辨率为 {request.Width}x{request.Height} 失败"); return TypedResults.InternalServerError($"设置分辨率失败: {ex.Message}"); } } /// /// 获取支持的分辨率列表 /// /// 支持的分辨率列表 [HttpGet("SupportedResolutions")] [EnableCors("Users")] [ProducesResponseType(typeof(object), StatusCodes.Status200OK)] [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)] public IResult GetSupportedResolutions() { // (640, 480, "640x480 (VGA)"), // (960, 540, "960x540 (qHD)"), // (1280, 720, "1280x720 (HD)"), // (1280, 960, "1280x960 (SXGA)"), // (1920, 1080, "1920x1080 (Full HD)") return TypedResults.Ok(new AvailableResolutionsResponse[] { new AvailableResolutionsResponse { Width = 640, Height = 480, Name = "640x480(VGA)" }, new AvailableResolutionsResponse { Width = 960, Height = 480, Name = "960x480(qHD)" }, new AvailableResolutionsResponse { Width = 1280, Height = 720, Name = "1280x720(HD)" }, new AvailableResolutionsResponse { Width = 1280, Height = 960, Name = "1280x960(SXGA)" }, new AvailableResolutionsResponse { Width = 1920, Height = 1080, Name = "1920x1080(Full HD)" } }); } /// /// 初始化摄像头自动对焦功能 /// /// 初始化结果 [HttpPost("InitAutoFocus")] [EnableCors("Users")] [ProducesResponseType(typeof(object), StatusCodes.Status200OK)] [ProducesResponseType(typeof(object), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)] public async Task InitAutoFocus() { try { var boardId = TryGetBoardId().OrThrow(() => new Exception("Board ID not found")); var result = await _videoStreamService.InitAutoFocusAsync(boardId); if (result) { logger.Info("自动对焦初始化成功"); return TypedResults.Ok(new { success = true, message = "自动对焦初始化成功", timestamp = DateTime.Now }); } else { logger.Warn("自动对焦初始化失败"); return TypedResults.BadRequest(new { success = false, message = "自动对焦初始化失败", timestamp = DateTime.Now }); } } catch (Exception ex) { logger.Error(ex, "初始化自动对焦时发生异常"); return TypedResults.InternalServerError($"初始化自动对焦失败: {ex.Message}"); } } /// /// 执行自动对焦 /// /// 对焦结果 [HttpPost("AutoFocus")] [EnableCors("Users")] [ProducesResponseType(typeof(object), StatusCodes.Status200OK)] [ProducesResponseType(typeof(object), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)] public async Task AutoFocus() { try { var boardId = TryGetBoardId().OrThrow(() => new Exception("Board ID not found")); var result = await _videoStreamService.PerformAutoFocusAsync(boardId); if (result) { logger.Info("自动对焦执行成功"); return TypedResults.Ok(new { success = true, message = "自动对焦执行成功", timestamp = DateTime.Now }); } else { logger.Warn("自动对焦执行失败"); return TypedResults.BadRequest(new { success = false, message = "自动对焦执行失败", timestamp = DateTime.Now }); } } catch (Exception ex) { logger.Error(ex, "执行自动对焦时发生异常"); return TypedResults.InternalServerError($"执行自动对焦失败: {ex.Message}"); } } }