Associando nós de saída a coletores de mídia

Este tópico descreve como inicializar os nós de saída em uma topologia, se você estiver usando o carregador de topologia fora da Sessão de Mídia. Inicialmente, um nó de saída contém um dos seguintes:

Neste último caso, o ponteiro IMFActivate deve ser convertido em um ponteiro IMFStreamSink antes que o carregador de topologia resolva a topologia. Na maioria dos cenários, o processo funciona da seguinte maneira:

  1. O aplicativo enfileira uma topologia parcial na Sessão de Mídia.
  2. Para todos os nós de saída, a Sessão de Mídia converte ponteiros IMFActivate em ponteiros IMFStreamSink . Esse processo é chamado de associar o nó de saída a um coletor de mídia.
  3. A Sessão de Mídia envia a topologia modificada para o método IMFTopoLoader::Load .

No entanto, se você estiver usando o carregador de topologia diretamente (fora da sessão de mídia), seu aplicativo deverá associar os nós de saída antes de chamar IMFTopoLoader::Load. Para associar um nó de saída, faça o seguinte:

  1. Chame IMFTopologyNode::GetObject para obter o ponteiro de objeto do nó.
  2. Consulte o ponteiro do objeto para a interface IMFStreamSink . Se essa chamada for bem-sucedida, não haverá mais nada a fazer, portanto, ignore as etapas restantes.
  3. Se a etapa anterior falhou, consulte o ponteiro do objeto para a interface IMFActivate .
  4. Crie o coletor de mídia chamando IMFActivate::ActivateObject. Especifique IID_IMFMediaSink para obter um ponteiro para a interface IMFMediaSink do coletor de mídia.
  5. Consulte o nó para o atributo MF_TOPONODE_STREAMID . O valor desse atributo é o identificador do coletor de fluxo para esse nó. Se o atributo MF_TOPONODE_STREAMID não estiver definido, o identificador de fluxo padrão será zero.
  6. O coletor de fluxo apropriado pode já existir no coletor de mídia. Para marcar, chame IMFMediaSink::GetStreamSinkById no coletor de mídia. Se o coletor de fluxo existir, o método retornará um ponteiro para sua interface IMFStreamSink . Se essa chamada falhar, tente adicionar um novo coletor de fluxo chamando IMFMediaSink::AddStreamSink. Se ambas as chamadas falharem, isso significa que o coletor de mídia não dá suporte ao identificador de fluxo solicitado e esse nó de topologia não está configurado corretamente. Retornar um código de erro e ignorar a próxima etapa.
  7. Chame IMFTopologyNode::SetObject, passando o ponteiro IMFStreamSink da etapa anterior. Essa chamada substitui o ponteiro de objeto do nó, de modo que o nó contenha um ponteiro para o coletor de fluxo, em vez de um ponteiro para o objeto de ativação.

O código a seguir mostra como associar um nó de saída.

// 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;
}

Observação

Este exemplo usa a função SafeRelease para liberar ponteiros de interface.

 

O exemplo a seguir mostra como associar todos os nós de saída em uma topologia. Este exemplo usa o método IMFTopology::GetOutputNodeCollection para obter uma coleção de nós de saída da topologia. Em seguida, ele chama a função mostrada no exemplo anterior em cada um desses nós por sua vez.

// 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;
}

Compilação avançada de topologia

Coletores de mídia

IMFTopoLoader