5

Web カム ビューを提供されたウィンドウに正常にプレビューする DirectShow C++ アプリを開発しました。今、このライブ Web カメラ プレビューから画像をキャプチャしたいと考えています。そのために、グラフマネージャー、ICaptureGraphBuilder2、IMoniker などを使用しました。次のオプションを検索して見つけました: WIA & Sample Grabber。多くの人が SampleGrabber の使用を推奨していますが、MS の msdn ドキュメントによると、 SampleGrabberは非推奨であり、使用すべきではありません。また、WIA API を使用したくありません。

では、ライブ Web カメラのプレビューから画像をキャプチャするための DirectShow の最良の方法はどれでしょうか?

4

3 に答える 3

4

以下は、DirectShow.NET ライブラリの DxSnap サンプルからの引用です。

DirectShow を使用して、キャプチャ デバイスの Still ピンからスナップショットを取得します。MS はこれに WIA を使用することを推奨していますが、DirectShow と C# を使用する場合は、次のようにします。

このサンプルは、圧縮されていないビデオを RBG24 として出力するデバイスでのみ機能することに注意してください。これには、ほとんどの Web カメラが含まれますが、おそらくテレビ チューナーは含まれません。

これは C# コードですが、インターフェイスはすべて同じであるため、理解できるはずです。Sample Grabber Filterまた、C++ での使用方法に関する他のサンプルもあります。

Sample Grabber は廃止され、いくつかの最新の SDK からヘッダーが削除されていますが、ランタイム コンポーネントはすべて存在し、長期間存在する予定です。そうしないと、多数のアプリケーションが壊れる可能性があります (例: ホストされているブラウザーでのビデオ チャット) GMail は Sample Grabber を使用しています)。したがって、基本的に Sample Grabber は、Web カメラからスナップショットをキャプチャする簡単な方法です。または、代わりに最新の MS API に従うことを希望する場合は、Media Foundation ( 2016 年 7 月 9 日更新: 新しい Windows Server のインストールでは必要になる場合があります) を調べてください。 「メディア ファンデーション」および/または「デスクトップ エクスペリエンス」機能を追加して、メディア ファンデーション API を DirectShow および DirectShow Editing Services と共に利用できるようにするため、Sample Grabber はその一部です。デフォルトのインストールでは qedit は提供されません。

また、C++ では、Sample Grabber Filter を使用する必要はありません。DirectShow BaseClasses を使用してカスタム フィルターを開発し、カスタム変換フィルターまたはカスタム レンダラーにすることができます。これらは、着信ビデオ フィードを受け入れ、DirectShow パイプラインからフレームをエクスポートします。もう 1 つのオプションは、古い SDK の 1 つから Sample Grabber サンプル ソース コードを使用することです (これは OS Sample Grabber の正確なソースではありませんが、同じことを行っています)。ただし、Windows に同梱されている Sample Grabber は依然として適切なオプションです。

于 2012-07-09T18:20:03.947 に答える
1

MicrosoftのWebサイトにリストされているのは、IVMRWindowlessControl9::GetCurrentImageを使用してフレームをキャプチャする方法の例です...これを行う1つの方法は次のとおりです。

IBaseFilter*            vmr9ptr; // I'm assuming that you got this pointer already
IVMRWindowlessControl9* controlPtr = NULL;

vmr9ptr->QueryInterface(IID_IVMRWindowlessControl9, (void**)controlPtr);
assert ( controlPtr != NULL );

// Get the current frame
BYTE*   lpDib = NULL;
hr = controlPtr->GetCurrentImage(&lpDib);

// If everything is okay, we can create a BMP
if (SUCCEEDED(hr))
{
    BITMAPINFOHEADER*   pBMIH = (BITMAPINFOHEADER*) lpDib;
    DWORD               bufSize = pBMIH->biSizeImage;

    // Let's create a bmp
    BITMAPFILEHEADER    bmpHdr;
    BITMAPINFOHEADER    bmpInfo;
    size_t              hdrSize     = sizeof(bmpHdr);
    size_t              infSize     = sizeof(bmpInfo);

    memset(&bmpHdr, 0, hdrSize);
    bmpHdr.bfType                   = ('M' << 8) | 'B';
    bmpHdr.bfOffBits                = static_cast<DWORD>(hdrSize + infSize);
    bmpHdr.bfSize                   = bmpHdr.bfOffBits + bufSize;

    // Builder the bit map info.
    memset(&bmpInfo, 0, infSize);
    bmpInfo.biSize                  = static_cast<DWORD>(infSize);
    bmpInfo.biWidth                 = pBMIH->biWidth;
    bmpInfo.biHeight                = pBMIH->biHeight;
    bmpInfo.biPlanes                = pBMIH->biPlanes;
    bmpInfo.biBitCount              = pBMIH->biBitCount;

    // boost::shared_arrays are awesome!
    boost::shared_array<BYTE> buf(new BYTE[bmpHdr.bfSize]);//(lpDib);
    memcpy(buf.get(),                       &bmpHdr,    hdrSize); // copy the header
    memcpy(buf.get() + hdrSize,             &bmpInfo,   infSize); // now copy the info block
    memcpy(buf.get() + bmpHdr.bfOffBits,    lpDib,      bufSize);

    // Do something with your image data ... seriously...
    CoTaskMemFree(lpDib);

} // All done!
于 2012-07-31T01:42:35.433 に答える
1

ええと... たくさんの偽情報。DirectShow グラフでプレビューしている場合は、何からプレビューしているかによって異なります。キャプチャ フィルタには、1、2、または 3 つのピンがあります。ピンが 1 つある場合は、「キャプチャ」ピンである可能性が高くなります (プレビュー ピンはありません)。このため、キャプチャとプレビューを同時に行いたい場合は、「スマート ティー」フィルターを挿入し、プレビュー ピンから VMR を接続し、キャプチャ ピンから「フレームを取得するもの」を接続します。DirectShow の安っぽいピンの開始/停止機能をいじりたくないからです (代わりに、単にグラフ全体の開始/停止状態を制御するだけです)。SampleGrabber を使用する必要はありません。これは非常に単純なフィルターであり、数時間で作成できます (私がそれを作成したことを知っておく必要があります)。それ' これは単純に CTransInPlace フィルターであり、強制的なメディア タイプを設定して受け入れることができ、サンプルを受信したときにコールバックするようにコールバック インターフェイスを設定できます。実際には、サンプルを受信したときにコールバックする NullRenderer を作成する方が簡単です。これは非常に簡単に作成できます。

キャプチャ フィルタに 2 つのピンがある場合は、ほとんどの場合、キャプチャ ピンと静止ピンです。この場合でも、ソースのキャプチャ ピンに接続されたスマート ティーが必要であり、スマート ティーのプレビュー ピンからプレビューし、スマート ティーのキャプチャ ピンからサンプルをキャプチャする必要があります。

(SmartTee が何かわからない場合、これはアロケーターのトリックを実行し、キャプチャ ピンが非常に行き詰っていない場合にのみサンプルをプレビュー ピンに送信するフィルターです。その仕事は、VMR にパスを提供することです。キャプチャ フィルタとキャプチャ フィルタの下流のフィルタの間のアロケータを台無しにしないレンダー)

キャプチャ フィルターにキャプチャ ピンとプレビュー ピンの両方がある場合は、そのときに何をする必要があるかを理解できると思います。

とにかく、要約: SampleGrabber は単なる CTransInPlaceFilter です。これを Null Renderer として記述することもできます。CheckInputType にいくつかのジャンクを入力し、DoRenderSample でコールバックを呼び出すようにしてください。

于 2014-02-13T07:02:57.340 に答える