Skip to main content.

Sunday, April 15, 2007

DirectShow基礎(その2)動画ファイル再生

DirectShowのプログラミングの基礎です。動画ファイル再生に関するテーマです。前回までのサンプルプログラムでは、コンソールアプリケーションでコンソールとは別にWindowが自動的に開いて、そこで動画ファイルが再生されました。今回は自前のWindowを作成してそこで動画を再生するというプログラムです。動作としては、起動して、ファイルメニュー → 動画ファイルの再生 で、単純にc:\Ruby.aviというファイルを再生します。ここにこの名前のファイルがなければ何も表示されませんので御注意下さい。

ベースとなるプログラム(スケルトン)は単純なWin32アプリケーションです。Visual C++ 2005 Express EditionでWindowsアプリケーションのプロジェクトを生成してそのプログラムにDirectShowのプログラムを追加しました。(※開発環境については、こちらを参照して下さい。)全体としては単純な関数ベースのプログラムです。

プログラムでは、以下のDirectShowのインターフェースを利用して動画のWindowに関するプログラミングを行っています。
IVideoWindow:Windowのオーナ、位置等のVideoWindowのプロパティの設定
IBasicVideo:Videoプロパティの設定、今回は動画ファイルの画面サイズを取得するために利用
IMediaEventEx:イベント通知を取得するメソッド等を提供、今回は動画再生の終了を取得するために利用
(※詳細は、参考サイト等を参照して下さい。)

プログラムの流れとしては以下のようになります。
メニューから動画ファイル再生を実行
 ↓
PlayFile()関数呼び出し
(動画サイズの取得、VideoWindow生成、メインWindowに割り当て、イベント通知の設定)
 ↓
再生開始
 ↓
再生終了待ち
 ↓
再生終了
 ↓
イベント発生、CleanUp()関数呼び出し
(後処理、メモリ解放)

以上のDirectShowのプログラムの部分は以下になります。全体を参照する場合は、お手数ですが、ファイルをダウンロードして御覧下さい。エラー処理(※戻り値の判定等)は行っていませんので御注意、御了承下さい。
//
// 動画の再生
//
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->QueryInterface(IID_IBasicVideo, (void **)&pBasicVideo);
    pGraph->QueryInterface(IID_IMediaEventEx, (void **)&pEvent);

    // グラフを構築
    pGraph->RenderFile(L"c:\\Ruby.avi", NULL);

    // 動画のサイズの取得
    long height=0;
    long width=0;

    pBasicVideo->get_VideoHeight(&height);
    pBasicVideo->get_VideoWidth(&width);

    // VideoWindowをメインWindowにアタッチして、子ウィンドウに設定
    pVidWin->put_Owner((OAHWND)g_hwnd);
    pVidWin->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS);

    // 親Windowの位置を取得
    RECT lpRect;
    GetWindowRect(g_hwnd,&lpRect);

    // 親Windowをビデオのサイズに設定(+8、+55は縦と横がうまく表示されるように適当に設定)
    SetWindowPos(g_hwnd,NULL,lpRect.left,lpRect.top,width+8,height+55,SWP_SHOWWINDOW);

    // VideWindowを動画のサイズに設定  
    pVidWin->SetWindowPosition(0, 0, width, height);

    // イベント通知を受け取るように所有者ウィンドウを設定
    pEvent->SetNotifyWindow((OAHWND)g_hwnd, WM_GRAPHNOTIFY, 0);

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

//
// 終了処理
//
void CleanUp(void)
{
    //グラフを停止する。
    pMediaControl->Stop();

    //リソースの解放
    pMediaControl->Release();
    pBasicVideo->Release();
    pVidWin->Release();
    pEvent->Release();
    pGraph->Release();
}

//
// イベントの処理
//
void HandleEvent()
{
    long evCode, param1, param2;
    HRESULT hr;

    //イベントをキューから取得する
    //ここでは、一応、while文でキューから全てのイベントを取得する
    while (hr = pEvent->GetEvent(&evCode, &param1, &param2, 0), SUCCEEDED(hr)){

        //イベントの引数に関連付けられたリソースを解放する
        hr = pEvent->FreeEventParams(evCode, param1, param2);
        
        //ストリーム終了または中断でCleanUp()の呼び出し
        if((evCode == EC_COMPLETE) || (evCode == EC_USERABORT)){
            CleanUp();
            break;
        }
    }
}



ソースファイル
プロジェクトファイル一式(Visual C++ 2005 Express Editionで作成)
参考リンク
DirectShow(※Microsoft DirectX 9.0のドキュメント)

Windowsプログラミング関連記事