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

时间: 2024-10-31 03:26:35

DirectShow基础编程 最简单transform filter 编写步骤的相关文章

易语言基础教程之简单代码的编写_易语言

要想使自己做的程序运行起来,就需要编写代码,下面我就以一个简单的程序为例,讲解一下代码编写过程 代码编写过程 我制作的小程序的功能就是当我点击点击按钮是,界面会出现"追梦小达人" 要想实现此功能,首先鼠标要双击一下点击按钮,进入程序编辑界面 这个子程序的完整代码为: 这个子程序用中文表达,意思就是:当单击按钮1时,标签1的标题就变成"追梦小达人!".我们可以把"标签1.标题"理解为"标签1的标题".可以看出易语言很接近人类的自

[译]JavaScript 让 Monad 更简单(软件编写)(第十一部分)

本文讲的是[译]JavaScript 让 Monad 更简单(软件编写)(第十一部分), 原文地址:JavaScript Monads Made Simple 原文作者:Eric Elliott 译文出自:掘金翻译计划 本文永久链接:github.com/xitu/gold-m- 译者:yoyoyohamapi 校对者:IridescentMia WJoan Smoke Art Cubes to Smoke - MattysFlicks - (CC BY 2.0) (译注:该图是用 PS 将烟雾

Mysql C API编程:用C语言编写的Mysql编程接口

软件开发中我们经常要访问数据库,存取数据,之前已经有网友提出让鸡啄米讲讲数据库编程的知识,本文就详细讲解如何使用Mysql的C语言API进行数据库编程. API,全称Application Programming Interfaces,即应用程序编程接口,我们可以调用这些接口,执行API函数提供的功能. Mysql C语言API就是用C语言编写的Mysql编程接口,使用这些接口函数可以实现对Mysql数据库的查询等操作. Mysql的安装 要进行Mysql编程首先要在充当Mysql服务器的电脑和

filter的调试-在对于写了简单的Filter,进行调试的时候,出现无法启动动态链库的问题。

问题描述 在对于写了简单的Filter,进行调试的时候,出现无法启动动态链库的问题. 图片说明 在用Directshow来开发Filter的时候 ,代码是照着网上的demo,demo的作者能编译和调试. 我在用graphedt.exe 来调试 .按了F5的之后 出现图片的内容. 解决方案 http://zhidao.baidu.com/link?url=T05uZEAGgNUAsvYFx7jmrszD6JnQBpwrPxlbplwUGZSsmTOt0_u9uGqxZHCxMYteJw5OVYnR

Android BLE与终端通信(一)——Android Bluetooth基础API以及简单使用获取本地蓝牙名称地址

Android BLE与终端通信(一)--Android Bluetooth基础API以及简单使用获取本地蓝牙名称地址 Hello,工作需要,也必须开始向BLE方向学习了,公司的核心技术就是BLE终端通信技术,无奈一直心不在此,但是真当自己要使用的时候还是比较迷茫,所以最近也有意向来学习这一块,同时,把自己的学习经历分享出来 一.摘要 Android智能硬件前几年野一直不温不火的,到了现在却热火朝天了,各种智能手环,智能手表,智能家居等,而使用BLE这个方向也越来越多,而这方面的资料却是真的很少

有关pl/sql编程的简单问题

问题描述 有关pl/sql编程的简单问题 declare my_name VARCHAR2(10):='张三';begin if length(my_name)<=2 THEN dbms_output.put_line('我的名字是两个字!');end; 解决方案 缺少'end if;' 解决方案二: declare type v_record is RECORD ( v_name emp.ename% TYPE; v_salary emp.sal% TYPE; v_job emp.job% T

java 基础编程题,急求结果

问题描述 java 基础编程题,急求结果 1,int isVesuvian(int n),如果n是有且仅是两组不同的两个数的平方和,返回1,否则0. 2,int isOneBalanced(int a[]),判读数组是否是平衡数组,开头连续为1的数 + 结尾连续为1的数 = 中间连续不为1的数 结果返回1,否则为0. 3,int closestFibonacci(int n),返回比n小的最大的斐波拉契元素.斐波拉契数列 1 1 2 3 5 8 13 21 34 PS:1 1 2 3 5 8 1

Java网络编程之简单的服务端客户端应用实例_java

本文实例讲述了Java网络编程之简单的服务端客户端应用.分享给大家供大家参考.具体如下: 在Java中,我们使用java.net.Socket及其相关类来完成有关网络的相关功能.Socket类非常简单易用,因为Java技术隐藏了建立网络连接和通过连接发送数据的复杂过程.下面所说的内容只适用于TCP协议. 一.连接到服务器 我们可以使用Socket类的构造函数来打开一个套接字,如 Socket sk = new Socket("210.0.235.14",13); 其中,210.0.23

决定用windows学习shell编程,用Notepad++编辑器编写shell程序

问题描述 今天自己想把shell编程好好的学习一边,我想看看自己可以用一星期时间可不可以学的行不.开始干.首先解决编写环境问题,我决定用windows学习shell编程,用Notepad++编辑器编写shell程序,下载cxywin程序模拟shell环境,这样就可以不破坏系统,也不用虚拟机耗内存了.最后实践发现当你做shell实验的时候用cxywin不行,所以我们还是要建一个虚拟机,最小化安装就行.在上面例子,变量count初始值是0,随后每次循环一次便增加1.echo语句打印count的值,我