在 DirectShow 编辑服务中选择解码器
[与此页面关联的功能 DirectShow 是旧版功能。 它已被 MediaPlayer、 IMFMediaEngine 和 Media Foundation 中的音频/视频捕获所取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能在 Media Foundation 中使用 MediaPlayer、 IMFMediaEngine 和 音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]
[此 API 不受支持,将来可能会更改或不可用。]
当 DirectShow 编辑服务 (DES) 呈现视频编辑项目时,呈现引擎会自动选择所需的解码器。 这可能会在 IRenderEngine::ConnectFrontEnd 方法中发生,或者在呈现期间动态发生。
用户可能会安装多个能够解码特定文件的解码器。 当有多个解码器可用时,DES 使用 智能连接 算法来选择解码器。
应用程序无法直接指定要使用的解码器。 但是,可以通过 IAMGraphBuilderCallback 回调接口间接选择解码器。 通过在应用程序中实现此接口,可以在图形生成过程中接收通知,并拒绝图形中的某些筛选器。
首先实现一个公开 IAMGraphBuilderCallback 接口的类:
class GraphBuilderCB : public IAMGraphBuilderCallback
{
public:
// Method declarations (not shown).
};
然后,创建 Filter Graph Manager 的实例并注册类以接收回调通知:
// Declare an instance of the callback object.
GraphBuilderCB GraphCB;
// Create the Filter Graph Manager.
CComPtr<IGraphBuilder> pGraph;
hr = pGraph.CoCreateInstance(CLSID_FilterGraph);
if (FAILED(hr))
{
// Handle error (not shown).
}
// Register to receive the callbacks.
CComQIPtr<IObjectWithSite> pSite(pGraph);
if (pSite)
{
hr = pSite->SetSite((IUnknown*)&GraphCB);
}
接下来,创建呈现引擎,并使用指向 Filter Graph Manager 的指针调用 IRenderEngine::SetFilterGraph 方法。 这可确保呈现引擎不会创建自己的 Filter Graph 管理器,而是使用为回调配置的实例。
CComPtr<IRenderEngine> pRender;
hr = pRender.CoCreateInstance(CLSID_RenderEngine);
if (FAILED(hr))
{
// Handle error (not shown).
}
hr = pRender->SetFilterGraph(pGraph);
呈现项目时,将在 Filter Graph 管理器创建新筛选器之前立即调用应用程序的 IAMGraphBuilderCallback::SelectedFilter 方法。 SelectedFilter 方法接收指向表示筛选器名字对象的 IMoniker 接口的指针。 检查名字对象,如果决定拒绝筛选器,请从 SelectedFilter 方法返回失败代码。
难点在于确定哪些名字对象表示解码器,特别是哪些名字对象表示要拒绝的解码器。 一种解决方案如下:
在呈现项目之前,请使用 IFilterMapper2::EnumMatchingFilters 方法创建注册为接受所需输入类型的筛选器列表。 对于视频或音频压缩类型,此列表应映射到一组解码器。
EnumMatchingFilters 方法返回名字对象的集合。 对于集合中的每个名字对象,获取 DisplayName 属性,如 使用筛选器映射器中所述。
存储显示名称的列表,但省略与要用于解码的筛选器匹配的显示名称。 软件筛选器的显示名称具有以下形式:
OLESTR("@device:sw:{CategoryGUID}\{FilterCLSID}");
where
CategoryGUID
是筛选器类别的 GUID,并且
FilterCLSID
是筛选器的 CLSID。 对于 DSO,格式相同,但更改为
sw
dmo
。该列表现在包含输出所需媒体类型但不是首选筛选器的每个筛选器的显示名称。
在 SelectedFilter 方法中,获取建议名字对象上的 DisplayName 属性,并针对存储列表检查该属性。 如果显示名称与列表中的条目匹配,请拒绝该筛选器。 否则,请通过返回S_OK接受它。
相关主题