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

一个最简单的源Filter的编写步骤 收藏

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

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

  1. //MySourceFilter.h   
  2. class  CMySourceFilter   
  3.     //从SDK库中的CSource类派生   
  4.     :   public  CSource            
  5. {  
  6. public :  
  7.     //实例化接口   
  8.     static  CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk,  HRESULT  *phr);  
  9. private :  
  10.     //构造函数   
  11.     CMySourceFilter(LPUNKNOWN lpunk, HRESULT  *phr);   
  12. };  
  1. //MyOutputPin.h   
  2. class  CMyOutputPin   
  3.     //CSource的派生类都使用 CSourceStream的派生类做为pin   
  4.     :public  CSourceStream  
  5. {  
  6. public :  
  7.     CMyOutputPin(HRESULT  *phr, CSource *pFilter);  
  8.     ~CMyOutputPin(void );  
  9.   
  10.     //填充样本函数   
  11.     //参数pMediaSample就是要传递到下一个 Filter输入pin的样本   
  12.     //把数据填充到pMediaSample中就是这个函数的功能   
  13.     HRESULT  FillBuffer(IMediaSample *pMediaSample);  
  14.   
  15.     //协商每个CMediaSample数据块的大小   
  16.     HRESULT  DecideBufferSize(IMemAllocator *pIMemAlloc,  
  17.         ALLOCATOR_PROPERTIES *pProperties);  
  18.   
  19.     //获得媒体类型   
  20.     //在枚举器中枚举支持的媒体类型时调用此函数得到PIN支持的媒体类型   
  21.     //此函数设置pmt的各个成员,因此,由此函数的内容觉 得PIN支持什么媒体类型   
  22.     HRESULT  GetMediaType( int  iPosition, CMediaType *pmt);  
  23.   
  24.     //检测是否支持参数传入的媒体类型   
  25.     HRESULT  CheckMediaType( const  CMediaType *pMediaType);  
  26.   
  27.     //这是质量控制接口,最简单的源Filter不需要质量控制   
  28.     STDMETHODIMP Notify(IBaseFilter *pSelf, Quality q)  
  29.     {  
  30.         return  E_FAIL;  
  31.     }  
  32.   
  33. private :  
  34.     BYTE * m_pData[3]; //存储图片数据   
  35.     int  m_nWidth; //图片的宽   
  36.     int  m_nHeight; //图片的高   
  37.     int  m_nImageSize; //图片数据的大小   
  38.     int  m_nCount; //计数器,用来切换图片数据的缓冲区   
  39. };  

3.实现CMySourceFilter类。这个类只有两个函数需要编写,很简单。

  1. //CMySourceFilter.cpp   
  2. CUnknown* CMySourceFilter::CreateInstance(LPUNKNOWN lpunk, HRESULT  *phr)  
  3. {  
  4.     //实例化函数的工作就是实例化一个源Filter的对象   
  5.      CUnknown *punk = new  CMySourceFilter(lpunk,phr);  
  6.      if  (punk == NULL)  
  7.      {  
  8.          *phr = E_OUTOFMEMORY;  
  9.      }  
  10.      return  punk;  
  11. }  
  12.   
  13. CMySourceFilter::CMySourceFilter(LPUNKNOWN lpunk, HRESULT  *phr)  
  14.  : CSource(L"MyFilter" ,lpunk,CLSID_MyFilter,phr)  
  15. {  
  16.     //创建一个pin的对象实例   
  17.     //在CSourceStream的构造函数中,会把pin 添加到Filter中   
  18.     CMyOutputPin* pOutPin = new  CMyOutputPin(phr, this );  
  19.     if  (FAILED(*phr))  
  20.     {  
  21.         //因此,在创建失败的时候,要将这个pin从Filter中移除   
  22.         RemovePin(pOutPin);  
  23.         pOutPin->Release();  
  24.     }  
  25. }  

4.实现CMyOutputPin类,编写Filter主要就是写pin。

  1. //MyOutputPin.cpp   
  2.   
  3. //构造函数   
  4. CMyOutputPin::CMyOutputPin(HRESULT  *phr, CSource *pFilter)  
  5. : CSourceStream(L"MyFilter" ,phr,pFilter,L "Out" )  
  6. , m_nWidth(0)  
  7. , m_nHeight(0)  
  8. , m_nImageSize(0)  
  9. , m_nCount(0)  
  10. {  
  11.     //把图片读到内存中,准备好数据   
  12.     m_pData[0] = LoadBitmapFileToMemory(L"E://DirectShow//MySourceFilter//1.bmp" ,  
  13.         m_nWidth,m_nHeight,m_nImageSize);  
  14.     m_pData[1] = LoadBitmapFileToMemory(L"E://DirectShow//MySourceFilter//2.bmp" ,  
  15.         m_nWidth,m_nHeight,m_nImageSize);  
  16.     m_pData[2] = LoadBitmapFileToMemory(L"E://DirectShow//MySourceFilter//3.bmp" ,  
  17.         m_nWidth,m_nHeight,m_nImageSize);  
  18. }  
  19.   
  20. //析构函数   
  21. CMyOutputPin::~CMyOutputPin(void )  
  22. {  
  23.     //释放内存   
  24.     delete  []m_pData[0];  
  25.     delete  []m_pData[1];  
  26.     delete  []m_pData[2];  
  27. }  
  28.   
  29. //获取媒体类型   
  30. //填充pmt   
  31. //最简单的源Filter,因此只支持一种类型,所以 iPosition为0   
  32. HRESULT  CMyOutputPin::GetMediaType( int  iPosition, CMediaType *pmt)  
  33. {  
  34.     CheckPointer(pmt,E_POINTER);  
  35.   
  36.     CAutoLock cAutoLock(m_pFilter->pStateLock());  
  37.     if (iPosition < 0)  
  38.     {  
  39.         return  E_INVALIDARG;  
  40.     }  
  41.     // Have we run off the end of types?   
  42.     if (iPosition > 0)  
  43.     {  
  44.         return  VFW_S_NO_MORE_ITEMS;  
  45.     }  
  46.   
  47.     //给媒体类型申请Format的空间   
  48.     //填充每一个对象,主要是BITMAPINFOHEADER结 构   
  49.     VIDEOINFO *pvi = (VIDEOINFO *) pmt->AllocFormatBuffer(sizeof (VIDEOINFO));  
  50.     if (NULL == pvi)  
  51.         return (E_OUTOFMEMORY);  
  52.   
  53.     ZeroMemory(pvi, sizeof (VIDEOINFO));  
  54.     pvi->bmiHeader.biBitCount = 24;  
  55.     pvi->bmiHeader.biHeight = m_nHeight;  
  56.     pvi->bmiHeader.biWidth = m_nWidth;  
  57.     pvi->bmiHeader.biSizeImage = m_nImageSize;  
  58.     pvi->bmiHeader.biPlanes = 1;  
  59.     pvi->bmiHeader.biSize = sizeof (BITMAPINFOHEADER);  
  60.     pvi->bmiHeader.biCompression = BI_RGB;  
  61.     pvi->bmiHeader.biClrImportant = 0;  
  62.   
  63.     SetRectEmpty(&pvi->rcSource);  
  64.     SetRectEmpty(&pvi->rcTarget);  
  65.   
  66.     pmt->SetType(&MEDIATYPE_Video);//设置主媒体类型   
  67.     pmt->SetSubtype(&MEDIASUBTYPE_RGB24);//设置子媒体类型   
  68.     pmt->SetFormatType(&FORMAT_VideoInfo);//设置详细格式类型   
  69.     pmt->SetSampleSize(m_nImageSize);//设置Sample的大小   
  70.     pmt->SetTemporalCompression(FALSE);  
  71.   
  72.     return  NOERROR;  
  73. }  
  74.   
  75. //检查媒体类型   
  76. //主要是对GetMediaType中设置的各个参数进行比较   
  77. HRESULT  CMyOutputPin::CheckMediaType( const  CMediaType *pMediaType)  
  78. {  
  79.     CheckPointer(pMediaType,E_POINTER);  
  80.   
  81.     if  (*(pMediaType->Type()) != MEDIATYPE_Video  
  82.         || !(pMediaType->IsFixedSize()))  
  83.     {  
  84.         return  E_INVALIDARG;  
  85.     }  
  86.   
  87.     const  GUID *SubType = pMediaType->Subtype();  
  88.     if  (SubType == NULL)  
  89.     {  
  90.         return  E_INVALIDARG;  
  91.     }  
  92.     if  (*SubType != MEDIASUBTYPE_RGB24)  
  93.     {  
  94.         return  E_INVALIDARG;  
  95.     }  
  96.     const  GUID* FormatType = pMediaType->FormatType();  
  97.     if  (FormatType == NULL)  
  98.     {  
  99.         return  E_INVALIDARG;  
  100.     }  
  101.     if  (*FormatType != FORMAT_VideoInfo)  
  102.     {  
  103.         return  E_INVALIDARG;  
  104.     }  
  105.   
  106.     VIDEOINFO* pvi = (VIDEOINFO*)pMediaType->Format();  
  107.     if  (pvi == NULL)  
  108.     {  
  109.         return  E_INVALIDARG;  
  110.     }  
  111.     if  (pvi->bmiHeader.biBitCount != 24 ||   
  112.         pvi->bmiHeader.biWidth != m_nWidth ||  
  113.         pvi->bmiHeader.biHeight != m_nHeight)  
  114.     {  
  115.         return  E_INVALIDARG;  
  116.     }  
  117.   
  118.     return  S_OK;  
  119. }  
  120.   
  121. //协商Sample的大小   
  122. HRESULT  CMyOutputPin::DecideBufferSize(IMemAllocator *pIMemAlloc, ALLOCATOR_PROPERTIES *pProperties)  
  123. {  
  124.     CheckPointer(pIMemAlloc,E_POINTER);  
  125.     CheckPointer(pProperties,E_POINTER);  
  126.   
  127.     CAutoLock cAutoLock(m_pFilter->pStateLock());  
  128.     HRESULT  hr = NOERROR;  
  129.   
  130.     VIDEOINFO *pvi = (VIDEOINFO *) m_mt.Format();  
  131.     //确定只有一个buffer   
  132.     pProperties->cBuffers = 1;  
  133.     //设置buffer的大小   
  134.     pProperties->cbBuffer = m_nImageSize;  
  135.   
  136.     ASSERT(pProperties->cbBuffer);  
  137.   
  138.     //设置属性页   
  139.     ALLOCATOR_PROPERTIES Actual;  
  140.     hr = pIMemAlloc->SetProperties(pProperties,&Actual);  
  141.     if (FAILED(hr))  
  142.     {  
  143.         return  hr;  
  144.     }  
  145.   
  146.     if (Actual.cbBuffer < pProperties->cbBuffer)  
  147.     {  
  148.         return  E_FAIL;  
  149.     }  
  150.   
  151.     ASSERT(Actual.cBuffers == 1);  
  152.     return  NOERROR;  
  153. }  
  154.   
  155. //填充Sample   
  156. HRESULT  CMyOutputPin::FillBuffer(IMediaSample *pMediaSample)  
  157. {  
  158.     CheckPointer(pMediaSample,E_POINTER);  
  159.     BYTE * pData = NULL;  
  160.     long  lDataSize = 0;  
  161.   
  162.     //获得Sample中存放数据的地址   
  163.     pMediaSample->GetPointer(&pData);  
  164.     //取得Sample分配的内存大小   
  165.     lDataSize = pMediaSample->GetSize();  
  166.   
  167.     ZeroMemory(pData,lDataSize);  
  168.     //把当前需要显示的数据拷贝到内存中   
  169.     CopyMemory(pData,m_pData[m_nCount%3],m_nImageSize);  
  170.   
  171.     //设置时间戳   
  172.     REFERENCE_TIME start = TS_ONE * m_nCount;  
  173.     REFERENCE_TIME stop = TS_ONE + start;  
  174.     pMediaSample->SetTime(&start,&stop);  
  175.   
  176.     //准备下一帧数据   
  177.     m_nCount++;  
  178.   
  179.     pMediaSample->SetSyncPoint(TRUE);      
  180.   
  181.     return  NOERROR;  
  182. }  

LoadBitmapFileToMemory函数的实现

  1. BYTE * LoadBitmapFileToMemory( TCHAR * pFileName,  int & nWidth,  int & nHeight,  int & nImageDataSize)  
  2. {  
  3.     HBITMAP  hBitmap = ( HBITMAP )LoadImage( NULL, pFileName, IMAGE_BITMAP, 0, 0,  
  4.         LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE );  
  5.   
  6.     if (hBitmap == NULL)  
  7.         return  NULL;  
  8.   
  9.     HDC  hDC = CreateCompatibleDC(NULL);  
  10.     HBITMAP  hOldBitmap = ( HBITMAP )SelectObject(hDC, hBitmap);  
  11.   
  12.     BITMAP bmp;  
  13.     GetObject(hBitmap, sizeof (bmp), &bmp);  
  14.   
  15.     BITMAPINFOHEADER bih = {0};//位图信息头   
  16.     bih.biBitCount = bmp.bmBitsPixel;//每个像素字节大小   
  17.     bih.biCompression = BI_RGB;  
  18.     bih.biHeight = bmp.bmHeight;//高 度   
  19.     bih.biPlanes = 1;  
  20.     bih.biSize = sizeof (BITMAPINFOHEADER);  
  21.     bih.biSizeImage = bmp.bmWidthBytes * bmp.bmHeight;//图像数据大小   
  22.     bih.biWidth = bmp.bmWidth;//宽度   
  23.   
  24.     nImageDataSize = bmp.bmWidthBytes * bmp.bmHeight;  
  25.     byte * p = new  byte[nImageDataSize]; //申请内存保存位图数据   
  26.     GetDIBits(hDC, hBitmap, 0, bmp.bmHeight, p,  
  27.         (LPBITMAPINFO) &bih, DIB_RGB_COLORS);//获取位图数据   
  28.   
  29.     SelectObject(hDC, hOldBitmap);  
  30.     DeleteObject(hBitmap);  
  31.     DeleteDC(hDC);  
  32.   
  33.     nWidth = bmp.bmWidth;  
  34.     nHeight = bmp.bmHeight;  
  35.   
  36.     return  p;  
  37. }  

5.主要的工作已经做完了,功能已经实现,接下来就是生成Filter。

  1. //MySourceFilter.h   
  2. //动态库工程自然也要有入口函数(固定格式)   
  3.     extern   "C"   BOOL  WINAPI DllEntryPoint( HINSTANCEULONGLPVOID );  
  4.   
  5.     BOOL  APIENTRY DllMain( HANDLE  hModule,   
  6.         DWORD   dwReason,   
  7.         LPVOID  lpReserved)  
  8.     {  
  9.         return  DllEntryPoint(( HINSTANCE )(hModule), dwReason, lpReserved);  
  10.     }  
  11. //组件就少不了注册与注销函数(固定格式)   
  12. STDAPI DllRegisterServer()  
  13.     {  
  14.         return  AMovieDllRegisterServer2(TRUE);  
  15.   
  16.     }  
  17. STDAPI DllUnregisterServer()  
  18.     {  
  19.         return  AMovieDllRegisterServer2(FALSE);  
  20.   
  21.     }  
  22.   
  23. //组件,就要有GUID(通过工具创建)   
  24. DEFINE_GUID(CLSID_MyFilter,   
  25.             0x159386e0, 0x5193, 0x48ac, 0x8a, 0x57, 0x17, 0x88, 0xc7, 0x33, 0x40, 0xc1);  
  26.   
  27. //以下是注册信息的模版,写了注释的地方是我们需要填写的,其他的采用默认   
  28. const  AMOVIESETUP_MEDIATYPE sudOpPinTypes =  
  29. {  
  30.     &MEDIATYPE_Video,       // Major type   
  31.     &MEDIASUBTYPE_NULL      // Minor type   
  32. };  
  33.   
  34. const  AMOVIESETUP_PIN sudOpPin =  
  35. {  
  36.     L"Output" ,               
  37.     FALSE,                   
  38.     TRUE,                     
  39.     FALSE,                    
  40.     FALSE,                    
  41.     &CLSID_NULL,             
  42.     NULL,                    
  43.     1,                        
  44.     &sudOpPinTypes };       
  45.   
  46.     const  AMOVIESETUP_FILTER sudBallax =  
  47.     {  
  48.         &CLSID_MyFilter,    // 自定义的GUID   
  49.         L"MyFilter" ,        // Filter的名字   
  50.         MERIT_DO_NOT_USE,         
  51.         1,                        
  52.         &sudOpPin           
  53.     };  
  54.   
  55.   
  56.     // COM global table of objects in this dll   
  57.   
  58.     CFactoryTemplate g_Templates[] = {  
  59.         { L"MyFilter" //Filter的名字   
  60.         , &CLSID_MyFilter//自定义的 GUID   
  61.         , CMySourceFilter::CreateInstance//Filter的实例化接口   
  62.         , NULL  
  63.         , &sudBallax }  
  64.     };  
  65.     int  g_cTemplates =  sizeof (g_Templates) /  sizeof (g_Templates[0]);  

6.MySourceFilter.def文件的内容

  1. LIBRARY  "MySourceFilter.ax"   
  2.   
  3. EXPORTS  
  4.             DllMain                 PRIVATE  
  5.             DllGetClassObject       PRIVATE  
  6.             DllCanUnloadNow         PRIVATE  
  7.             DllRegisterServer       PRIVATE  
  8.             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,效果出来了,三幅图片轮流显示在窗口中。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值