次の方法で共有


手順 3: フィルター グラフを作成する

[このページに関連付けられている機能 DirectShow は、従来の機能です。 MediaPlayer、IMFMediaEngine、Media Foundation のオーディオ/ビデオ キャプチャに置き換わりました。 これらの機能は、Windows 10とWindows 11用に最適化されています。 新しいコードでは、可能であれば、DirectShow ではなく Media Foundation で MediaPlayerIMFMediaEngineAudio/Video Capture を使用することを強くお勧めします。 Microsoft は、レガシ API を使用する既存のコードを、可能であれば新しい API を使用するように書き換えるよう提案しています。]

このトピックは、 DirectShow でのオーディオ/ビデオ再生に関するチュートリアルの手順 3 です。 完全なコードについては、「 DirectShow 再生の例」を参照してください。

次の手順では、メディア ファイルを再生するフィルター グラフを作成します。

メディア ファイルを開く

メソッドは DShowPlayer::OpenFile 、再生用のメディア ファイルを開きます。 このメソッドは、次の処理を行います。

  1. 新しい (空の) フィルター グラフを作成します。
  2. IGraphBuilder::AddSourceFilter を呼び出して、指定したファイルのソース フィルターを追加します。
  3. ソース フィルターにストリームをレンダリングします。
HRESULT DShowPlayer::OpenFile(PCWSTR pszFileName)
{
    IBaseFilter *pSource = NULL;

    // Create a new filter graph. (This also closes the old one, if any.)
    HRESULT hr = InitializeGraph();
    if (FAILED(hr))
    {
        goto done;
    }
    
    // Add the source filter to the graph.
    hr = m_pGraph->AddSourceFilter(pszFileName, NULL, &pSource);
    if (FAILED(hr))
    {
        goto done;
    }

    // Try to render the streams.
    hr = RenderStreams(pSource);

done:
    if (FAILED(hr))
    {
        TearDownGraph();
    }
    SafeRelease(&pSource);
    return hr;
}

フィルター グラフ マネージャーの作成

メソッドは DShowPlayer::InitializeGraph 、新しいフィルター グラフを作成します。 このメソッドは、次の処理を行います。

  1. CoCreateInstance を呼び出して、フィルター グラフ マネージャーの新しいインスタンスを作成します。
  2. フィルター グラフ マネージャーで IMediaControl インターフェイスと IMediaEventEx インターフェイスに 対してクエリを実行します。
  3. IMediaEventEx::SetNotifyWindow を呼び出してイベント通知を設定します。 詳細については、「 DirectShow でのイベント通知」を参照してください。
HRESULT DShowPlayer::InitializeGraph()
{
    TearDownGraph();

    // Create the Filter Graph Manager.
    HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, 
        CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_pGraph));
    if (FAILED(hr))
    {
        goto done;
    }

    hr = m_pGraph->QueryInterface(IID_PPV_ARGS(&m_pControl));
    if (FAILED(hr))
    {
        goto done;
    }

    hr = m_pGraph->QueryInterface(IID_PPV_ARGS(&m_pEvent));
    if (FAILED(hr))
    {
        goto done;
    }

    // Set up event notification.
    hr = m_pEvent->SetNotifyWindow((OAHWND)m_hwnd, WM_GRAPH_EVENT, NULL);
    if (FAILED(hr))
    {
        goto done;
    }

    m_state = STATE_STOPPED;

done:
    return hr;
}

ストリームのレンダリング

次の手順では、ソース フィルターを 1 つ以上のレンダラー フィルターに接続します。

メソッドは DShowPlayer::RenderStreams 、次の手順を実行します。

  1. IFilterGraph2 インターフェイスのフィルター グラフ マネージャーに対してクエリを実行します。
  2. ビデオ レンダラー フィルターをフィルター グラフに追加します。
  3. オーディオ再生をサポートするために、 DirectSound レンダラー フィルター をフィルター グラフに追加します。 フィルター グラフへのフィルターの追加の詳細については、「 CLSID によるフィルターの追加」を参照してください。
  4. ソース フィルターの出力ピンを列挙します。 ピンの列挙の詳細については、「ピンの 列挙」を参照してください。
  5. ピンごとに、 IFilterGraph2::RenderEx メソッドを呼び出します。 このメソッドは、出力ピンをレンダラー フィルターに接続し、必要に応じて中間フィルター (デコーダーなど) を追加します。
  6. を呼び出 CVideoRenderer::FinalizeGraph して、ビデオ レンダラーの初期化を完了します。
  7. そのフィルターが別のフィルターに接続されていない場合は、 DirectSound レンダラー フィルターを削除します。 これは、ソース ファイルにオーディオ ストリームが含まれていない場合に発生する可能性があります。
// Render the streams from a source filter. 

HRESULT DShowPlayer::RenderStreams(IBaseFilter *pSource)
{
    BOOL bRenderedAnyPin = FALSE;

    IFilterGraph2 *pGraph2 = NULL;
    IEnumPins *pEnum = NULL;
    IBaseFilter *pAudioRenderer = NULL;
    HRESULT hr = m_pGraph->QueryInterface(IID_PPV_ARGS(&pGraph2));
    if (FAILED(hr))
    {
        goto done;
    }

    // Add the video renderer to the graph
    hr = CreateVideoRenderer();
    if (FAILED(hr))
    {
        goto done;
    }

    // Add the DSound Renderer to the graph.
    hr = AddFilterByCLSID(m_pGraph, CLSID_DSoundRender, 
        &pAudioRenderer, L"Audio Renderer");
    if (FAILED(hr))
    {
        goto done;
    }

    // Enumerate the pins on the source filter.
    hr = pSource->EnumPins(&pEnum);
    if (FAILED(hr))
    {
        goto done;
    }

    // Loop through all the pins
    IPin *pPin;
    while (S_OK == pEnum->Next(1, &pPin, NULL))
    {           
        // Try to render this pin. 
        // It's OK if we fail some pins, if at least one pin renders.
        HRESULT hr2 = pGraph2->RenderEx(pPin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL);

        pPin->Release();
        if (SUCCEEDED(hr2))
        {
            bRenderedAnyPin = TRUE;
        }
    }

    hr = m_pVideo->FinalizeGraph(m_pGraph);
    if (FAILED(hr))
    {
        goto done;
    }

    // Remove the audio renderer, if not used.
    BOOL bRemoved;
    hr = RemoveUnconnectedRenderer(m_pGraph, pAudioRenderer, &bRemoved);

done:
    SafeRelease(&pEnum);
    SafeRelease(&pAudioRenderer);
    SafeRelease(&pGraph2);

    // If we succeeded to this point, make sure we rendered at least one 
    // stream.
    if (SUCCEEDED(hr))
    {
        if (!bRenderedAnyPin)
        {
            hr = VFW_E_CANNOT_RENDER;
        }
    }
    return hr;
}

前の例で使用した 関数のコード RemoveUnconnectedRenderer を次に示します。

HRESULT RemoveUnconnectedRenderer(IGraphBuilder *pGraph, IBaseFilter *pRenderer, BOOL *pbRemoved)
{
    IPin *pPin = NULL;

    *pbRemoved = FALSE;

    // Look for a connected input pin on the renderer.

    HRESULT hr = FindConnectedPin(pRenderer, PINDIR_INPUT, &pPin);
    SafeRelease(&pPin);

    // If this function succeeds, the renderer is connected, so we don't remove it.
    // If it fails, it means the renderer is not connected to anything, so
    // we remove it.

    if (FAILED(hr))
    {
        hr = pGraph->RemoveFilter(pRenderer);
        *pbRemoved = TRUE;
    }

    return hr;
}

フィルター グラフの解放

アプリケーションが終了したら、次のコードに示すように、フィルター グラフを解放する必要があります。

void DShowPlayer::TearDownGraph()
{
    // Stop sending event messages
    if (m_pEvent)
    {
        m_pEvent->SetNotifyWindow((OAHWND)NULL, NULL, NULL);
    }

    SafeRelease(&m_pGraph);
    SafeRelease(&m_pControl);
    SafeRelease(&m_pEvent);

    delete m_pVideo;
    m_pVideo = NULL;

    m_state = STATE_NO_GRAPH;
}

次へ: 手順 4: ビデオ レンダラーを追加します

DirectShow でのオーディオ/ビデオ再生

DirectShow 再生の例

フィルター グラフの作成

一般的なGraph-Building手法