add: 添加分辨率设置逻辑

This commit is contained in:
alivender
2025-07-13 11:42:26 +08:00
parent b913f58f13
commit 352ee1f4f2
5 changed files with 581 additions and 21 deletions

View File

@@ -33,6 +33,26 @@ public class VideoStreamController : ControllerBase
public int Port { get; set; }
}
/// <summary>
/// 分辨率配置请求模型
/// </summary>
public class ResolutionConfigRequest
{
/// <summary>
/// 宽度
/// </summary>
[Required]
[Range(640, 1920, ErrorMessage = "宽度必须在640-1920范围内")]
public int Width { get; set; }
/// <summary>
/// 高度
/// </summary>
[Required]
[Range(480, 1080, ErrorMessage = "高度必须在480-1080范围内")]
public int Height { get; set; }
}
/// <summary>
/// 初始化HTTP视频流控制器
/// </summary>
@@ -233,4 +253,116 @@ public class VideoStreamController : ControllerBase
return TypedResults.Ok(false);
}
}
/// <summary>
/// 设置视频流分辨率
/// </summary>
/// <param name="request">分辨率配置请求</param>
/// <returns>设置结果</returns>
[HttpPost("Resolution")]
[EnableCors("Users")]
[ProducesResponseType(typeof(object), StatusCodes.Status200OK)]
[ProducesResponseType(typeof(string), StatusCodes.Status400BadRequest)]
[ProducesResponseType(typeof(string), StatusCodes.Status500InternalServerError)]
public async Task<IResult> 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}");
}
}
/// <summary>
/// 获取当前分辨率
/// </summary>
/// <returns>当前分辨率信息</returns>
[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}");
}
}
/// <summary>
/// 获取支持的分辨率列表
/// </summary>
/// <returns>支持的分辨率列表</returns>
[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}");
}
}
}

View File

@@ -26,19 +26,13 @@ class Camera
const uint CAM_I2C_ADDR = 0x3C;
const Peripherals.I2cClient.I2cProtocol CAM_PROTO = Peripherals.I2cClient.I2cProtocol.SCCB;
const UInt16 H_START = 0; //default: 0
const UInt16 V_START = 0; //default: 0
const UInt16 DVPHO = 640; //default: 2592 (0xA20)
const UInt16 DVPVO = 480; //default: 1944 (0x798)
const UInt16 H_END = H_START + 1500 - 1; //default: 2624-1 (0xA3F)
const UInt16 V_END = V_START + 1300 - 1; //default: 1951-1 (0x79F)
const UInt16 HTS = 1700; //default: 2844 (0xB1C)
const UInt16 VTS = 1500; //default: 1968 (0x7B0)
const UInt16 H_OFFSET = 16; //default: 16 (0x10)
const UInt16 V_OFFSET = 4; //default: 4 (0x04)
const byte PLL_MUX = 10;
const UInt32 FrameAddr = 0x00;
const UInt32 FrameLength = DVPHO * DVPVO * 16 / 32;
// 动态分辨率参数
private UInt16 _currentWidth = 640;
private UInt16 _currentHeight = 480;
private UInt32 _currentFrameLength = 640 * 480 * 2 / 4; // RGB565格式2字节/像素按4字节对齐
/// <summary>
@@ -183,8 +177,7 @@ class Camera
this.ep,
this.taskID, // taskID
FrameAddr,
// ((int)FrameLength),
1280*720/2,
(int)(_currentWidth * _currentHeight * 2), // 使用当前分辨率的动态大小
this.timeout);
if (!result.IsSuccessful)
@@ -423,6 +416,67 @@ class Camera
);
}
/// <summary>
/// 切换摄像头分辨率
/// </summary>
/// <param name="width">宽度</param>
/// <param name="height">高度</param>
/// <returns>配置结果</returns>
public async ValueTask<Result<bool>> ChangeResolution(int width, int height)
{
try
{
logger.Info($"正在切换摄像头分辨率到 {width}x{height}");
Result<bool> result;
switch ($"{width}x{height}")
{
case "640x480":
result = await ConfigureResolution640x480();
break;
case "1280x720":
result = await ConfigureResolution1280x720();
break;
default:
logger.Error($"不支持的分辨率: {width}x{height}");
return new(new ArgumentException($"不支持的分辨率: {width}x{height}"));
}
if (result.IsSuccessful)
{
_currentWidth = (UInt16)width;
_currentHeight = (UInt16)height;
_currentFrameLength = (UInt32)(width * height * 2 / 4); // RGB565格式按4字节对齐
logger.Info($"摄像头分辨率已切换到 {width}x{height}");
}
return result;
}
catch (Exception ex)
{
logger.Error(ex, $"切换分辨率到 {width}x{height} 时发生错误");
return new(ex);
}
}
/// <summary>
/// 获取当前分辨率
/// </summary>
/// <returns>当前分辨率(宽度, 高度)</returns>
public (int Width, int Height) GetCurrentResolution()
{
return (_currentWidth, _currentHeight);
}
/// <summary>
/// 获取当前帧长度
/// </summary>
/// <returns>当前帧长度</returns>
public UInt32 GetCurrentFrameLength()
{
return _currentFrameLength;
}
/// <summary>
/// 复位摄像头
/// </summary>

View File

@@ -82,8 +82,11 @@ public class HttpVideoStreamService : BackgroundService
private HttpListener? _httpListener;
private readonly int _serverPort = 8080;
private readonly int _frameRate = 30; // 30 FPS
private readonly int _frameWidth = 1280;
private readonly int _frameHeight = 720;
// 动态分辨率配置
private int _frameWidth = 640; // 默认640x480
private int _frameHeight = 480;
private readonly object _resolutionLock = new object();
// 摄像头客户端
private Camera? _camera;
@@ -439,8 +442,16 @@ public class HttpVideoStreamService : BackgroundService
// 获取当前帧
var imageData = await GetFPGAImageData();
// 获取当前分辨率
int currentWidth, currentHeight;
lock (_resolutionLock)
{
currentWidth = _frameWidth;
currentHeight = _frameHeight;
}
// 直接使用Common.Image.ConvertRGB24ToJpeg进行转换
var jpegResult = Common.Image.ConvertRGB24ToJpeg(imageData, _frameWidth, _frameHeight, 80);
var jpegResult = Common.Image.ConvertRGB24ToJpeg(imageData, currentWidth, currentHeight, 80);
if (!jpegResult.IsSuccessful)
{
logger.Error("RGB24转JPEG失败: {Error}", jpegResult.Error);
@@ -647,6 +658,14 @@ public class HttpVideoStreamService : BackgroundService
try
{
// 获取当前分辨率
int currentWidth, currentHeight;
lock (_resolutionLock)
{
currentWidth = _frameWidth;
currentHeight = _frameHeight;
}
// 从摄像头读取帧数据
var readStartTime = DateTime.UtcNow;
var result = await currentCamera.ReadFrame();
@@ -662,15 +681,15 @@ public class HttpVideoStreamService : BackgroundService
var rgb565Data = result.Value;
// 验证数据长度是否正确
if (!Common.Image.ValidateImageDataLength(rgb565Data, _frameWidth, _frameHeight, 2))
if (!Common.Image.ValidateImageDataLength(rgb565Data, currentWidth, currentHeight, 2))
{
logger.Warn("摄像头数据长度不匹配,期望: {Expected}, 实际: {Actual}",
_frameWidth * _frameHeight * 2, rgb565Data.Length);
currentWidth * currentHeight * 2, rgb565Data.Length);
}
// 将 RGB565 转换为 RGB24
var convertStartTime = DateTime.UtcNow;
var rgb24Result = Common.Image.ConvertRGB565ToRGB24(rgb565Data, _frameWidth, _frameHeight, isLittleEndian: false);
var rgb24Result = Common.Image.ConvertRGB565ToRGB24(rgb565Data, currentWidth, currentHeight, isLittleEndian: false);
var convertEndTime = DateTime.UtcNow;
var convertTime = (convertEndTime - convertStartTime).TotalMilliseconds;
@@ -708,8 +727,16 @@ public class HttpVideoStreamService : BackgroundService
return;
}
// 获取当前分辨率
int currentWidth, currentHeight;
lock (_resolutionLock)
{
currentWidth = _frameWidth;
currentHeight = _frameHeight;
}
// 直接使用Common.Image.ConvertRGB24ToJpeg进行转换
var jpegResult = Common.Image.ConvertRGB24ToJpeg(frameData, _frameWidth, _frameHeight, 80);
var jpegResult = Common.Image.ConvertRGB24ToJpeg(frameData, currentWidth, currentHeight, 80);
if (!jpegResult.IsSuccessful)
{
logger.Error("RGB24转JPEG失败: {Error}", jpegResult.Error);
@@ -904,4 +931,102 @@ public class HttpVideoStreamService : BackgroundService
base.Dispose();
}
/// <summary>
/// 设置视频流分辨率
/// </summary>
/// <param name="width">宽度</param>
/// <param name="height">高度</param>
/// <returns>设置结果</returns>
public async Task<(bool IsSuccess, string Message)> SetResolutionAsync(int width, int height)
{
try
{
logger.Info($"正在设置视频流分辨率为 {width}x{height}");
// 验证分辨率
if (!IsSupportedResolution(width, height))
{
var message = $"不支持的分辨率: {width}x{height},支持的分辨率: 640x480, 1280x720";
logger.Error(message);
return (false, message);
}
Camera? currentCamera = null;
lock (_cameraLock)
{
currentCamera = _camera;
}
if (currentCamera == null)
{
var message = "摄像头未配置,无法设置分辨率";
logger.Error(message);
return (false, message);
}
// 设置摄像头分辨率
var cameraResult = await currentCamera.ChangeResolution(width, height);
if (!cameraResult.IsSuccessful)
{
var message = $"设置摄像头分辨率失败: {cameraResult.Error}";
logger.Error(message);
return (false, message);
}
// 更新HTTP服务的分辨率配置
lock (_resolutionLock)
{
_frameWidth = width;
_frameHeight = height;
}
var successMessage = $"视频流分辨率已成功设置为 {width}x{height}";
logger.Info(successMessage);
return (true, successMessage);
}
catch (Exception ex)
{
var message = $"设置分辨率时发生错误: {ex.Message}";
logger.Error(ex, message);
return (false, message);
}
}
/// <summary>
/// 获取当前分辨率
/// </summary>
/// <returns>当前分辨率(宽度, 高度)</returns>
public (int Width, int Height) GetCurrentResolution()
{
lock (_resolutionLock)
{
return (_frameWidth, _frameHeight);
}
}
/// <summary>
/// 检查是否支持该分辨率
/// </summary>
/// <param name="width">宽度</param>
/// <param name="height">高度</param>
/// <returns>是否支持</returns>
private bool IsSupportedResolution(int width, int height)
{
var resolution = $"{width}x{height}";
return resolution == "640x480" || resolution == "1280x720";
}
/// <summary>
/// 获取支持的分辨率列表
/// </summary>
/// <returns>支持的分辨率列表</returns>
public List<(int Width, int Height, string Name)> GetSupportedResolutions()
{
return new List<(int, int, string)>
{
(640, 480, "640x480 (VGA)"),
(1280, 720, "1280x720 (HD)")
};
}
}