Compartir a través de


Reproducción de audio multicanal en DirectShow

[La característica asociada a esta página, SDK de Windows Media Format 11, es una característica heredada. Se ha reemplazado por lector de origen y receptor escritor. lector de origen y receptor escritor se han optimizado para Windows 10 y Windows 11. Microsoft recomienda encarecidamente que el nuevo código use lector de origen y escritor receptor en lugar de SDK de Windows Media Format 11, siempre que sea posible. Microsoft sugiere que el código existente que usa las API heredadas se reescriba para usar las nuevas API si es posible.

Para reproducir un archivo de audio de Windows Media multicanal en DirectShow, debes establecer la propiedad "_HIRESOUTPUT" directamente en el descodificador después de que se haya conectado al lector de ASF de WM. No es necesaria ninguna configuración del objeto Reader. Sin embargo, para trabajar directamente con DMO, necesita wmcodecconst.h desde el código de ejemplo para usar el paquete de descarga interfaces de códec de audio y vídeo de Windows Media.

Nota Este procedimiento de configuración solo se admite para los archivos que no están protegidos por Digital Rights Management.

Los pasos básicos para habilitar la salida multicanal son los siguientes:

  1. Llame a RenderFile para crear el grafo de filtro.
  2. Obtención de un puntero al filtro contenedor DMO
  3. Desconecte el contenedor DMO del representador de audio
  4. Establezca la propiedad "_HIRESOUTPUT" en el descodificador.
  5. Vuelva a conectar el contenedor DMO y el representador de audio.
  6. Ejecute el gráfico.

En los fragmentos de código siguientes se muestran estos pasos. (Se ha omitido toda la comprobación de errores por motivos de simplicidad. Debe agregar rutinas de control de errores adecuadas si usa este código en una aplicación).

    ...
    //ENABLE MULTICHANNEL OUTPUT
    //Render the file
    hr = m_pGraphBuilder->RenderFile(wFileName, NULL);

    // Get pointers to the two DMO Wrapper interfaces we need.
    // (Function bodies provided at the end of this snippet.)
    hr = GetDMOWrapper(pGB, &m_pDMOBaseFilter, &m_pWrapper); 

    //Disconnect the DMO Wrapper from the Audio Renderer
    CComPtr<IPin> pDMOOut;
    CComPtr<IPin> pRendererIn;
    hr = GetPin(m_pDMOBaseFilter, PINDIR_OUTPUT, &pDMOOut);
    hr = pDMOOut->ConnectedTo(&pRendererIn);
    hr = pDMOOut->Disconnect();
    hr = pRendererIn->Disconnect();

    //Set the property on the DMO
    VARIANT varg;
    ::VariantInit(&varg);
    varg.vt    = VT_BOOL;
    varg.boolVal = TRUE;
    CComQIPtr<IMediaObject, &IID_IMediaObject> pMediaObject(m_pWrapper);
    CComQIPtr<IPropertyBag, &IID_IPropertyBag> pPropertyBag(pMediaObject);
    hr = pPropertyBag->Write(g_wszWMACHiResOutput, &varg);

    // Reconnect the DMO Wrapper and the Audio Renderer
    hr = pGB->Connect(pDMOOut, pRendererIn);
    //END MULTICHANNEL (now the graph can be run)
...

Las funciones GetDMOWrapper y GetPin del fragmento de código anterior se implementan de la siguiente manera:

// In this example, the IBaseFilter and IDMOWrapperFilter interfaces are
// declared  at global scope
HRESULT GetDMOWrapper (IFilterGraph *pGraph, IBaseFilter** m_pDMOBaseFilter, IDMOWrapperFilter** m_pWrapper) 
{
    CComPtr<IEnumFilters> pEnum;
    CComPtr<IBaseFilter> pFilter;
    ULONG cFetched;

    HRESULT hr = pGraph->EnumFilters(&pEnum);
    if (FAILED(hr)) return hr;

    while(pEnum->Next(1, &pFilter, &cFetched) == S_OK)
    {
        // If we find the IDMOWrapperFilter interface, that means we 
        // have the DMO Wrapper filter. Store both interfaces for future use.
        CComPtr<IDMOWrapperFilter> pWrapper;
        hr = pFilter->QueryInterface(IID_IDMOWrapperFilter, (void**) &pWrapper);
        if (SUCCEEDED(hr))
        {
            *m_pWrapper = pWrapper.Detach();
            *m_pDMOBaseFilter = pFilter.Detach();
            return S_OK;
        }

        pFilter.Release();
    }

    return E_FAIL;
}

HRESULT GetPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin** ppPin)
{
    CComPtr<IEnumPins>  pEnum;
    CComPtr<IPin>       pPin;

         HRESULT hr = pFilter->EnumPins(&pEnum);
    if (FAILED(hr))
    {
        return hr;
    }
    while(pEnum->Next(1, &pPin, 0) == S_OK)
    {
        PIN_DIRECTION PinDirThis;
        pPin->QueryDirection(&PinDirThis);
        if (PinDir == PinDirThis)
        {
            *ppPin = pPin.Detach();
            return S_OK;
        }
        pPin.Release();
    }
    
    return E_FAIL;
}