我的代碼本質上是嘗試通過不斷更新系結到 UI (WPF) 的 BitmapImage 來創建視頻源。這意味著每秒將多次將位圖轉換為 BitmapImage。然而,這會導致持續的垃圾收集(每秒多次),這似乎是一個壞兆頭?
位圖被正確處理,它只是導致問題的 BitmapImage 部分。我嘗試寫入 BitmapImage 而不是創建一個新的,但是一旦凍結它就變成了只讀的。如果我解凍它,我會得到錯誤:“必須在與 DependencyObject 相同的執行緒上創建 DependencySource”。
下面是我用來創建位圖影像的方法
//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;
}
uj5u.com熱心網友回復:
您應該使用曾經分配給 Image 元素的 Source 屬性的 WriteableBitmap,而不是為每個幀創建一個新的 BitmapImage。
int frameWidth = ...
int frameHeight = ...
var pixelFormat = PixelFormats.Bgr24; // must match Bitmap.PixelFormat
var writeableBitmap = new WriteableBitmap(
frameWidth, frameHeight, 96, 96, pixelFormat, null);
image.Source = writeableBitmap;
然后,您將像這樣從 Bitmap 回圈更新 WriteableBitmap(以及 Image 元素):
Bitmap bitmap = ... // a frame
var bitmapData = bitmap.LockBits(
new System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height),
System.Drawing.Imaging.ImageLockMode.ReadOnly, bitmap.PixelFormat);
image.Dispatcher.Invoke(() => writeableBitmap.WritePixels(
new Int32Rect(0, 0, bitmap.Width, bitmap.Height),
bitmapData.Scan0, bitmapData.Stride * bitmapData.Height, bitmapData.Stride));
bitmap.UnlockBits(bitmapData);
uj5u.com熱心網友回復:
此方法將保存影像并為每一幀解碼,可能會多次分配整個影像緩沖區。所以也就不足為奇了,它會造成大量的記憶體分配,并且可能在大物件堆上讓事情變得更糟。
要解決此問題,我建議改用WritableBitmap。假設您有兩個位圖的相同大小/顏色空間并且正在運行不安全的代碼:
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);
但是您也許可以呼叫 C memcopy 函式來避免任何實際的指標。另請注意,您應該在鎖定/解鎖資料時添加錯誤處理。
這應該允許您避免分配,除了首先創建位圖。理想情況下,您希望完全避免創建任何新位圖,并為影像資料重用任何緩沖區。但是很難說出如何執行此操作,因為您沒有顯示位圖是如何創建的。
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/496844.html
