从用于动态PictureBox的位图释放资源时出现异常

时间:2015-08-23 15:41:26

标签: c# winforms bitmap aforge

我希望尽可能少地使用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;

    }

此代码用于随机时间异常(我不知道究竟是什么火上浇油)。我也尝试了一些其他的解决方案,但我找不到任何工作/帮助(比如在pB_Camera.Image = bitmap之后make bitmap.Dispose();但这也是例外)

如何解决此问题并尽可能多地释放内存?

1 个答案:

答案 0 :(得分:-1)

避免异常和闪烁的正确顺序是:

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可以使用,但如果框架仅用于显示,我认为最好实现一个小的单项生产者/消费者&#34;非阻塞模式,为了让工作线程在您使用图像时继续处理,如下所示:

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;
}