我的应用程序使用 RTSPClientSharp 库从相机流式传输,当解码帧准备好时,会引发一个 OnFramesReceived 事件。我在同一个事件中将解码帧转换为位图,这是一个阻塞调用,耗时超过 100 毫秒,导致帧速率降至 10 FPS。
为了解决这个问题,我使用了此处的任务队列代码,该代码使用 Task.ContinueWith.UnWrap 将 ProcessFrame 事件(具有将解码帧转换为位图的代码)排队。我的目标是按照收到帧的顺序依次执行 ProcessFrame 调用。使用任务队列解决了阻塞呼叫的问题,现在我可以每秒处理 30 帧。
但是,我现在遇到了内存问题,如果我的应用程序运行时间更长,内存使用量会逐渐增加。ANTS 内存分析器说(检查屏幕截图) ContinuationResultFrom 任务是 Gen2 中最大的类。
更新 我想包括的一些事实,我有 10 个这样的摄像头连接到我的应用程序,每个摄像头都有自己的摄像头类实例。我正在使用具有超线程和 32GB RAM 的 16 核处理器,但如果 CPU 无法处理负载,我宁愿将 FPS 降低到 10。
private void OnFramesReceived(object sender, RawFrame rawFrame)
{
taskQueue.Enqueue(() => Task.Run(() => ProcessFrame?.Invoke(this, decodedFrame)));
}
private void HandleProcessFrame(object sender, IDecodedVideoFrame decodedFrame)
{
try
{
using (Bitmap bmpBitmap = new Bitmap(m_Width, m_Height))
{
BitmapData bmpData = bmpBitmap.LockBits(new Rectangle(0, 0, bmpBitmap.Width, bmpBitmap.Height), ImageLockMode.WriteOnly, bmpBitmap.PixelFormat);
try
{
decodedFrame.TransformTo(
bmpData.Scan0,
bmpData.Stride,
_transformParameters);
}
finally
{
bmpBitmap.UnlockBits(bmpData);
}
base.OnNewFrameEvent(this, bmpBitmap);
decodedFrame = null;
}
}
catch (Exception ex)
{
Logng.LogError(ex);
}
}
public class TaskQueue
{
private Task previous = Task.FromResult(false);
private object key = new object();
public Task<T> Enqueue<T>(Func<Task<T>> taskGenerator)
{
lock (key)
{
var next = previous.ContinueWith(t => taskGenerator()).Unwrap();
previous = next;
return next;
}
}
public Task Enqueue(Func<Task> taskGenerator)
{
lock (key)
{
var next = previous.ContinueWith(t => taskGenerator(), TaskContinuationOptions.ExecuteSynchronously).Unwrap();
previous = next;
return next;
}
}
}