步骤 6. 添加对 COM 的支持

[与此页面关联的功能 DirectShow 是旧版功能。 它已被 MediaPlayerIMFMediaEngineMedia Foundation 中的音频/视频捕获所取代。 这些功能已针对Windows 10和Windows 11进行了优化。 Microsoft 强烈建议新代码尽可能在 Media Foundation 中使用 MediaPlayerIMFMediaEngine音频/视频捕获 ,而不是 DirectShow。 如果可能,Microsoft 建议重写使用旧 API 的现有代码以使用新 API。]

这是教程 编写转换筛选器的步骤 6。

最后一步是添加对 COM 的支持。

引用计数

无需实现 IUnknown::AddRefIUnknown::Release。 所有筛选器和引脚类都派生自处理引用计数的 CUnknown

QueryInterface

所有筛选器和引脚类都为其继承的任何 COM 接口实现 IUnknown::QueryInterface 。 例如, CTransformFilter 通过 CBaseFilter) 继承 IBaseFilter (。 如果筛选器未公开任何其他接口,则无需执行任何其他操作。

若要公开其他接口,请重写 CUnknown::NonDelegatingQueryInterface 方法。 例如,假设筛选器实现名为 IMyCustomInterface 的自定义接口。 若要向客户端公开此接口,请执行以下操作:

以下代码演示了这些步骤:

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_TemplatesCFactoryTemplate 类实例的全局数组。 每个 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 将其添加到筛选器图中。 但在某些情况下,可能需要在注册表中提供有关筛选器的其他信息。 此信息执行以下操作:

以下示例在视频压缩器类别中注册 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;
}

智能连接

编写 DirectShow 筛选器

写入转换筛选器