步骤 6. 添加对 COM 的支持
[与此页面关联的功能 DirectShow 是旧版功能。 它已被 MediaPlayer、 IMFMediaEngine 和 Media Foundation 中的音频/视频捕获所取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能在 Media Foundation 中使用 MediaPlayer、 IMFMediaEngine 和 音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]
这是教程 编写转换筛选器的步骤 6。
最后一步是添加对 COM 的支持。
引用计数
无需实现 IUnknown::AddRef 或 IUnknown::Release。 所有筛选器和引脚类都派生自处理引用计数的 CUnknown。
QueryInterface
所有筛选器和引脚类都为其继承的任何 COM 接口实现 IUnknown::QueryInterface 。 例如, CTransformFilter 通过 CBaseFilter) 继承 IBaseFilter (。 如果筛选器未公开任何其他接口,则无需执行任何其他操作。
若要公开其他接口,请重写 CUnknown::NonDelegatingQueryInterface 方法。 例如,假设筛选器实现名为 IMyCustomInterface 的自定义接口。 若要向客户端公开此接口,请执行以下操作:
- 从该接口派生筛选器类。
- 将 DECLARE_IUNKNOWN 宏放入公共声明部分。
- 重写 NonDelegatingQueryInterface 以检查接口的 IID 并返回指向筛选器的指针。
以下代码演示了这些步骤:
CMyFilter : public CBaseFilter, public IMyCustomInterface
{
public:
DECLARE_IUNKNOWN
STDMETHODIMP NonDelegatingQueryInterface(REFIID iid, void **ppv);
};
STDMETHODIMP CMyFilter::NonDelegatingQueryInterface(REFIID iid, void **ppv)
{
if (riid == IID_IMyCustomInterface) {
return GetInterface(static_cast<IMyCustomInterface*>(this), ppv);
}
return CBaseFilter::NonDelegatingQueryInterface(riid,ppv);
}
有关详细信息,请参阅 如何实现 IUnknown。
对象创建
如果计划将筛选器打包到 DLL 中并使其可供其他客户端使用,则必须支持 CoCreateInstance 和其他相关的 COM 函数。 基类库实现其中的大部分操作:只需提供有关筛选器的一些信息。 本部分简要概述了要执行的操作。 有关详细信息,请参阅 如何创建 DirectShow 筛选器 DLL。
首先,编写一个静态类方法,该方法返回筛选器的新实例。 可以将此方法命名为任何你喜欢的名称,但签名必须与以下示例中显示的签名匹配:
CUnknown * WINAPI CRleFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)
{
CRleFilter *pFilter = new CRleFilter();
if (pFilter== NULL)
{
*pHr = E_OUTOFMEMORY;
}
return pFilter;
}
接下来,声明名为 g_Templates 的 CFactoryTemplate 类实例的全局数组。 每个 CFactoryTemplate 类都包含一个筛选器的注册表信息。 多个筛选器可以驻留在单个 DLL 中;只需包含其他 CFactoryTemplate 条目。 还可以声明其他 COM 对象,例如属性页。
static WCHAR g_wszName[] = L"My RLE Encoder";
CFactoryTemplate g_Templates[] =
{
{
g_wszName,
&CLSID_RLEFilter,
CRleFilter::CreateInstance,
NULL,
NULL
}
};
定义一个名为 g_cTemplates 其值等于 g_Templates 数组长度的全局整数:
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);
最后,实现 DLL 注册函数。 以下示例演示了这些函数的最小实现:
STDAPI DllRegisterServer()
{
return AMovieDllRegisterServer2( TRUE );
}
STDAPI DllUnregisterServer()
{
return AMovieDllRegisterServer2( FALSE );
}
筛选注册表项
前面的示例演示如何为 COM 注册筛选器的 CLSID。 对于许多筛选器,这已足够。 然后,客户端应使用 CoCreateInstance 创建筛选器,并通过调用 IFilterGraph::AddFilter 将其添加到筛选器图中。 但在某些情况下,可能需要在注册表中提供有关筛选器的其他信息。 此信息执行以下操作:
- 使客户端能够使用筛选器 映射器 或 系统设备枚举器发现筛选器。
- 使 Filter Graph 管理器能够在自动图形生成期间发现筛选器。
以下示例在视频压缩器类别中注册 RLE 编码器筛选器。 有关详细信息,请参阅 如何注册 DirectShow 筛选器。 请务必阅读注册 筛选器指南部分,其中介绍了筛选器注册的建议做法。
// Declare media type information.
FOURCCMap fccMap = FCC('MRLE');
REGPINTYPES sudInputTypes = { &MEDIATYPE_Video, &GUID_NULL };
REGPINTYPES sudOutputTypes = { &MEDIATYPE_Video, (GUID*)&fccMap };
// Declare pin information.
REGFILTERPINS sudPinReg[] = {
// Input pin.
{ 0, FALSE, // Rendered?
FALSE, // Output?
FALSE, // Zero?
FALSE, // Many?
0, 0,
1, &sudInputTypes // Media types.
},
// Output pin.
{ 0, FALSE, // Rendered?
TRUE, // Output?
FALSE, // Zero?
FALSE, // Many?
0, 0,
1, &sudOutputTypes // Media types.
}
};
// Declare filter information.
REGFILTER2 rf2FilterReg = {
1, // Version number.
MERIT_DO_NOT_USE, // Merit.
2, // Number of pins.
sudPinReg // Pointer to pin information.
};
STDAPI DllRegisterServer(void)
{
HRESULT hr = AMovieDllRegisterServer2(TRUE);
if (FAILED(hr))
{
return hr;
}
IFilterMapper2 *pFM2 = NULL;
hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
IID_IFilterMapper2, (void **)&pFM2);
if (SUCCEEDED(hr))
{
hr = pFM2->RegisterFilter(
CLSID_RLEFilter, // Filter CLSID.
g_wszName, // Filter name.
NULL, // Device moniker.
&CLSID_VideoCompressorCategory, // Video compressor category.
g_wszName, // Instance data.
&rf2FilterReg // Filter information.
);
pFM2->Release();
}
return hr;
}
STDAPI DllUnregisterServer()
{
HRESULT hr = AMovieDllRegisterServer2(FALSE);
if (FAILED(hr))
{
return hr;
}
IFilterMapper2 *pFM2 = NULL;
hr = CoCreateInstance(CLSID_FilterMapper2, NULL, CLSCTX_INPROC_SERVER,
IID_IFilterMapper2, (void **)&pFM2);
if (SUCCEEDED(hr))
{
hr = pFM2->UnregisterFilter(&CLSID_VideoCompressorCategory,
g_wszName, CLSID_RLEFilter);
pFM2->Release();
}
return hr;
}
此外,筛选器不必打包在 DLL 中。 在某些情况下,可以编写仅用于特定应用程序的专用筛选器。 在这种情况下,可以直接在应用程序中编译筛选器类,并使用 new
运算符创建它,如以下示例所示:
#include "MyFilter.h" // Header file that declares the filter class.
// Compile and link MyFilter.cpp.
int main()
{
IBaseFilter *pFilter = 0;
{
// Scope to hide pF.
CMyFilter* pF = new MyFilter();
if (!pF)
{
printf("Could not create MyFilter.\n");
return 1;
}
pF->QueryInterface(IID_IBaseFilter,
reinterpret_cast<void**>(&pFilter));
}
/* Now use pFilter as normal. */
pFilter->Release(); // Deletes the filter.
return 0;
}
相关主题