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


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

    一、选择基类

    从CBaseFilter派生出三个用于编写transform filter的类,各自是:CTransformFilter 、CTransInPlaceFilter 和CVideoTransformFilter ,三个基类的差别能够看MSDN的说明,我们选择CTransformFilter类。

    选择好基类,我们就创建一个空的DLLproject,加入三个文件,各自是:FlipFilter.h、FlipFilter.cpp和FlipFilter.def。

     

    二、声明Filter类

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

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

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

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

    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。

     

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

    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调用。

     

    五、实现数据转换

    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实例。这是标准格式

    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、声明工厂类模版

    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的全局入口

    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编写完毕。

  • 相关阅读:
    es6作用域
    es6函数的扩展
    input输入框ios上光标与placeholder、value不能对齐居中
    移动端input常用样式
    webpack安装遇到的坑
    错误类型
    滚动超出一定高度后,导航栏吸顶
    表单change()事件
    第二周学习进度
    第一周学习进度
  • 原文地址:https://www.cnblogs.com/mengfanrong/p/5110396.html
Copyright © 2020-2023  润新知