摄像头播放后,增加分辨率的显示
This commit is contained in:
@@ -110,46 +110,68 @@ public class FrameConsumer : IDisposable
|
||||
/// </summary>
|
||||
private void RenderLoop()
|
||||
{
|
||||
// 创建 OpenCV 显示窗口
|
||||
Cv2.NamedWindow(_windowName, WindowFlags.Normal);
|
||||
bool isWindowCreated = false;
|
||||
|
||||
try
|
||||
{
|
||||
// 阻塞遍历队列:队列空时等待,收到取消信号时退出
|
||||
foreach (var frame in _frameBuffer.GetConsumingEnumerable(_cts.Token))
|
||||
// 我们不再使用简单的 foreach 阻塞等待数据,
|
||||
// 而是改用非阻塞模式或带有超时的读取,以保证 WaitKey 的活性
|
||||
while (!_cts.Token.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
// 尝试在 30ms 内获取一帧数据(相当于 33 fps 的响应速度)
|
||||
if (_frameBuffer.TryTake(out var frame, 30, _cts.Token))
|
||||
{
|
||||
// 渲染有效性校验:Mat 未释放且不为空
|
||||
if (frame.InternalMat != null && !frame.InternalMat.IsDisposed)
|
||||
try
|
||||
{
|
||||
// 零拷贝渲染:直接引用 InternalMat,无内存复制开销
|
||||
Cv2.ImShow(_windowName, frame.InternalMat);
|
||||
// 1ms 等待 UI 事件响应(必须调用,否则窗口无响应)
|
||||
Cv2.WaitKey(1);
|
||||
if (frame.InternalMat != null && !frame.InternalMat.IsDisposed)
|
||||
{
|
||||
if (!isWindowCreated)
|
||||
{
|
||||
Cv2.NamedWindow(_windowName, WindowFlags.Normal);
|
||||
isWindowCreated = true;
|
||||
}
|
||||
|
||||
Cv2.ImShow(_windowName, frame.InternalMat);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
frame.Dispose();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
// 【核心修复】无论有没有取到帧,都要执行 WaitKey
|
||||
// 只有这样,窗口在没视频时才能被拖动、最小化或手动点击 X 关闭
|
||||
if (isWindowCreated)
|
||||
{
|
||||
Debug.WriteLine($"[RenderError] 窗口[{_windowName}]渲染失败: {ex.Message}");
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 至关重要:渲染完成后释放帧引用
|
||||
// 引用计数归零 → 帧自动回池复用,避免内存泄漏
|
||||
frame.Dispose();
|
||||
// 1ms 的等待足以处理 Windows 窗口消息
|
||||
int key = Cv2.WaitKey(1);
|
||||
|
||||
// 如果用户点击了 OpenCV 窗口右上角的 X (部分版本支持)
|
||||
// 或者按下 ESC,可以根据需要在这里处理
|
||||
if (key == 27) break;
|
||||
|
||||
// 检查窗口是否还存在(防止用户手动关掉窗口后报错)
|
||||
// 如果窗口被手动关闭,我们标记为未创建,下次有流时重新弹窗
|
||||
try
|
||||
{
|
||||
if (Cv2.GetWindowProperty(_windowName, WindowPropertyFlags.Visible) < 1)
|
||||
{
|
||||
isWindowCreated = false;
|
||||
}
|
||||
}
|
||||
catch { isWindowCreated = false; }
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
// 正常取消,无需处理
|
||||
Debug.WriteLine($"[RenderInfo] 窗口[{_windowName}]渲染循环已取消");
|
||||
}
|
||||
catch (OperationCanceledException) { }
|
||||
catch { }
|
||||
finally
|
||||
{
|
||||
// 销毁 OpenCV 窗口,释放 UI 资源
|
||||
Cv2.DestroyWindow(_windowName);
|
||||
if (isWindowCreated)
|
||||
{
|
||||
Cv2.DestroyWindow(_windowName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user