Многоканальное воспроизведение звука WMA в DirectShow
[Функция, связанная с этой страницей, DirectShow, является устаревшей функцией. Он был заменен MediaPlayer, IMFMediaEngineи аудио и видеозахват в Media Foundation. Эти функции оптимизированы для Windows 10 и Windows 11. Корпорация Майкрософт настоятельно рекомендует использовать новый код MediaPlayer, IMFMediaEngine и аудио-видеозахват в Media Foundation вместо DirectShowпо возможности. Корпорация Майкрософт предлагает, что существующий код, использующий устаревшие API, будет перезаписан для использования новых API, если это возможно.]
Чтобы воспроизвести многоканальный аудиофайл Windows Media в DirectShow, необходимо задать свойство MFPKEY_WMADEC_HIRESOUTPUT непосредственно на декодировщике после подключения к средству чтения WM ASF. Это свойство определяется в файле заголовка wmcodecdsp.h, который доступен в пакете SDK для Windows.
Заметка
Эта процедура конфигурации поддерживается только для файлов, которые не защищены 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;
}
Связанные разделы