Пользовательские загрузчики топологии

Когда приложение помещает в очередь частичную топологию в сеансе мультимедиа, сеанс мультимедиа использует загрузчик топологии для разрешения топологии. По умолчанию сеанс мультимедиа использует стандартную реализацию Загрузчика топологии 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 , так как они будут зависеть от конкретных требований приложения.

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

Расширенное построение топологии