天天看点

DirectShow基础编程 最简单transform filter 编写步骤

目标编写一个transform filter,功能是对图像进行翻转。

一、选择基类

从cbasefilter派生出三个用于编写transform filter的类,分别是:ctransformfilter 、ctransinplacefilter 和cvideotransformfilter ,三个基类的区别可以看msdn的说明,我们选择ctransformfilter类。

选择好基类,我们就创建一个空的dll工程,添加三个文件,分别是:flipfilter.h、flipfilter.cpp和flipfilter.def。

二、声明filter类

在flipfilter.h中添加下列代码声明

#include <streams.h>  

extern "c" const guid clsid_flipfilter;  

class cflipfilter : public ctransformfilter  

{  

private:  

    cflipfilter(tchar *tszname, lpunknown punk, hresult *phr);  

public:  

    static cunknown * winapi createinstance(lpunknown punk, hresult *phr);  

    hresult checkinputtype(const cmediatype *mtin);  

    hresult getmediatype(int iposition, cmediatype *pmediatype);  

    hresult checktransform(const cmediatype *mtin, const cmediatype *mtout);  

    hresult decidebuffersize(imemallocator * pallocator, allocator_properties *pprop);  

    hresult transform(imediasample *pin, imediasample *pout);  

};  

三、媒体类型协商

这一步是filter的pin在连接的时候必须进行的步骤,主要重载三个函数:

1、hresult checkinputtype(const cmediatype *mtin);

hresult cflipfilter::checkinputtype(const cmediatype *mtin)  

    if (mtin->majortype != mediatype_video ||  

        mtin->subtype != mediasubtype_rgb24 ||  

        mtin->formattype != format_videoinfo )  

    {  

        return vfw_e_type_not_accepted;  

    }  

    videoinfo* pvi = (videoinfo*)mtin->format();  

    if (pvi->bmiheader.bibitcount != 24)  

    return s_ok;  

}  

ctransformfilter使用ctransforminputpin类作为输入pin,ctransforminputpin::checkmediatype(const cmediatype* pmt)中调用m_ptransformfilter->checkinputtype(pmt);因此我们可以简单的认为checkinputtype就是输入pin的checkmediatype。这样设计的是为了不需要重新定义输入pin类,只需要定义filter类,简化编写transform filter的步骤,另外的几个接口也是这样的一个设计原理。

2、hresult getmediatype(int iposition, cmediatype *pmediatype);

hresult cflipfilter::getmediatype(int iposition, cmediatype *pmediatype)  

    if (m_pinput->isconnected() == false) {  

        return e_unexpected;  

    if (iposition < 0) {  

        return e_invalidarg;  

    if (iposition > 0) {  

        return vfw_s_no_more_items;  

    checkpointer(pmediatype,e_pointer);  

    *pmediatype = m_pinput->currentmediatype();  

    return noerror;  

同样的,这个函数也是为输入pin所写。

3、hresult checktransform(const cmediatype *mtin, const cmediatype *mtout);

hresult cflipfilter::checktransform(const cmediatype *mtin, const cmediatype *mtout)  

    if (*mtin == *mtout)  

        return noerror;  

    return e_fail;  

这个函数是输出pin调用。ctransformoutputpin::checkmediatype(const cmediatype* pmtout)中调用m_ptransformfilter->checktransform。

四、协商分配器的属性,决定数据的属性

hresult cflipfilter::decidebuffersize(imemallocator * pallocator, allocator_properties *pprop)  

    checkpointer(pallocator,e_pointer);  

    checkpointer(pprop,e_pointer);  

    hresult hr = noerror;  

    pprop->cbuffers = 1;  

    pprop->cbbuffer = m_pinput->currentmediatype().getsamplesize();  

    assert(pprop->cbbuffer);  

    allocator_properties actual;  

    hr = pallocator->setproperties(pprop,&actual);  

    if (failed(hr)) {  

        return hr;  

    assert( actual.cbuffers == 1 );  

    if (pprop->cbuffers > actual.cbuffers ||  

        pprop->cbbuffer > actual.cbbuffer) {  

            return e_fail;  

这个函数由ctransformoutputpin::decidebuffersize调用。

五、实现数据转换

hresult cflipfilter::transform(imediasample *pin, imediasample *pout)  

    checkpointer(pin,e_pointer);  

    checkpointer(pout,e_pointer);  

    byte *psourcebuffer, *pdestbuffer;  

    long lsourcesize = pin->getactualdatalength();  

    pin->getpointer(&psourcebuffer);  

    pout->getpointer(&pdestbuffer);  

    //翻转图像  

    cmediatype pmediatype1 = m_pinput->currentmediatype();  

    videoinfoheader* pvi = (videoinfoheader*)pmediatype1.pbformat;  

    int nwidth = widthbytes(pvi->bmiheader.biwidth * pvi->bmiheader.bibitcount);  

    for (int i = 0; i < pvi->bmiheader.biheight; i ++)  

        copymemory((pvoid) (pdestbuffer + nwidth * i),  

            (pvoid) (psourcebuffer + nwidth * (pvi->bmiheader.biheight - i - 1)),  

            nwidth);  

    }      

    reference_time timestart, timeend;  

    if(noerror == pin->gettime(&timestart, &timeend))  

        pout->settime(&timestart, &timeend);  

    longlong mediastart, mediaend;  

    if(pin->getmediatime(&mediastart,&mediaend) == noerror)  

        pout->setmediatime(&mediastart,&mediaend);  

    hresult hr = pin->issyncpoint();  

    if(hr == s_ok)  

        pout->setsyncpoint(true);  

    else if(hr == s_false)  

        pout->setsyncpoint(false);  

    else  

    hr = pin->ispreroll();  

        pout->setpreroll(true);  

        pout->setpreroll(false);  

    {   

    hr = pin->isdiscontinuity();  

        pout->setdiscontinuity(true);  

        pout->setdiscontinuity(false);  

    long ldatalength = pin->getactualdatalength();  

    pout->setactualdatalength(ldatalength);  

六、添加com信息,使dll成为filter

1、创建filter实例,这是标准格式

cunknown* cflipfilter::createinstance(lpunknown punk, hresult *phr)  

    assert(phr);  

    cflipfilter *pnewobject = new cflipfilter(name("flipfilter"), punk, phr);  

    if (pnewobject == null) {  

        if (phr)  

            *phr = e_outofmemory;  

    return pnewobject;  

2、声明工厂类模版

const amoviesetup_mediatype sudinputpintypes =  

    &mediatype_video,   

    &mediasubtype_null   

const amoviesetup_mediatype sudoutputpintypes =  

    &mediatype_video,  

const amoviesetup_pin sudppins[] =  

    { l"input",   

    false,   

    &clsid_null,   

    null,  

    1,  

    &sudinputpintypes  

    },  

    { l"output",   

    false,    

    true,  

    false,  

    &clsid_null,  

    null,   

    1,   

    &sudoutputpintypes   

const amoviesetup_filter sudflipfilter =  

    &clsid_flipfilter,  

    l"flipfilter",   

    merit_do_not_use,  

    2,  

    sudppins  

cfactorytemplate g_templates[] = {  

    { l"flipfilter"  

    , &clsid_flipfilter  

    , cflipfilter::createinstance  

    , null  

    , &sudflipfilter }  

int g_ctemplates = sizeof(g_templates) / sizeof(g_templates[0]);  

regfilter2 rf2filterreg = {  

    merit_do_not_use,   

    2,   

    sudppins   

3、注册和注销filter,dll的全局入口

bool apientry dllmain(handle hmodule,   

                      dword  dwreason,   

                      lpvoid lpreserved)  

    return dllentrypoint((hinstance)(hmodule), dwreason, lpreserved);  

stdapi dllregisterserver()  

    return amoviedllregisterserver2( true );  

}   

stdapi dllunregisterserver()  

    return amoviedllregisterserver2( false );  

filter编写完成。

继续阅读