Question

I created a C# application that receive a RGB stream in input, then compress the stream and save it on the disk. For my test I'm running an application that acts as server(on the same pc) which streams out the video.

The core of my client application is:

void client_ColorFrameReady(object sender, ColorFrameReadyEventArgs e)
{
    if (writer != null)
    {
        count++;
        if (count % 2 == 0)
            writer.WriteVideoFrame(ResizeBitmap(BitmapImage2Bitmap(e.ColorFrame.BitmapImage), 320, 240));
        }
        else
        {
            writer.Close();
        }
    }
}

the type of writer is VideoFileWriter from aforge.net library.

My application works well, but I have a problem related to the amount of RAM used.

When my application is acquiring frames the RAM used from the server application (the application that stream out the video) increases linearly with time. The RAM is freed only when writer.Close() is executed.

The methods BitmapImage2Bitmap and ResieBitmap are shown below:

private Bitmap BitmapImage2Bitmap(BitmapImage bitmapImage)
{
    // BitmapImage bitmapImage = new BitmapImage(new Uri("../Images/test.png", UriKind.Relative));

    using (MemoryStream outStream = new MemoryStream())
    {
         BitmapEncoder enc = new BmpBitmapEncoder();
         enc.Frames.Add(BitmapFrame.Create(bitmapImage));
         enc.Save(outStream);
         System.Drawing.Bitmap bitmap = new System.Drawing.Bitmap(outStream);

         // return bitmap; <-- leads to problems, stream is closed/closing ...
         return new Bitmap(bitmap);
    }
}

private static Bitmap ResizeBitmap(Bitmap sourceBMP, int width, int height)
{
    Bitmap result = new Bitmap(width, height);
    using (Graphics g = Graphics.FromImage(result))
    g.DrawImage(sourceBMP, 0, 0, width, height);
    return result;
}

Can I limit the usage of RAM in my application?

Was it helpful?

Solution

I use always using

You are not. Unfortunately you also use it when you should not. There are three bitmap objects being 'leaked' here for every frame.

You got in trouble by using using on the MemoryStream. And patched the problem by copying the bitmap, but the bitmap object is not being disposed. Fix this the right way, do not dispose the MemoryStream. Not disposing the MemoryStream is fine, it only uses memory and has no disposable members when you don't use the MemoryStream(Stream) constructor. Now you don't need the copy you make with the Bitmap(image) constructor anymore either. That's one.

The bitmap returned by BitmapImage2Bitmap() is not being disposed. That's two.

The bitmap returned by ResizeBitmap() is not being disposed. That's three.

It should look like this:

using (var frame = BitmapImage2Bitmap(e.ColorFrame.BitmapImage))                   
using (var thumb = ResizeBitmap(frame, 320, 240)) {
    writer.WriteVideoFrame(thumb);
}

and:

private Bitmap BitmapImage2Bitmap(BitmapImage bitmapImage)
{
    var outStream = new MemoryStream();  
    var enc = new BmpBitmapEncoder();
    enc.Frames.Add(BitmapFrame.Create(bitmapImage));
    enc.Save(outStream);
    return new System.Drawing.Bitmap(outStream);
}

You may well still have a firehose problem as I mentioned in the comment, this code certainly is faster than the original by avoiding the bitmap copy but still won't burn rubber.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top