步骤 3:生成筛选器图
[与此页面关联的功能 DirectShow 是旧版功能。 它已被 MediaPlayer、 IMFMediaEngine 和 Media Foundation 中的音频/视频捕获所取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能在 Media Foundation 中使用 MediaPlayer、 IMFMediaEngine 和 音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]
本主题是 DirectShow 中的音频/视频播放教程的步骤 3。 主题 DirectShow 播放示例中显示了完整的代码。
下一步是生成筛选器图以播放媒体文件。
打开媒体文件
方法 DShowPlayer::OpenFile
打开媒体文件进行播放。 此方法执行以下操作:
- 创建新的 (空) 筛选器图。
- 调用 IGraphBuilder::AddSourceFilter 为指定文件添加源筛选器。
- 在源筛选器上呈现流。
HRESULT DShowPlayer::OpenFile(PCWSTR pszFileName)
{
IBaseFilter *pSource = NULL;
// Create a new filter graph. (This also closes the old one, if any.)
HRESULT hr = InitializeGraph();
if (FAILED(hr))
{
goto done;
}
// Add the source filter to the graph.
hr = m_pGraph->AddSourceFilter(pszFileName, NULL, &pSource);
if (FAILED(hr))
{
goto done;
}
// Try to render the streams.
hr = RenderStreams(pSource);
done:
if (FAILED(hr))
{
TearDownGraph();
}
SafeRelease(&pSource);
return hr;
}
创建 Filter Graph 管理器
方法 DShowPlayer::InitializeGraph
创建新的筛选器图。 此方法执行以下操作:
- 调用 CoCreateInstance 以创建 Filter Graph 管理器的新实例。
- 查询 IMediaControl 和 IMediaEventEx 接口的 Filter Graph 管理器。
- 调用 IMediaEventEx::SetNotifyWindow 来设置事件通知。 有关详细信息,请参阅 DirectShow 中的事件通知。
HRESULT DShowPlayer::InitializeGraph()
{
TearDownGraph();
// Create the Filter Graph Manager.
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL,
CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&m_pGraph));
if (FAILED(hr))
{
goto done;
}
hr = m_pGraph->QueryInterface(IID_PPV_ARGS(&m_pControl));
if (FAILED(hr))
{
goto done;
}
hr = m_pGraph->QueryInterface(IID_PPV_ARGS(&m_pEvent));
if (FAILED(hr))
{
goto done;
}
// Set up event notification.
hr = m_pEvent->SetNotifyWindow((OAHWND)m_hwnd, WM_GRAPH_EVENT, NULL);
if (FAILED(hr))
{
goto done;
}
m_state = STATE_STOPPED;
done:
return hr;
}
呈现流
下一步是将源筛选器连接到一个或多个呈现器筛选器。
方法 DShowPlayer::RenderStreams
执行以下步骤。
- 查询 IFilterGraph2 接口的 Filter Graph 管理器。
- 将视频呈现器筛选器添加到筛选器图。
- 将 DirectSound 呈现器筛选器 添加到筛选器图,以支持音频播放。 有关向筛选器图添加筛选器的详细信息,请参阅 添加按 CLSID 筛选。
- 枚举源筛选器上的输出引脚。 有关枚举引脚的详细信息,请参阅 枚举引脚。
- 对于每个图钉,调用 IFilterGraph2::RenderEx 方法。 此方法将输出引脚连接到呈现器筛选器,并根据需要添加中间筛选器 (,例如解码器) 。
- 调用
CVideoRenderer::FinalizeGraph
以完成视频呈现器初始化。 - 如果该筛选器未连接到另一个筛选器,则删除 DirectSound 呈现器 筛选器。 如果源文件不包含音频流,则可能会发生这种情况。
// Render the streams from a source filter.
HRESULT DShowPlayer::RenderStreams(IBaseFilter *pSource)
{
BOOL bRenderedAnyPin = FALSE;
IFilterGraph2 *pGraph2 = NULL;
IEnumPins *pEnum = NULL;
IBaseFilter *pAudioRenderer = NULL;
HRESULT hr = m_pGraph->QueryInterface(IID_PPV_ARGS(&pGraph2));
if (FAILED(hr))
{
goto done;
}
// Add the video renderer to the graph
hr = CreateVideoRenderer();
if (FAILED(hr))
{
goto done;
}
// Add the DSound Renderer to the graph.
hr = AddFilterByCLSID(m_pGraph, CLSID_DSoundRender,
&pAudioRenderer, L"Audio Renderer");
if (FAILED(hr))
{
goto done;
}
// Enumerate the pins on the source filter.
hr = pSource->EnumPins(&pEnum);
if (FAILED(hr))
{
goto done;
}
// Loop through all the pins
IPin *pPin;
while (S_OK == pEnum->Next(1, &pPin, NULL))
{
// Try to render this pin.
// It's OK if we fail some pins, if at least one pin renders.
HRESULT hr2 = pGraph2->RenderEx(pPin, AM_RENDEREX_RENDERTOEXISTINGRENDERERS, NULL);
pPin->Release();
if (SUCCEEDED(hr2))
{
bRenderedAnyPin = TRUE;
}
}
hr = m_pVideo->FinalizeGraph(m_pGraph);
if (FAILED(hr))
{
goto done;
}
// Remove the audio renderer, if not used.
BOOL bRemoved;
hr = RemoveUnconnectedRenderer(m_pGraph, pAudioRenderer, &bRemoved);
done:
SafeRelease(&pEnum);
SafeRelease(&pAudioRenderer);
SafeRelease(&pGraph2);
// If we succeeded to this point, make sure we rendered at least one
// stream.
if (SUCCEEDED(hr))
{
if (!bRenderedAnyPin)
{
hr = VFW_E_CANNOT_RENDER;
}
}
return hr;
}
下面是函数的代码 RemoveUnconnectedRenderer
,在上一个示例中使用了该代码。
HRESULT RemoveUnconnectedRenderer(IGraphBuilder *pGraph, IBaseFilter *pRenderer, BOOL *pbRemoved)
{
IPin *pPin = NULL;
*pbRemoved = FALSE;
// Look for a connected input pin on the renderer.
HRESULT hr = FindConnectedPin(pRenderer, PINDIR_INPUT, &pPin);
SafeRelease(&pPin);
// If this function succeeds, the renderer is connected, so we don't remove it.
// If it fails, it means the renderer is not connected to anything, so
// we remove it.
if (FAILED(hr))
{
hr = pGraph->RemoveFilter(pRenderer);
*pbRemoved = TRUE;
}
return hr;
}
释放筛选器图
当应用程序退出时,它必须释放筛选器图,如以下代码所示。
void DShowPlayer::TearDownGraph()
{
// Stop sending event messages
if (m_pEvent)
{
m_pEvent->SetNotifyWindow((OAHWND)NULL, NULL, NULL);
}
SafeRelease(&m_pGraph);
SafeRelease(&m_pControl);
SafeRelease(&m_pEvent);
delete m_pVideo;
m_pVideo = NULL;
m_state = STATE_NO_GRAPH;
}
下一 步:步骤 4:添加视频呈现器。
相关主题