Microsoft DirectX 8.0

ビデオ ウィンドウの設定

このトピックでは、特定のウィンドウにビデオ再生をアタッチする方法を解説する。サンプル プログラムを示し、サンプルを理解するために必要な考え方を説明する。このサンプル プログラムは、「ファイルの再生法」で示したサンプルを基にしている。

このトピックは以下のセクションで構成される。

ビデオ ウィンドウ

ビデオ ファイルをレンダリングするとき、フィルタ グラフにはビデオ レンダリング フィルタが含まれる。ビデオ レンダラは、圧縮されていないビデオ データを受け取り、ウィンドウ内の画面にそれをレンダリングする。指定しなければ、ビデオ再生ウィンドウは、自身の境界とタイトル バーを持つトップレベルのウィンドウになる。しかし、アプリケーションで作成した特定のウィンドウにビデオを表示することの方が多い。解決策は、レンダラのビデオ ウィンドウをアプリケーション ウィンドウの子ウィンドウにすることである。これを行うには、ビデオ ウィンドウのプロパティを設定して、ウィンドウの所有者、スタイル、および位置を指定する。

ビデオ レンダリング フィルタがサポートする IVideoWindow インターフェイスに、ビデオ ウィンドウのプロパティを設定および取得するためのメソッドが含まれている。しかし、フィルタ グラフ マネージャを使ってフィルタ グラフを構築した場合は、ビデオ レンダリング フィルタへのポインタを持っているとは限らない。そのため、フィルタ グラフ マネージャも IVideoWindow をサポートしている。フィルタ グラフ マネージャは、グラフ内で IVideoWindow を公開しているフィルタのリストを保持し、フィルタ グラフ マネージャの IVideoWindow メソッドが呼び出されると、これらのフィルタへの呼び出しを割り当てる。このようにして、アプリケーションが適切なフィルタを見つけなくても、フィルタ グラフ マネージャがそれぞれのフィルタの処理をサポートできる。

フィルタ グラフ マネージャは、これと同じ手法で IBasicVideo2 および IBasicAudio インターフェイスを公開している。これらのインターフェイスには、オーディオおよびビデオのプロパティを設定するためのメソッドが含まれる。それぞれのフィルタに対してこれらのインターフェイスを呼び出すのではなく、フィルタ グラフ マネージャに対して呼び出す。

IVideoWindow インターフェイスの使用

このセクションでは、IVideoWindow インターフェイスを使って所有者やスタイルなど、ビデオ ウィンドウのプロパティを設定する方法を説明する。

注 :  このトピックのサンプル プログラムでは、コードの大部分は標準のウィンドウ処理を行うものなので、ここでは説明しない。特に、WindowProc および WinMain 関数には、Microsoft® Windows® アプリケーションの典型的なフレームワークが含まれている。アプリケーションで定義する関数、PlayFile および CleanUp については説明する。

まず、フィルタ グラフ マネージャのインスタンスを生成し、IGraphBuilder::RenderFile メソッドを呼び出してフィルタ グラフを構築する。この処理の詳細については、「ファイルの再生法」を参照すること。

次に、再生を始める前に、以下のようにビデオ ウィンドウのプロパティを設定する。

  1. ビデオ再生ウィンドウを親ウィンドウにアタッチする。これを行うには、IVideoWindow::put_Owner メソッドを呼び出して、所有者ウィンドウへのハンドルを渡す。このメソッドは OAHWND 型の変数を受け取るため、必要な場合はハンドルをこの型にキャストする。
    IVideoWindow    *pVidWin = NULL;
    pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin);
    pVidWin->put_Owner((OAHWND)g_hwnd);
    
  2. ビデオ ウィンドウのスタイルを子ウィンドウに変更する。これを行うには、IVideoWindow::put_WindowStyle メソッドを呼び出して、スタイル フラグの組み合わせを渡す。WS_CHILD フラグは、ウィンドウが子ウィンドウであることを指定する。WS_CLIPSIBLINGS フラグは、ウィンドウがほかの子ウィンドウの内部に描かれないようにする。
    pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);
    
  3. ビデオ ウィンドウの位置を設定する。これには、IVideoWindow::SetWindowPosition メソッドを呼び出す。このメソッドは、ウィンドウの左端 (x-軸)、上端 (y-軸)、幅、高さを指定するデバイス座標を受け取る。サンプル プログラムでは、親ウィンドウの全体が入るようにビデオ ウィンドウを拡大している。
    RECT grc;
    GetClientRect(g_hwnd, &grc);
    pVidWin->SetWindowPosition(0, 0, grc.right, grc.bottom);
    

    GetClientRect 関数は、RECT 構造体をウィンドウのクライアント領域の座標で満たす。この座標は、クライアント領域の左上隅からのものであるため、left および top メンバは 0 で、right および bottom メンバがそれぞれ幅と高さを定義する。

アプリケーションが終了する前に、ビデオ ウィンドウの表示を False に設定することが重要である。そうしないと、ビデオ イメージが画面に残り、ユーザーはそれを除去することができない。次に、所有者を NULL にリセットする。そうしないと、間違ったウィンドウにメッセージが送信され、エラーが発生する可能性がある。

HRESULT hr = pVidWin->put_Visible(OAFALSE);
hr = pVidWin->put_Owner(NULL);   

サンプル コード

以下のサンプル プログラムは、Test.avi という名前のファイルをアプリケーション ウィンドウの内部にレンダリングする。簡単であるため、以下の機能は省略している。

#include <windows.h>
#include <dshow.h>

#define CLASSNAME "VideoWindow"

IGraphBuilder   *pGraph = NULL;
IMediaControl   *pMediaControl = NULL;
IVideoWindow    *pVidWin = NULL;
HWND            g_hwnd;

void PlayFile(void)
{
    // フィルタ グラフ マネージャを生成する。
    CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC, 
        IID_IGraphBuilder, (void **)&pGraph);
    pGraph->QueryInterface(IID_IMediaControl, (void **)&pMediaControl);
    pGraph->QueryInterface(IID_IVideoWindow, (void **)&pVidWin);

    // グラフを構築する。
    pGraph->RenderFile(L"Test.avi", NULL);

    // ビデオ ウィンドウを設定する。
    pVidWin->put_Owner((OAHWND)g_hwnd);
    pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);

    RECT grc;
    GetClientRect(g_hwnd, &grc);
    pVidWin->SetWindowPosition(0, 0, grc.right, grc.bottom);

// グラフを実行する。
    pMediaControl->Run();
}

void CleanUp(void)
{
    pVidWin->put_Visible(OAFALSE);
    pVidWin->put_Owner(NULL);   
    pMediaControl->Release();
    pVidWin->Release();
    pGraph->Release();
}

// メッセージ ハンドラ
long FAR PASCAL WindowProc( HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
    switch (msg)
    {
        case WM_DESTROY:
            CleanUp();
            PostQuitMessage(0);
            break;
        default:
            return (DefWindowProc(hwnd, msg, wParam, lParam));
    }
    return(NULL);
}

// メイン
int PASCAL WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR  lpCmdLine, 
    int nCmdShow )
{
    MSG         msg;
    WNDCLASS    wc;

    CoInitialize(NULL);

    ZeroMemory(&wc, sizeof wc);
    wc.lpfnWndProc  = WindowProc;
    wc.hInstance    = hInst;
    wc.hIcon        = LoadIcon( NULL, IDI_APPLICATION );
    wc.hCursor      = LoadCursor( NULL, IDC_ARROW );
    wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
    wc.lpszMenuName = NULL;
    wc.lpszClassName = CLASSNAME;
    RegisterClass( &wc );

    g_hwnd = CreateWindow(
        CLASSNAME,
        "DirectShow Sample",
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
NULL,
NULL,
        hInst,
        NULL);

    ShowWindow( g_hwnd, nCmdShow );
    UpdateWindow( g_hwnd );
    PlayFile();

    while( GetMessage( &msg, NULL, 0, 0 ) )
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }

    CoUninitialize();
    return msg.wParam;
}