My code is essentially attempting to create a video feed by constantly updating a BitmapImage that is binded to the UI (WPF). This means a bitmap is being converted to BitmapImage multiple times per second. However this is causing constant garbage collection (multiple times per second) which seems like a bad sign?
The bitmaps are being disposed of correctly its just the BitmapImage part which is causing the problem. I've tried writing to the BitmapImage instead of creating a new one, But once frozen it becomes Readonly. And if I unfreeze it I get Error: "Must create DependencySource on same Thread as the DependencyObject".
Below is the method I'm using to create a bitmap Image
//CapturedBitmapmapImage bound to the UI
CapturedBitmapImage = BitMap2BitMapImage(bitmap);
//Method for converting Bitmap to BitmapImage
public static BitmapImage BitMap2BitMapImage(Bitmap bitmap)
{
MemoryStream ms = new MemoryStream();
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
BitmapImage image = new BitmapImage();
image.BeginInit();
ms.Seek(0, SeekOrigin.Begin);
image.StreamSource = ms;
image.EndInit();
image.Freeze();
return image;
}
CodePudding user response:
This method will save the image and decode it for each frame, probably allocating the entire image buffer multiple times. So it should be no surprise that it will cause a lot of memory allocation, and probably on the Large object heap to make things even worse.
To fix this I would recommend using a WritableBitmap instead. Assuming you have the same size/color space of both bitmaps and are running unsafe code:
var bitmapData = sourceBitmap.LockBits(
new Rectangle(0, 0, sourceBitmap.Width, sourceBitmap.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly,
sourceBitmap.PixelFormat);
var sourcePtr = bitmapData.Scan0;
myWriteableBitmap.Lock();
var destPtr = bitmap.BackBuffer;
var totalBytes = bitmapData.Stride * bitmapData.Height * myWriteableBitmap.Format.BitsPerPixel / 8;
Buffer.MemoryCopy((byte*)sourcePtr, (byte*)destPtr, totalBytes, totalBytes);
myWriteableBitmap.Unlock();
sourceBitmap.UnlockBits(bitmapData);
But you might be able to call the C memcopy function to avoid any actual pointers. Also note that you should add error handling whenever locking/unlocking data.
This should allow you to avoid allocations, except for creating the bitmap in the first place. Ideally you would want to avoid creating any new bitmaps at all, and reuse any buffers for image data. But it is difficult to tell how to do this since you do not show how the bitmap is created.
CodePudding user response:
Instead of creating a new BitmapImage for each frame, you should use a WriteableBitmap that is once assigned to the Source property of an Image element.
Provided that the WritableBitmap is created with the appropriate widthm height and pixel format, you would update it from a Bitmap
like this:
var bitmapData = bitmap.LockBits(
new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat);
writeableBitmap.WritePixels(new Int32Rect(0, 0, bitmap.Width, bitmap.Height),
bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride);
bitmap.UnlockBits(bitmapData);