4

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 ストリームを既存のバイト配列または既存の画像にデコードすることは可能ですか?

4

2 に答える 2

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 フレームをデコードする代わりに、データから (WinForms から) 新しいビットマップを作成します。次に、使用する WriteableBitmap のみにピクセルをコピーするだけです。

これが他の人にも役立つことを願っています。

于 2013-05-31T09:12:59.700 に答える
1

コードをプロファイリングすると、bdec.Frames[0];が確認されます。CPU 時間の比較的大きなチャンクを使用します。ILSpy のコードを見ると、' Frames ' ゲッターには空の実装 (JpgBitmapDecodersub-class によってオーバーライドされていない仮想メソッド) があるため、基になる Windows API に対して何らかの呼び出しが行われていると思います (?)

肝心なのは、JPG のデコードは、PNG や GIF よりも遅くなるということです。PNG エンコーディングを試してみると、圧縮率は高くなりますが、パフォーマンスは向上します。

于 2013-05-28T12:32:06.643 に答える