次の方法で共有


C++ でのビデオ ウィンドウへの画像のミキシング

このトピックは Windows XP にのみ適用。

このセクションでは、アルファ ブレンディングした画像をビデオ コントロールのビデオ イメージ上に表示する方法について説明する。内部的には、ビデオ コントロールは Video Mixing Renderer フィルタ (VMR) を使う。

IPictureDisp オブジェクトのミキシング

C++ では、IPictureDisp オブジェクトまたはビットマップとして画像を表示できる。IPictureDisp オブジェクトは Automation クライアント用に設計されたもので、一般に C++ ではビットマップの方が簡単に扱える。ただし、ビデオ コントロールから画像をキャプチャすると、ビデオ コントロールは IPictureDisp オブジェクトを返す。したがって、最初の例ではキャプチャした画像をミキシング イメージとして使う方法を示す。実行結果では、バックグラウンドでビデオの再生を続けながら、ウィンドウの隅にビデオの "スナップショット" を表示する。

最初に、チューニング要求を送信し、ビデオ コントロールの IMSVidCtl::Run メソッドを呼び出す。詳細については、「ビデオ コントロールを使ったチューニング」を参照すること。

画像をキャプチャするには :

IMSVidCtl::get_VideoRendererActive メソッドを呼び出す。このメソッドはビデオ レンダラ デバイスの IMSVidVideoRenderer インターフェイスへのポインタを返す。

IMSVidVideoRenderer::Capture メソッドを呼び出す。このメソッドは IPictureDisp オブジェクトを返す。このオブジェクトに画像が含まれている。

次に、IMSVidVideoRenderer::SetupMixerBitmap メソッドを呼び出して、IPictureDisp オブジェクトを VMR のミキサ イメージとして使える。このメソッドは以下のパラメータをとる。

  • IPictureDisp ポインタ。
  • 0 ~ 100 の整数で表した目的の不透明性。
  • ビデオ ウィンドウ上での画像の位置。IMSVidRect インターフェイスとして指定する。

IMSVidRect インターフェイスは矩形用の Automation 互換ラッパーである。次の例では、IMSVidVideoRenderer::get_MixerBitmap を呼び出して矩形を取得し、その後に矩形のサイズをオーバーライドしている。さらに、画像をキャプチャし、それをビデオ ウィンドウ上にミキシングする。簡略化のため、エラー チェックは行っていない。

CComPtr<IMSVidCtl> m_pVideoControl;  // ビデオ コントロール
CComPtr<IMSVidVideoRenderer> pVideo; // ビデオ レンダラ デバイス
CComPtr<IPictureDisp> pPic;          // ピクチャ オブジェクト
CComPtr<IMSVidRect> pRect;           // Automation 互換の矩形
RECT rcWin;

/* フィルタ グラフを作成して実行する (省略) */

// 画像をキャプチャする。
hr = m_pVideoControl->get_VideoRendererActive(&pVideo);
hr = pVideo->Capture(&pPic);

// 矩形をウィンドウの 1/4 に設定する。
hr = pVideo->get_MixerBitmapPositionRect(&pRect);
::GetWindowRect(GetDlgItem(IDC_MSVIDCTL1), &rcWin);
hr = pRect->put_Width(rcWin.right / 2);
hr = pRect->put_Height(rcWin.bottom / 2);
hr = pRect->put_Top(0);
hr = pRect->put_Left(0);

// ミキサのビットマップを設定する。
long lOpacity = 80;  // 0 = 透明、100 = 不透明
hr = pVideo->SetupMixerBitmap(pPic, lOpacity, pRect);

デフォルトでは、矩形はビデオ コントロール ウィンドウの全体に表示される。矩形を指定しない場合は、IMSVidVideoRenderer::put_MixerBitmap および IMSVidVideoRenderer::put_MixerBitmapOpacity メソッドを使える。

hr = pVideo->put_MixerBitmap(pPic);
hr = pVideo->put_MixerBitmapOpacity(lOpacity);

ビットマップのミキシング

C++ では、DirectShow サーフェイスとして、または GDI オブジェクトのハンドルとして指定したビットマップをミキシングすることもできる。そのためには、IMSVidVideoRenderer::put__MixerBitmap メソッドを使う。このメソッドは VMR の IVMRMixerBitmap::SetAlphaBitmap メソッドへのパススルーとして機能する。別の方法として、IMSVidVideoRenderer::get__MixerBitmap メソッドを使って VMR の IVMRMixerBitmap インターフェイスを取得し、SetAlphaBitmap を直接呼び出すことができる。

詳細については、「アプリケーションが提供するビットマップを合成イメージ上に表示する」を参照すること。ここに示す例は、そのトピックにある例を修正したものである。

次の例では、ビットマップ リソースをロードし、それを 50% の不透明性でブレンディングして、ビデオ ウィンドウの左上隅に表示している。簡略化のため、エラー チェックは行っていない。

HRESULT ShowBitmap(IMSVidCtl *pVideoControl, WORD nID)
{ 
    CComPtr<IVMRMixerBitmap> pVmrBitmap;
    CComPtr<IMSVidVideoRenderer> pVideo;
    HRESULT hr = pVideoControl->get_VideoRendererActive(&pVideo);
    hr = pVideo->get__MixerBitmap(&pVmrBitmap);
    if (SUCCEEDED(hr))
    {
        RECT rc;
        HBITMAP hBitmap = LoadBitmap(hInst, MAKEINTRESOURCE(nID));
        ::GetWindowRect(GetDlgItem(IDC_MSVIDCTL1), &rc);
        hr = MixImage(hWnd, pVmrBitmap, hBitmap, rc.right, rc.bottom);
    }
}

HRESULT MixImage(HWND hwndApp, IVMRMixerBitmap* pBmp, HBITMAP hbm,
  long cx, long cy)
{
    HRESULT hr;
    BITMAP bm;
    HBITMAP hbmOld;
    HDC hdc = GetDC(hwndApp);
    HDC hdcBmp = CreateCompatibleDC(hdc);
    ReleaseDC(hwndApp, hdc);

    GetObject(hbm, sizeof(bm), &bm);
    hbmOld = (HBITMAP)SelectObject(hdcBmp, hbm);

        VMRALPHABITMAP bmpInfo;  // ビットマップに関する情報を保持する。
    ZeroMemory(&bmpInfo, sizeof(bmpInfo));
        bmpInfo.dwFlags = VMRBITMAP_HDC; // HDC を使用することを VMR に対して指定する。
    bmpInfo.hdc = hdcBmp;

        // 転送元矩形はビットマップ全体である。
    SetRect(&bmpInfo.rSrc, 0, 0, bm.bmWidth, bm.bmHeight);

        // 転送先矩形はビデオ イメージの左上隅であり、
        // イメージに対する割合で指定する。
    bmpInfo.rDest.left = 0.f;
    bmpInfo.rDest.top = 0.f;
    bmpInfo.rDest.right = static_cast<float>(bm.bmWidth) /
                          static_cast<float>(cx);
    bmpInfo.rDest.bottom = static_cast<float>(bm.bmHeight) /
                           static_cast<float>(cy);
        bmpInfo.fAlpha = 0.5f; // アルファを 50% に設定
    hr = pBmp->SetAlphaBitmap(&bmpInfo);
  
        // クリーン アップ。
    DeleteObject(SelectObject(hdcBmp, hbmOld));
    DeleteDC(hdcBmp);
    return hr;

}