DirectShow의 다중 채널 WMA 오디오 재생
[이 페이지와 연결된 기능인 DirectShow는 레거시 기능입니다. MediaPlayer, IMFMediaEngine 및 Media Foundation의 오디오/비디오 캡처로 대체되었습니다. 이러한 기능은 Windows 10 및 Windows 11 최적화되었습니다. 가능한 경우 새 코드에서 DirectShow 대신 MediaPlayer, IMFMediaEngine 및 오디오/비디오 캡처를 사용하는 것이 좋습니다. 가능한 경우 레거시 API를 사용하는 기존 코드를 다시 작성하여 새 API를 사용하도록 제안합니다.]
DirectShow에서 다중 채널 Windows Media Audio 파일을 재생하려면 디코더가 WM ASF Reader에 연결된 후 디코더에서 직접 MFPKEY_WMADEC_HIRESOUTPUT 속성을 설정해야 합니다. 이 속성은 Windows SDK에서 사용할 수 있는 wmcodecdsp.h 헤더 파일에 정의되어 있습니다.
참고
이 구성 절차는 디지털 권한 관리로 보호되지 않는 파일에 대해서만 지원됩니다.
다중 채널 출력을 사용하도록 설정하는 기본 단계는 다음과 같습니다.
- 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;
}
관련 항목