出力ノードをメディア シンクにバインドする
このトピックでは、メディア セッションの外部でトポロジ ローダーを使用している場合に、トポロジ内の出力ノードを初期化する方法について説明します。 出力ノードには、最初に次のいずれかが含まれています。
- IMFStreamSink ポインター。
- IMFActivate ポインター。
後者の場合、トポロジ ローダーがトポロジを解決する前に、 IMFActivate ポインターを IMFStreamSink ポインターに変換する必要があります。 ほとんどのシナリオでは、このプロセスは次のように機能します。
- アプリケーションは、メディア セッションで部分的なトポロジをキューに入れます。
- すべての出力ノードについて、メディア セッションは IMFActivate ポインターを IMFStreamSink ポインターに変換します。 このプロセスは、出力ノードをメディア シンクに バインド することを呼び出します。
- メディア セッションは、変更されたトポロジを IMFTopoLoader::Load メソッドに送信します。
ただし、トポロジ ローダーを (メディア の外部で) 直接使用している場合は、 IMFTopoLoader::Load を呼び出す前に、アプリケーションで出力ノードをバインドする必要があります。 出力ノードをバインドするには、次の操作を行います。
- IMFTopologyNode::GetObject を呼び出して、ノードのオブジェクト ポインターを取得します。
- IMFStreamSink インターフェイスのオブジェクト ポインターに対してクエリを実行します。 この呼び出しが成功した場合は、それ以上の操作は行わないので、残りの手順はスキップしてください。
- 前の手順で失敗した場合は、 IMFActivate インターフェイスのオブジェクト ポインターに対してクエリを実行します。
- IMFActivate::ActivateObject を呼び出してメディア シンクを作成します。 メディア シンクのIMFMediaSink インターフェイスへのポインターを取得するには、IID_IMFMediaSinkを指定します。
- MF_TOPONODE_STREAMID属性のノードに対してクエリを実行します。 この属性の値は、このノードのストリーム シンクの識別子です。 MF_TOPONODE_STREAMID属性が設定されていない場合、既定のストリーム識別子は 0 です。
- メディア シンクには、適切なストリーム シンクが既に存在している可能性があります。 チェックするには、メディア シンクで IMFMediaSink::GetStreamSinkById を呼び出します。 ストリーム シンクが存在する場合、メソッドは IMFStreamSink インターフェイスへのポインターを返します。 この呼び出しが失敗した場合は、 IMFMediaSink::AddStreamSink を呼び出して、新しいストリーム シンクを追加してみてください。 両方の呼び出しが失敗した場合は、メディア シンクが要求されたストリーム識別子をサポートしていないため、このトポロジ ノードが正しく構成されていないことを意味します。 エラー コードを返し、次の手順をスキップします。
- 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;
}
関連トピック