首页 > 代码库 > DirectShow基础编程 最简单transform filter 编写步骤

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

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

一、选择基类

从CBaseFilter派生出三个用于编写transform filter的类,分别是:CTransformFilter 、CTransInPlaceFilter 和CVideoTransformFilter ,三个基类的区别可以看MSDN的说明,我们选择CTransformFilter类。

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

 

二、声明Filter类

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

[cpp] view plaincopyprint?
  1. #include <streams.h>  
  2. extern "C" const GUID CLSID_FlipFilter;  
  3.   
  4. class CFlipFilter : public CTransformFilter  
  5. {  
  6. private:  
  7.     CFlipFilter(TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr);  
  8.   
  9. public:  
  10.     static CUnknown * WINAPI CreateInstance(LPUNKNOWN punk, HRESULT *phr);  
  11.   
  12.     HRESULT CheckInputType(const CMediaType *mtIn);  
  13.     HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);  
  14.     HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut);  
  15.     HRESULT DecideBufferSize(IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop);  
  16.     HRESULT Transform(IMediaSample *pIn, IMediaSample *pOut);  
  17. };  

 

三、媒体类型协商

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

1、HRESULT CheckInputType(const CMediaType *mtIn);

[cpp] view plaincopyprint?
  1. HRESULT CFlipFilter::CheckInputType(const CMediaType *mtIn)  
  2. {  
  3.     if (mtIn->majortype != MEDIATYPE_Video ||  
  4.         mtIn->subtype != MEDIASUBTYPE_RGB24 ||  
  5.         mtIn->formattype != FORMAT_VideoInfo )  
  6.     {  
  7.         return VFW_E_TYPE_NOT_ACCEPTED;  
  8.     }  
  9.   
  10.     VIDEOINFO* pvi = (VIDEOINFO*)mtIn->Format();  
  11.   
  12.     if (pvi->bmiHeader.biBitCount != 24)  
  13.     {  
  14.         return VFW_E_TYPE_NOT_ACCEPTED;  
  15.     }  
  16.   
  17.     return S_OK;  
  18. }  

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

[cpp] view plaincopyprint?
  1. HRESULT CFlipFilter::GetMediaType(int iPosition, CMediaType *pMediaType)  
  2. {  
  3.     if (m_pInput->IsConnected() == FALSE) {  
  4.         return E_UNEXPECTED;  
  5.     }  
  6.   
  7.     if (iPosition < 0) {  
  8.         return E_INVALIDARG;  
  9.     }  
  10.   
  11.     if (iPosition > 0) {  
  12.         return VFW_S_NO_MORE_ITEMS;  
  13.     }  
  14.   
  15.     CheckPointer(pMediaType,E_POINTER);  
  16.     *pMediaType = m_pInput->CurrentMediaType();  
  17.   
  18.     return NOERROR;  
  19. }  

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

3、HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut);

[cpp] view plaincopyprint?
  1. HRESULT CFlipFilter::CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut)  
  2. {  
  3.     if (*mtIn == *mtOut)  
  4.     {  
  5.         return NOERROR;  
  6.     }  
  7.   
  8.     return E_FAIL;  
  9. }  

这个函数是输出pin调用。CTransformOutputPin::CheckMediaType(const CMediaType* pmtOut)中调用m_pTransformFilter->CheckTransform。

 

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

[cpp] view plaincopyprint?
  1. HRESULT CFlipFilter::DecideBufferSize(IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop)  
  2. {  
  3.     if (m_pInput->IsConnected() == FALSE) {  
  4.         return E_UNEXPECTED;  
  5.     }  
  6.   
  7.     CheckPointer(pAllocator,E_POINTER);  
  8.     CheckPointer(pprop,E_POINTER);  
  9.     HRESULT hr = NOERROR;  
  10.   
  11.     pprop->cBuffers = 1;  
  12.     pprop->cbBuffer = m_pInput->CurrentMediaType().GetSampleSize();  
  13.     ASSERT(pprop->cbBuffer);  
  14.   
  15.     ALLOCATOR_PROPERTIES Actual;  
  16.     hr = pAllocator->SetProperties(pprop,&Actual);  
  17.     if (FAILED(hr)) {  
  18.         return hr;  
  19.     }  
  20.   
  21.     ASSERT( Actual.cBuffers == 1 );  
  22.   
  23.     if (pprop->cBuffers > Actual.cBuffers ||  
  24.         pprop->cbBuffer > Actual.cbBuffer) {  
  25.             return E_FAIL;  
  26.     }  
  27.     return NOERROR;  
  28. }  

这个函数由CTransformOutputPin::DecideBufferSize调用。

 

五、实现数据转换

[cpp] view plaincopyprint?
  1. HRESULT CFlipFilter::Transform(IMediaSample *pIn, IMediaSample *pOut)  
  2. {  
  3.     CheckPointer(pIn,E_POINTER);  
  4.     CheckPointer(pOut,E_POINTER);  
  5.   
  6.     BYTE *pSourceBuffer, *pDestBuffer;  
  7.     long lSourceSize = pIn->GetActualDataLength();  
  8.   
  9.     pIn->GetPointer(&pSourceBuffer);  
  10.     pOut->GetPointer(&pDestBuffer);  
  11.   
  12.     //翻转图像  
  13.     CMediaType pMediaType1 = m_pInput->CurrentMediaType();  
  14.     VIDEOINFOHEADER* pvi = (VIDEOINFOHEADER*)pMediaType1.pbFormat;  
  15.     int nWidth = WIDTHBYTES(pvi->bmiHeader.biWidth * pvi->bmiHeader.biBitCount);  
  16.     for (int i = 0; i < pvi->bmiHeader.biHeight; i ++)  
  17.     {  
  18.         CopyMemory((PVOID) (pDestBuffer + nWidth * i),  
  19.             (PVOID) (pSourceBuffer + nWidth * (pvi->bmiHeader.biHeight - i - 1)),  
  20.             nWidth);  
  21.     }      
  22.   
  23.     REFERENCE_TIME TimeStart, TimeEnd;  
  24.     if(NOERROR == pIn->GetTime(&TimeStart, &TimeEnd))  
  25.     {  
  26.         pOut->SetTime(&TimeStart, &TimeEnd);  
  27.     }  
  28.   
  29.     LONGLONG MediaStart, MediaEnd;  
  30.     if(pIn->GetMediaTime(&MediaStart,&MediaEnd) == NOERROR)  
  31.     {  
  32.         pOut->SetMediaTime(&MediaStart,&MediaEnd);  
  33.     }  
  34.   
  35.     HRESULT hr = pIn->IsSyncPoint();  
  36.     if(hr == S_OK)  
  37.     {  
  38.         pOut->SetSyncPoint(TRUE);  
  39.     }  
  40.     else if(hr == S_FALSE)  
  41.     {  
  42.         pOut->SetSyncPoint(FALSE);  
  43.     }  
  44.     else  
  45.     {  
  46.         return E_UNEXPECTED;  
  47.     }  
  48.   
  49.     hr = pIn->IsPreroll();  
  50.     if(hr == S_OK)  
  51.     {  
  52.         pOut->SetPreroll(TRUE);  
  53.     }  
  54.     else if(hr == S_FALSE)  
  55.     {  
  56.         pOut->SetPreroll(FALSE);  
  57.     }  
  58.     else  
  59.     {   
  60.         return E_UNEXPECTED;  
  61.     }  
  62.   
  63.     hr = pIn->IsDiscontinuity();  
  64.   
  65.     if(hr == S_OK)  
  66.     {  
  67.         pOut->SetDiscontinuity(TRUE);  
  68.     }  
  69.     else if(hr == S_FALSE)  
  70.     {  
  71.         pOut->SetDiscontinuity(FALSE);  
  72.     }  
  73.     else  
  74.     {  
  75.         return E_UNEXPECTED;  
  76.     }  
  77.   
  78.     long lDataLength = pIn->GetActualDataLength();  
  79.     pOut->SetActualDataLength(lDataLength);  
  80.   
  81.     return NOERROR;  
  82. }  

 

六、添加COM信息,使DLL成为filter

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

[cpp] view plaincopyprint?
  1. CUnknown* CFlipFilter::CreateInstance(LPUNKNOWN punk, HRESULT *phr)  
  2. {  
  3.     ASSERT(phr);  
  4.   
  5.     CFlipFilter *pNewObject = new CFlipFilter(NAME("FlipFilter"), punk, phr);  
  6.   
  7.     if (pNewObject == NULL) {  
  8.         if (phr)  
  9.             *phr = E_OUTOFMEMORY;  
  10.     }  
  11.     return pNewObject;  
  12. }  

2、声明工厂类模版

[cpp] view plaincopyprint?
  1. const AMOVIESETUP_MEDIATYPE sudInputPinTypes =  
  2. {  
  3.     &MEDIATYPE_Video,   
  4.     &MEDIASUBTYPE_NULL   
  5. };  
  6.   
  7. const AMOVIESETUP_MEDIATYPE sudOutputPinTypes =  
  8. {  
  9.     &MEDIATYPE_Video,  
  10.     &MEDIASUBTYPE_NULL   
  11. };  
  12.   
  13. const AMOVIESETUP_PIN sudpPins[] =  
  14. {  
  15.     { L"Input",   
  16.     FALSE,   
  17.     FALSE,   
  18.     FALSE,   
  19.     FALSE,   
  20.     &CLSID_NULL,   
  21.     NULL,  
  22.     1,  
  23.     &sudInputPinTypes  
  24.     },  
  25.     { L"Output",   
  26.     FALSE,    
  27.     TRUE,  
  28.     FALSE,   
  29.     FALSE,  
  30.     &CLSID_NULL,  
  31.     NULL,   
  32.     1,   
  33.     &sudOutputPinTypes   
  34.     }  
  35. };  
  36.   
  37. const AMOVIESETUP_FILTER sudFlipFilter =  
  38. {  
  39.     &CLSID_FlipFilter,  
  40.     L"FlipFilter",   
  41.     MERIT_DO_NOT_USE,  
  42.     2,  
  43.     sudpPins  
  44. };  
  45.   
  46. CFactoryTemplate g_Templates[] = {  
  47.     { L"FlipFilter"  
  48.     , &CLSID_FlipFilter  
  49.     , CFlipFilter::CreateInstance  
  50.     , NULL  
  51.     , &sudFlipFilter }  
  52. };  
  53. int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);  
  54.   
  55. REGFILTER2 rf2FilterReg = {  
  56.     1,   
  57.     MERIT_DO_NOT_USE,   
  58.     2,   
  59.     sudpPins   
  60. };  

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

[cpp] view plaincopyprint?
  1. BOOL APIENTRY DllMain(HANDLE hModule,   
  2.                       DWORD  dwReason,   
  3.                       LPVOID lpReserved)  
  4. {  
  5.     return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);  
  6. }  
  7.   
  8. STDAPI DllRegisterServer()  
  9. {  
  10.     return AMovieDllRegisterServer2( TRUE );  
  11.   
  12. }   
  13. STDAPI DllUnregisterServer()  
  14. {  
  15.     return AMovieDllRegisterServer2( FALSE );  
  16.   
  17. }  

 

Filter编写完成。

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