Поделиться через


Привязка выходных узлов к приемникам мультимедиа

В этом разделе описывается, как инициализировать выходные узлы в топологии, если вы используете загрузчик топологии вне сеанса мультимедиа. Выходной узел изначально содержит один из следующих элементов:

В последнем случае указатель IMFActivate необходимо преобразовать в указатель IMFStreamSink , прежде чем загрузчик топологии разрешит топологию. В большинстве сценариев процесс работает следующим образом:

  1. Приложение помещает в очередь частичную топологию в сеансе мультимедиа.
  2. Для всех выходных узлов сеанс мультимедиа преобразует указатели IMFActivate в указатели IMFStreamSink . Этот процесс называется привязкой выходного узла к приемнику мультимедиа.
  3. Сеанс мультимедиа отправляет измененную топологию в метод IMFTopoLoader::Load .

Однако если вы используете загрузчик топологии напрямую (за пределами медиасайта), приложение должно привязать выходные узлы перед вызовом 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