I am working on a recording application and I am able to get 10 - 15 screenshots per second. The issue is saving all of the images fast enough so that the queue of screenshots doesn't build up in RAM and drain the user's memory.
Currently I am able to do this by using two threads that save the images in order and then collect the garbage.
while (true)
{
bmp = null;
Dispatcher.Invoke(new Action(delegate()
{
if (images.Count > 0)
{
bmp = images[0];
images.RemoveAt(0);
}
}));
if (bmp != null)
{
bmp.Save("frames\\" + framesImagesIndex++ + ".png", ImageFormat.Png);
bmp.Dispose();
bmp = null;
GC.Collect();
}
Thread.Sleep(10);
}
The problem with this, is that it is very CPU intensive so I do not think it will work on less capable systems. This method takes 30 CPU on my 3.31 GHz process.
I can alleviate the CPU to around 17 when I set it to write all the images to one file and write just the bytes by locking the bits of the bitmap.
byte[] rgbValues;
IntPtr ptr;
System.Drawing.Rectangle rect;
System.Drawing.Imaging.BitmapData bmpData;
System.Drawing.Imaging.PixelFormat pxf;
pxf = System.Drawing.Imaging.PixelFormat.Format24bppRgb;
//using(FileStream fs = new FileStream("frames.data", FileMode.OpenOrCreate, FileAccess.Write))
while (true)
{
bmp = null;
Dispatcher.Invoke(new Action(delegate()
{
if (images.Count > 0)
{
bmp = images[0];
images.RemoveAt(0);
}
}));
rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);
bmpData = bmp.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, pxf);
ptr = bmpData.Scan0;
rgbValues = new byte[bmpData.Stride * bmp.Height];
Marshal.Copy(ptr, rgbValues, 0, rgbValues.Length);
fs.Write(rgbValues, 0, rgbValues.Length);
bmp.UnlockBits(bmpData);
bmp.Dispose();
bmp = null;
GC.Collect();
}
This method helps the CPU issue, but because its not fast enough. The queue of images builds up and overloads the ram so I don't know what else I can do to solve both issues.
Is there any other method available?