출력 노드를 미디어 싱크에 바인딩

이 항목에서는 미디어 세션 외부에서 토폴로지 로더를 사용하는 경우 토폴로지에서 출력 노드를 초기화하는 방법을 설명합니다. 출력 노드는 처음에 다음 중 하나를 포함합니다.

후자의 경우 토폴로지 로더가 토폴로지를 확인하기 전에 IMFActivate 포인터를 IMFStreamSink 포인터로 변환해야 합니다. 대부분의 시나리오에서 프로세스는 다음과 같이 작동합니다.

  1. 애플리케이션은 미디어 세션에서 부분 토폴로지를 큐에 대기합니다.
  2. 모든 출력 노드에 대해 미디어 세션은 IMFActivate 포인터를 IMFStreamSink 포인터로 변환합니다. 이 프로세스를 미디어 싱크에 출력 노드 바인딩 이라고 합니다.
  3. 미디어 세션은 수정된 토폴로지를 IMFTopoLoader::Load 메서드로 보냅니다.

그러나 토폴로지 로더를 직접 사용하는 경우(미디어 sesssion 외부에서) 애플리케이션은 IMFTopoLoader::Load를 호출하기 전에 출력 노드를 바인딩해야 합니다. 출력 노드를 바인딩하려면 다음을 수행합니다.

  1. IMFTopologyNode::GetObject를 호출하여 노드의 개체 포인터를 가져옵니다.
  2. IMFStreamSink 인터페이스에 대한 개체 포인터를 쿼리합니다. 이 호출이 성공하면 더 이상 수행할 작업이 없으므로 나머지 단계를 건너뜁니다.
  3. 이전 단계가 실패한 경우 IMFActivate 인터페이스에 대한 개체 포인터를 쿼리합니다.
  4. IMFActivate::ActivateObject를 호출하여 미디어 싱크를 만듭니다. 미디어 싱크의 IMFMediaSink 인터페이스에 대한 포인터를 가져올 IID_IMFMediaSink 지정합니다.
  5. 노드에서 MF_TOPONODE_STREAMID 특성을 쿼리합니다. 이 특성의 값은 이 노드에 대한 스트림 싱크의 식별자입니다. MF_TOPONODE_STREAMID 특성이 설정되지 않은 경우 기본 스트림 식별자는 0입니다.
  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