Chinaunix首页 | 论坛 | 博客
  • 博客访问: 190668
  • 博文数量: 20
  • 博客积分: 1400
  • 博客等级: 上尉
  • 技术积分: 290
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-16 13:08
文章分类

全部博文(20)

文章存档

2010年(1)

2009年(10)

2008年(9)

我的朋友

分类: C/C++

2008-04-22 17:45:25

 
当我们自己在开发Filter时,通常需要了解一下我们自开发的Filter是在何时、怎么样被创建出来的!
 
其实,写Filter程序时,我们只要按照固定的格式定义以下几个结构体和类工厂模板,这样DirectShow就能够自动帮我们创建出Filter组件了!
(Note:根据自己的实际要求填写相应的部分,下面的代码来自DirectShow文档)
 
static const WCHAR g_wszName[] = L"Some Filter";

AMOVIESETUP_MEDIATYPE sudMediaTypes[] = {
    { &MEDIATYPE_Video, &MEDIASUBTYPE_RGB24 },
    { &MEDIATYPE_Video, &MEDIASUBTYPE_RGB32 },
};

AMOVIESETUP_PIN sudOutputPin = {
    L"",            // Obsolete, not used.
    FALSE,          // Is this pin rendered?
    TRUE,           // Is it an output pin?
    FALSE,          // Can the filter create zero instances?
    FALSE,          // Does the filter create multiple instances?
    &GUID_NULL,     // Obsolete.
    NULL,           // Obsolete.
    2,              // Number of media types.
    sudMediaTypes   // Pointer to media types.
};

AMOVIESETUP_FILTER sudFilterReg = {
    &CLSID_SomeFilter,      // Filter CLSID.
    g_wszName,              // Filter name.
    MERIT_NORMAL,           // Merit.
    1,                      // Number of pin types.
    &sudOutputPin           // Pointer to pin information.
};
CFactoryTemplate g_Templates[] = {
    {
        g_wszName,                      // Name.
        &CLSID_SomeFilter,              // CLSID.
        CSomeFilter::CreateInstance,    // Creation function.
        NULL,
        &sudFilterReg                   // Pointer to filter information.
    }
};
int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);

了解一下:
typedef struct
{
    const CLSID *clsMajorType;
    const CLSID *clsMinorType;
} REGPINTYPES;

typedef REGPINTYPES AMOVIESETUP_MEDIATYPE, 
    * PAMOVIESETUP_MEDIATYPE, 
    * LPAMOVIESETUP_MEDIATYPE;
typedef struct {
    LPWSTR            strName;
    BOOL              bRendered;
    BOOL              bOutput;
    BOOL              bZero;
    BOOL              bMany;
    const CLSID       *clsConnectsToFilter;
    const WCHAR       *strConnectsToPin;
    UINT              nMediaTypes;
    const REGPINTYPES *lpMediaType;
} REGFILTERPINS;

typedef REGFILTERPINS AMOVIESETUP_PIN, 
    * PAMOVIESETUP_PIN, 
    * LPAMOVIESETUP_PIN;
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;

原因在于DirectShow的BaseClasses已经为我们设计好了Filter的架构,在基类中已经实现了DllGetClassObject,我们知道它是用来创建类工厂的,OK,来看一下其实现:
//called by COM to get the class factory object for a given class
STDAPI
DllGetClassObject(
    REFCLSID rClsID, //客户端传进来的,来自于CoCreateInstance或CoDllGetClassObject
    REFIID riid,
    void **pv)
{
    if (!(riid == IID_IUnknown) && !(riid == IID_IClassFactory)) {
            return E_NOINTERFACE;
    }
    // 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;
}

从上面的代码可以清楚地看到,当在类工厂模板中找到客户端传进来的CLSID时就创建对应的类工厂组件。当类工厂创建后,客户就可以调用类工厂的CreateInstance来创建我们的自己组件,即Filter。看一下CreateInstance的具体实现。

STDMETHODIMP
CClassFactory::CreateInstance(
    LPUNKNOWN pUnkOuter, // 客户传进来,一般为NULL,非聚合
    REFIID riid,
    void **pv)
{
    CheckPointer(pv,E_POINTER)
    ValidateReadWritePtr(pv,sizeof(void *));

    /* Enforce the normal OLE rules regarding interfaces and delegation */

    if (pUnkOuter != NULL) {
        if (IsEqualIID(riid,IID_IUnknown) == FALSE) {
            return ResultFromScode(E_NOINTERFACE);
        }
    }

    /* Create the new object through the derived class's create function */

    HRESULT hr = NOERROR; //和pUnkOuter一起传给我们自己实现的CreateInstance
    CUnknown *pObj = m_pTemplate->CreateInstance(pUnkOuter, &hr);

    if (pObj == NULL) {
       if (SUCCEEDED(hr)) {
       hr = E_OUTOFMEMORY;
       }
    return hr;
    }

    /* Delete the object if we got a construction error */

    if (FAILED(hr)) {
        delete pObj;
        return hr;
    }

    /* Get a reference counted interface on the object */

    /* We wrap the non-delegating QI with NDAddRef & NDRelease. */
    /* This protects any outer object from being prematurely    */
    /* released by an inner object that may have to be created  */
    /* in order to supply the requested interface.              */
    pObj->NonDelegatingAddRef();
    hr = pObj->NonDelegatingQueryInterface(riid, pv);
    pObj->NonDelegatingRelease();
    /* Note that if NonDelegatingQueryInterface fails, it will  */
    /* not increment the ref count, so the NonDelegatingRelease */
    /* will drop the ref back to zero and the object will "self-*/
    /* destruct".  Hence we don't need additional tidy-up code  */
    /* to cope with NonDelegatingQueryInterface failing.        */

    if (SUCCEEDED(hr)) {
        ASSERT(*pv);
    }

    return hr;
}

m_pTemplate->CreateInstance(pUnkOuter, &hr);//这里实际上调用了我们自己Filter组件类中的CreateInstance,因为这里的m_pTemplate中保存了我们自己定义的类模板(在CClassFactory的构造函数中)。

好了,再看一下CFactoryTemplate的定义,其实就是一个结构体,到了这里也就知道上面的g_Templates为什么要那样写了!注意这里的m_lpfnNew,它是一个函数指针,对应我们自己写的CreateInstance,这是Filter能够被创建的关键之处.

/* A function that can create a new COM object */

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);

class CFactoryTemplate {

public:

    const WCHAR *              m_Name;
    const CLSID *              m_ClsID;
    LPFNNewCOMObject           m_lpfnNew;
    LPFNInitRoutine            m_lpfnInit; //用于DLL加载时初始化的,一般不用
    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);
    };
};

OK,有了上面的这些基础,我们就可以清楚自己开发的Filter是如何被创建的。


总结一下Filter创建的大概过程

客户端在将Filter加入到FilterGraph之前,必须先创建对应某个CLSID的Filter组件(只有Filter被创建了,才能够通过AddFilter将其加入到FilterGraph中,继续实现Pin的连接等过程),客户可以通过CoCreateInstance创建Filter,而在CoCreateInstance会调用CoDllGetClassObject,CoDllGetClassObject又会调用DirectShow基类中DllGetClassObject来创建对应这个CLSID的类工厂,类工厂创建好了之后返回到CoDllGetClassObject中,在这里继续查询刚才创建的类工厂组件的IClassFactory接口,获得这个接口指针后就可以利用这个接口指针来调用类工厂中的CreateInstance,这样可以跳转至我们自己实现的CreateInstance中实现自己开发的Filter能够被创建。


阅读(3284) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~