カクタスソフトウェア
カクタスソフトウェア
サウンド MIDI マルチメディア アプリケーション

グラフの構築

メディアファイルの再生などよく使われる事例には便利なコマンドが用意されています。ここではIGraphBuilder::RenderFile()関数とRender()関数によるグラフ構築を紹介します。

一般的なグラフ構築は、フィルターを挿入しピンを接続する工程を繰り返さなければなりません。しかしRenderFile()と後述のRender()は、入力情報を示すだけで最終出力までフィルター接続を試みる賢い関数です。

ファイルの属性(拡張子)が分かると再生までの手順はおおよそ決まります。RenderFile()関数は最もオーソドックスなグラフを自動的に構築します。以下にコード例を示します。

pGBはIGraphBuilderインターフェース、strFilePathはサウンドファイルへのフルパスです。

HRESULT CMyClass::RenderAudio(
    IGraphBuilder       *pGB,
    LPCWSTR             strFilePath)
{
    HRESULT result = S_OK;

    try
    {
        result = pGB->RenderFile(strFilePath, NULL);
        if (FAILED(result))     throw result;
    }
    catch (HRESULT result)
    {
        // TODO:
    }
    return result;
}

RenderFile()関数はメディアプレーヤ6.4との互換性を考え古いバージョンのソースフィルター(ASF Reader)が組み込まれます。新しいバージョンはシーク速度などが改善されているので、できるだけ新しいバージョンを使った方が有利です。そこで以下の拡張子を持つメディアファイルについては別の処理でグラフを構築します。

拡張子
.asf
.wma
.wmv

以下に「.asf、.wma、.wmv」に対応したコード例を示します。

HRESULT CMyClass::RenderWindowsMediaFile(
    IGraphBuilder       *pGB,
    LPCWSTR             strFilePath)
{
    HRESULT result = S_OK;
    IBaseFilter *pReader = NULL;
    IFileSourceFilter *pFS = NULL;

    try
    {
        result = CoCreateInstance(CLSID_WMAsfReader,
            NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pReader);
        if (FAILED(result))     throw result;

        result = pGB->AddFilter(pReader, L"ASF Reader");
        if (FAILED(result))     throw result;

        result = pReader->QueryInterface(IID_IFileSourceFilter, (void **)&pFS);
        if (FAILED(result))     throw result;

        result = pFS->Load(strFilePath, NULL);
        if (FAILED(result))     throw result;

        result = RenderOutputPins(pGB, pReader);
        if (FAILED(result))     throw result;
    }
    catch (HRESULT result)
    {
        // TODO:
    }
    SAFE_RELEASE(pReader);
    SAFE_RELEASE(pFS);
    return result;
}

以下に手順を示します。

ソースフィルターを作成する

CLSID_WMAsfReaderを用いてソースフィルター(新バージョンのASF Reader)を作成します。

    result = CoCreateInstance(CLSID_WMAsfReader,
        NULL, CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pReader);

フィルターをグラフに追加する

フィルタグラフに上記フィルターを追加します。AddFilter()関数の第2引数で追加するフィルターに名前を付けることができます。

    result = m_pGB->AddFilter(pReader, L"ASF Reader");

ソースフィルターのインターフェースを取得する

IFileSourceFilterインターフェースを使ってレンダリングしたいファイルへのパスを設定・参照します。

    result = pReader->QueryInterface(IID_IFileSourceFilter, (void **)&pFS);

ソースフィルターにファイルパスを設定する

ここで設定するファイルパスは一般的なURLをも受け付けます。ディスク上にあるファイルだけでなく、インターネット上にあるメディアファイルの再生も可能です。

    result = pFS->Load(strFilePath, NULL);

次にいよいよグラフを構築します。少し処理が煩雑なので独立した関数(RenderOutputPins)として実装しています。

HRESULT CMyClass::RenderOutputPins(
    IGraphBuilder       *pGB,
    IBaseFilter         *pFilter)
{
    IEnumPins* pEnumPin = NULL;
    HRESULT result = pFilter->EnumPins(&pEnumPin);

    if (SUCCEEDED(result))
    {
        IPin* pPin = NULL;
        DWORD dwFetched;

        while ((result = pEnumPin->Next(1L, &pPin, &dwFetched)) == S_OK)
        {
            IPin* pConnectedPin = NULL;
            result = pPin->ConnectedTo(&pConnectedPin);
            SAFE_RELEASE(pConnectedPin);

            if (result == VFW_E_NOT_CONNECTED)
            {
                PIN_DIRECTION pinDirection;
                result = pPin->QueryDirection(&pinDirection);

                if ((result == S_OK)&&(pinDirection == PINDIR_OUTPUT))
                {
                    result = pGB->Render(pPin);
                }
            }
            SAFE_RELEASE(pPin);
            if (FAILED(result))     break;
        }
    }
    SAFE_RELEASE(pEnumPin);
    return result;
}

Render()関数の実行にはソースフィルターの出力ピンを必要とします。以下の処理でソースフィルターの出力ピンを探し、見つかったらRender()関数を実行します。

  1. ピンを列挙する。
  2. 接続先のピンを取得する。
  3. 何もつながっていないピンを選ぶ。
  4. 出力ピンかどうか確認する。
  5. 出力ピンに対してRender()コマンドを実行する。

ピンを列挙する

フィルターからピンを列挙するIEnumPinsインターフェースを取得します。

    IEnumPins* pEnumPin = NULL;
    result = pReader->EnumPins(&pEnumPin);

IEnumPins::Next()関数を用いてピンを列挙します。ピンの利用が終わったら忘れずにリリースします。

    IPin* pPin = NULL;
    DWORD dwFetched;

    while ((result = pEnumPin->Next(1L, &pPin, &dwFetched)) == S_OK)
    {
        // ピンが列挙される
        pPin->Release();
    }

接続先のピンを取得する

列挙されたピンの中から、何もつながっていないピンを見つけます。そのためにIPin::ConnectedTo()関数で接続先のピンを取得してみます。成功すればピンがつながっていることが分かります。

    IPin* pConnectedPin = NULL;
    result = pPin->ConnectedTo(&pConnectedPin);

    if (pConnectedPin)
    {
        pConnectedPin->Release();
        pConnectedPin = NULL;
    }

接続先のピンは必要ないので取得できても即リリースします。ここはConnectedTo()関数にNULLポインターを渡したいところですが、残念ながらこの引数はNULLにできません。

何もつながっていないピンを選ぶ

ピンに何もつながっていない場合、resultにVFW_E_NOT_CONNECTEDが戻ります。

    if (result == VFW_E_NOT_CONNECTED)
    {
        // 何もつながっていないピンが見つかった
    }

出力ピンかどうか確認する

IPin::QueryDirection()関数でピンの入出力が分かります。出力ピンであれば見つかったピンを引数にIGraphBuilder::Render()関数を実行します。

    PIN_DIRECTION pinDirection;
    result = pPin->QueryDirection(&pinDirection);

    if ((result == S_OK)&&(pinDirection == PINDIR_OUTPUT))
    {
        result = pGB->Render(pPin);
    }

最後に列挙子をリリースします。

    pEnumPin->Release();

ドキュメントの先頭へ

カクタスソフトウェア 技術協力 資料室 資料室の広場 SourceForge.jp お問い合わせ