目标编写一个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. class CFlipFilter : public CTransformFilter
  4. {
  5. private:
  6. CFlipFilter(TCHAR *tszName, LPUNKNOWN punk, HRESULT *phr);
  7. public:
  8. static CUnknown * WINAPI CreateInstance(LPUNKNOWN punk, HRESULT *phr);
  9. HRESULT CheckInputType(const CMediaType *mtIn);
  10. HRESULT GetMediaType(int iPosition, CMediaType *pMediaType);
  11. HRESULT CheckTransform(const CMediaType *mtIn, const CMediaType *mtOut);
  12. HRESULT DecideBufferSize(IMemAllocator * pAllocator, ALLOCATOR_PROPERTIES *pprop);
  13. HRESULT Transform(IMediaSample *pIn, IMediaSample *pOut);
  14. };

三、媒体类型协商

这一步是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. VIDEOINFO* pvi = (VIDEOINFO*)mtIn->Format();
  10. if (pvi->bmiHeader.biBitCount != 24)
  11. {
  12. return VFW_E_TYPE_NOT_ACCEPTED;
  13. }
  14. return S_OK;
  15. }

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. if (iPosition < 0) {
  7. return E_INVALIDARG;
  8. }
  9. if (iPosition > 0) {
  10. return VFW_S_NO_MORE_ITEMS;
  11. }
  12. CheckPointer(pMediaType,E_POINTER);
  13. *pMediaType = m_pInput->CurrentMediaType();
  14. return NOERROR;
  15. }

相同的,这个函数也是为输入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. return E_FAIL;
  8. }

这个函数是输出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. CheckPointer(pAllocator,E_POINTER);
  7. CheckPointer(pprop,E_POINTER);
  8. HRESULT hr = NOERROR;
  9. pprop->cBuffers = 1;
  10. pprop->cbBuffer = m_pInput->CurrentMediaType().GetSampleSize();
  11. ASSERT(pprop->cbBuffer);
  12. ALLOCATOR_PROPERTIES Actual;
  13. hr = pAllocator->SetProperties(pprop,&Actual);
  14. if (FAILED(hr)) {
  15. return hr;
  16. }
  17. ASSERT( Actual.cBuffers == 1 );
  18. if (pprop->cBuffers > Actual.cBuffers ||
  19. pprop->cbBuffer > Actual.cbBuffer) {
  20. return E_FAIL;
  21. }
  22. return NOERROR;
  23. }

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

五、实现数据转换

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

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

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

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

2、声明工厂类模版

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

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. STDAPI DllRegisterServer()
  8. {
  9. return AMovieDllRegisterServer2( TRUE );
  10. }
  11. STDAPI DllUnregisterServer()
  12. {
  13. return AMovieDllRegisterServer2( FALSE );
  14. }

Filter编写完毕。

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

  1. 简单的TSQL基础编程格式,存储过程,视图

    这里简单整理一下数据库简单的编程,变量定义,赋值,分支语句和循环(这里以Sqlserver),以及存储过程格式 首先是变量定义,赋值,分支语句 --======TSQL数据库基础编程,定义变量,赋值, ...

  2. Hadoop 综合揭秘——MapReduce 基础编程(介绍 Combine、Partitioner、WritableComparable、WritableComparator 使用方式)

    前言 本文主要介绍 MapReduce 的原理及开发,讲解如何利用 Combine.Partitioner.WritableComparator等组件对数据进行排序筛选聚合分组的功能.由于文章是针对开 ...

  3. MQ java 基础编程

    MQ java 基础编程 编写人:邬文俊 编写时间 : 2006-2-16 联系邮件 : wenjunwu430@gmail.com 前言 通过 2 个多星期对 MQ 学习,在 partner 丁 & ...

  4. 【Linux基础总结】Shell 基础编程

    Shell 基础编程 重启虚拟机遇到磁盘损坏如何解决 Shell编程中变量的声明.引用及作用域 Shell程序 概述 以文件形式存放批量的Linux命令集合,该文件能够被Shell解释执行,这种文件就 ...

  5. ARM Cortex-M嵌入式C基础编程(下)

    ARM Cortex-M嵌入式C基础编程(下) ARM Cortex-M Embedded C Fundamentals/Tutorial -Aviral Mittal Load Region Vs ...

  6. ARM Cortex-M嵌入式C基础编程(上)

    ARM Cortex-M嵌入式C基础编程(上) ARM Cortex-M Embedded C Fundamentals/Tutorial -Aviral Mittal 此技术是关于从编写简单的嵌入式 ...

  7. 异步编程系列第04章 编写Async方法

    p { display: block; margin: 3px 0 0 0; } --> 写在前面 在学异步,有位园友推荐了<async in C#5.0>,没找到中文版,恰巧也想提 ...

  8. 【转】【C#】C# 5.0 新特性——Async和Await使异步编程更简单

    一.引言 在之前的C#基础知识系列文章中只介绍了从C#1.0到C#4.0中主要的特性,然而.NET 4.5 的推出,对于C#又有了新特性的增加--就是C#5.0中async和await两个关键字,这两 ...

  9. JS基础(超级简单)

    1     JS基础(超级简单) 1.1 数据类型 1.1.1   基本类型: 1)        Number:特别注意:NaN的检测方法:Nan!=NaN;或者使用isNaN方法 2)       ...

随机推荐

  1. 方案猿身高project联赛,艺术家,相反,养殖场!-------三笔

    已经看到了程序猿在电影中都是非常厉害的人物,硬道理键盘噼里啪啦后,奇妙的事情会发生. 当我报了这个专业,開始认真的写程序,在这个领域学习的时候,却发现非常多干这一行 的都自称"码农" ...

  2. HDU 4916 树分治

    Mart Master II Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) ...

  3. CH BR4思考熊(恒等有理式-逆波兰表达式求值)

    恒等有理式 总时限 10s 内存限制 256MB 出题人 fotile96 提交情况 4/43 描述 给定两个有理式f(X)与g(X),判断他们是否恒等(任意A,如果f(A)与g(A)均有定义,那么f ...

  4. Vsphere client 无法登陆VCenter 处理的方法

    上周做安全的时候将DC.DB和VCenter 三台机器的防火墙都启用了,结果Vcenter 登陆的时候总是提示服务器没有响应,连web client 都无法登陆. 处理过程 一.首先要保证 vmvar ...

  5. NAT ALG原理

    1      NAT ALG简介 普通NAT实现了对UDP或TCP报文头中的的IP地址及端口转换功能,但对应用层数据载荷中的字段无能为力,在许多应用层协议中,比如多媒体协议(H.323.SIP等).F ...

  6. 在内网架设一个可供外网登录的ftpserver

    ftpserver是使用比較寻常的server,可是IP资源是有限的.那么怎么让内网的server給外网的用户提供服务了? 首先须要找一个FTPserver程序,我在这边使用pure-ftpd-mys ...

  7. 通过Java反射调用方法

    这是个测试用的例子,通过反射调用对象的方法.     TestRef.java import java.lang.reflect.Method; import java.lang.reflect.In ...

  8. mysql事务、触发器、视图、存储过程、函数

    存储过程: procedure 概念类似于函数,就是把一段代码封装起来, 当要执行这一段代码的时候,可以通过调用该存储过程来实现. 在封装的语句体里面,可以用if/else, case,while等控 ...

  9. jsoup方法string转document

    //Document doc2 = Jsoup.parseBodyFragment(element.text());                    //String FieldName=doc ...

  10. 算法8-4:Kruskal算法

    Kruskal算法用于计算一个图的最小生成树.这个算法的过程例如以下: 依照边的权重从小到达进行排序 依次将每条边添加到最小生成树中,除非这条边会造成回路 实现思路 第一个步骤须要对边进行排序,排序方 ...