转自: http://blog.csdn.net/bwmwm/article/details/5463852

1.创建一个空的Dll工程,添加5个空文件分别名为:MyOutputPin.h、MySourceFilter.h、MyOutputPin.cpp、MySourceFilter.cpp和MySourceFilter.def。

2.声明两个类,一个是Filter的实现类,一个是输出Pin的实现类,由于是最简单的源Filter,因此Filter只有一个输出Pin。实现的功能是从本地磁盘读取三个图片文件,轮流显示这三张图片,效果是模拟一个视频流。这两个类的声明代码:

[cpp] view plaincopyprint?
  1. //MySourceFilter.h
  2. class CMySourceFilter
  3. //从SDK库中的CSource类派生
  4. :   public CSource
  5. {
  6. public:
  7. //实例化接口
  8. static CUnknown * WINAPI CreateInstance(LPUNKNOWN lpunk, HRESULT *phr);
  9. private:
  10. //构造函数
  11. CMySourceFilter(LPUNKNOWN lpunk, HRESULT *phr);
  12. };
[cpp] view plaincopyprint?
  1. //MyOutputPin.h
  2. class CMyOutputPin
  3. //CSource的派生类都使用CSourceStream的派生类做为pin
  4. :public CSourceStream
  5. {
  6. public:
  7. CMyOutputPin(HRESULT *phr, CSource *pFilter);
  8. ~CMyOutputPin(void);
  9. //填充样本函数
  10. //参数pMediaSample就是要传递到下一个Filter输入pin的样本
  11. //把数据填充到pMediaSample中就是这个函数的功能
  12. HRESULT FillBuffer(IMediaSample *pMediaSample);
  13. //协商每个CMediaSample数据块的大小
  14. HRESULT DecideBufferSize(IMemAllocator *pIMemAlloc,
  15. ALLOCATOR_PROPERTIES *pProperties);
  16. //获得媒体类型
  17. //在枚举器中枚举支持的媒体类型时调用此函数得到PIN支持的媒体类型
  18. //此函数设置pmt的各个成员,因此,由此函数的内容觉得PIN支持什么媒体类型
  19. HRESULT GetMediaType(int iPosition, CMediaType *pmt);
  20. //检测是否支持参数传入的媒体类型
  21. HRESULT CheckMediaType(const CMediaType *pMediaType);
  22. //这是质量控制接口,最简单的源Filter不需要质量控制
  23. STDMETHODIMP Notify(IBaseFilter *pSelf, Quality q)
  24. {
  25. return E_FAIL;
  26. }
  27. private:
  28. BYTE* m_pData[3];//存储图片数据
  29. int m_nWidth;//图片的宽
  30. int m_nHeight;//图片的高
  31. int m_nImageSize;//图片数据的大小
  32. int m_nCount;//计数器,用来切换图片数据的缓冲区
  33. };

3.实现CMySourceFilter类。这个类只有两个函数需要编写,很简单。

[cpp] view plaincopyprint?
  1. //CMySourceFilter.cpp
  2. CUnknown* CMySourceFilter::CreateInstance(LPUNKNOWN lpunk, HRESULT *phr)
  3. {
  4. //实例化函数的工作就是实例化一个源Filter的对象
  5. CUnknown *punk = new CMySourceFilter(lpunk,phr);
  6. if (punk == NULL)
  7. {
  8. *phr = E_OUTOFMEMORY;
  9. }
  10. return punk;
  11. }
  12. CMySourceFilter::CMySourceFilter(LPUNKNOWN lpunk, HRESULT *phr)
  13. : CSource(L"MyFilter",lpunk,CLSID_MyFilter,phr)
  14. {
  15. //创建一个pin的对象实例
  16. //在CSourceStream的构造函数中,会把pin添加到Filter中
  17. CMyOutputPin* pOutPin = new CMyOutputPin(phr,this);
  18. if (FAILED(*phr))
  19. {
  20. //因此,在创建失败的时候,要将这个pin从Filter中移除
  21. RemovePin(pOutPin);
  22. pOutPin->Release();
  23. }
  24. }

4.实现CMyOutputPin类,编写Filter主要就是写pin。

[cpp] view plaincopyprint?
  1. //MyOutputPin.cpp
  2. //构造函数
  3. CMyOutputPin::CMyOutputPin(HRESULT *phr, CSource *pFilter)
  4. : CSourceStream(L"MyFilter",phr,pFilter,L"Out")
  5. , m_nWidth(0)
  6. , m_nHeight(0)
  7. , m_nImageSize(0)
  8. , m_nCount(0)
  9. {
  10. //把图片读到内存中,准备好数据
  11. m_pData[0] = LoadBitmapFileToMemory(L"E://DirectShow//MySourceFilter//1.bmp",
  12. m_nWidth,m_nHeight,m_nImageSize);
  13. m_pData[1] = LoadBitmapFileToMemory(L"E://DirectShow//MySourceFilter//2.bmp",
  14. m_nWidth,m_nHeight,m_nImageSize);
  15. m_pData[2] = LoadBitmapFileToMemory(L"E://DirectShow//MySourceFilter//3.bmp",
  16. m_nWidth,m_nHeight,m_nImageSize);
  17. }
  18. //析构函数
  19. CMyOutputPin::~CMyOutputPin(void)
  20. {
  21. //释放内存
  22. delete []m_pData[0];
  23. delete []m_pData[1];
  24. delete []m_pData[2];
  25. }
  26. //获取媒体类型
  27. //填充pmt
  28. //最简单的源Filter,因此只支持一种类型,所以iPosition为0
  29. HRESULT CMyOutputPin::GetMediaType(int iPosition, CMediaType *pmt)
  30. {
  31. CheckPointer(pmt,E_POINTER);
  32. CAutoLock cAutoLock(m_pFilter->pStateLock());
  33. if(iPosition < 0)
  34. {
  35. return E_INVALIDARG;
  36. }
  37. // Have we run off the end of types?
  38. if(iPosition > 0)
  39. {
  40. return VFW_S_NO_MORE_ITEMS;
  41. }
  42. //给媒体类型申请Format的空间
  43. //填充每一个对象,主要是BITMAPINFOHEADER结构
  44. VIDEOINFO *pvi = (VIDEOINFO *) pmt->AllocFormatBuffer(sizeof(VIDEOINFO));
  45. if(NULL == pvi)
  46. return(E_OUTOFMEMORY);
  47. ZeroMemory(pvi, sizeof(VIDEOINFO));
  48. pvi->bmiHeader.biBitCount = 24;
  49. pvi->bmiHeader.biHeight = m_nHeight;
  50. pvi->bmiHeader.biWidth = m_nWidth;
  51. pvi->bmiHeader.biSizeImage = m_nImageSize;
  52. pvi->bmiHeader.biPlanes = 1;
  53. pvi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  54. pvi->bmiHeader.biCompression = BI_RGB;
  55. pvi->bmiHeader.biClrImportant = 0;
  56. SetRectEmpty(&pvi->rcSource);
  57. SetRectEmpty(&pvi->rcTarget);
  58. pmt->SetType(&MEDIATYPE_Video);//设置主媒体类型
  59. pmt->SetSubtype(&MEDIASUBTYPE_RGB24);//设置子媒体类型
  60. pmt->SetFormatType(&FORMAT_VideoInfo);//设置详细格式类型
  61. pmt->SetSampleSize(m_nImageSize);//设置Sample的大小
  62. pmt->SetTemporalCompression(FALSE);
  63. return NOERROR;
  64. }
  65. //检查媒体类型
  66. //主要是对GetMediaType中设置的各个参数进行比较
  67. HRESULT CMyOutputPin::CheckMediaType(const CMediaType *pMediaType)
  68. {
  69. CheckPointer(pMediaType,E_POINTER);
  70. if (*(pMediaType->Type()) != MEDIATYPE_Video
  71. || !(pMediaType->IsFixedSize()))
  72. {
  73. return E_INVALIDARG;
  74. }
  75. const GUID *SubType = pMediaType->Subtype();
  76. if (SubType == NULL)
  77. {
  78. return E_INVALIDARG;
  79. }
  80. if (*SubType != MEDIASUBTYPE_RGB24)
  81. {
  82. return E_INVALIDARG;
  83. }
  84. const GUID* FormatType = pMediaType->FormatType();
  85. if (FormatType == NULL)
  86. {
  87. return E_INVALIDARG;
  88. }
  89. if (*FormatType != FORMAT_VideoInfo)
  90. {
  91. return E_INVALIDARG;
  92. }
  93. VIDEOINFO* pvi = (VIDEOINFO*)pMediaType->Format();
  94. if (pvi == NULL)
  95. {
  96. return E_INVALIDARG;
  97. }
  98. if (pvi->bmiHeader.biBitCount != 24 ||
  99. pvi->bmiHeader.biWidth != m_nWidth ||
  100. pvi->bmiHeader.biHeight != m_nHeight)
  101. {
  102. return E_INVALIDARG;
  103. }
  104. return S_OK;
  105. }
  106. //协商Sample的大小
  107. HRESULT CMyOutputPin::DecideBufferSize(IMemAllocator *pIMemAlloc, ALLOCATOR_PROPERTIES *pProperties)
  108. {
  109. CheckPointer(pIMemAlloc,E_POINTER);
  110. CheckPointer(pProperties,E_POINTER);
  111. CAutoLock cAutoLock(m_pFilter->pStateLock());
  112. HRESULT hr = NOERROR;
  113. VIDEOINFO *pvi = (VIDEOINFO *) m_mt.Format();
  114. //确定只有一个buffer
  115. pProperties->cBuffers = 1;
  116. //设置buffer的大小
  117. pProperties->cbBuffer = m_nImageSize;
  118. ASSERT(pProperties->cbBuffer);
  119. //设置属性页
  120. ALLOCATOR_PROPERTIES Actual;
  121. hr = pIMemAlloc->SetProperties(pProperties,&Actual);
  122. if(FAILED(hr))
  123. {
  124. return hr;
  125. }
  126. if(Actual.cbBuffer < pProperties->cbBuffer)
  127. {
  128. return E_FAIL;
  129. }
  130. ASSERT(Actual.cBuffers == 1);
  131. return NOERROR;
  132. }
  133. //填充Sample
  134. HRESULT CMyOutputPin::FillBuffer(IMediaSample *pMediaSample)
  135. {
  136. CheckPointer(pMediaSample,E_POINTER);
  137. BYTE* pData = NULL;
  138. long lDataSize = 0;
  139. //获得Sample中存放数据的地址
  140. pMediaSample->GetPointer(&pData);
  141. //取得Sample分配的内存大小
  142. lDataSize = pMediaSample->GetSize();
  143. ZeroMemory(pData,lDataSize);
  144. //把当前需要显示的数据拷贝到内存中
  145. CopyMemory(pData,m_pData[m_nCount%3],m_nImageSize);
  146. //设置时间戳
  147. REFERENCE_TIME start = TS_ONE * m_nCount;
  148. REFERENCE_TIME stop = TS_ONE + start;
  149. pMediaSample->SetTime(&start,&stop);
  150. //准备下一帧数据
  151. m_nCount++;
  152. pMediaSample->SetSyncPoint(TRUE);
  153. return NOERROR;
  154. }

LoadBitmapFileToMemory函数的实现

[cpp] view plaincopyprint?
  1. BYTE* LoadBitmapFileToMemory(TCHAR* pFileName, int& nWidth, int& nHeight, int& nImageDataSize)
  2. {
  3. HBITMAP hBitmap = (HBITMAP)LoadImage( NULL, pFileName, IMAGE_BITMAP, 0, 0,
  4. LR_CREATEDIBSECTION | LR_DEFAULTSIZE | LR_LOADFROMFILE );
  5. if(hBitmap == NULL)
  6. return NULL;
  7. HDC hDC = CreateCompatibleDC(NULL);
  8. HBITMAP hOldBitmap = (HBITMAP)SelectObject(hDC, hBitmap);
  9. BITMAP bmp;
  10. GetObject(hBitmap, sizeof(bmp), &bmp);
  11. BITMAPINFOHEADER bih = {0};//位图信息头
  12. bih.biBitCount = bmp.bmBitsPixel;//每个像素字节大小
  13. bih.biCompression = BI_RGB;
  14. bih.biHeight = bmp.bmHeight;//高度
  15. bih.biPlanes = 1;
  16. bih.biSize = sizeof(BITMAPINFOHEADER);
  17. bih.biSizeImage = bmp.bmWidthBytes * bmp.bmHeight;//图像数据大小
  18. bih.biWidth = bmp.bmWidth;//宽度
  19. nImageDataSize = bmp.bmWidthBytes * bmp.bmHeight;
  20. byte * p = new byte[nImageDataSize];//申请内存保存位图数据
  21. GetDIBits(hDC, hBitmap, 0, bmp.bmHeight, p,
  22. (LPBITMAPINFO) &bih, DIB_RGB_COLORS);//获取位图数据
  23. SelectObject(hDC, hOldBitmap);
  24. DeleteObject(hBitmap);
  25. DeleteDC(hDC);
  26. nWidth = bmp.bmWidth;
  27. nHeight = bmp.bmHeight;
  28. return p;
  29. }

5.主要的工作已经做完了,功能已经实现,接下来就是生成Filter。

[cpp] view plaincopyprint?
  1. //MySourceFilter.h
  2. //动态库工程自然也要有入口函数(固定格式)
  3. extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);
  4. BOOL APIENTRY DllMain(HANDLE hModule,
  5. DWORD  dwReason,
  6. LPVOID lpReserved)
  7. {
  8. return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);
  9. }
  10. //组件就少不了注册与注销函数(固定格式)
  11. STDAPI DllRegisterServer()
  12. {
  13. return AMovieDllRegisterServer2(TRUE);
  14. }
  15. STDAPI DllUnregisterServer()
  16. {
  17. return AMovieDllRegisterServer2(FALSE);
  18. }
  19. //组件,就要有GUID(通过工具创建)
  20. DEFINE_GUID(CLSID_MyFilter,
  21. 0x159386e0, 0x5193, 0x48ac, 0x8a, 0x57, 0x17, 0x88, 0xc7, 0x33, 0x40, 0xc1);
  22. //以下是注册信息的模版,写了注释的地方是我们需要填写的,其他的采用默认
  23. const AMOVIESETUP_MEDIATYPE sudOpPinTypes =
  24. {
  25. &MEDIATYPE_Video,       // Major type
  26. &MEDIASUBTYPE_NULL      // Minor type
  27. };
  28. const AMOVIESETUP_PIN sudOpPin =
  29. {
  30. L"Output",
  31. FALSE,
  32. TRUE,
  33. FALSE,
  34. FALSE,
  35. &CLSID_NULL,
  36. NULL,
  37. 1,
  38. &sudOpPinTypes };
  39. const AMOVIESETUP_FILTER sudBallax =
  40. {
  41. &CLSID_MyFilter,    // 自定义的GUID
  42. L"MyFilter",       // Filter的名字
  43. MERIT_DO_NOT_USE,
  44. 1,
  45. &sudOpPin
  46. };
  47. // COM global table of objects in this dll
  48. CFactoryTemplate g_Templates[] = {
  49. { L"MyFilter"//Filter的名字
  50. , &CLSID_MyFilter//自定义的GUID
  51. , CMySourceFilter::CreateInstance//Filter的实例化接口
  52. , NULL
  53. , &sudBallax }
  54. };
  55. int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);

6.MySourceFilter.def文件的内容

[cpp] view plaincopyprint?
  1. LIBRARY "MySourceFilter.ax"
  2. EXPORTS
  3. DllMain                 PRIVATE
  4. DllGetClassObject       PRIVATE
  5. DllCanUnloadNow         PRIVATE
  6. DllRegisterServer       PRIVATE
  7. DllUnregisterServer     PRIVATE

7.注意

1)包含头文件 #include <initguid.h>,否则有可能提示 error LNK2001: 无法解析的外部符号 _CLSID_MyFilter

2)包含导出库#pragma comment(lib, "winmm")

3)包含导入库#pragma comment(lib, "strmbase.lib"),Debug下包含#pragma comment(lib, "strmbasd.lib")

8.大功告成。调用regsvr32注册Filter。使用GraphEdit调试Filter。(VS2005)

在工程的属性中选择调试,在命令中填入GraphEdit的完整路径,把Filter的工程作为启动项。按下F5,在运行的GraphEdit中选择我们的Filter,Render pin,就可以看到一条完整的链路,然后run,效果出来了,三幅图片轮流显示在窗口中。

转载于:https://www.cnblogs.com/signal/p/4094102.html

DirectShow基础编程 最简单的源Filter的编写步骤 (转)相关推荐

  1. PTA 基础编程题目集 7-12 两个数的简单计算器 C语言

    PTA 基础编程题目集 7-12 两个数的简单计算器 C语言 本题要求编写一个简单计算器程序,可根据输入的运算符,对2个整数进行加.减.乘.除或求余运算.题目保证输入和输出均不超过整型范围. 输入格式 ...

  2. PTA 基础编程题目集 6-8 简单阶乘计算 C语言

    PTA 基础编程题目集 6-8 简单阶乘计算 C语言 本题要求实现一个计算非负整数阶乘的简单函数. 函数接口定义: int Factorial( const int N ); 其中N是用户传入的参数, ...

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

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

  4. Linux应用程序设计之网络基础编程

    1.TCP/IP协议概述 1.1.OSI参考模型及TCP/IP参考模型 OSI协议参考模型是基于国际标准化组织(ISO)的建议发展起来的,从上到下工分为7层:应用层,表示层,会话层,传输层,网络层,数 ...

  5. 【人工智能】基于百度AI+Python编程的简单应用:关于人像照片动漫化的分析实现(可进行批量化处理)——教你看到二次元中的自己

    前两天博主刚写过一篇文章:[人工智能]基于百度AI和Python编程的简单实现:通过QQ/Tim截图进行文本识别功能的分析实战详解--以获取百度文库付费内容为例.由于这两天博主摸鱼时又一次使用到了百度 ...

  6. 大数据第二阶段Python基础编程学习笔记(待完善)

    大数据第二阶段Python基础编程学习笔记(待完善) 第一章 Python基础语法 3.8 1-1Python概述 python基础部分: ●Python基础语法: 标识符,关键字,变量,判断循环.. ...

  7. C#网络编程服务器端程序实现源码浅析

    C#网络编程服务器端程序实现源码是怎么样的呢?让我们来看看其中重要的一部分: 由于在此次程序中我们采用的结构是异步阻塞方式,所以在实际的程序中,为了不影响服务器端程序的运行速度,我们在程序中设计了一个 ...

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

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

  9. 实验四 数据库SQL语言基础编程

    -- 实验四 数据库SQL语言基础编程 -- 实验目的: --  掌握数据库查询语句的编写方法 --  掌握利用查询语言完成基本查询 --  掌握利用SQL语句完成数据的添加.删除.修改操作 -- 实 ...

最新文章

  1. 初级开发人员的缺点_作为一名初级开发人员,我如何努力克服自己的挣扎
  2. SCL+Devtoolset 安装与使用笔记
  3. centos7 安装 mysql rpm_CentOS7使用rpm安装MySQL8
  4. PostgreSQL — 常规操作
  5. 多线程-多图下载综合案例-SDWebImage框架实现代码
  6. Nginx的index指令
  7. java外围设计_Java 编程(23 种设计模式)
  8. 一建机电实务教材电子版_必背!一建《机电实务》高频考点,每日一背
  9. Schedulerx2.0工作流支持数据传输
  10. 【Android】EditText标签调用键盘
  11. uploadify 3.1 的修改
  12. n986原生android,【极光ROM】-【三星NOTE20高通全系列(国行/港版/台版/韩版/美版/日版) N98XX】-【V8.0 Android-R-UDC】...
  13. Linux系统软件看门狗
  14. C语言实现矩阵的乘法
  15. html跳转函数,javascript函数里如何实现页面跳转?
  16. 服务器端请求伪造——SSRF
  17. Android强制竖屏
  18. 【Codecs系列】HEVC官方软件HM源代码简单分析-解码器TAppDecoder
  19. 一年有50万主播入驻淘宝,宇宙的尽头是编制,直播的尽头是淘宝?
  20. 群晖linux文件夹颜色红色,技术干货分享 | 群晖备份Linux文件夹~

热门文章

  1. mysql-5.7.17-winx64的安装配置
  2. mysqlsla的使用
  3. Android数据库新王者-Realm入门教程
  4. as3+java+mysql(mybatis) 数据自动工具(三)
  5. 使用Team Foundation Server进行源代码管理(转)
  6. 服务器状态监控之二软硬件环境介绍
  7. 网站中人性化提示信息的JavaScript实现
  8. js中对函数设置默认参数值的3种方法
  9. ASP.NET页面通过URL传递参数(一)(转载)
  10. asp.net(c#) linkbutton CommandArgument