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

简介: <p style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;">目标编写一个transform filter,功能是对图像进行翻转。</p><p style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14p

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

一、选择基类

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

选择好基类,我们就创建一个空的DLL工程,添加三个文件,分别是: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编写完成。

相关文章
|
开发工具 git
【Ant Design Pro】使用ant design pro做为你的开发模板(五)去除无效代码,生成一个清晰的开发模板
【Ant Design Pro】使用ant design pro做为你的开发模板(五)去除无效代码,生成一个清晰的开发模板
689 0
【Ant Design Pro】使用ant design pro做为你的开发模板(五)去除无效代码,生成一个清晰的开发模板
|
5月前
|
C++
win32编程 -- 通过空项目学习自动生成的代码框架
win32编程 -- 通过空项目学习自动生成的代码框架
36 0
|
缓存 JavaScript iOS开发
iOS 逆向编程(十五)Cycript 语法进阶(封装 .cy 脚本文件)
iOS 逆向编程(十五)Cycript 语法进阶(封装 .cy 脚本文件)
176 0
|
API 图形学
【Unity细节】RigidBody中Dynamic和Kinematic的区别
【Unity细节】RigidBody中Dynamic和Kinematic的区别
130 0
|
数据安全/隐私保护 Python
python接口自动化(三十四)-封装与调用--函数和参数化(详解)
参数化的思维只需记住一点:不要写死,这样就便于维护,否则就会牵一发而动全身,一处修改导致处处修改,不便于维护。
1190 1
python接口自动化(三十四)-封装与调用--函数和参数化(详解)
|
数据管理 测试技术 API
python接口自动化(三十七)-封装与调用--读取excel 数据(详解)
在进行软件接口测试或设计自动化测试框架时,一个不比可避免的过程就是: 参数化,在利用python进行自动化测试开发时,通常会使用excel来做数据管理,利用xlrd、xlwt开源包来读写excel。例如:当我们登录的账号有多个的时候,我们一般用 excel 存放测试数据,本篇文章介绍,python 读取excel 方法,并保存为字典格式。
365 0
python接口自动化(三十七)-封装与调用--读取excel 数据(详解)
|
测试技术 数据库 Python
python接口自动化(二十二)--unittest执行顺序隐藏的坑(详解)
大多数的初学者在使用 unittest 框架时候,不清楚用例的执行顺序到底是怎样的。对测试类里面的类和方法分不清楚,不知道什么时候执行,什么时候不执行。虽然或许通过代码实现了,也是稀里糊涂的一知半解,这样还好,好歹自己鼓 捣出了,但是时间和效率并不是很高,下次遇到还是老样子。那么本篇通过最简单案例来给给为小伙伴详细讲解、演示一下 unittest 执行顺序。
251 0
python接口自动化(二十二)--unittest执行顺序隐藏的坑(详解)
|
Ruby
《Cucumber:行为驱动开发指南》——2.3 创建步骤定义
现在在fetures/step_definitions目录下创建一个名为calculator_steps.rb的文件,只要这是一个Ruby文件,Cucumber并不介意你给这个文件起什么名字,但这里我们给这个文件起的名字其实不错。
2382 0
|
机器人 测试技术 Python
Robot Framework(4)- 测试套件的基本使用
Robot Framework(4)- 测试套件的基本使用
484 0
Robot Framework(4)- 测试套件的基本使用
|
API vr&ar 图形学
【100个 Unity小知识点】☀️ | Unity中使用代码查询Draw call、Tris和Verts等信息
Unity 小科普 老规矩,先介绍一下 Unity 的科普小知识: Unity是 实时3D互动内容创作和运营平台 。 包括游戏开发、美术、建筑、汽车设计、影视在内的所有创作者,借助 Unity 将创意变成现实。 Unity 平台提供一整套完善的软件解决方案,可用于创作、运营和变现任何实时互动的2D和3D内容,支持平台包括手机、平板电脑、PC、游戏主机、增强现实和虚拟现实设备。 也可以简单把 Unity 理解为一个游戏引擎,可以用来专业制作游戏!
【100个 Unity小知识点】☀️ | Unity中使用代码查询Draw call、Tris和Verts等信息