Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memory leak in webcam code [closed]

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;
}
like image 569
C Smith Avatar asked Apr 15 '13 14:04

C Smith


People also ask

What causes memory leaks in code?

Memory leaks occur when new memory is allocated dynamically and never deallocated. In C programs, new memory is allocated by the malloc or calloc functions, and deallocated by the free function. In C++, new memory is usually allocated by the new operator and deallocated by the delete or the delete [] operator.

Is memory leak serious?

Very dangerous. Memory leaks in the kernel level lead to serious system stability issues. Kernel memory is very limited compared to user land memory and should be handled cautiously. Memory is allocated but never freed.


2 Answers

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.

like image 137
Steven Mills Avatar answered Nov 15 '22 18:11

Steven Mills


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.

like image 35
code4life Avatar answered Nov 15 '22 18:11

code4life