出力ノードをメディア シンクにバインドする

このトピックでは、メディア セッションの外部でトポロジ ローダーを使用している場合に、トポロジ内の出力ノードを初期化する方法について説明します。 出力ノードには、最初に次のいずれかが含まれています。

後者の場合、トポロジ ローダーがトポロジを解決する前に、 IMFActivate ポインターを IMFStreamSink ポインターに変換する必要があります。 ほとんどのシナリオでは、このプロセスは次のように機能します。

  1. アプリケーションは、メディア セッションで部分的なトポロジをキューに入れます。
  2. すべての出力ノードについて、メディア セッションは IMFActivate ポインターを IMFStreamSink ポインターに変換します。 このプロセスは、出力ノードをメディア シンクに バインド することを呼び出します。
  3. メディア セッションは、変更されたトポロジを IMFTopoLoader::Load メソッドに送信します。

ただし、トポロジ ローダーを (メディア の外部で) 直接使用している場合は、 IMFTopoLoader::Load を呼び出す前に、アプリケーションで出力ノードをバインドする必要があります。 出力ノードをバインドするには、次の操作を行います。

  1. IMFTopologyNode::GetObject を呼び出して、ノードのオブジェクト ポインターを取得します。
  2. IMFStreamSink インターフェイスのオブジェクト ポインターに対してクエリを実行します。 この呼び出しが成功した場合は、それ以上の操作は行わないので、残りの手順はスキップしてください。
  3. 前の手順で失敗した場合は、 IMFActivate インターフェイスのオブジェクト ポインターに対してクエリを実行します。
  4. IMFActivate::ActivateObject を呼び出してメディア シンクを作成します。 メディア シンクのIMFMediaSink インターフェイスへのポインターを取得するには、IID_IMFMediaSinkを指定します。
  5. MF_TOPONODE_STREAMID属性のノードに対してクエリを実行します。 この属性の値は、このノードのストリーム シンクの識別子です。 MF_TOPONODE_STREAMID属性が設定されていない場合、既定のストリーム識別子は 0 です。
  6. メディア シンクには、適切なストリーム シンクが既に存在している可能性があります。 チェックするには、メディア シンクで IMFMediaSink::GetStreamSinkById を呼び出します。 ストリーム シンクが存在する場合、メソッドは IMFStreamSink インターフェイスへのポインターを返します。 この呼び出しが失敗した場合は、 IMFMediaSink::AddStreamSink を呼び出して、新しいストリーム シンクを追加してみてください。 両方の呼び出しが失敗した場合は、メディア シンクが要求されたストリーム識別子をサポートしていないため、このトポロジ ノードが正しく構成されていないことを意味します。 エラー コードを返し、次の手順をスキップします。
  7. IMFTopologyNode::SetObject を呼び出し、前の手順の IMFStreamSink ポインターを渡します。 この呼び出しはノードのオブジェクト ポインターを置き換えます。これにより、ノードにはアクティブ化オブジェクトへのポインターではなく、ストリーム シンクへのポインターが含まれます。

次のコードは、出力ノードをバインドする方法を示しています。

// BindOutputNode
// Sets the IMFStreamSink pointer on an output node.

HRESULT BindOutputNode(IMFTopologyNode *pNode)
{
    IUnknown *pNodeObject = NULL;
    IMFActivate *pActivate = NULL;
    IMFStreamSink *pStream = NULL;
    IMFMediaSink *pSink = NULL;

    // Get the node's object pointer.
    HRESULT hr = pNode->GetObject(&pNodeObject);
    if (FAILED(hr))
    {
        return hr;
    }

    // The object pointer should be one of the following:
    // 1. An activation object for the media sink.
    // 2. The stream sink.

    // If it's #2, then we're already done.

    // First, check if it's an activation object.
    hr = pNodeObject->QueryInterface(IID_PPV_ARGS(&pActivate));

    if (SUCCEEDED(hr))
    {
        DWORD dwStreamID = 0;

        // The object pointer is an activation object. 
        
        // Try to create the media sink.
        hr = pActivate->ActivateObject(IID_PPV_ARGS(&pSink));

        // Look up the stream ID. (Default to zero.)

        if (SUCCEEDED(hr))
        {
           dwStreamID = MFGetAttributeUINT32(pNode, MF_TOPONODE_STREAMID, 0);
        }

        // Now try to get or create the stream sink.

        // Check if the media sink already has a stream sink with the requested ID.

        if (SUCCEEDED(hr))
        {
            hr = pSink->GetStreamSinkById(dwStreamID, &pStream);
            if (FAILED(hr))
            {
                // Try to add a new stream sink.
                hr = pSink->AddStreamSink(dwStreamID, NULL, &pStream);
            }
        }

        // Replace the node's object pointer with the stream sink. 
        if (SUCCEEDED(hr))
        {
            hr = pNode->SetObject(pStream);
        }
    }
    else
    {
        // Not an activation object. Is it a stream sink?
        hr = pNodeObject->QueryInterface(IID_PPV_ARGS(&pStream));
    }

    SafeRelease(&pNodeObject);
    SafeRelease(&pActivate);
    SafeRelease(&pStream);
    SafeRelease(&pSink);
    return hr;
}

Note

この例では、 SafeRelease 関数を使用してインターフェイス ポインターを解放します。

 

次の例では、トポロジ内のすべての出力ノードをバインドする方法を示します。 この例では、 IMFTopology::GetOutputNodeCollection メソッドを使用して、トポロジから出力ノードのコレクションを取得します。 次に、これらの各ノードで前の例で示した関数を順番に呼び出します。

// BindOutputNodes
// Sets the IMFStreamSink pointers on all of the output nodes in a topology.

HRESULT BindOutputNodes(IMFTopology *pTopology)
{
    DWORD cNodes = 0;

    IMFCollection *pCol = NULL;
    IUnknown *pUnk = NULL;
    IMFTopologyNode *pNode = NULL;

    // Get the collection of output nodes. 
    HRESULT hr = pTopology->GetOutputNodeCollection(&pCol);
    
    // Enumerate all of the nodes in the collection.
    if (SUCCEEDED(hr))
    {
        hr = pCol->GetElementCount(&cNodes);
    }

    if (SUCCEEDED(hr))
    {
        for (DWORD i = 0; i < cNodes; i++)
        {
            hr = pCol->GetElement(i, &pUnk);

            if (FAILED(hr)) { break; }

            hr = pUnk->QueryInterface(IID_IMFTopologyNode, (void**)&pNode);

            if (FAILED(hr)) { break; }

            // Bind this node.
            hr = BindOutputNode(pNode);

            if (FAILED(hr)) { break; }
        }
    }

    SafeRelease(&pCol);
    SafeRelease(&pUnk);
    SafeRelease(&pNode);
    return hr;
}

高度なトポロジの構築

メディア シンク

IMFTopoLoader