DirectShow 中的多重通道 WMA 音訊播放
[與此頁面 相關的功能 DirectShow是舊版功能。 它已被 MediaPlayer、 IMFMediaEngine和 Media Foundation 中的音訊/視訊擷取取代。 這些功能已針對Windows 10和Windows 11進行優化。 Microsoft 強烈建議新程式碼盡可能使用 MediaPlayer、 IMFMediaEngine 和 音訊/視訊擷取 ,而不是 DirectShow。 Microsoft 建議盡可能重寫使用舊版 API 的現有程式碼,以使用新的 API。]
若要在 DirectShow 中播放多重通道 Windows Media 音訊檔案,您必須在解碼器上直接設定 MFPKEY_WMADEC_HIRESOUTPUT 屬性,才能連線到 WM ASF 讀取器。 此屬性定義于 Windows SDK 中提供的標頭檔 wmcodecdsp.h 中。
注意
只有不受 Digital Rights Management 保護的檔案才支援此組態程式。
啟用多重通道輸出的基本步驟如下:
- 呼叫 RenderFile 以建立篩選圖形。
- 取得 DMO 包裝函式篩選的指標。
- 中斷 DMO 包裝函式與音訊轉譯器的連接。
- 使用 IPropertyBag 介面,在解碼器上設定 MFPKEY_WMADEC_HIRESOUTPUT 屬性。 屬性名稱是由全域常數 g_wszWMACHiResOutput所定義。
- 重新連接 DMO 包裝函式和音訊轉譯器。
- 執行圖形。
下列程式碼片段示範這些步驟。 此程式碼假設原始程式檔包含音訊資料流程,且沒有視訊串流。 視訊編解碼器 DMO 不支援 MFPKEY_WMADEC_HIRESOUTPUT 屬性。
HRESULT BuildGraph(IGraphBuilder *pGraph, const WCHAR *wFileName)
{
HRESULT hr = S_OK;
IBaseFilter *pDmoWrapper = NULL;
IPin *pDmoOut = NULL;
IPin *pRendererIn = NULL;
IPropertyBag *pPropBag = NULL;
hr = pGraph->RenderFile(wFileName, NULL);
// Get pointers to the two DMO Wrapper interfaces we need.
// (Function bodies provided at the end of this snippet.)
if (SUCCEEDED(hr))
{
hr = GetDMOWrapper(pGraph, &pDmoWrapper);
}
//Disconnect the DMO Wrapper from the Audio Renderer.
if (SUCCEEDED(hr))
{
hr = GetPin(pDmoWrapper, PINDIR_OUTPUT, &pDmoOut);
}
if (SUCCEEDED(hr))
{
hr = DisconnectPin(pGraph, pDmoOut, &pRendererIn);
}
//Set the property on the DMO.
VARIANT varg;
::VariantInit(&varg);
varg.vt = VT_BOOL;
varg.boolVal = TRUE;
if (SUCCEEDED(hr))
{
hr = pDmoWrapper->QueryInterface(IID_IPropertyBag, (void**)&pPropBag);
}
if (SUCCEEDED(hr))
{
hr = pPropBag->Write(g_wszWMACHiResOutput, &varg);
}
// Reconnect the DMO Wrapper and the Audio Renderer
if (SUCCEEDED(hr))
{
hr = pGraph->Connect(pDmoOut, pRendererIn);
}
SAFE_RELEASE(pDmoWrapper);
SAFE_RELEASE(pDmoOut);
SAFE_RELEASE(pRendererIn);
SAFE_RELEASE(pPropBag);
return hr;
}
先前程式碼片段的協助程式函式會實作如下:
HRESULT GetDMOWrapper (IFilterGraph *pGraph, IBaseFilter** ppFilter)
{
BOOL bFound = FALSE;
IEnumFilters *pEnum = NULL;
IBaseFilter *pFilter = NULL;
IDMOWrapperFilter *pWrapper = NULL;
HRESULT hr = pGraph->EnumFilters(&pEnum);
if (SUCCEEDED(hr))
{
while(pEnum->Next(1, &pFilter, NULL) == S_OK)
{
// If we find the IDMOWrapperFilter interface, that means we
// have the DMO Wrapper filter.
hr = pFilter->QueryInterface(IID_IDMOWrapperFilter, (void**) &pWrapper);
if (SUCCEEDED(hr))
{
bFound = TRUE;
break;
}
SAFE_RELEASE(pFilter);
}
}
if (bFound)
{
*ppFilter = pFilter;
(*ppFilter)->AddRef();
}
else
{
hr = E_FAIL;
}
SAFE_RELEASE(pEnum);
SAFE_RELEASE(pFilter);
SAFE_RELEASE(pWrapper);
return hr;
}
HRESULT GetPin(IBaseFilter *pFilter, PIN_DIRECTION PinDir, IPin** ppPin)
{
BOOL bFound = FALSE;
IEnumPins *pEnum = NULL;
IPin *pPin = NULL;
HRESULT hr = pFilter->EnumPins(&pEnum);
if (SUCCEEDED(hr))
{
while(pEnum->Next(1, &pPin, 0) == S_OK)
{
PIN_DIRECTION PinDirThis;
hr = pPin->QueryDirection(&PinDirThis);
if (FAILED(hr))
{
break;
}
if (PinDir == PinDirThis)
{
bFound = TRUE;
break;
}
SAFE_RELEASE(pPin);
}
}
if (bFound)
{
*ppPin = pPin;
(*ppPin)->AddRef();
}
else
{
hr = E_FAIL;
}
SAFE_RELEASE(pPin);
SAFE_RELEASE(pEnum);
return hr;
}
HRESULT DisconnectPin(IGraphBuilder *pGraph, IPin *pPin, IPin **ppConnected)
{
IPin *pConnected = NULL;
HRESULT hr = pPin->ConnectedTo(&pConnected);
if (SUCCEEDED(hr))
{
hr = pGraph->Disconnect(pPin);
}
if (SUCCEEDED(hr))
{
hr = pGraph->Disconnect(pConnected);
}
if (SUCCEEDED(hr))
{
*ppConnected = pConnected;
(*ppConnected)->AddRef();
}
SAFE_RELEASE(pConnected);
return hr;
}
相關主題