将输出节点绑定到媒体接收器

本主题介绍如何初始化拓扑中的输出节点(如果在媒体会话之外使用拓扑加载程序)。 输出节点最初包含以下项之一:

在后一种情况下,在拓扑加载程序解析拓扑之前,必须将 IMFActivate 指针转换为 IMFStreamSink 指针。 在大多数情况下,该过程的工作方式如下:

  1. 应用程序将媒体会话上的部分拓扑排队。
  2. 对于所有输出节点,媒体会话会将 IMFActivate 指针转换为 IMFStreamSink 指针。 此过程称为将输出节点 绑定到 媒体接收器。
  3. 媒体会话将修改后的拓扑发送到 IMFTopoLoader::Load 方法。

但是,如果直接 (媒体 sesssion) 外部使用拓扑加载程序,则应用程序必须在调用 IMFTopoLoader::Load 之前绑定输出节点。 若要绑定输出节点,请执行以下操作:

  1. 调用 IMFTopologyNode::GetObject 以获取节点的对象指针。
  2. 查询 IMFStreamSink 接口的对象指针。 如果此调用成功,则无需执行其他操作,因此请跳过其余步骤。
  3. 如果上一步失败,请查询 IMFActivate 接口的对象指针。
  4. 通过调用 IMFActivate::ActivateObject 创建媒体接收器。 指定 IID_IMFMediaSink 以获取指向媒体接收器的 IMFMediaSink 接口的指针。
  5. 查询节点以获取 MF_TOPONODE_STREAMID 属性。 此属性的值是此节点的流接收器的标识符。 如果未设置 MF_TOPONODE_STREAMID 属性,则默认流标识符为零。
  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;
}

注意

此示例使用 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