(转载)闲话下visual studio 2008和directshow SDK开发filter

来源:互联网 发布:软件编辑部职能 编辑:程序博客网 时间:2024/06/05 20:58

最近在做基于directshow的render filter,乱七八糟的心得积了写,拿出来侃侃。我的配置环境是vista, visual studio 2008, windows sdk, directshow9b sdk。据说,从visual studio 2005开始,directshow就从directX中分离出来了,而部分header/library被加到了windows sdk里,而且最终逐渐会被media foundation取代。我对directshow不熟,不过摸爬滚打几天也算有点进展。开发filter之前,需要先编译出strmbase.lib和strmbasd.lib用。

编译baseclass

先下载好directshow9b sdk(不是9.0c噢,c就不带directshow sdk了),然后进入C:/DXSDK/Samples/C++/DirectShow/BaseClasses/。打开它的工程。我用的是visual studio 2008,但是baseclass只有VC6的工程文件,没办法,用2008的转换功能。转换好之后编译,通常会有大排的错误,比如winnt的missing type specifier – int assumed. Note: C++ does not support default-int ,那是因为有些什么没有返回类型,c++不像c那样默认认为是int。这样的话直接在错的地方天上int就行了。分别编译出debug_unicode和release_unicode版本待用。

添加header和library

下面正式进入filter的开发过程,首先要添加header文件路径和library文件路径,跟很多google上所述的一样:在Options -> projects and solutions -> VC++ Directories

//headers

C:/DXSDK/Include

C:/DXSDK/Samples/C++/Common/Include

C:/DXSDK/Samples/C++/DirectShow/Common

C:/DXSDK/Samples/C++/DirectShow/BaseClasses

//librarys

C:/DXSDK/Lib

C:/DXSDK/Samples/C++/DirectShow/BaseClasses/Debug_Unicode

C:/DXSDK/Samples/C++/DirectShow/BaseClasses/Debug

C:/DXSDK/Samples/C++/DirectShow/BaseClasses/Release_Unicode

C:/DXSDK/Samples/C++/DirectShow/BaseClasses/Release

注意他们都要排在windows sdk之前,不然貌似有问题。

自注册功能

filter还要有自注册功能,要声明DllRegisterServer等方法,网上有叙述不讲了。这里我还遇到一个很菜的问题:

1>strmbasd.lib(dllsetup.obj) : error LNK2001: unresolved external symbol “class CFactoryTemplate * g_Templates” (?g_Templates@@3PAVCFactoryTemplate@@A)
1>strmbasd.lib(dllentry.obj) : error LNK2001: unresolved external symbol “class CFactoryTemplate * g_Templates” (?g_Templates@@3PAVCFactoryTemplate@@A)
1>strmbasd.lib(dllsetup.obj) : error LNK2001: unresolved external symbol “int g_cTemplates” (?g_cTemplates@@3HA)
1>strmbasd.lib(dllentry.obj) : error LNK2001: unresolved external symbol “int g_cTemplates” (?g_cTemplates@@3HA)

经过无数google后才发现,原来我没有声明CFactoryTemplate g_Templates[]和int g_cTemplates。作为一个ActiveX,它们是必须的。我特意从MSDN上找了个解释ms-help://MS.VSCC.v90/MS.MSDNQTR.v90.en/directshow/htm/factorytemplatearray.htm

Factory Template Array

Suppose you are creating a DLL that contains a component named CMyComponent, which inherits from CUnknown. You must provide the following items in your DLL:

  • The initialization function, a public method that returns a new instance of CMyComponent.
  • A global array of factory templates, named g_Templates. This array contains the factory template for CMyComponent.
  • A global variable named g_cTemplates that specifies the size of the array.

The following example shows how to declare these items:

// Public method that returns a new instance.CUnknown * WINAPI CMyComponent::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr){    CMyComponent *pNewObject = new CMyComponent(NAME("My Component"), pUnk, pHr );    if (pNewObject == NULL) {        *pHr = E_OUTOFMEMORY;    }    return pNewObject;} CFactoryTemplate g_Templates[1] ={    {      L"My Component",                // Name      &CLSID_MyComponent,             // CLSID      CMyComponent::CreateInstance,   // Method to create an instance of MyComponent      NULL,                           // Initialization function      NULL                            // Set-up information (for filters)    }};int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);

The CreateInstance method calls the class constructor and returns a pointer to the new class instance. The parameter pUnk is a pointer to the aggregating IUnknown. You can simply pass this parameter to the class constructor. The parameter pHr is a pointer to an HRESULT value. The class constructor sets this to an appropriate value, but if the constructor fails, set the value to E_OUTOFMEMORY.

The NAME macro generates a string in debug builds but resolves to NULL in retail builds. It is used in this example to give the component a name that appears in debug logs but does not occupy memory in the final version.

The CreateInstance method can have any name, because the class factory refers to the function pointer in the factory template. However, g_Templates and g_cTemplates are global variables that the class factory expects to find, so they must have exactly those names.

GraphEdit测试

编译pass之后,就可以拿regsvr32程序来注册啦,然后打开GraphEdit测试,我在添加自己的filter的时候还报了个断言:

!!szObjectName   ^   !!wszObjectName
At   line   809   of   …./BaseClass/wxdebug.cpp

原来是在release版本里添加了strmbasd.lib(它是baseclass的debug版本),应该换成strmbase.lib。这样就没断言了。搞定!

原创粉丝点击