using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; using System.ComponentModel.DataAnnotations; /// /// 视频流控制器,支持动态配置摄像头连接 /// [ApiController] [Route("api/[controller]")] public class VideoStreamController : ControllerBase { private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); private readonly server.Services.HttpVideoStreamService _videoStreamService; /// /// 摄像头配置请求模型 /// public class CameraConfigRequest { [Required] [RegularExpression(@"^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$", ErrorMessage = "请输入有效的IP地址")] public string Address { get; set; } = ""; [Required] [Range(1, 65535, ErrorMessage = "端口必须在1-65535范围内")] public int Port { get; set; } } /// /// 初始化HTTP视频流控制器 /// /// HTTP视频流服务 public VideoStreamController(server.Services.HttpVideoStreamService videoStreamService) { logger.Info("创建VideoStreamController,命名空间:{Namespace}", this.GetType().Namespace); _videoStreamService = videoStreamService; } /// /// 获取 HTTP 视频流服务状态 /// /// 服务状态信息 [HttpGet("Status")] [EnableCors("Users")] [ProducesResponseType(typeof(object), StatusCodes.Status200OK)] [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] public IResult GetStatus() { try { logger.Info("GetStatus方法被调用,控制器:{Controller},路径:api/VideoStream/Status", this.GetType().Name); // 使用HttpVideoStreamService提供的状态信息 var status = _videoStreamService.GetServiceStatus(); // 转换为小写首字母的JSON属性(符合前端惯例) return TypedResults.Ok(new { isRunning = true, // HTTP视频流服务作为后台服务始终运行 serverPort = _videoStreamService.ServerPort, streamUrl = $"http://localhost:{_videoStreamService.ServerPort}/video-feed.html", mjpegUrl = $"http://localhost:{_videoStreamService.ServerPort}/video-stream", snapshotUrl = $"http://localhost:{_videoStreamService.ServerPort}/snapshot", connectedClients = _videoStreamService.ConnectedClientsCount, clientEndpoints = _videoStreamService.GetConnectedClientEndpoints(), cameraStatus = _videoStreamService.GetCameraStatus() }); } catch (Exception ex) { logger.Error(ex, "获取 HTTP 视频流服务状态失败"); return TypedResults.InternalServerError(ex.Message); } } /// /// 获取 HTTP 视频流信息 /// /// 流信息 [HttpGet("StreamInfo")] [EnableCors("Users")] [ProducesResponseType(typeof(object), StatusCodes.Status200OK)] [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] public IResult GetStreamInfo() { try { logger.Info("获取 HTTP 视频流信息"); return TypedResults.Ok(new { frameRate = _videoStreamService.FrameRate, frameWidth = _videoStreamService.FrameWidth, frameHeight = _videoStreamService.FrameHeight, format = "MJPEG", htmlUrl = $"http://localhost:{_videoStreamService.ServerPort}/video-feed.html", mjpegUrl = $"http://localhost:{_videoStreamService.ServerPort}/video-stream", snapshotUrl = $"http://localhost:{_videoStreamService.ServerPort}/snapshot", cameraAddress = _videoStreamService.CameraAddress, cameraPort = _videoStreamService.CameraPort }); } catch (Exception ex) { logger.Error(ex, "获取 HTTP 视频流信息失败"); return TypedResults.InternalServerError(ex.Message); } } /// /// 配置摄像头连接参数 /// /// 摄像头配置 /// 配置结果 [HttpPost("ConfigureCamera")] [EnableCors("Users")] [ProducesResponseType(typeof(object), StatusCodes.Status200OK)] [ProducesResponseType(typeof(object), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] public async Task ConfigureCamera([FromBody] CameraConfigRequest config) { try { logger.Info("配置摄像头连接: {Address}:{Port}", config.Address, config.Port); var success = await _videoStreamService.ConfigureCameraAsync(config.Address, config.Port); if (success) { return TypedResults.Ok(new { success = true, message = "摄像头配置成功", cameraAddress = config.Address, cameraPort = config.Port }); } else { return TypedResults.BadRequest(new { success = false, message = "摄像头配置失败", cameraAddress = config.Address, cameraPort = config.Port }); } } catch (Exception ex) { logger.Error(ex, "配置摄像头连接失败"); return TypedResults.InternalServerError(ex.Message); } } /// /// 获取当前摄像头配置 /// /// 摄像头配置信息 [HttpGet("CameraConfig")] [EnableCors("Users")] [ProducesResponseType(typeof(object), StatusCodes.Status200OK)] [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] public IResult GetCameraConfig() { try { logger.Info("获取摄像头配置"); var cameraStatus = _videoStreamService.GetCameraStatus(); return TypedResults.Ok(new { address = _videoStreamService.CameraAddress, port = _videoStreamService.CameraPort, isConfigured = cameraStatus.GetType().GetProperty("IsConfigured")?.GetValue(cameraStatus), connectionString = $"{_videoStreamService.CameraAddress}:{_videoStreamService.CameraPort}" }); } catch (Exception ex) { logger.Error(ex, "获取摄像头配置失败"); return TypedResults.InternalServerError(ex.Message); } } /// /// 测试摄像头连接 /// /// 连接测试结果 [HttpPost("TestCameraConnection")] [EnableCors("Users")] [ProducesResponseType(typeof(object), StatusCodes.Status200OK)] [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] public async Task TestCameraConnection() { try { logger.Info("测试摄像头连接"); var (isSuccess, message) = await _videoStreamService.TestCameraConnectionAsync(); return TypedResults.Ok(new { success = isSuccess, message = message, cameraAddress = _videoStreamService.CameraAddress, cameraPort = _videoStreamService.CameraPort, timestamp = DateTime.Now }); } 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 { logger.Info("测试 HTTP 视频流连接"); // 尝试通过HTTP请求检查视频流服务是否可访问 using (var httpClient = new HttpClient()) { httpClient.Timeout = TimeSpan.FromSeconds(2); // 设置较短的超时时间 var response = await httpClient.GetAsync($"http://localhost:{_videoStreamService.ServerPort}/"); // 只要能连接上就认为成功,不管返回状态 bool isConnected = response.IsSuccessStatusCode; return TypedResults.Ok(isConnected); } } catch (Exception ex) { logger.Error(ex, "HTTP 视频流连接测试失败"); // 连接失败但不抛出异常,而是返回连接失败的结果 return TypedResults.Ok(false); } } }