0

Windows Imaging Componentライブラリを使用して、多数の画像をエンコードしています。理想的には、特定のプロパティを使用してエンコーダーを一度セットアップしてから、そのエンコーダーをすべての画像に再利用したいと思います。しかし、私が見たすべての例では、エンコーダーは単一の画像用に作成されているようです。

ファイルではなくバイトストリームとの間で読み取りと書き込みを行っているため、複数のスレッドが同時に実行されている可能性があります。

コードのスニペットは次のとおりです。

CComPtr<IWICBitmapEncoder> pEncoder;
CComPtr<IWICBitmapFrameEncode> pBitmapFrame;
CComPtr<IPropertyBag2> pPropertyBag;
CComPtr<IWICStream> pStream;
CComPtr<IStream> pOutputStream;

HRESULT hr;
//  Setup memory stream, which is needed to stage raw image bits
if (CreateStreamOnHGlobal(NULL, TRUE, &pOutputStream) != S_OK)
{
    LogAssert(false, "Could not create pOutputStream. Err (%d)", GetLastError());
}
//Setup WIC stream which encapsulates the output stream
hr = m_pFactory->CreateStream(&pStream);

hr = pStream->InitializeFromIStream(pOutputStream);
hr = m_pFactory->CreateEncoder(GUID_ContainerFormatWmp, NULL, &pEncoder);
hr = pEncoder->Initialize(pStream, WICBitmapEncoderNoCache);
hr = pEncoder->CreateNewFrame(&pBitmapFrame, &pPropertyBag);
SetEncodingProperties(pPropertyBag);
hr = pBitmapFrame->Initialize(pPropertyBag);

問題1:CreateStreamOnHGlobalを使用して作成されたIStreamに書き込みを行っています。複数の画像pStreamに再利用できますか?pOutputStreamスレッドセーフの問題はありますか?

問題2:このスニペットのどの部分を一度実行できますか?また、異なる画像に対してどの部分を繰り返す必要がありますか?すべての初期化は互いに結びついているようです。

4

1 に答える 1

2

ここで説明されているように、すべての組み込みWICオブジェクトはWindows 7でスレッドセーフになるように更新されました:http://msdn.microsoft.com/en-us/library/ee720061%28v=vs.85%29.aspx#_multi_threaded_apartment_support

以前のWindowsバージョンでは、オブジェクトはスレッドセーフではなく、Windowsは呼び出しを自動的に別のスレッドにマーシャリングして、複数のスレッドからアクセスできるようにします。これは、COMを適切に初期化した場合にのみ機能します。複数のスレッドからオブジェクトにアクセスする場合は、オブジェクトにアクセスできるすべてのスレッドからマルチスレッドオプションを指定してCoInitializeExを呼び出す必要があり、CoInitializeExが成功を返すことを確認する必要があります( S_OKまたはS_FALSE)。

一度に1つのIStreamオブジェクトに対して2つの異なるエンコーダーを使用することは安全ではありません。エンコーダーオブジェクトでCommitを呼び出したら、他の場所でストリームを使用しても安全ですが、別のエンコーダーで使用することは実際には意味がありません。1つのファイルに複数の画像を含めることはできません(画像形式が複数のフレームをサポートしている場合を除きますが、必要なのは1つのエンコーダオブジェクトのみです)。別のエンコーダーで使用する前にストリームサイズを0に設定できると思いますが、HGLOBALストリームの割り当てはおそらくそれよりも速くはありません。

すでにIStreamを持っているので、あなたのケースでIWICStreamを作成することは意味がありません、そしてこれはすべてエンコーダーが必要とするものです。IWICStreamは主に、ファイル、固定サイズのメモリバッファ、または既存のストリームのセクションからストリームを作成するための便利な関数として存在します。InitializeFromIStreamメソッドが存在する理由は、IWICStreamがCloneメソッドをサポートしていないためです。InitializeFromIStreamは、クローンがサポートされていない場合に独立したカーソルで新しいIStreamオブジェクトを取得できるようにする回避策ですが、これを行う方法はスレッドセーフではありません(また、そうすることはできません)。(これが機能するには、基になるストリームに一度に1つのスレッドのみがアクセスする必要があります。通常、ストリームが一度に1つのエンコーダー/デコーダーにのみ割り当てられている限り、エンコーダーまたはデコーダーオブジェクトがこれを確認します。 )。

パフォーマンスが心配なので、HGLOBALを拡大するには既存のすべてのデータを新しい場所にコピーする必要があるため、WICエンコーダーが行う可能性が高いように、HGLOBALストリームへの書き込みはO(n ** 2)であることを知っておく必要があります。 。

Windows 7より前の複数のスレッドからWICにアクセスする場合は、シングルスレッドのアパートメントを使用し、1つのスレッドで初期化するオブジェクトがそのスレッドからのみアクセスされるようにすることをお勧めします。これにより、別のスレッドへの呼び出しをマーシャリングするコストを節約できます。

エンコーダークラスが同じであり、複数のシングルスレッドアパートメント(またはシングルスレッドおよびマルチスレッドのアパート)。

ただし、画像データの書き込みプロセスにもっと関心を払う必要がある場合は、パフォーマンスにほとんど影響を与えないことに関心がありすぎると思います。常にメモリをコピーする必要がないストリームタイプを使用すると(おそらく、バックグラウンドで固定サイズのメモリバッファを使用しますが、適切な場合は小さいサイズを報告できます)、画像ファイルが大きくなる場合に役立ちます(ただし、非常に大きな画像を使用している場合は、代わりにimagemagickの使用を検討する必要があります)。各スレッドに完全に独立したオブジェクトを与えることも役立つ場合があります(単一のオブジェクトは、一度に1つのスレッドでしか作業できない可能性が高いため)。

于 2012-09-23T18:47:13.287 に答える