1

I am trying to output whatever is captured from a webcam to an Image control in a WPF window. I am using the AForge.NET library.

Unfortunately, after a few minutes of successful capturing, I am getting an OutOfMemoryException. Likewise, as soon as I start capturing, I can see my memory usage rise continuously in the task manager until the moment of the exception (although there have been a few occasions where memory usage kept rising, then steeply dropped back to its original state, and then kept rising again to the point of the exception).

This is my code for the handler of the NewFrame event of the VideoCaptureDevice class (whose code for converting the Bitmap instance to an ImageSource is largely based on an answer by Sascha Hennig):

[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);

private void videoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
    try
    {
        using (var streamBitmap = (Bitmap)eventArgs.Frame.Clone()) {
            BitmapSource bitmapSourceVideo;

            var hBitmap = streamBitmap.GetHbitmap();
            try
            {
                bitmapSourceVideo = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                    hBitmap,
                    IntPtr.Zero,
                    Int32Rect.Empty,
                    BitmapSizeOptions.FromEmptyOptions());
            }
            finally
            {
                DeleteObject(hBitmap);
            }
            bitmapSourceVideo.Freeze();

            Dispatcher.BeginInvoke(new ThreadStart(delegate
                                                       {
                                                           videoControl.Source = bitmapSourceVideo;
                                                       }));
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
}

In case you wonder, the call to eventArgs.Frame.Clone() seems to be required. Explanations can be found here, and possibly here.

While trying to isolate the source of the issue, I have commented out various portions of this code until I arrived at this state:

[System.Runtime.InteropServices.DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);

private void videoSource_NewFrame(object sender, NewFrameEventArgs eventArgs)
{
    try
    {
        using (var streamBitmap = (Bitmap)eventArgs.Frame.Clone()) {
            BitmapSource bitmapSourceVideo;

            var hBitmap = streamBitmap.GetHbitmap();
            try
            {/*
                bitmapSourceVideo = System.Windows.Interop.Imaging.CreateBitmapSourceFromHBitmap(
                    hBitmap,
                    IntPtr.Zero,
                    Int32Rect.Empty,
                    BitmapSizeOptions.FromEmptyOptions());
            */}
            finally
            {
                DeleteObject(hBitmap);
            }
            /*
            bitmapSourceVideo.Freeze();

            Dispatcher.BeginInvoke(new ThreadStart(delegate
                                                       {
                                                           videoControl.Source = bitmapSourceVideo;
                                                       }));*/
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.ToString());
    }
}

(Obviously, this doesn't draw anything to the window, but that is beside the point now.) This version of the method does not feature the memory leak. Removing the comment signs around the statement with the call to CreateBitmapSourceFromHBitmap brings the memory leak back. What am I missing here?

There have been various resources about seemingly similar problems, none of which have helped me find a solution:

Community
  • 1
  • 1
O. R. Mapper
  • 20,083
  • 9
  • 69
  • 114

1 Answers1

0

My instinct tells me that it is something to do with the bitmapSourceVideo being inside the delegate, and therefore creating a closure and not being cleaned up.

EDIT

Try

        Dispatcher.BeginInvoke(new ThreadStart(delegate
        {
            videoControl.Source = bitmapSourceVideo;
            bitmapSourceVideo = null;
        }));
Michal Ciechan
  • 13,492
  • 11
  • 76
  • 118
  • I have looked into that, but how exactly am I supposed to clean up a [`BitmapSource`](https://msdn.microsoft.com/en-us/library/system.windows.media.imaging.bitmapsource%28v=vs.110%29.aspx)? It's not [disposable](https://msdn.microsoft.com/en-us/libraRy/system.idisposable%28v=vs.100%29.aspx) or something. [This answer](http://stackoverflow.com/a/11950108/1430156) (though it's not accepted ...) implies no further clean-up is necessary. – O. R. Mapper Mar 09 '15 at 23:47
  • Also what happens if you was to wrap this whole method inside a `Dispatcher.BeginInvoke` Rather than just for the setting of source? – Michal Ciechan Mar 10 '15 at 00:33
  • I can try, though I don't expect anything good to come out of that - in particular, I'd be surprised if I could rely on `eventArgs.Frame` still being around after the event handler has terminated in the thread in which it was invoked. – O. R. Mapper Mar 10 '15 at 00:49