Memory leak in webcam code [closed]
Asked Answered
F

2

9

Ok, I've been trying to do something specific with video feed from a webcam. I have a Lumenera Infinity 2 microscope that I am trying to pull feed from, and want to be able to modify the feed as it comes in. Since I couldn't find a way to do that using Video Source Player, I decided to instead pull each frame (max of 15fps for the camera) as a bitmap so I can do my modifications there.

The problem is: I have a HUGE memory leak. When I run the video just using the videoSourcePlayer, it hovers at using around 30 megs. When I run pulling the frames as bitmaps, it breaks 1 gig of memory in a matter of seconds.

What am I missing, here? I figured auto-garbage collection would scoop up the old frames as they became inaccessible. Should I try to force garbage collection on bitmap? Or is it something else entirely and I am noobishly missing it.

FilterInfoCollection captureDevices;
VideoCaptureDevice cam;
Bitmap bitmap;

public Form1()
{
  InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)
{
  try
  {
    captureDevices = new FilterInfoCollection(FilterCategory.VideoInputDevice);

    if (captureDevices.Count == 0)
      throw new ApplicationException();

    CameraSelectComboBox.Items.Clear();

    foreach (FilterInfo device in captureDevices)
    {
      CameraSelectComboBox.Items.Add(device.Name);
    }

    CameraSelectComboBox.SelectedIndex = 0;
    CameraSelectComboBox.Enabled = true;
  }
  catch (ApplicationException)
  {
    CameraSelectComboBox.Enabled = false;
  }
}

private void connectButton_Click(object sender, EventArgs e)
{
  cam = new VideoCaptureDevice(captureDevices[CameraSelectComboBox.SelectedIndex].MonikerString);
  cam.NewFrame -= Handle_New_Frame; //Just to avoid the possibility of a second event handler being put on
  cam.NewFrame += new AForge.Video.NewFrameEventHandler(Handle_New_Frame);
  videoSourcePlayer1.Visible = false;
  cam.Start();

  //videoPictureBox1.Visible = false;
  //videoSourcePlayer1.VideoSource = new VideoCaptureDevice(captureDevices[CameraSelectComboBox.SelectedIndex].MonikerString);
  //videoSourcePlayer1.Start();
}

private void Handle_New_Frame(object sender, NewFrameEventArgs eventArgs)
{
  bitmap = (Bitmap)eventArgs.Frame.Clone();

  videoPictureBox1.Image = bitmap;
}
Forgo answered 15/4, 2013 at 14:17 Comment(4)
Bitmap is IDisposableWasting
Just a quick guess: Maybe the Handle New Frame event? it is cloning a frame, how many times and how fast does this event gets called?Secunderabad
I'm assuming at each frame, so a maximum of (based on the hardware) 15 times a second. I'll check and make sure thoughForgo
Similar question here: https://mcmap.net/q/1319419/-aforge-camera-memory-leakContrariwise
A
2

Try this:

private void Handle_New_Frame(object sender, NewFrameEventArgs eventArgs)
{
    if(bitmap != null)
        bitmap.Dispose();
    bitmap = new Bitmap(eventArgs.Frame);

    if(videoPictureBox1.Image != null)
        this.Invoke(new MethodInvoker(delegate() {videoPictureBox1.Image.Dispose();}));
    videoPictureBox1.Image = bitmap;
}

It solved some of the memory leaks I experienced with Aforge and PictureBoxes, but the VideoSourcePlayer is much better where memory consumption is concerned.

Annabelleannabergite answered 15/4, 2013 at 14:29 Comment(3)
Awesome! That should help a bunch! I am running into one issue with it, though- getting a cross thread error on the videoPictureBox1.Image.Dispose(). "Cross-thread operation not valid: Control 'videoPictureBox1' accessed from a thread other than the thread it was created on."Forgo
Did you run into that problem when you were working with this, by chance?Forgo
ah right yeah, you'd need to use Invoke. I've edited my answer, so it should fix the cross thread error.Annabelleannabergite
B
2

I think this is one area that can use improvement:

cam = new 
  VideoCaptureDevice(captureDevices[CameraSelectComboBox.SelectedIndex].MonikerString);

cam.NewFrame -= Handle_New_Frame; // you're pointing to the new instance of VCD, so this will have no effect.

cam.NewFrame += new AForge.Video.NewFrameEventHandler(Handle_New_Frame);
videoSourcePlayer1.Visible = false;
cam.Start();

That code block is bleeding memory every time you press the connect button.

You pretty much need to have a reference to the VCD at the main level. So define a member variable at Form1 class level:

private VideoCaptureDevice _cameraContext;

And in the connect event handler, do this:

if (_camerContext != null)
{
  _cameraContext.NewFrame -= Handle_New_Frame;
}
_cameraContext = new VideoCaptureDevice(blah blah blah);
_cameraContext.NewFrame += Handle_New_Frame;
videoSourcePlayer1.Visible = false;
_cameraContext.Start();

BTW, I'm assuming you're .NET 3.5 or later, hence the new delegate assignment syntax.

Bogbean answered 15/4, 2013 at 14:25 Comment(2)
Note: this is only one area of code that I see an obvious leak. Considering that the memory leak is significant, you should also look at how the bitmap is being disposed.Bogbean
Awesome! Thanks a bunch for that information. And yes, your assumption is correct- I am using 4.5Forgo
A
2

Try this:

private void Handle_New_Frame(object sender, NewFrameEventArgs eventArgs)
{
    if(bitmap != null)
        bitmap.Dispose();
    bitmap = new Bitmap(eventArgs.Frame);

    if(videoPictureBox1.Image != null)
        this.Invoke(new MethodInvoker(delegate() {videoPictureBox1.Image.Dispose();}));
    videoPictureBox1.Image = bitmap;
}

It solved some of the memory leaks I experienced with Aforge and PictureBoxes, but the VideoSourcePlayer is much better where memory consumption is concerned.

Annabelleannabergite answered 15/4, 2013 at 14:29 Comment(3)
Awesome! That should help a bunch! I am running into one issue with it, though- getting a cross thread error on the videoPictureBox1.Image.Dispose(). "Cross-thread operation not valid: Control 'videoPictureBox1' accessed from a thread other than the thread it was created on."Forgo
Did you run into that problem when you were working with this, by chance?Forgo
ah right yeah, you'd need to use Invoke. I've edited my answer, so it should fix the cross thread error.Annabelleannabergite

© 2022 - 2024 — McMap. All rights reserved.