Associazione di nodi di output a sink multimediali

In questo argomento viene descritto come inizializzare i nodi di output in una topologia, se si usa il caricatore della topologia all'esterno della sessione multimediale. Un nodo di output contiene inizialmente uno dei seguenti elementi:

In quest'ultimo caso, il puntatore FMActivate deve essere convertito in un puntatore FMStreamSink prima che il caricatore della topologia risolve la topologia. Nella maggior parte degli scenari, il processo funziona come segue:

  1. L'applicazione accoda una topologia parziale nella sessione multimediale.
  2. Per tutti i nodi di output, la sessione multimediale converte i puntatori FMActivate in puntatori FMStreamSink . Questo processo viene chiamato associazione del nodo di output a un sink multimediale.
  3. La sessione multimediale invia la topologia modificata al metodo IMFTopoLoader::Load .

Tuttavia, se si usa il caricatore della topologia direttamente (all'esterno della sesssion multimediale), l'applicazione deve associare i nodi di output prima di chiamare FMTopoLoader::Load. Per associare un nodo di output, eseguire le operazioni seguenti:

  1. Chiamare IMFTopologyNode::GetObject per ottenere il puntatore a oggetti del nodo.
  2. Eseguire una query sul puntatore dell'oggetto per l'interfaccia FMStreamSink . Se questa chiamata ha esito positivo, non c'è altro da fare, quindi ignorare i passaggi rimanenti.
  3. Se il passaggio precedente non è riuscito, eseguire una query sul puntatore dell'oggetto per l'interfaccia FMActivate .
  4. Creare il sink multimediale chiamando FMActivate::ActivateObject. Specificare IID_IMFMediaSink per ottenere un puntatore all'interfaccia FMIMediaSink del sink multimediale.
  5. Eseguire una query sul nodo per l'attributo MF_TOPONODE_STREAMID . Il valore di questo attributo è l'identificatore del sink di flusso per questo nodo. Se l'attributo MF_TOPONODE_STREAMID non è impostato, l'identificatore di flusso predefinito è zero.
  6. Il sink di flusso appropriato potrebbe già esistere nel sink multimediale. Per controllare, chiamare FMMediaSink::GetStreamSinkById nel sink multimediale. Se il sink di flusso esiste, il metodo restituisce un puntatore all'interfaccia FMStreamSink . Se questa chiamata ha esito negativo, provare a aggiungere un nuovo sink di flusso chiamando FMMediaSink::AddStreamSink. Se entrambe le chiamate hanno esito negativo, significa che il sink multimediale non supporta l'identificatore di flusso richiesto e questo nodo della topologia non è configurato correttamente. Restituire un codice di errore e ignorare il passaggio successivo.
  7. Chiamare IMFTopologyNode::SetObject, passando il puntatore FMStreamSink dal passaggio precedente. Questa chiamata sostituisce il puntatore a oggetti del nodo, in modo che il nodo contenga un puntatore al sink di flusso, anziché un puntatore all'oggetto di attivazione.

Il codice seguente illustra come associare un nodo di output.

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

Nota

In questo esempio viene usata la funzione SafeRelease per rilasciare i puntatori all'interfaccia.

 

Nell'esempio successivo viene illustrato come associare tutti i nodi di output in una topologia. In questo esempio viene usato il metodo IMFTopology::GetOutputNodeCollection per ottenere una raccolta di nodi di output dalla topologia. Chiama quindi la funzione illustrata nell'esempio precedente in ognuno di questi nodi.

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

Compilazione avanzata della topologia

Sink multimediali

FMTopoLoader