Media Foundation y COM

Microsoft Media Foundation usa una combinación de construcciones COM, pero no es una API totalmente basada en COM. En este tema se describe la interacción entre COM y Media Foundation. También define algunos procedimientos recomendados para desarrollar componentes de complemento de Media Foundation. Seguir estos procedimientos puede ayudarle a evitar algunos errores de programación comunes pero sutiles.

Procedimientos recomendados para aplicaciones

En Media Foundation, las colas de trabajo controlan el procesamiento asincrónico y las devoluciones de llamada. Las colas de trabajo siempre tienen subprocesos de apartamento multiproceso (MTA), por lo que una aplicación tendrá una implementación más sencilla si también se ejecuta en un subproceso MTA. Por lo tanto, se recomienda llamar a CoInitializeEx con la marca COINIT_MULTITHREADED .

Media Foundation no serializa objetos de apartamento de un solo subproceso (STA) para trabajar subprocesos de cola. Tampoco garantiza que se mantengan las invariables STA. Por lo tanto, una aplicación STA debe tener cuidado de no pasar objetos STA ni servidores proxy a las API de Media Foundation. Los objetos que son solo STA no se admiten en Media Foundation.

Si tiene un proxy STA en un objeto MTA o sin subproceso, el objeto se puede serializar en un proxy MTA mediante una devolución de llamada de cola de trabajo. La función CoCreateInstance puede devolver un puntero sin formato o un proxy STA, según el modelo de objetos definido en el Registro para ese CLSID. Si se devuelve un proxy STA, no debe pasar el puntero a una API de Media Foundation.

Por ejemplo, supongamos que desea pasar un puntero IPropertyStore al método IMFSourceResolver::BeginCreateObjectFromURL . Puede llamar a PSCreateMemoryPropertyStore para crear el puntero IPropertyStore . Si llama desde un STA, debe serializar el puntero antes de pasarlo a BeginCreateObjectFromURL.

En el código siguiente se muestra cómo serializar un proxy STA en una API de 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;
};

Para obtener más información sobre la tabla de interfaz global, vea IGlobalInterfaceTable.

Si usa Media Foundation en proceso, los objetos devueltos desde los métodos y funciones de Media Foundation son punteros directos al objeto . En el caso de Media Foundation entre procesos, estos objetos pueden ser servidores proxy MTA y deben serializarse en un subproceso STA si es necesario. Del mismo modo, los objetos obtenidos dentro de una devolución de llamada (por ejemplo, una topología del evento MESessionTopologyStatus ) son punteros directos cuando Media Foundation se usa en proceso, pero son servidores proxy MTA cuando Se usa Media Foundation entre procesos.

Nota

El escenario más común para usar Media Foundation entre procesos es con la ruta de acceso multimedia protegida (PMP). Sin embargo, estas observaciones se aplican a cualquier situación cuando las API de Media Foundation se usan a través de RPC.

 

Todas las implementaciones de IMFAsyncCallback deben ser compatibles con MTA. Estos objetos no necesitan ser objetos COM. Pero si lo son, no pueden ejecutarse en el STA. La función IMFAsyncCallback::Invoke se invocará en un subproceso de cola de trabajo de MTA y el objeto IMFAsyncResult proporcionado será un puntero de objeto directo o un proxy MTA.

Procedimientos recomendados para los componentes de Media Foundation

Hay dos categorías de objetos de Media Foundation que deben preocuparse por COM. Algunos componentes, como transformaciones o controladores de flujos de bytes, son objetos COM completos creados por CLSID. Estos objetos deben seguir las reglas de los apartamentos COM, tanto para Media Foundation en proceso como entre procesos. Otros componentes de Media Foundation no son objetos COM completos, pero necesitan servidores proxy COM para la reproducción entre procesos. Los objetos de esta categoría incluyen orígenes multimedia y objeto de activación. Estos objetos pueden omitir los problemas de los apartamentos si solo se usarán para Media Foundation en proceso.

Aunque no todos los objetos de Media Foundation son objetos COM, todas las interfaces de Media Foundation derivan de IUnknown. Por lo tanto, todos los objetos de Media Foundation deben implementar IUnknown según las especificaciones COM, incluidas las reglas para el recuento de referencias y QueryInterface. Todos los objetos con recuento de referencias también deben asegurarse de que DllCanUnloadNow no permitirá que el módulo se descargue mientras los objetos siguen conservando.

Los componentes de Media Foundation no pueden ser objetos STA. Muchos objetos de Media Foundation no necesitan ser objetos COM en absoluto. Pero si lo son, no pueden ejecutarse en el STA. Todos los componentes de Media Foundation deben ser seguros para subprocesos. Algunos objetos de Media Foundation también deben ser de subproceso libre o independiente del apartamento. En la tabla siguiente se especifican los requisitos para las implementaciones de interfaz personalizadas:

Interfaz Category Apartamento requerido
IMFActivate Proxy entre procesos Subproceso libre o neutro
IMFByteStreamHandler Com (objeto) MTA
IMFContentProtectionManager Proxy entre procesos Subproceso libre o neutro
IMFQualityManager Com (objeto) Subproceso libre o neutro
IMFMediaSource Proxy entre procesos Subproceso libre o neutro
IMFSchemeHandler Com (objeto) MTA
IMFTopoLoader Com (objeto) Subproceso libre o neutro
IMFTransform Com (objeto) MTA

 

Puede haber requisitos adicionales en función de la implementación. Por ejemplo, si un receptor multimedia implementa otra interfaz que permite a la aplicación realizar llamadas de función directas al receptor, el receptor tendría que ser libre o neutro, de modo que pueda controlar las llamadas directas entre procesos. Cualquier objeto puede ser subproceso libre; esta tabla especifica los requisitos mínimos.

La manera recomendada de implementar objetos sin subprocesos o neutros es mediante la agregación del serializador sin subprocesos. Para obtener más información, consulte la documentación de MSDN sobre CoCreateFreeThreadedMarshaler. De acuerdo con el requisito de no pasar objetos STA o servidores proxy a las API de Media Foundation, los objetos sin subprocesos no tienen que preocuparse por serializar punteros de entrada STA en componentes sin subprocesos.

Los componentes que usan la cola de trabajo de función larga (MFASYNC_CALLBACK_QUEUE_LONG_FUNCTION) deben tener más cuidado. Los subprocesos de la función long ponen en cola su propio STA. Los componentes que usan la función long workqueue para las devoluciones de llamada deben evitar la creación de objetos COM en estos subprocesos y deben tener cuidado de serializar los servidores proxy a sta según sea necesario.

Resumen

Las aplicaciones tendrán un tiempo más fácil si interactúan con Media Foundation desde un subproceso de MTA, pero es posible con cierta atención usar Media Foundation desde un subproceso STA. Media Foundation no controla los componentes de STA y las aplicaciones deben tener cuidado de no pasar objetos STA a las API de Media Foundation. Algunos objetos tienen requisitos adicionales, especialmente los objetos que se ejecutan en una situación entre procesos. Siguiendo estas instrucciones, ayudará a evitar errores COM, interbloqueos y retrasos inesperados en el procesamiento de medios.

API de media Foundation Platform

Arquitectura de Media Foundation