Condividi tramite


Riproduzione audio multicanale in DirectShow

[La funzionalità associata a questa pagina, Windows Media Format 11 SDK, è una funzionalità legacy. È stata sostituita da lettore di origine e writer sink. lettore di origine e sink writer sono stati ottimizzati per Windows 10 e Windows 11. Microsoft consiglia vivamente che il nuovo codice usi lettore di origine e writer sink invece di Windows Media Format 11 SDK, quando possibile. Microsoft suggerisce che il codice esistente che usa le API legacy venga riscritto per usare le nuove API, se possibile.

Per riprodurre un file Windows Media Audio multicanale in DirectShow, devi impostare la proprietà "_HIRESOUTPUT" direttamente sul decodificatore dopo che è stata connessa al lettore ASF WM. Non è necessaria alcuna configurazione dell'oggetto lettore. Tuttavia, per lavorare direttamente con DMO, è necessario wmcodecconst.h dal codice di esempio per l'uso del pacchetto di download delle interfacce codec audio e video di Windows Media.

Nota Questa procedura di configurazione è supportata solo per i file non protetti da Digital Rights Management.

I passaggi di base per abilitare l'output multicanale sono i seguenti:

  1. Chiamare RenderFile per creare il grafico del filtro.
  2. Ottenere un puntatore al filtro wrapper DMO
  3. Disconnettere il wrapper DMO dal renderer audio
  4. Impostare la proprietà "_HIRESOUTPUT" nel decodificatore.
  5. Riconnettere il wrapper DMO e il renderer audio.
  6. Eseguire il grafico.

I frammenti di codice seguenti illustrano questi passaggi. Tutti i controlli degli errori sono stati omessi per motivi di semplicità. Se si usa questo codice in un'applicazione, è necessario aggiungere routine di gestione degli errori appropriate.

    ...
    //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)
...

Le funzioni GetDMOWrapper e GetPin del frammento di codice precedente vengono implementate nel modo seguente:

// 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;
}