0

I've looked through a few pages of similar inquiries, implemented most of the suggestions, but can't seem to find anything that's worked so far. Hopefully I'm not overlooking something glaringly obvious.

Right, so I'm using AForge.net to capture an image. It provides an event, which is triggered for each new frame received, which in my code looks like this:

private void videoSourcePlayer_NewFrame(object sender, ref Bitmap image)
    {
        framesRecieved++;
        try
        {
            if (!stopCapturing)
            {
                if (pictureBox1.Image != null)
                {
                    pictureBox1.Image.Dispose();
                }
                pictureBox1.Image = image.Clone(new Rectangle(0, 0, image.Width, image.Height), image.PixelFormat);
            }

        }
        catch { }
        finally { GC.Collect(); }
    }

Memory usage is very stable so long as the window remains stationary, but as soon as I grab the window form and start moving it about, memory usage keeps going up. The reason I've been led to believe it might be related to the picturebox, is because as soon as I turn the "stopCapturing" bool to true, memory stops rising, even if I'm moving the window around the screen. "stopCapturing" is not used for anything else, and the event continues triggering as normal, the only difference is the image being displayed in the picturebox. I'm at a loss as to the cause, so any help would be appreciated.

PS: Not sure if it's related, but my workstation has 2 screens.

Steven Mills
  • 2,363
  • 26
  • 36

2 Answers2

0

Bitmap.Clone() does a shallow copy, the actual bytes are still owned by the caller, so this could potentially cause all kind of troubles. You need to do a deep copy.

For example, the AForge way:

Bitmap bmp = AForge.Imaging.Image.Clone(image);

Or the GDI+ way (could also use lockbits, etc. for better perfs):

Bitmap bmp = new Bitmap(image.Width, image.Height, image.PixelFormat);
Graphics g = Graphics.FromImage(bmp);
g.DrawImageUnscaled(image, Point.Empty);
Joan Charmant
  • 2,012
  • 1
  • 18
  • 23
0

I'm wondering why you're cloning the image at all. It strikes me that you should only allocate a new image when either pictureBox1.Image is null or when the dimensions or pixel format of the image change:

private bool BitmapChanged(Bitmap old, Bitmap new)
{
    return old == null || old.PixelFormat != new.PixelFormat ||
        old.Width != new.Width || old.Height != new.Height;
}

private Bitmap MakeSimilarBitmap(Bitmap source)
{
    Bitmap copy = new Bitmap(source.Width, source.Height, source.PixelFormat);
    return copy;
}

private void DrawOnto(Image im, Bitmap source)
{
    using (Graphics g = Graphics.FromImage(im)) {
        g.DrawImage(source, 0, 0);
    }
}

then when you get a frame, you'll do something like this:

Image im = BitmapChanged(pictureBox1.Image as Bitmap, srcBmp) ?
                          MakeSimilarBitmap(image) : pictureBox1.Image;
DrawOnto(im, srcBmp);
bool same = im == pictureBox1.Image;
if (same)
    pictureBox1.Invalidate();
else {
    Image old = pictureBox1.Image;
    pictureBox1.Image = im;
    old.Dispose();
}
plinth
  • 48,267
  • 11
  • 78
  • 120
  • You need to make a copy because the image is owned by the VideoSource. It will be disposed at its own discretion. See also : http://www.aforgenet.com/framework/docs/html/63e8ac47-e9c1-d257-c587-c995c5a99b3f.htm – Joan Charmant Mar 22 '13 at 09:57
  • My point is that you copy the contents into a single retained Bitmap rather than allocating a new copy every frame. – plinth Mar 22 '13 at 17:31