3

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?

Patrick
  • 17,669
  • 6
  • 70
  • 85
GVillani82
  • 17,196
  • 30
  • 105
  • 172
  • What type is `writer` and does it have a `Flush()` method? – H H Jun 03 '13 at 15:08
  • the type of `writer` is `VideoFileWriter` from `aforge.net` library. I have not found any `Flush()` method. – GVillani82 Jun 03 '13 at 15:10
  • Have you run a profiler to see what is occupying the ram? I have not used any memory profilers, only execution profilers to see where my code is slow, so I don't have any recommendations of which one to try :( – Scott Chamberlain Jun 03 '13 at 15:20
  • Yes, @ScottChamberlain I've already try it. – GVillani82 Jun 03 '13 at 15:22
  • @Joseph82 can you edit your question to include some of the results from the profiler, Instead of treating the symptom (too much ram usage) maybe we can help fix the underlying problem that is causing it. – Scott Chamberlain Jun 03 '13 at 15:24
  • You know, _RAM increases linearly with time_ is not an error by itself. Do you get OOM exceptions? – H H Jun 03 '13 at 15:51
  • 1
    Not seeing any Dispose() calls on objects like bitmaps that are normally disposable is red flag number one. The other is the common issue with video, it is a firehose problem. Cameras can generate data a lot faster than you can write them to disk. The only ways to solve that is to set the camera to a lower resolution, get a faster disk like SSD and to use a good quality video encoder that is both good at compressing video, so there's less data to write, and can do so fast enough so it can keep up with the frame rate. They always cost money. – Hans Passant Jun 03 '13 at 16:11
  • I have not get any error. I know that the increse of RAM is not a problem itself, but the device I need to use has some performance constraints. @HansPassant I've edited my question: I use always `using`. – GVillani82 Jun 04 '13 at 07:38
  • You don't have to add tags to your title, there's a tag system for that. Please read http://meta.stackexchange.com/q/19190/147072 for more information. – Patrick Jun 04 '13 at 13:19

1 Answers1

4

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.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • I can argue that http://stackoverflow.com/a/6484754/1584654 is a bad answer. Also this maybe is bad http://www.deltasblog.co.uk/code-snippets/c-resizing-a-bitmap-image/ – GVillani82 Jun 04 '13 at 10:00
  • That's the usual problem with copying code from a website without understanding what it does. Don't copy my code either, read a book like Richter's "CLR via C#" instead. – Hans Passant Jun 04 '13 at 10:11
  • You are right! But I have to create a c# application without any experience, on time delivery (just few days). :( – GVillani82 Jun 04 '13 at 10:29
  • @Joseph82: If you believe the answer you mentioned (stackoverflow.com/a/6484754/1584654) to be a bad answer I would ask you to please help me improve it. After all you might not be the only one who will copy paste it and run into problems. Also I might be able to learn something and write better answers in the future. – Sascha Hennig May 12 '14 at 15:06