我有一个与NAudio播放音频的应用程序。 NAudio的一个已知限制是,每次垃圾收集器运行时,每个线程都会暂停,直到完成为止。
应用程序运行正常,所有GC都在可接受的时间内完成,没有口吃。
但是我们还有一个单独的应用程序,它每秒通过TCP向主应用程序(带有音频播放器)发送缩略图。当编码为JPEG时,缩略图大约为1300字节。
这是我们目前用于解码图像的代码:
MemoryStream ms = new MemoryStream(data);
BitmapDecoder bdec = BitmapDecoder.Create(ms, BitmapCreateOptions.None, BitmapCacheOption.Default);
BitmapSource source = bdec.Frames[0];
imgPreview.Source = source;
并编码:
JpegBitmapEncoder jpgEncoder = new JpegBitmapEncoder();
jpgEncoder.QualityLevel = quality;
jpgEncoder.Frames.Add(BitmapFrame.Create(renderTarget));
byte[] imageArray;
using (MemoryStream outputStream = new MemoryStream())
{
jpgEncoder.Save(outputStream);
imageArray = outputStream.ToArray();
}
其中RenderTarget是具有图像内容的RenderTargetBitmap。
现在我们每秒都在创建并丢弃一个MemoryStream,一个BitmapDecoder和一个BitmapSource。我已经注释掉了代码中的行,看起来像MemoryStream和BitmapDecoder构造函数没有创建任何断言,但是一旦通过Frames [0]访问它,就会开始断断续续。
我们也尝试过这种方法而不是BitmapDecoder,但结果相同:
img.BeginInit();
img.StreamSource = ms;
img.EndInit();
当然有更好的方法可以持续更新图像吗?
最好的方法是只发送原始图像数据,然后创建一个WriteableBitmap,这些只是每秒重写一次。但是原始图像是170 kb,比编码图像多100多倍,我们真的不想这样做。是否可以将JPEG流解码为现有的字节数组或现有的图像?
答案 0 :(得分:4)
好的,所以我找到了解决问题的方法。
我没有使用WPF BitmapDecoder来解码图像,而是使用Windows窗体位图。它是一次性的,对垃圾收集器来说更好。
所以解决方案如下:
var stream = new MemoryStream(data);
var formsBitmap = new Bitmap(stream);
var width = formsBitmap.Width;
var height = formsBitmap.Height;
if (bitmap == null || height != bitmap.PixelHeight || width != bitmap.PixelWidth)
{
bitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Pbgra32, null);
imgPreview.Source = bitmap;
}
BitmapData data = formsBitmap.LockBits(new Rectangle(0, 0, formsBitmap.Width, formsBitmap.Height),
ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);
try
{
bitmap.WritePixels(new Int32Rect(0, 0, width, height), data.Scan0, data.Stride * data.Height, data.Stride);
}
finally
{
formsBitmap.UnlockBits(data);
}
formsBitmap.Dispose();
不是解码我收到的每个JPEG帧,而是从数据中创建一个新的Bitmap(来自WinForms)。然后我只是将像素复制到我使用的WriteableBitmap。
希望这对其他人也有帮助。
答案 1 :(得分:1)
分析代码确认 bdec.Frames [0]; 需要相当大的CPU时间。看一下ILSpy中的代码,' Frames 'getter有一个空的实现(虚方法没有被JpgBitmapDecodersub类覆盖),所以我假设对底层的Windows API进行了某种调用在那里(?)
底线是解码JPG会比PNG或GIF慢;我会尝试PNG编码,因为它仍然应该提供良好的压缩比,但具有更好的性能。