DirectShow 中的多声道 WMA 音频播放
[与此页面关联的功能 DirectShow 是一项旧功能。 它已被 MediaPlayer、 IMFMediaEngine 和 媒体基金会中的音频/视频捕获取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能使用 MediaPlayer、 IMFMediaEngine 和 Media Foundation 中的音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]
若要在 DirectShow 中播放多声道 Windows Media Audio 文件,必须在解码器连接到 WM ASF 读取器后直接在解码器上设置 MFPKEY_WMADEC_HIRESOUTPUT 属性。 此属性在头文件 wmcodecdsp.h 中定义,可在 Windows SDK 中使用。
注意
仅对不受数字版权管理保护的文件支持此配置过程。
启用多通道输出的基本步骤如下:
- 调用 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;
}
相关主题