Enlazar nodos de salida a receptores multimedia
En este tema se describe cómo inicializar los nodos de salida en una topología, si usa el cargador de topologías fuera de la sesión multimedia. Un nodo de salida contiene inicialmente uno de los siguientes elementos:
- Puntero IMFStreamSink .
- Un puntero IMFActivate .
En este último caso, el puntero IMFActivate debe convertirse en un puntero IMFStreamSink antes de que el cargador de topología resuelva la topología. En la mayoría de los escenarios, el proceso funciona de la siguiente manera:
- La aplicación pone en cola una topología parcial en la sesión multimedia.
- Para todos los nodos de salida, la sesión multimedia convierte punteros IMFActivate a punteros IMFStreamSink . Este proceso se denomina enlace del nodo de salida a un receptor multimedia.
- La sesión multimedia envía la topología modificada al método IMFTopoLoader::Load .
Sin embargo, si usa el cargador de topología directamente (fuera de la sessión multimedia), la aplicación debe enlazar los nodos de salida antes de llamar a IMFTopoLoader::Load. Para enlazar un nodo de salida, haga lo siguiente:
- Llame a IMFTopologyNode::GetObject para obtener el puntero de objeto del nodo.
- Consulte el puntero de objeto para la interfaz IMFStreamSink . Si esta llamada se realiza correctamente, no hay más que hacer, así que omita los pasos restantes.
- Si se produjo un error en el paso anterior, consulte el puntero de objeto para la interfaz IMFActivate .
- Cree el receptor de medios llamando a IMFActivate::ActivateObject. Especifique IID_IMFMediaSink para obtener un puntero a la interfaz IMFMediaSink del receptor multimedia.
- Consulte el nodo para el atributo MF_TOPONODE_STREAMID . El valor de este atributo es el identificador del receptor de secuencia para este nodo. Si no se establece el atributo MF_TOPONODE_STREAMID , el identificador de flujo predeterminado es cero.
- Es posible que el receptor de flujo adecuado ya exista en el receptor multimedia. Para comprobarlo, llame a IMFMediaSink::GetStreamSinkById en el receptor multimedia. Si el receptor de la secuencia existe, el método devuelve un puntero a su interfaz IMFStreamSink . Si se produce un error en esta llamada, intente agregar un nuevo receptor de secuencia llamando a IMFMediaSink::AddStreamSink. Si se produce un error en ambas llamadas, significa que el receptor de medios no admite el identificador de secuencia solicitado y este nodo de topología no está configurado correctamente. Devuelve un código de error y omite el paso siguiente.
- Llame a IMFTopologyNode::SetObject y pase el puntero IMFStreamSink del paso anterior. Esta llamada reemplaza al puntero de objeto del nodo, de modo que el nodo contenga un puntero al receptor de secuencia, en lugar de un puntero al objeto de activación.
En el código siguiente se muestra cómo enlazar un nodo de salida.
// 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
En este ejemplo se usa la función SafeRelease para liberar punteros de interfaz.
En el ejemplo siguiente se muestra cómo enlazar todos los nodos de salida de una topología. En este ejemplo se usa el método IMFTopology::GetOutputNodeCollection para obtener una colección de nodos de salida de la topología. A continuación, llama a la función que se muestra en el ejemplo anterior en cada uno de esos nodos a su 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;
}
Temas relacionados