WCE下添加fliter及使用filter(一)

 

转载请标明是引用于 http://blog.csdn.net/chenyujing1234

 例子代码:

http://www.rayfile.com/zh-cn/files/ee306f61-71a1-11e1-8468-0015c55db73d/

 

参考书本:

《DirectShow开发指南》

1、添加入口函数.

Filter是个基于DLL的进程内的com组件,所以一般的Filter都要实现下面几个入口函数

在cim_capture.def中添加

; cim_capture.def : Filter exports

LIBRARY     "cim_capture.dll"

EXPORTS             DllMain                 PRIVATE             DllCanUnloadNow         PRIVATE             DllGetClassObject       PRIVATE             DllRegisterServer       PRIVATE             DllUnregisterServer     PRIVATE


2、然后要定义这些函数的实现

其实这些工作dshow的基类里都已经替我们做好了,我们所要做的就拿来用就是了,最重要的三个函数的实现一般如下

STDAPI DllRegisterServer()
{
	return AMovieDllRegisterServer2(true);
}

STDAPI DllUnregisterServer()
{
	return AMovieDllRegisterServer2(false);
}

extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);

BOOL APIENTRY DllMain(HANDLE hModule, DWORD  dwReason, LPVOID lpReserved)
{
	return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
}

 显然

 DllCanUnloadNow         PRIVATE
DllGetClassObject       PRIVATE

dshow的基类里都已经替我们做好了

可以看到AMovieDllRegisterServer2是在dllsetup.h中定义的。

而在PC机的DX9上是在

C:\DX90SDK\Samples\C++\DirectShow\BaseClasses\dllsetup.cpp这个文件定义的

DllEntryPoint在PC的DX9是在C:\DX90SDK\Samples\C++\DirectShow\BaseClasses\dllentry.cpp定义;


3、添加头文件和lib

首先包含

#include <Streams.h>

如果是Release版本则包含

strmbase.lib strmiids.lib Msvcrt.lib Winmm.lib

如果是Debug版本则包含

strmbasd.lib strmiids.lib Msvcrtd.lib Winmm.lib

 

在PC的DX9环境下是

c:\DX90SDK\Samples\C++\DirectShow\BaseClasses\debug\strmbasd.lib msvcrtd.lib quartz.lib vfw32.lib winmm.lib kernel32.lib advapi32.lib version.lib largeint.lib user32.lib gdi32.lib comctl32.lib ole32.lib olepro32.lib oleaut32.lib uuid.lib

4、实现Filter的com接口

Filter是如何实现com接口的,它和其他的com实现方式的不同。

我们知道一个Filter是一个com组件,所以它com特性的实现其实在其基类中实现的,比如IUnknown接口,我们直接从基类派生出我们的Filter后,它就支持com接口了,它就是一个com组件了。

所有的com组件为了实现二进制的封装,所以连创建的接口都封装了,因此每个com对象都有个类对象(也叫类厂对象,本身也是com对象,用来创建com组件)来创建com组件。

下面温习一下com组件的创建过程,其中涉及到几个函数

1 当客户端要创建一个com组件时,它通过底层的COM API函数 CoGetClassObject()使用SCM的服务,这个函数请SCM把一个指针绑定到客户端请求的com组件的类对象上,

其实在CoGetClassObject()里它装载了该DLL的库,通过该dll的导出函数DllGetClassObject();DllGetClassObject根据客户端提供的com组件CLASSID,返回该com组件类对象的指针。下面com组件的创建就是SCM无关了。

2 客户端利用组件的类对象(类厂对象)的IClassFactory::CreateInstance方法创建com组件。

Filter在这里使用了一个类厂模板类来当作Filter的类厂对象。

下面看看类厂在DShow是怎么工作的。

类厂对象也是一个com组件。本来DllGetClassObject是我们自己写的一个函数,在directshow里已经完成了,我们不用自己来完成它了。它的功能就是来寻找这个DLL中的类厂对象,看是否有符合客户端请求的类厂对象。

DLL里声明了一个全局的类厂模板数组,当DllGetClassObject请求类厂对象的时候,它就搜索这个数组,看是否有和CLSID匹配的类厂对象。当它找到一个匹配的CLSID,它就创建一个类厂对象,然后讲类厂指针返回给CoGetClassObject,然后客户端可以根据返回去的类厂指针,调用IClassFactory::CreateInstance方法创建组件,类厂就根据数组里定义的方法创建com组件。

factory template包含下列变量:

const WCHAR *              m_Name;                // Name
const CLSID *              m_ClsID;               // CLSID
LPFNNewCOMObject           m_lpfnNew;             // Function to  //create an instance   of the component
LPFNInitRoutine      m_lpfnInit; // Initialization function (optional)
const AMOVIESETUP_FILTER * m_pAMovieSetup_Filter; // Set-up information (for filters)

其中的两个函数指针m_lpfnNew and m_lpfnInit使用下面的定义

typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(LPUNKNOWN pUnkOuter, HRESULT *phr);
typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid);

 

你可以参照如下的方式定义你的类厂对象

以下是我们com组件创建函数
CUnknown * WINAPI CMyFilter::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr) 
{  
	CMyFilter *pFilter = new CMyFilter( pUnk, pHr);
	if (pFilter== NULL) 
	{
		*pHr = E_OUTOFMEMORY;
	}
	return pFilter;
}
你可以声明自己的类厂数组如下:如果在这个com组件中你要支持多个filter,你可以在这个数组中继续添加就是了。
CFactoryTemplate g_Templates[] = 
{
	{ 
		L"my filter",                // 名字
		CMyFilter::m_sudFilter.clsID,             // CLSID
		CMyFilter::CreateInstance,   // 创建一个实例的方法
		NULL,                        // 初始化函数
		&CMyFilter::m_sudFilter                   // 设置数据、信息 (for filters)
	}

};

int g_cTemplates = NUMELMS(g_Templates);


5、如何实现自己的Filter

1 选择一个基类,声明自己的类

创建filter很简单,你只要根据自己的需要选择不同的基类Filter派生出自己的Filter,它就已经支持com特性了。 

从逻辑上考虑,在写Filter之前,选择一个合适的Filter基类是至关重要的。为此,你必须对几个Filter的基类有相当的了解。在实际应用中,Filter的基类并不总是选择CBaseFilter的。相反,因为我们绝大部分写的都是中间的传输Filter(Transform Filter),所以基类选择CTransformFilter和CTransInPlaceFilter的居多如果我们写的是源Filter,我们可以选择CSource作为基类;如果是Renderer Filter,可以选择CBaseRenderer或CBaseVideoRenderer等
   总之,选择好Filter的基类是很重要的。当然,选择Filter的基类也是很灵活的,没有绝对的标准。能够通过CTransformFilter实现的Filter当然也能从CBaseFilter一步一步实现。下面,笔者就从本人的实际经验出发,对Filter基类的选择提出几点建议供大家参考。

首先,你必须明确这个Filter要完成什么样的功能,即要对Filter项目进行需求分析。请尽量保持Filter实现的功能的单一性。如果必要的话,你可以将需求分解,由两个(或者更多的)功能单一的Filter去实现总的功能需求。

其次,你应该明确这个Filter大致在整个Filter Graph的位置,这个Filter的输入是什么数据,输出是什么数据,有几个输入Pin、几个输出Pin等等。你可以画出这个Filter的草图。弄清这一点十分重要,这将直接决定你使用哪种“模型”的Filter。比如,如果Filter仅有一个输入Pin和一个输出Pin,而且一进一处的媒体类型相同,则一般采用CTransInPlaceFilter作为Filter的基类;如果媒体类型不一样,则一般选择CTransformFilter作为基类。
  再者,考虑一些数据传输、处理的特殊性要求。比如Filter的输入和输出的Sample并不是一一对应的,这就一般要在输入Pin上进行数据的缓存,而在输出Pin上使用专门的线程进行数据处理。这种情况下,Filter的基类选择CSource为宜(虽然这个Filter并不是源Filter)。
当Filter的基类选定了之后,Pin的基类也就相应选定了。接下去,就是Filter和Pin上的代码实现了。有一点需要注意的是,从软件设计的角度上来说,应该将你的逻辑类代码同Filter的代码分开

下面,我们一起来看一下输入Pin的实现。你需要实现基类所有的纯虚函数,比如CheckMediaType等。在CheckMediaType内,你可以对媒体类型进行检验,看是否是你期望的那种。因为大部分Filter采用的是推模式传输数据,所以在输入Pin上一般都实现了Receive方法。有的基类里面已经实现了Receive,而在Filter类上留一个纯虚函数供用户重载进行数据处理。这种情况下一般是无需重载Receive方法的,除非基类的实现不符合你的实际要求。而如果你重载了Receive方法,一般会同时重载以下三个函数EndOfStream、BeginFlush和EndFlush。我们再来看一下输出Pin的实现。一般情况下,你要实现基类所有的纯虚函数,除了CheckMediaType进行媒体类型检查外,一般还有DecideBufferSize以决定Sample使用内存的大小,GetMediaType提供支持的媒体类型。

最后,我们看一下Filter类的实现。首先当然也要实现基类的所有纯虚函数。除此之外,Filter还要实现CreateInstance以提供COM的入口,实现NonDelegatingQueryInterface以暴露支持的接口。如果我们创建了自定义的输入、输出Pin,一般我们还要重载GetPinCount和GetPin两个函数。

我的Filter类的定义如下:

class DECLSPEC_UUID("55D36CED-7FC1-47ea-8AAE-C4C82F4EB656") 
CMyFilter 
: public CBaseFilter
{
public:
	static CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT *phr);



	// filter registration table
	static const AMOVIESETUP_MEDIATYPE m_sudType;
	static const AMOVIESETUP_PIN m_sudPin;
	static const AMOVIESETUP_FILTER m_sudFilter;


	// CBaseFilter methods
	int GetPinCount();
	CBasePin *GetPin(int n);
	
private:
	CMyFilter(LPUNKNOWN lpunk, HRESULT *phr);
	~CMyFilter();	

private:
	CCritSec m_csFilter;
};

注:因为基类是一个纯虚的基类,所以在你的filter一定要派生一个其中的纯虚函数,否则编译器会提示你的派生类也是一个纯虚类,你在创建这个com组件对象的时候,纯虚类是没法创建对象的。


这样基本上就实现了一个filter,但是这个filter没有与之相联系的PIN。

2、 CMyFilter类的简单实现

CMyFilter::CMyFilter(LPUNKNOWN lpunk, HRESULT *phr) 
: CBaseFilter(NAME("CMyFilter"), lpunk,  &m_csFilter, *m_sudFilter.clsID)
{
	
}


CMyFilter::~CMyFilter()
{

} 


CBasePin * CMyFilter::GetPin(int n) 
{
	return NULL;
}
int CMyFilter::GetPinCount() 
{
	return 0;
}

=================================================================

终于完成了设计,大家编译发现报错了



解决方法:

工程属性->C/C++->语言->将wchar_t 视为内置类型 设为 否

 

当布置到设备时选择注册,那么马上会进入到

CMyFilter::CMyFilter(LPUNKNOWN lpunk, HRESULT *phr)
: CBaseFilter(NAME("CMyFilter"), lpunk,  &m_csFilter, *m_sudFilter.clsID)
{

}

关于strmbase.lib的生成可以参考我博客中转载别人的文章

关于Windows Mobile手机视听电脑视音频的程序实现(一)

如何使用请参考我的第二篇文章

<<WCE下添加fliter及使用filter(二)>> 

http://blog.csdn.net/chenyujing1234/article/details/7369763  

 

 

你可能感兴趣的:(WCE下添加fliter及使用filter(一))