Media Foundation и COM

Microsoft Media Foundation использует сочетание com-конструкций, но не является полностью COM-API. В этом разделе описывается взаимодействие между COM и Media Foundation. В нем также определены некоторые рекомендации по разработке подключаемых компонентов Media Foundation. Следуя этим методикам, вы можете избежать некоторых распространенных, но незначительных ошибок программирования.

Рекомендации для приложений

В Media Foundation асинхронная обработка и обратные вызовы обрабатываются рабочими очередями. Рабочие очереди всегда имеют потоки многопоточных квартир (MTA), поэтому приложение будет иметь более простую реализацию, если оно также выполняется в потоке MTA. Поэтому рекомендуется вызывать CoInitializeEx с флагом COINIT_MULTITHREADED .

Media Foundation не маршалирует однопоточные объекты квартир (STA) для рабочих потоков очередей. Он также не гарантирует, что инварианты STA поддерживаются. Поэтому приложение STA должно быть осторожным, чтобы не передавать объекты STA или прокси-серверы в API Media Foundation. Объекты, имеющие только STA, не поддерживаются в Media Foundation.

Если у вас есть прокси-сервер STA для объекта MTA или объекта с произвольным потоком, этот объект можно маршалировать в прокси-сервер MTA с помощью обратного вызова рабочей очереди. Функция CoCreateInstance может возвращать необработанный указатель или прокси-сервер STA в зависимости от объектной модели, определенной в реестре для этого ИДЕНТИФИКАТОРА CLSID. Если возвращается прокси-сервер STA, не следует передавать указатель на API Media Foundation.

Например, предположим, что вы хотите передать указатель IPropertyStore на метод IMFSourceResolver::BeginCreateObjectFromURL . Чтобы создать указатель IPropertyStore, можно вызвать PSCreateMemoryPropertyStore. При вызове из STA необходимо маршалировать указатель перед его передачей в BeginCreateObjectFromURL.

В следующем коде показано, как маршалировать прокси-сервер STA в API Media Foundation.

class CCreateSourceMarshalCallback
    : public IMFAsyncCallback
{
public:
    CCreateSourceMarshalCallback(
        LPCWSTR szURL, 
        IMFSourceResolver* pResolver, 
        IPropertyStore* pSourceProps, 
        IMFAsyncCallback* pCompletionCallback, 
        HRESULT& hr
        )
        : m_szURL(szURL), 
          m_pResolver(pResolver), 
          m_pCompletionCallback(pCompletionCallback),
          m_pGIT(NULL),
          m_cRef(1)
    {
        hr = CoCreateInstance(CLSID_StdGlobalInterfaceTable, NULL, 
            CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_pGIT));

        if(SUCCEEDED(hr))
        {
            hr = m_pGIT->RegisterInterfaceInGlobal(
                pSourceProps, IID_IPropertyStore, &m_dwInterfaceCookie);
        }
    }
    ~CCreateSourceMarshalCallback()
    {
        SafeRelease(&m_pResolver);
        SafeRelease(&m_pCompletionCallback);
        SafeRelease(&m_pGIT);
    }


    STDMETHOD_(ULONG, AddRef)()
    {
        return InterlockedIncrement(&m_cRef);
    }

    STDMETHOD_(ULONG, Release)()
    {
        LONG cRef = InterlockedDecrement(&m_cRef);
        if (0 == cRef)
        {
            delete this;
        }
        return cRef;
    }

    STDMETHOD(QueryInterface)(REFIID riid, LPVOID* ppvObject)
    {
        static const QITAB qit[] = 
        {
            QITABENT(CCreateSourceMarshalCallback, IMFAsyncCallback),
            { 0 }
        };
        return QISearch(this, qit, riid, ppvObject);

    }

    STDMETHOD(GetParameters)(DWORD* pdwFlags, DWORD* pdwQueue)
    {
        return E_NOTIMPL;
    }

    STDMETHOD(Invoke)(IMFAsyncResult* pResult)
    {
        IPropertyStore *pSourceProps = NULL;

        HRESULT hr = m_pGIT->GetInterfaceFromGlobal(
            m_dwInterfaceCookie, 
            IID_PPV_ARGS(&pSourceProps)
            );

        if(SUCCEEDED(hr))
        {
            hr = m_pResolver->BeginCreateObjectFromURL(
                m_szURL, MF_RESOLUTION_MEDIASOURCE, pSourceProps, NULL, 
                m_pCompletionCallback, NULL);
        }

        SafeRelease(&pSourceProps);
        return hr;
    }

private:
    LPCWSTR m_szURL;
    IMFSourceResolver *m_pResolver;
    IMFAsyncCallback *m_pCompletionCallback;
    IGlobalInterfaceTable *m_pGIT;
    DWORD m_dwInterfaceCookie;
    LONG m_cRef;
};

Дополнительные сведения о таблице глобального интерфейса см. в разделе IGlobalInterfaceTable.

Если вы используете Media Foundation внутри процесса, объекты, возвращаемые из методов и функций Media Foundation, являются прямыми указателями на объект . Для межпроцессного Media Foundation эти объекты могут быть прокси-серверами MTA. При необходимости их следует маршалировать в поток STA. Аналогичным образом, объекты, полученные внутри обратного вызова , например топология из события MESessionTopologyStatus , являются прямыми указателями при использовании Media Foundation в процессе, но являются прокси-серверами MTA, когда Media Foundation используется между процессами.

Примечание

Наиболее распространенным сценарием использования нескольких процессов Media Foundation является использование защищенного пути к мультимедиа (PMP). Однако эти замечания применимы к любой ситуации, когда API Media Foundation используются через RPC.

 

Все реализации IMFAsyncCallback должны быть совместимы с MTA. Эти объекты вообще не обязательно должны быть COM-объектами. Но если они есть, они не могут работать в STA. Функция IMFAsyncCallback::Invoke будет вызываться в потоке рабочей очереди MTA, а предоставленный объект IMFAsyncResult будет либо прямым указателем, либо прокси-сервером MTA.

Рекомендации по компонентам Media Foundation

Существует две категории объектов Media Foundation, которые должны быть связаны с COM. Некоторые компоненты, такие как преобразования или обработчики потока байтов, являются полными COM-объектами, созданными CLSID. Эти объекты должны соответствовать правилам для com-квартир для внутрипроцессного и межпроцессного Media Foundation. Другие компоненты Media Foundation не являются полными COM-объектами, но им требуются прокси-серверы COM для воспроизведения между процессами. Объекты в этой категории включают источники мультимедиа и объект активации. Эти объекты могут игнорировать проблемы с квартирами, если они будут использоваться только для внутрипроцессного Media Foundation.

Хотя не все объекты Media Foundation являются COM-объектами, все интерфейсы Media Foundation являются производными от IUnknown. Поэтому все объекты Media Foundation должны реализовывать IUnknown в соответствии со спецификациями COM, включая правила подсчета ссылок и QueryInterface. Все подсчитаемые объекты должны также гарантировать, что DllCanUnloadNow не позволит выгрузить модуль, пока объекты все еще сохраняются.

Компоненты Media Foundation не могут быть объектами STA. Многие объекты Media Foundation не обязательно должны быть COM-объектами. Но если они есть, они не могут работать в STA. Все компоненты Media Foundation должны быть потокобезопасны. Некоторые объекты Media Foundation также должны быть свободными или нейтральная. В следующей таблице указаны требования к реализации пользовательского интерфейса:

Интерфейс Категория Необходимая квартира
IMFActivate Межпроцессный прокси-сервер Свободнопоточенный или нейтральный
IMFByteStreamHandler COM-объект MTA
IMFContentProtectionManager Межпроцессный прокси-сервер Свободнопоточенный или нейтральный
IMFQualityManager COM-объект Свободнопоточенный или нейтральный
IMFMediaSource Межпроцессный прокси-сервер Свободнопоточенный или нейтральный
IMFSchemeHandler COM-объект MTA
IMFTopoLoader COM-объект Свободнопоточенный или нейтральный
IMFTransform COM-объект MTA

 

В зависимости от реализации могут существовать дополнительные требования. Например, если приемник мультимедиа реализует другой интерфейс, позволяющий приложению выполнять прямые вызовы функций к приемнику, приемник должен быть свободным или нейтральным, чтобы он мог обрабатывать прямые вызовы между процессами. Любой объект может быть свободно потокованным; В этой таблице указаны минимальные требования.

Рекомендуемый способ реализации свободнопоточных или нейтральных объектов — агрегирование маршалера со свободным потоком. Дополнительные сведения см. в документации MSDN по CoCreateFreeThreadedMarshaler. В соответствии с требованием не передавать объекты STA или прокси-серверы в API-интерфейсы Media Foundation, объекты с свободным потоком не должны беспокоиться о маршале указателей входных данных STA в компонентах со свободным потоком.

Компоненты, использующие очередь работы с длинными функциями (MFASYNC_CALLBACK_QUEUE_LONG_FUNCTION), должны проявлять большую осторожность. Потоки в рабочей очереди функции long создают собственный STA. Компоненты, использующие функцию long для обратных вызовов, должны избегать создания COM-объектов в этих потоках и должны быть осторожны, чтобы маршалировать прокси-серверы в STA при необходимости.

Сводка

Приложениям будет проще взаимодействовать с Media Foundation из потока MTA, но можно с некоторой осторожностью использовать Media Foundation из потока STA. Media Foundation не обрабатывает компоненты STA, и приложения должны быть осторожны, чтобы не передавать объекты STA в API Media Foundation. К некоторым объектам предъявляются дополнительные требования, особенно объекты, которые выполняются в ситуации между процессами. Соблюдение этих рекомендаций поможет избежать com-ошибок, взаимоблокировок и непредвиденных задержек при обработке мультимедиа.

API платформы Media Foundation

Архитектура Media Foundation