사용자 지정 토폴로지 로더

애플리케이션이 미디어 세션에서 부분 토폴로지를 큐에 대기하는 경우 미디어 세션은 토폴로지 로더를 사용하여 토폴로지를 resolve. 기본적으로 미디어 세션은 토폴로지 로더의 표준 Media Foundation 구현을 사용하지만 사용자 지정 구현을 제공할 수도 있습니다. 이렇게 하면 최종 토폴로지를 더 많이 제어할 수 있습니다. 사용자 지정 토폴로지 로더는 IMFTopoLoader 인터페이스를 구현해야 합니다.

미디어 세션에서 사용자 지정 토폴로지 로더를 설정하려면 다음을 수행합니다.

  1. MFCreateAttributes를 호출하여 빈 특성 저장소를 만듭니다.
  2. 특성 저장소에서 MF_SESSION_TOPOLOADER 특성을 설정합니다. 특성 값은 사용자 지정 로더의 CLSID입니다.
  3. MFCreateMediaSession을 호출하여 보호되지 않는 콘텐츠에 대한 미디어 세션을 만들거나 MFCreatePMPMediaSession을 호출하여 보호된 미디어 경로(PMP) 내에 미디어 세션을 만듭니다.

참고

PMP 내에서 사용자 지정 토폴로지 로더를 사용하려면 토폴로지 로더가 신뢰할 수 있는 구성 요소여야 합니다. 자세한 내용은 보호된 미디어 경로를 참조하세요.

 

다음 코드는 미디어 세션에서 사용자 지정 토폴로지 로더를 설정하는 방법을 보여줍니다.

HRESULT CreateSession_CustomTopoLoader(REFCLSID clsid, IMFMediaSession **ppSession)
{
    *ppSession = NULL;

    IMFMediaSession *pSession = NULL;
    IMFAttributes *pConfig = NULL;

    // Create an attribute store to configure the media session.
    HRESULT hr = MFCreateAttributes(&pConfig, 1);

    // Set the CLSID of the custom topology loader.
    if (SUCCEEDED(hr))
    {
        hr = pConfig->SetGUID(MF_SESSION_TOPOLOADER, clsid);
    }

    // Create the media session.
    if (SUCCEEDED(hr))
    {
        hr = MFCreateMediaSession(pConfig, &pSession);
    }

    // Return the pointer to the caller.
    if (SUCCEEDED(hr))
    {
        *ppSession = pSession;
        (*ppSession)->AddRef();
    }

    SafeRelease(&pSession);
    SafeRelease(&pConfig);

    return hr;
}

토폴로지 로더에서 전체 토폴로지 로드 알고리즘을 구현할 필요는 없습니다. 또는 표준 Media Foundation 토폴로지 로더를 래핑할 수 있습니다. IMFTopoLoader::Load 메서드 구현에서 필요에 따라 토폴로지를 수정하고 수정된 토폴로지를 표준 토폴로지 로더에 전달합니다. 그런 다음 표준 토폴로지 로더가 토폴로지를 완료합니다. 완료된 토폴로지를 수정한 후 미디어 세션으로 다시 전달할 수도 있습니다.

다음 코드에서는 이 방법의 일반적인 개요를 보여 줍니다. Load 메서드는 애플리케이션의 특정 요구 사항에 따라 달라지므로 Load 메서드의 세부 정보를 표시하지 않습니다.

class CTopoLoader : public IMFTopoLoader
{
public:

    static HRESULT CreateInstance(REFIID iid, void **ppv)
    {
        HRESULT hr = S_OK;

        CTopoLoader *pTopoLoader = new (std::nothrow) CTopoLoader(&hr);
        
        if (pTopoLoader == NULL)
        {
            return E_OUTOFMEMORY;
        }

        if (SUCCEEDED(hr))
        {
            hr = pTopoLoader->QueryInterface(iid, ppv);
        }

        SafeRelease(&pTopoLoader);
        return hr;
    }

    // IUnknown methods.
    STDMETHODIMP QueryInterface(REFIID riid, void** ppv)
    {
        static const QITAB qit[] = 
        {
            QITABENT(CTopoLoader, IMFTopoLoader),
            { 0 },
        };
        return QISearch(this, qit, riid, ppv);
    }

    STDMETHODIMP_(ULONG) AddRef()
    {
        return InterlockedIncrement(&m_cRef);
    }

    STDMETHODIMP_(ULONG) Release()
    {
        long cRef = InterlockedDecrement(&m_cRef);
        if (cRef == 0)
        {
            delete this;
        }
        return cRef;
    }

    // IMTopoLoader methods.
    STDMETHODIMP Load(
        IMFTopology *pInput, 
        IMFTopology **ppOutput, 
        IMFTopology *pCurrent
        )
    {
        HRESULT hr = S_OK;

        // TODO: Add custom topology-building code here.
        //       Modify pInput as needed.

        if (SUCCEEDED(hr))
        {
            hr = m_pTopoLoader->Load(pInput, ppOutput, pCurrent);
        }

        // TODO: Add custom topology-building code here.
        //       Modify ppOutput as needed.

        return hr;
    }

private:
    CTopoLoader(HRESULT *phr) : m_cRef(1), m_pTopoLoader(NULL)
    {
        *phr = MFCreateTopoLoader(&m_pTopoLoader);
    }

    virtual ~CTopoLoader()
    {
        SafeRelease(&m_pTopoLoader);
    }

private:
    long            m_cRef;          // Reference count.
    IMFTopoLoader   *m_pTopoLoader;  // Standard topoloader.
};

MFCreateTopoLoader

고급 토폴로지 빌드