• 一个最简单的源Filter的编写步骤 转贴


    1.创建一个空的Dll工程,添加5个空文件分别名为:MyOutputPin.h、 MySourceFilter.h、MyOutputPin.cpp、MySourceFilter.cpp和MySourceFilter.def。

    2.声明两个类,一个是Filter的实现类,一个是输出Pin的实现类,由于是最简单的源Filter,因此Filter只有一个输出Pin。实 现的功能是从本地磁盘读取三个图片文件,轮流显示这三张图片,效果是模拟一个视频流。这两个类的声明代码:


    view plain copy to clipboard print ?
    //MySourceFilter.h   
    class  CMySourceFilter   
        //从SDK库中的CSource类派生   
        :   public  CSource            
    {  
    public :  
        //实例化接口   
        static  CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk,  HRESULT  *phr);  
    private :  
        //构造函数   
        CMySourceFilter(LPUNKNOWN lpunk, HRESULT  *phr);   
    };  
    view plain copy to clipboard print ?
    //MyOutputPin.h   
    class  CMyOutputPin   
        //CSource的派生类都使用 CSourceStream的派生类做为pin   
        :public  CSourceStream  
    {  
    public :  
        CMyOutputPin(HRESULT  *phr, CSource *pFilter);  
        ~CMyOutputPin(void );  
      
        //填充样本函数   
        //参数pMediaSample就是要传递到下一个 Filter输入pin的样本   
        //把数据填充到pMediaSample中就是这个函数的功能   
        HRESULT  FillBuffer(IMediaSample *pMediaSample);  
      
        //协商每个CMediaSample数据块的大小   
        HRESULT  DecideBufferSize(IMemAllocator *pIMemAlloc,  
            ALLOCATOR_PROPERTIES *pProperties);  
      
        //获得媒体类型   
        //在枚举器中枚举支持的媒体类型时调用此函数得到PIN支持的媒体类型   
        //此函数设置pmt的各个成员,因此,由此函数的内容觉 得PIN支持什么媒体类型   
        HRESULT  GetMediaType( int  iPosition, CMediaType *pmt);  
      
        //检测是否支持参数传入的媒体类型   
        HRESULT  CheckMediaType( const  CMediaType *pMediaType);  
      
        //这是质量控制接口,最简单的源Filter不需要质量控制   
        STDMETHODIMP Notify(IBaseFilter *pSelf, Quality q)  
        {  
            return  E_FAIL;  
        }  
      
    private :  
        BYTE * m_pData[3]; //存储图片数据   
        int  m_nWidth; //图片的宽   
        int  m_nHeight; //图片的高   
        int  m_nImageSize; //图片数据的大小   
        int  m_nCount; //计数器,用来切换图片数据的缓冲区   
    };  
    3.实现CMySourceFilter类。这个类只有两个函数需要编写,很简单。
    view plain copy to clipboard print ?
    //CMySourceFilter.cpp   
    CUnknown* CMySourceFilter::CreateInstance(LPUNKNOWN lpunk, HRESULT  *phr)  
    {  
        //实例化函数的工作就是实例化一个源Filter的对象   
         CUnknown *punk = new  CMySourceFilter(lpunk,phr);  
         if  (punk == NULL)  
         {  
             *phr = E_OUTOFMEMORY;  
         }  
         return  punk;  
    }  
      
    CMySourceFilter::CMySourceFilter(LPUNKNOWN lpunk, HRESULT  *phr)  
     : CSource(L"MyFilter" ,lpunk,CLSID_MyFilter,phr)  
    {  
        //创建一个pin的对象实例   
        //在CSourceStream的构造函数中,会把pin 添加到Filter中   
        CMyOutputPin* pOutPin = new  CMyOutputPin(phr, this );  
        if  (FAILED(*phr))  
        {  
            //因此,在创建失败的时候,要将这个pin从Filter中移除   
            RemovePin(pOutPin);  
            pOutPin->Release();  
        }  
    }  
    4.实现CMyOutputPin类,编写Filter主要就是写pin。
    view plain copy to clipboard print ?
    //MyOutputPin.cpp   
      
    //构造函数   
    CMyOutputPin::CMyOutputPin(HRESULT  *phr, CSource *pFilter)  
    : CSourceStream(L"MyFilter" ,phr,pFilter,L "Out" )  
    , m_nWidth(0)  
    , m_nHeight(0)  
    , m_nImageSize(0)  
    , m_nCount(0)  
    {  
        //把图片读到内存中,准备好数据   
        m_pData[0] = LoadBitmapFileToMemory(L"E:\\DirectShow\\MySourceFilter\\1.bmp" ,  
            m_nWidth,m_nHeight,m_nImageSize);  
        m_pData[1] = LoadBitmapFileToMemory(L"E:\\DirectShow\\MySourceFilter\\2.bmp" ,  
            m_nWidth,m_nHeight,m_nImageSize);  
        m_pData[2] = LoadBitmapFileToMemory(L"E:\\DirectShow\\MySourceFilter\\3.bmp" ,  
            m_nWidth,m_nHeight,m_nImageSize);  
    }  
      
    //析构函数   
    CMyOutputPin::~CMyOutputPin(void )  
    {  
        //释放内存   
        delete  []m_pData[0];  
        delete  []m_pData[1];  
        delete  []m_pData[2];  
    }  
      
    //获取媒体类型   
    //填充pmt   
    //最简单的源Filter,因此只支持一种类型,所以 iPosition为0   
    HRESULT  CMyOutputPin::GetMediaType( int  iPosition, CMediaType *pmt)  
    {  
        CheckPointer(pmt,E_POINTER);  
      
        CAutoLock cAutoLock(m_pFilter->pStateLock());  
        if (iPosition < 0)  
        {  
            return  E_INVALIDARG;  
        }  
        // Have we run off the end of types?   
        if (iPosition > 0)  
        {  
            return  VFW_S_NO_MORE_ITEMS;  
        }  
      
        //给媒体类型申请Format的空间   
        //填充每一个对象,主要是BITMAPINFOHEADER结 构   
        VIDEOINFO *pvi = (VIDEOINFO *) pmt->AllocFormatBuffer(sizeof (VIDEOINFO));  
        if (NULL == pvi)  
            return (E_OUTOFMEMORY);  
      
        ZeroMemory(pvi, sizeof (VIDEOINFO));  
        pvi->bmiHeader.biBitCount = 24;  
        pvi->bmiHeader.biHeight = m_nHeight;  
        pvi->bmiHeader.biWidth = m_nWidth;  
        pvi->bmiHeader.biSizeImage = m_nImageSize;  
        pvi->bmiHeader.biPlanes = 1;  
        pvi->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);  
        pvi->bmiHeader.biCompression = BI_RGB;  
        pvi->bmiHeader.biClrImportant = 0;  
      
        SetRectEmpty(&pvi->rcSource);  
        SetRectEmpty(&pvi->rcTarget);  
      
        pmt->SetType(&MEDIATYPE_Video);//设置主媒体类型   
        pmt->SetSubtype(&MEDIASUBTYPE_RGB24);//设置子媒体类型   
        pmt->SetFormatType(&FORMAT_VideoInfo);//设置详细格式类型   
        pmt->SetSampleSize(m_nImageSize);//设置Sample的大小   
        pmt->SetTemporalCompression(FALSE);  
      
        return  NOERROR;  
    }  
      
    //检查媒体类型   
    //主要是对GetMediaType中设置的各个参数进行比较   
    HRESULT  CMyOutputPin::CheckMediaType( const  CMediaType *pMediaType)  
    {  
        CheckPointer(pMediaType,E_POINTER);  
      
        if  (*(pMediaType->Type()) != MEDIATYPE_Video  
            || !(pMediaType->IsFixedSize()))  
        {  
            return  E_INVALIDARG;  
        }  
      
        const  GUID *SubType = pMediaType->Subtype();  
        if  (SubType == NULL)  
        {  
            return  E_INVALIDARG;  
        }  
        if  (*SubType != MEDIASUBTYPE_RGB24)  
        {  
            return  E_INVALIDARG;  
        }  
        const  GUID* FormatType = pMediaType->FormatType();  
        if  (FormatType == NULL)  
        {  
            return  E_INVALIDARG;  
        }  
        if  (*FormatType != FORMAT_VideoInfo)  
        {  
            return  E_INVALIDARG;  
        }  
      
        VIDEOINFO* pvi = (VIDEOINFO*)pMediaType->Format();  
        if  (pvi == NULL)  
        {  
            return  E_INVALIDARG;  
        }  
        if  (pvi->bmiHeader.biBitCount != 24 ||   
            pvi->bmiHeader.biWidth != m_nWidth ||  
            pvi->bmiHeader.biHeight != m_nHeight)  
        {  
            return  E_INVALIDARG;  
        }  
      
        return  S_OK;  
    }  
      
    //协商Sample的大小   
    HRESULT  CMyOutputPin::DecideBufferSize(IMemAllocator *pIMemAlloc, ALLOCATOR_PROPERTIES *pProperties)  
    {  
        CheckPointer(pIMemAlloc,E_POINTER);  
        CheckPointer(pProperties,E_POINTER);  
      
        CAutoLock cAutoLock(m_pFilter->pStateLock());  
        HRESULT  hr = NOERROR;  
      
        VIDEOINFO *pvi = (VIDEOINFO *) m_mt.Format();  
        //确定只有一个buffer   
        pProperties->cBuffers = 1;  
        //设置buffer的大小   
        pProperties->cbBuffer = m_nImageSize;  
      
        ASSERT(pProperties->cbBuffer);  
      
        //设置属性页   
        ALLOCATOR_PROPERTIES Actual;  
        hr = pIMemAlloc->SetProperties(pProperties,&Actual);  
        if (FAILED(hr))  
        {  
            return  hr;  
        }  
      
        if (Actual.cbBuffer < pProperties->cbBuffer)  
        {  
            return  E_FAIL;  
        }  
      
        ASSERT(Actual.cBuffers == 1);  
        return  NOERROR;  
    }  
      
    //填充Sample   
    HRESULT  CMyOutputPin::FillBuffer(IMediaSample *pMediaSample)  
    {  
        CheckPointer(pMediaSample,E_POINTER);  
        BYTE * pData = NULL;  
        long  lDataSize = 0;  
      
        //获得Sample中存放数据的地址   
        pMediaSample->GetPointer(&pData);  
        //取得Sample分配的内存大小   
        lDataSize = pMediaSample->GetSize();  
      
        ZeroMemory(pData,lDataSize);  
        //把当前需要显示的数据拷贝到内存中   
        CopyMemory(pData,m_pData[m_nCount%3],m_nImageSize);  
      
        //设置时间戳   
        REFERENCE_TIME start = TS_ONE * m_nCount;  
        REFERENCE_TIME stop = TS_ONE + start;  
        pMediaSample->SetTime(&start,&stop);  
      
        //准备下一帧数据   
        m_nCount++;  
      
        pMediaSample->SetSyncPoint(TRUE);      
      
        return  NOERROR;  
    }  
    LoadBitmapFileToMemory函数的实现
    view plain copy to clipboard print ?
    BYTE * LoadBitmapFileToMemory( TCHAR * pFileName,  int & nWidth,  int & nHeight,  int & nImageDataSize)  
    {  
        HBITMAP  hBitmap = ( HBITMAP )LoadImage( NULL, pFileName, IMAGE_BITMAP, 0, 0,  
            LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE );  
      
        if (hBitmap == NULL)  
            return  NULL;  
      
        HDC  hDC = CreateCompatibleDC(NULL);  
        HBITMAP  hOldBitmap = ( HBITMAP )SelectObject(hDC, hBitmap);  
      
        BITMAP bmp;  
        GetObject(hBitmap, sizeof (bmp), &bmp);  
      
        BITMAPINFOHEADER bih = {0};//位图信息头   
        bih.biBitCount = bmp.bmBitsPixel;//每个像素字节大小   
        bih.biCompression = BI_RGB;  
        bih.biHeight = bmp.bmHeight;//高 度   
        bih.biPlanes = 1;  
        bih.biSize = sizeof (BITMAPINFOHEADER);  
        bih.biSizeImage = bmp.bmWidthBytes * bmp.bmHeight;//图像数据大小   
        bih.biWidth = bmp.bmWidth;//宽度   
      
        nImageDataSize = bmp.bmWidthBytes * bmp.bmHeight;  
        byte * p = new  byte[nImageDataSize]; //申请内存保存位图数据   
        GetDIBits(hDC, hBitmap, 0, bmp.bmHeight, p,  
            (LPBITMAPINFO) &bih, DIB_RGB_COLORS);//获取位图数据   
      
        SelectObject(hDC, hOldBitmap);  
        DeleteObject(hBitmap);  
        DeleteDC(hDC);  
      
        nWidth = bmp.bmWidth;  
        nHeight = bmp.bmHeight;  
      
        return  p;  
    }  
    5.主要的工作已经做完了,功能已经实现,接下来就是生成Filter。
    view plain copy to clipboard print ?
    //MySourceFilter.h   
    //动态库工程自然也要有入口函数(固定格式)   
        extern   "C"   BOOL  WINAPI DllEntryPoint( HINSTANCE ,  ULONG ,  LPVOID );  
      
        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);  
      
        }  
      
    //组件,就要有GUID(通过工具创建)   
    DEFINE_GUID(CLSID_MyFilter,   
                0x159386e0, 0x5193, 0x48ac, 0x8a, 0x57, 0x17, 0x88, 0xc7, 0x33, 0x40, 0xc1);  
      
    //以下是注册信息的模版,写了注释的地方是我们需要填写的,其他的采用默认   
    const  AMOVIESETUP_MEDIATYPE sudOpPinTypes =  
    {  
        &MEDIATYPE_Video,       // Major type   
        &MEDIASUBTYPE_NULL      // Minor type   
    };  
      
    const  AMOVIESETUP_PIN sudOpPin =  
    {  
        L"Output" ,               
        FALSE,                   
        TRUE,                     
        FALSE,                    
        FALSE,                    
        &CLSID_NULL,             
        NULL,                    
        1,                        
        &sudOpPinTypes };       
      
        const  AMOVIESETUP_FILTER sudBallax =  
        {  
            &CLSID_MyFilter,    // 自定义的GUID   
            L"MyFilter" ,        // Filter的名字   
            MERIT_DO_NOT_USE,         
            1,                        
            &sudOpPin           
        };  
      
      
        // COM global table of objects in this dll   
      
        CFactoryTemplate g_Templates[] = {  
            { L"MyFilter" //Filter的名字   
            , &CLSID_MyFilter//自定义的 GUID   
            , CMySourceFilter::CreateInstance//Filter的实例化接口   
            , NULL  
            , &sudBallax }  
        };  
        int  g_cTemplates =  sizeof (g_Templates) /  sizeof (g_Templates[0]);  
    6.MySourceFilter.def文件的内容
    view plain copy to clipboard print ?
    LIBRARY  "MySourceFilter.ax"   
      
    EXPORTS  
                DllMain                 PRIVATE  
                DllGetClassObject       PRIVATE  
                DllCanUnloadNow         PRIVATE  
                DllRegisterServer       PRIVATE  
                DllUnregisterServer     PRIVATE  
    7.注意

    1)包含头文件 #include <initguid.h>,否则有可能提示 error LNK2001: 无法解析的外部符号 _CLSID_MyFilter

    2)包含导出库#pragma comment(lib, "winmm")

    3)包含导入库#pragma comment(lib, "strmbase.lib"),Debug下包含#pragma comment(lib, "strmbasd.lib")

    8.大功告成。调用regsvr32注册Filter。使用GraphEdit调试Filter。(VS2005)

    在工程的属性中选择调试,在命令中填入GraphEdit的完整路径,把Filter的工程作为启动项。按下F5,在运行的GraphEdit中选 择我们的Filter,Render pin,就可以看到一条完整的链路,然后run,效果出来了,三幅图片轮流显示在窗口中。
  • 相关阅读:
    Win10下 Docker Flask实例
    4.1 线性映射的概念
    桥梁的基本组成和分类
    Qt5字符串编码转换学习
    在右键菜单中添加用Jupyter Notebook打开
    左右手(直角)坐标系叉乘计算公式
    __new__方法与单键实例
    向量组的秩
    从线性组合的角度理解三维运算
    Hexo使用小结
  • 原文地址:https://www.cnblogs.com/qq78292959/p/2077017.html
Copyright © 2020-2023  润新知