using System.ComponentModel.DataAnnotations; using System.Threading.Tasks; using Microsoft.AspNetCore.Cors; using Microsoft.AspNetCore.Mvc; /// /// 视频流控制器,支持动态配置摄像头连接 /// [ApiController] [Route("api/[controller]")] public class VideoStreamController : ControllerBase { private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); private readonly server.Services.HttpVideoStreamService _videoStreamService; /// /// 视频流信息结构体 /// public class StreamInfoResult { /// /// TODO: /// public int FrameRate { get; set; } /// /// TODO: /// public int FrameWidth { get; set; } /// /// TODO: /// public int FrameHeight { get; set; } /// /// TODO: /// public string Format { get; set; } = "MJPEG"; /// /// TODO: /// public string HtmlUrl { get; set; } = ""; /// /// TODO: /// public string MjpegUrl { get; set; } = ""; /// /// TODO: /// public string SnapshotUrl { get; set; } = ""; /// /// TODO: /// public string UsbCameraUrl { get; set; } = ""; } /// /// 摄像头配置请求模型 /// 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; } } /// /// 分辨率配置请求模型 /// 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; } } /// /// 初始化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(status); } catch (Exception ex) { logger.Error(ex, "获取 HTTP 视频流服务状态失败"); return TypedResults.InternalServerError(ex.Message); } } /// /// 获取 HTTP 视频流信息 /// /// 流信息 [HttpGet("StreamInfo")] [EnableCors("Users")] [ProducesResponseType(typeof(StreamInfoResult), StatusCodes.Status200OK)] [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] public IResult GetStreamInfo() { try { logger.Info("获取 HTTP 视频流信息"); var result = new StreamInfoResult { FrameRate = _videoStreamService.FrameRate, FrameWidth = _videoStreamService.FrameWidth, FrameHeight = _videoStreamService.FrameHeight, Format = "MJPEG", HtmlUrl = $"http://{Global.localhost}:{_videoStreamService.ServerPort}/video-feed.html", MjpegUrl = $"http://{Global.localhost}:{_videoStreamService.ServerPort}/video-stream", SnapshotUrl = $"http://{Global.localhost}:{_videoStreamService.ServerPort}/snapshot", UsbCameraUrl = $"http://{Global.localhost}:{_videoStreamService.ServerPort}/usb-camera" }; return TypedResults.Ok(result); } 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(cameraStatus); } catch (Exception ex) { logger.Error(ex, "获取摄像头配置失败"); return TypedResults.InternalServerError(ex.Message); } } /// /// 控制 HTTP 视频流服务开关 /// /// 是否启用服务 /// 操作结果 [HttpPost("SetEnabled")] [EnableCors("Users")] [ProducesResponseType(typeof(object), StatusCodes.Status200OK)] [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] public async Task SetEnabled([FromQuery] bool enabled) { logger.Info("设置视频流服务开关: {Enabled}", enabled); await _videoStreamService.SetEnable(enabled); return TypedResults.Ok(); } /// /// 测试 HTTP 视频流连接 /// /// 连接测试结果 [HttpPost("TestConnection")] [EnableCors("Users")] [ProducesResponseType(typeof(bool), StatusCodes.Status200OK)] [ProducesResponseType(typeof(Exception), StatusCodes.Status500InternalServerError)] public async Task TestConnection() { try { logger.Info("测试 HTTP 视频流连接"); // 尝试通过HTTP请求检查视频流服务是否可访问 bool isConnected = false; using (var httpClient = new HttpClient()) { httpClient.Timeout = TimeSpan.FromSeconds(2); // 设置较短的超时时间 var response = await httpClient.GetAsync($"http://{Global.localhost}:{_videoStreamService.ServerPort}/"); // 只要能连接上就认为成功,不管返回状态 isConnected = response.IsSuccessStatusCode; } logger.Info("测试摄像头连接"); var (isSuccess, message) = await _videoStreamService.TestCameraConnectionAsync(); return TypedResults.Ok(new { isConnected = isConnected, success = isSuccess, message = message, cameraAddress = _videoStreamService.CameraAddress, cameraPort = _videoStreamService.CameraPort, timestamp = DateTime.Now }); } catch (Exception ex) { logger.Error(ex, "HTTP 视频流连接测试失败"); // 连接失败但不抛出异常,而是返回连接失败的结果 return TypedResults.Ok(false); } } /// /// 设置视频流分辨率 /// /// 分辨率配置请求 /// 设置结果 [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 { logger.Info($"设置视频流分辨率为 {request.Width}x{request.Height}"); var (isSuccess, message) = await _videoStreamService.SetResolutionAsync(request.Width, request.Height); if (isSuccess) { return TypedResults.Ok(new { success = true, message = message, width = request.Width, height = request.Height, timestamp = DateTime.Now }); } else { return TypedResults.BadRequest(new { success = false, message = message, timestamp = DateTime.Now }); } } catch (Exception ex) { logger.Error(ex, $"设置分辨率为 {request.Width}x{request.Height} 失败"); return TypedResults.InternalServerError($"设置分辨率失败: {ex.Message}"); } } /// /// 获取当前分辨率 /// /// 当前分辨率信息 [HttpGet("Resolution")] [EnableCors("Users")] [ProducesResponseType(typeof(object), StatusCodes.Status200OK)] [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)] public IResult GetCurrentResolution() { try { logger.Info("获取当前视频流分辨率"); var (width, height) = _videoStreamService.GetCurrentResolution(); return TypedResults.Ok(new { width = width, height = height, resolution = $"{width}x{height}", timestamp = DateTime.Now }); } catch (Exception ex) { logger.Error(ex, "获取当前分辨率失败"); return TypedResults.InternalServerError($"获取当前分辨率失败: {ex.Message}"); } } /// /// 获取支持的分辨率列表 /// /// 支持的分辨率列表 [HttpGet("SupportedResolutions")] [EnableCors("Users")] [ProducesResponseType(typeof(object), StatusCodes.Status200OK)] [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)] public IResult GetSupportedResolutions() { try { logger.Info("获取支持的分辨率列表"); var resolutions = _videoStreamService.GetSupportedResolutions(); return TypedResults.Ok(new { resolutions = resolutions.Select(r => new { width = r.Width, height = r.Height, name = r.Name, value = $"{r.Width}x{r.Height}" }), timestamp = DateTime.Now }); } catch (Exception ex) { logger.Error(ex, "获取支持的分辨率列表失败"); return TypedResults.InternalServerError($"获取支持的分辨率列表失败: {ex.Message}"); } } /// /// 初始化摄像头自动对焦功能 /// /// 初始化结果 [HttpPost("InitAutoFocus")] [EnableCors("Users")] [ProducesResponseType(typeof(object), StatusCodes.Status200OK)] [ProducesResponseType(typeof(object), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)] public async Task InitAutoFocus() { try { logger.Info("收到初始化自动对焦请求"); var result = await _videoStreamService.InitAutoFocusAsync(); 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 { logger.Info("收到执行自动对焦请求"); var result = await _videoStreamService.PerformAutoFocusAsync(); 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}"); } } /// /// 执行一次自动对焦 (GET方式) /// /// 对焦结果 [HttpGet("Focus")] [EnableCors("Users")] [ProducesResponseType(typeof(object), StatusCodes.Status200OK)] [ProducesResponseType(typeof(object), StatusCodes.Status400BadRequest)] [ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)] public async Task Focus() { try { logger.Info("收到执行一次对焦请求 (GET)"); // 检查摄像头是否已配置 if (!_videoStreamService.IsCameraConfigured()) { logger.Warn("摄像头未配置,无法执行对焦"); return TypedResults.BadRequest(new { success = false, message = "摄像头未配置,请先配置摄像头连接", timestamp = DateTime.Now }); } var result = await _videoStreamService.PerformAutoFocusAsync(); 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}"); } } }