更新transformmedbitmap '源的内容不会更新渲染的图片
本文关键字:更新 transformmedbitmap | 更新日期: 2023-09-27 18:15:15
我需要从网络摄像头渲染实时视频馈送。每次新帧到达时,我都试图改变图像对象的源。我创建了WritableBitmap,每次都用新帧更新,transformmedbitmap在WritableBitmap上应用翻转变换作为其源。如果我为每一帧创建新的transformmedbitmap,它可以工作,并且我看到视频馈电,尽管内存占用增长非常快,导致GC非常频繁地收集内存。如果我试图重用单个transformmedbitmap,我看到渲染没有更新,第一帧总是显示。
如何重用相同的transformmedbitmap对象而不增加内存占用?
下面是使用两个不同文件模拟网络摄像头的示例代码。
public partial class Window1 : Window
{
Thread m_thread;
BitmapImage source1;
BitmapImage source2;
byte[] data;
int stride;
WriteableBitmap bitmap;
TransformedBitmap tb;
public Window1()
{
InitializeComponent();
FileStream stream = new FileStream("1.png", FileMode.Open, FileAccess.Read);
source1 = new BitmapImage();
source1.BeginInit();
source1.StreamSource = stream;
source1.EndInit();
FileStream stream2 = new FileStream("2.png", FileMode.Open, FileAccess.Read);
source2 = new BitmapImage();
source2.BeginInit();
source2.StreamSource = stream2;
source2.EndInit();
stride = source1.PixelWidth * (source1.Format.BitsPerPixel / 8);
data = new byte[stride * source1.PixelHeight];
bitmap = new WriteableBitmap(source1.PixelWidth, source1.PixelHeight, source1.DpiX, source1.DpiY, source1.Format, source1.Palette);
WritePixels(source1, bitmap, data);
tb = new TransformedBitmap(bitmap, new ScaleTransform(-1, 1));
m_thread = new Thread(ThreadFunc);
m_thread.Start();
}
public void ThreadFunc()
{
int i = 0;
while (true)
{
Dispatcher.Invoke(new Action(() => {
BitmapSource source = (i % 2 == 0) ? source2 : source1;
WritePixels(source, bitmap, data);
image1.Source = tb;
}));
++i;
Thread.Sleep(100);
}
}
public void WritePixels(BitmapSource source, WriteableBitmap target, byte[] data)
{
int stride = source.PixelWidth * (source.Format.BitsPerPixel / 8);
source.CopyPixels(data, stride, 0);
target.WritePixels(new Int32Rect(0, 0, source.PixelWidth, source.PixelHeight), data, stride, 0);
}
}
我明白了,问题是由于transformmedbitmap是相同的,所以可能图像对象没有识别变化,如果我使用两个不同的transformmedbitmap对象具有相同的来源,然后在编写新内容后我切换transformmedbitmap它工作,我有新的内容渲染。
所以代码是:public partial class MainWindow : Window
{
Thread m_thread;
BitmapImage source1;
BitmapImage source2;
byte[] data;
int stride;
WriteableBitmap bitmap1;
TransformedBitmap tb1;
TransformedBitmap tb2;
public MainWindow()
{
InitializeComponent();
FileStream stream = new FileStream("1.jpg", FileMode.Open, FileAccess.Read);
source1 = new BitmapImage();
source1.BeginInit();
source1.StreamSource = stream;
source1.EndInit();
FileStream stream2 = new FileStream("2.jpg", FileMode.Open, FileAccess.Read);
source2 = new BitmapImage();
source2.BeginInit();
source2.StreamSource = stream2;
source2.EndInit();
stride = source1.PixelWidth * (source1.Format.BitsPerPixel / 8);
data = new byte[stride * source1.PixelHeight];
bitmap1 = new WriteableBitmap(source1.PixelWidth, source1.PixelHeight, source1.DpiX, source1.DpiY, source1.Format, source1.Palette);
WritePixels(source1, bitmap1, data);
tb1 = new TransformedBitmap(bitmap1, new ScaleTransform(-1, -1));
tb2 = new TransformedBitmap(bitmap1, new ScaleTransform(-1, -1));
m_thread = new Thread(ThreadFunc);
m_thread.Start();
}
public void ThreadFunc()
{
int i = 0;
while (true)
{
Dispatcher.Invoke(new Action(() => {
BitmapSource source = (i % 2 == 0) ? source2 : source1;
WritePixels(source, bitmap1, data);
// this is the trick we have to set different TransformedBitmap as
// Image.Source
// so since we don't want to create new one each time we just
// switch between two
image1.Source = (i % 2 == 0) ? tb1 : tb2;
}));
++i;
Thread.Sleep(100);
}
}
public void WritePixels(BitmapSource source, WriteableBitmap target, byte[] data)
{
int stride = source.PixelWidth * (source.Format.BitsPerPixel / 8);
source.CopyPixels(data, stride, 0);
target.WritePixels(new Int32Rect(0, 0, source.PixelWidth, source.PixelHeight), data, stride, 0);
}
}