从用于动态 PictureBox 的位图中释放资源时出现异常
Exception when release resources from bitmap used for dynamic PictureBox
我想使用尽可能少的 RAM - 使用 Windows 表单和 Aforge.Net 来捕获视频。
问题是,当我尝试例如“.Dispose()”时,一些元素出现异常:
static void Main()
{
Console.WriteLine("Main");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1()); <----- here VS showing me an exception (An unhandled exception of type 'System.InvalidOperationException' occurred in System.Drawing.dll)
}
执行此操作的代码:
public void setLocalCamera(string cameraName)
{
videoSource = new VideoCaptureDevice(cameraName);
videoSource.NewFrame += new NewFrameEventHandler(video_NewFrame);
videoSource.Start();
}
Bitmap bitmap;
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
if (bitmap != null)
bitmap.Dispose(); <--- here is the problematic code
bitmap = (Bitmap)eventArgs.Frame.Clone();
pB_Camera.Image = bitmap;
}
这段代码产生了随机时间异常(我不知道究竟是什么触发了它)。我还尝试了一些我发现的其他解决方案,但什么都没有 work/help(比如在 pB_Camera.Image = 位图之后制作 bitmap.Dispose();但这也是一个例外)
如何解决这个问题并释放尽可能多的 RAM?
同时避免异常和闪烁的正确顺序是:
Bitmap bitmap;
void SetBitmap(Bitmap value)
{
pB_Camera.Image = value;
if (bitmap != null) bitmap.Dispose();
bitmap = value;
}
而且用法很简单:
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
SetBitmap((Bitmap)eventArgs.Frame.Clone());
}
编辑:但是,您的具体情况略有不同,因为事件是在非 UI 线程上引发的。虽然一个简单的 Control.Invoke
就可以工作,但如果框架仅用于显示,我认为最好实现一点 "single item producer/consumer" 非阻塞模式,以便让工作线程在您继续处理时继续处理正在使用图像,如下所示:
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
PushNextFrame((Bitmap)eventArgs.Frame.Clone());
}
Bitmap nextFrame;
void PushNextFrame(Bitmap value)
{
var prevFrame = Interlocked.Exchange(ref nextFrame, value);
if (prevFrame != null)
{
// previous frame has not been consumed, so just discard it.
// no need to notify the consumer, because it should have been done already.
prevFrame.Dispose();
}
else
{
// previos frame has been consumed and we just set a new one, so we need to notity the consumer.
BeginInvoke((Action)OnNextFrameAvailable);
}
}
Bitmap PullNextFrame() { return Interlocked.Exchange(ref nextFrame, null); }
void OnNextFrameAvailable()
{
DisplayFrame(PullNextFrame());
}
Bitmap currentFrame;
void DisplayFrame(Bitmap value)
{
pb_Camera.Image = value;
if (currentFrame != null) currentFrame.Dispose();
currentFrame = value;
}
我想使用尽可能少的 RAM - 使用 Windows 表单和 Aforge.Net 来捕获视频。 问题是,当我尝试例如“.Dispose()”时,一些元素出现异常:
static void Main()
{
Console.WriteLine("Main");
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1()); <----- here VS showing me an exception (An unhandled exception of type 'System.InvalidOperationException' occurred in System.Drawing.dll)
}
执行此操作的代码:
public void setLocalCamera(string cameraName)
{
videoSource = new VideoCaptureDevice(cameraName);
videoSource.NewFrame += new NewFrameEventHandler(video_NewFrame);
videoSource.Start();
}
Bitmap bitmap;
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
if (bitmap != null)
bitmap.Dispose(); <--- here is the problematic code
bitmap = (Bitmap)eventArgs.Frame.Clone();
pB_Camera.Image = bitmap;
}
这段代码产生了随机时间异常(我不知道究竟是什么触发了它)。我还尝试了一些我发现的其他解决方案,但什么都没有 work/help(比如在 pB_Camera.Image = 位图之后制作 bitmap.Dispose();但这也是一个例外)
如何解决这个问题并释放尽可能多的 RAM?
同时避免异常和闪烁的正确顺序是:
Bitmap bitmap;
void SetBitmap(Bitmap value)
{
pB_Camera.Image = value;
if (bitmap != null) bitmap.Dispose();
bitmap = value;
}
而且用法很简单:
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
SetBitmap((Bitmap)eventArgs.Frame.Clone());
}
编辑:但是,您的具体情况略有不同,因为事件是在非 UI 线程上引发的。虽然一个简单的 Control.Invoke
就可以工作,但如果框架仅用于显示,我认为最好实现一点 "single item producer/consumer" 非阻塞模式,以便让工作线程在您继续处理时继续处理正在使用图像,如下所示:
private void video_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
PushNextFrame((Bitmap)eventArgs.Frame.Clone());
}
Bitmap nextFrame;
void PushNextFrame(Bitmap value)
{
var prevFrame = Interlocked.Exchange(ref nextFrame, value);
if (prevFrame != null)
{
// previous frame has not been consumed, so just discard it.
// no need to notify the consumer, because it should have been done already.
prevFrame.Dispose();
}
else
{
// previos frame has been consumed and we just set a new one, so we need to notity the consumer.
BeginInvoke((Action)OnNextFrameAvailable);
}
}
Bitmap PullNextFrame() { return Interlocked.Exchange(ref nextFrame, null); }
void OnNextFrameAvailable()
{
DisplayFrame(PullNextFrame());
}
Bitmap currentFrame;
void DisplayFrame(Bitmap value)
{
pb_Camera.Image = value;
if (currentFrame != null) currentFrame.Dispose();
currentFrame = value;
}