018 DirectShow 学习(一) COM实现部分和部分辅助源码浅读

Post date: 2015/4/10 上午 02:24:57

1. BaseClasses中实现COM的部分源代码分析[combase.h/combase.cpp]

o class CBaseObject是BaseClasses中的基类,它只维护一个m_cObjects的计数信息。同时它只支持输入名称的Constructor。

o CUnknown是实现了COM的基类,它从INonDelegationUnknown接口继承支持Aggregation。同时它使用Member作为Delegation Unknown接口:

const LPUNKNOWN m_pUnknown;

同时它维护了COM的Reference Count - volatile LONG m_cRef;

它的Constructor为:

CUnknown(const TCHAR *pName, LPUNKNOWN pUnk);

CUnknown(TCHAR *pName, LPUNKNOWN pUnk,HRESULT *phr);

当然Unicode版本还要多两个支持CHAR类型的Constructor.

o 类厂模板定义(真正写DirectShow可能用不到该模板,主要是它自己的实现,下面将会见到):

class CFactoryTemplate {

public:

const WCHAR * m_Name; // 名称

const CLSID * m_ClsID; // CLSID

LPFNNewCOMObject m_lpfnNew; // 真正的Create函数

LPFNInitRoutine m_lpfnInit;

const AMOVIESETUP_FILTER * m_pAMovieSetup_Filter;

BOOL IsClassID(REFCLSID rclsid) const {return (IsEqualCLSID(*m_ClsID,rclsid));}

CUnknown *CreateInstance(LPUNKNOWN pUnk, HRESULT *phr) const

{

CheckPointer(phr,NULL);

return m_lpfnNew(pUnk, phr);

};

其中LPFNNewCOMObject和LPFNInitRoutine的宏定义如下:

typedef CUnknown *(CALLBACK *LPFNNewCOMObject)(LPUNKNOWN pUnkOuter, HRESULT *phr);

/* A function (can be NULL) which is called from the DLL entrypoint routine for each factory template:

bLoading - TRUE on DLL load, FALSE on DLL unload

rclsid - the m_ClsID of the entry*/

typedef void (CALLBACK *LPFNInitRoutine)(BOOL bLoading, const CLSID *rclsid);

AMOVIESETUP_FILTER的定义稍微复杂一点:

// Pin上的Media type

typedef REGPINTYPES

AMOVIESETUP_MEDIATYPE, * PAMOVIESETUP_MEDIATYPE, * FAR LPAMOVIESETUP_MEDIATYPE;

typedef REGFILTERPINS

AMOVIESETUP_PIN, * PAMOVIESETUP_PIN, * FAR LPAMOVIESETUP_PIN;

// 真正的Filter结构定义

typedef struct _AMOVIESETUP_FILTER {

const CLSID * clsID;

const WCHAR * strName;

DWORD dwMerit;

UINT nPins;

const AMOVIESETUP_PIN * lpPin;

} AMOVIESETUP_FILTER, * PAMOVIESETUP_FILTER, * FAR LPAMOVIESETUP_FILTER;

o 实现Delegation Unknown接口的宏:

#define DECLARE_IUNKNOWN /

STDMETHODIMP QueryInterface(REFIID riid, void **ppv) { /

return GetOwner()->QueryInterface(riid,ppv); /

}; /

STDMETHODIMP_(ULONG) AddRef() { /

return GetOwner()->AddRef(); /

}; /

STDMETHODIMP_(ULONG) Release() { /

return GetOwner()->Release(); /

};

2. DirectShow Filter实现COM自注册机理[dllsetup.h/dllsetup.cpp/dllentry.cpp]

o 作为自注册的COM组件,必须支持DllRegisterServer和DllUnregisterServer两个导出函数。而基类的实现中只是简单调用了AMovieDllRegisterServer2函数。

o AMovieDllRegisterServer2函数的伪代码,其参数Flag控制了Register和Unregister的切换。

(1)获取当前Filter自身的名称,使用了全局变量g_hInit

(2)调用RegisterAllServers(参数为Filter的名称和Flag) 注册所有 OLE servers

(3)通过取得IFilterMapper2或者IFilterMapper接口来调用AMovieSetupRegisterFilter2或者AMovieSetupRegisterFilter完成注册,注意这里使用了全局变量(必须由Filter实现)

extern int g_cTemplates;

extern CFactoryTemplate g_Templates[];

其中,RegisterAllServers调用的AMovieSetupRegisterServer和AMovieSetupUnregisterServer,这两个函数负责该Filter 注册为标准的COM组件或者注销,而AMovieSetupRegisterFilter2则把Filter注册在DirectShow的Category下,该Category支持Filter的Enum等操作。

3. 实现DllGetClassObjectDllCanUnloadNow函数的机制[dllentry.cpp]

基于BaseClasses的Filter实现一般使用了DllMain来初始化信息,而作为COM的实现,BaseClasses中已经生成了DllGetClassObject和DllCanUnloadNow函数。

o CClassFactory类

派生自IClassFactory、CBaseObject。

成员变量:

const CFactoryTemplate *const m_pTemplate;

ULONG m_cRef; // 计数信息

static int m_cLocked;

Constructor:

CClassFactory(const CFactoryTemplate *);

赋值 m_cRef(0), m_pTemplate(pTemplate)

IClassFactory接口函数:

STDMETHODIMP CreateInstance(LPUNKNOWN pUnkOuter, REFIID riid, void **pv);

{

// 标准的支持Aggregation的ClassFactory的实现方法,使用

// CUnknown *pObj = m_pTemplate->CreateInstance(pUnkOuter, &hr);

}

STDMETHODIMP LockServer(BOOL fLock);

{只是根据fLock来加减m_cLocked}

o DllMain函数分析

基于BaseClasses构建的Filter一般直接在DllMain中调用DllEntryPoint函数。

o DllEntryPoint函数分析

几个global变量:

extern CFactoryTemplate g_Templates[]; //用户实现

extern int g_cTemplates; // 用户实现

DWORD g_amPlatform;// VER_PLATFORM_WIN32_WINDOWS etc... (from GetVersionEx)

OSVERSIONINFO g_osInfo;

BOOL WINAPI DllEntryPoint(HINSTANCE hInstance, ULONG ulReason, LPVOID pv)

{

switch (ulReason)

{

case DLL_PROCESS_ATTACH:

DisableThreadLibraryCalls(hInstance); // 取消DLL_THREAD_ATTACH和DLL_THREAD_DETACH的通知消息

DbgInitialise(hInstance);// 准备Debug信息

g_amPlatform = VER_PLATFORM_WIN32_WINDOWS; // win95 assumed in case GetVersionEx fails

g_osInfo.dwOSVersionInfoSize = sizeof(g_osInfo);

if (GetVersionEx(&g_osInfo)) {g_amPlatform = g_osInfo.dwPlatformId; }

else {

DbgLog((LOG_ERROR, 1, TEXT("Failed to get the OS platform, assuming Win95")));}

g_hInst = hInstance;

DllInitClasses(TRUE);

break;

case DLL_PROCESS_DETACH:

DllInitClasses(FALSE);

break;

}

}

// Call any initialization routines

void DllInitClasses(BOOL bLoading)

{

for (i = 0; i < g_cTemplates; i++) {

const CFactoryTemplate * pT = &g_Templates[i];

if (pT->m_lpfnInit != NULL) {

(*pT->m_lpfnInit)(bLoading, pT->m_ClsID);

}

}

}

o DllGetClassObject函数:

代码比较简单,只要得出global变量g_Templates进行遍历即可。

STDAPI DllGetClassObject(REFCLSID rClsID, REFIID riid, void **pv)

{

// traverse the array of templates looking for one with this class id

for (int i = 0; i < g_cTemplates; i++) {

const CFactoryTemplate * pT = &g_Templates[i];

if (pT->IsClassID(rClsID)) {

// found a template - make a class factory based on this template

*pv = (LPVOID) (LPUNKNOWN) new CClassFactory(pT);

if (*pv == NULL) { return E_OUTOFMEMORY;}

((LPUNKNOWN)*pv)->AddRef();

return NOERROR;

}

}

return CLASS_E_CLASSNOTAVAILABLE;

}

o DllCanUnloadNow函数:

STDAPI DllCanUnloadNow()

{

if (CClassFactory::IsLocked() || CBaseObject::ObjectsActive())return S_FALSE;

else return S_OK;

}

4. DirectShow中常用结构定义[strmif.h]

o AM_MEDIA_TYPE以及PIN_DIRECTION结构定义

typedef struct _AMMediaType

{

GUID majortype;// 主类型

GUID subtype;// 子类型

BOOL bFixedSizeSamples;

BOOL bTemporalCompression;

ULONG lSampleSize;

GUID formattype;

IUnknown *pUnk;

ULONG cbFormat;

/* [size_is] */ BYTE *pbFormat;

} AM_MEDIA_TYPE;

typedef enum _PinDirection

{ PINDIR_INPUT = 0,

PINDIR_OUTPUT = PINDIR_INPUT + 1

} PIN_DIRECTION;

o 其他一些定义

#define MAX_PIN_NAME 128

#define MAX_FILTER_NAME 128

typedef LONGLONG REFERENCE_TIME;

typedef double REFTIME;

typedef DWORD_PTR HSEMAPHORE;

typedef DWORD_PTR HEVENT;

o CMediaType [mtype.h/mtype.cpp]

CMediaType类从AM_MEDIA_TYPE继承,常用函数有CreateMediaTypeDeleteMediaTypeInitMediaTypeFreeMediaType以及CreateAudioMediaType等。

5. DirectShow常用的Debug宏[wxdebug.h/wxdebug.cpp]

o 三种类型的ASSERT,分别是ASSERTEXECUTE_ASSERT以及KASSERT,EXECUTE_ASSERT与ASSERT唯一的不同是Non-Debug环境下该语句照样执行。KASSERT则不会弹出MessageBox而是将错误信息写入文件等调试设备。

o DbgLog用来显示输出信息。