使用捕获图形生成器生成图形
[与此页面关联的功能 DirectShow 是一项旧功能。 它已被 MediaPlayer、 IMFMediaEngine 和 媒体基金会中的音频/视频捕获取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能使用 MediaPlayer、 IMFMediaEngine 和 Media Foundation 中的音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]
尽管具有名称,但捕获图形生成器对于生成多种类型的自定义筛选器图非常有用,而不仅仅是捕获图。 本文简要概述了如何使用此对象。
捕获图形生成器公开 ICaptureGraphBuilder2 接口。 首先调用 CoCreateInstance 以创建捕获图形生成器和筛选器关系图管理器。 然后,通过使用指向筛选器关系图管理器的指针调用 ICaptureGraphBuilder2::SetFiltergraph 来初始化捕获图形生成器,如下所示:
IGraphBuilder *pGraph = NULL;
ICaptureGraphBuilder2 *pBuilder = NULL;
// Create the Filter Graph Manager.
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL,
CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph);
if (SUCCEEDED(hr))
{
// Create the Capture Graph Builder.
hr = CoCreateInstance(CLSID_CaptureGraphBuilder2, NULL,
CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2,
(void **)&pBuilder);
if (SUCCEEDED(hr))
{
pBuilder->SetFiltergraph(pGraph);
}
};
连接筛选器
ICaptureGraphBuilder2::RenderStream 方法将链中的两个或三个筛选器连接在一起。 通常,当每个筛选器没有多个相同类型的输入引脚或输出引脚时,该方法最有效。 此讨论首先忽略 RenderStream 的前两个参数,并专注于最后三个参数。 第三个参数是 IUnknown 指针,它可以将筛选器 (指定为 IBaseFilter 接口指针) 或输出引脚 (指定为 IPin 接口指针) 。 第四个和第五个参数指定 IBaseFilter 指针。 RenderStream 方法连接链中的所有三个筛选器。 例如,假设 A、 B 和 C 是筛选器。 现在假设每个筛选器只有一个输入引脚和一个输出引脚。 以下调用将 A 连接到 B,然后将 B 连接到 C:
- 'RenderStream (NULL, NULL, A, B, C) '
所有连接都是“智能的”,这意味着会根据需要向图形添加其他筛选器。 有关详细信息,请参阅 智能连接。 若要仅连接两个筛选器,请将中间值设置为 NULL。 例如,此调用将 A 连接到 C:
- 'RenderStream (NULL, NULL, A, NULL, C) '
可以通过调用 方法两次来创建更长的链:
- 'RenderStream (NULL, NULL, A, B, C) ' 'RenderStream (NULL, NULL, C, D, E) '
如果最后一个参数为 NULL,该方法会自动查找默认呈现器。 它将 视频呈现器 用于视频,将 DirectSound 呈现器 用于音频。 因此:
- 'RenderStream (NULL, NULL, A, NULL, NULL) '
等效于
- 'RenderStream (NULL, NULL, A, NULL, R) '
其中 R 是适当的呈现器。 但是,若要连接视频混合呈现器筛选器而不是视频呈现器,必须显式指定它。
如果在第三个参数中指定筛选器而不是引脚,则可能需要指示应将哪个输出引脚用于连接。 这就是方法的前两个参数的用途。 第一个参数仅适用于捕获筛选器。 它指定指示引脚类别的 GUID。 有关类别的完整列表,请参阅 固定属性集。 其中两个类别对所有捕获筛选器都有效:
- PIN_CATEGORY_CAPTURE
- PIN_CATEGORY_PREVIEW
如果捕获筛选器未为捕获和预览提供单独的引脚, RenderStream 方法将插入 智能 Tee 筛选器,该筛选器将流拆分为捕获流和预览流。 从应用程序的角度来看,只需将所有捕获筛选器视为具有单独的引脚,并忽略图形的基础拓扑。
对于文件捕获,请将捕获引脚连接到复用筛选器。 对于实时预览,请将预览图钉连接到呈现器。 如果切换这两个类别,图形可能会在文件捕获期间丢弃过多的帧数;但如果图形连接正确,它会根据需要删除预览帧,以保持捕获流的吞吐量。
以下示例演示如何连接这两个流:
// Capture to file:
pBuilder->RenderStream(&PIN_CATEGORY_CAPTURE, NULL, pCapFilter, NULL, pMux);
// Preview:
pBuilder->RenderStream(&PIN_CATEGORY_PREVIEW, NULL, pCapFilter, NULL, NULL);
某些捕获筛选器还支持PIN_CATEGORY_VBI指示的隐藏式字幕。 若要捕获文件的隐藏式字幕,请将此类别呈现到复用器筛选器。 若要在预览窗口中查看隐藏式字幕,请连接到呈现器:
// Capture to file:
pBuilder->RenderStream(&PIN_CATEGORY_VBI, NULL, pCapFilter, NULL, pMux);
// Preview on screen:
pBuilder->RenderStream(&PIN_CATEGORY_VBI, NULL, pCapFilter, NULL, NULL);
RenderStream 的第二个参数标识媒体类型,通常为下列类型之一:
- MEDIATYPE_Audio
- MEDIATYPE_Video
- MEDIATYPE_Interleaved (DV)
每当筛选器的输出引脚支持首选媒体类型的枚举时,都可以使用此参数。 对于文件源,捕获图形生成器会根据需要自动添加分析程序筛选器,然后在分析器上查询媒体类型。 (有关示例,请参阅 重新压缩 AVI File.) 此外,如果链中的最后一个筛选器具有多个输入引脚,该方法将尝试枚举其媒体类型。 但是,并非所有筛选器都支持此功能。
在筛选器和引脚上查找接口
生成图形后,通常需要在图中查找筛选器和引脚公开的各种接口。 例如,捕获筛选器可能会公开 IAMDroppedFrames 接口,而筛选器的输出引脚可能会公开 IAMStreamConfig 接口。
查找接口的最简单方法是使用 ICaptureGraphBuilder2::FindInterface 方法。 此方法遍查图形 (筛选器和固定) ,直到找到所需的接口。 可以指定搜索的起点,并且可以将搜索限制为从起点上游或下游筛选。
以下示例在视频预览引脚上搜索 IAMStreamConfig 接口:
IAMStreamConfig *pConfig = NULL;
HRESULT hr = pBuild->FindInterface(
&PIN_CATEGORY_PREVIEW,
&MEDIATYPE_Video,
pVCap,
IID_IAMStreamConfig,
(void**)&pConfig
);
if (SUCCESSFUL(hr))
{
/* ... */
pConfig->Release();
}
注意
在 筛选器或固定上查找接口 主题演示了使用 IGraphBuilder 接口而不是 ICaptureGraphBuilder2 的替代方法。 使用哪种方法取决于应用程序。 如果应用程序已使用 ICaptureGraphBuilder2 生成图形,则 ICaptureGraphBuilder2::FindInterface 是一个很好的方法。 否则,请考虑使用 IGraphBuilder 方法。
查找图钉
不太常见的情况是,可能需要在筛选器上查找单个引脚,但在大多数情况下 ,RenderStream 和 FindInterface 方法将为你省去麻烦。 如果需要在筛选器上查找特定引脚, ICaptureGraphBuilder2::FindPin 帮助程序方法非常有用。 指定类别、媒体类型 (视频或音频) 、方向以及引脚是否必须未连接。
例如,以下代码在捕获筛选器上搜索未连接的视频预览引脚:
IPin *pPin = NULL;
hr = pBuild->FindPin(
pCap, // Pointer to the filter to search.
PINDIR_OUTPUT, // Search for an output pin.
&PIN_CATEGORY_PREVIEW, // Search for a preview pin.
&MEDIATYPE_Video, // Search for a video pin.
TRUE, // The pin must be unconnected.
0, // Return the first matching pin (index 0).
&pPin); // This variable receives the IPin pointer.
if (SUCCESSFUL(hr))
{
/* ... */
pPin->Release();
}
相关主题