• DirectShow Filter 基础与简单的示例程序


    DirectShow 是一个 Windows 平台上的流媒体框架,提供了高质量的多媒体流采集和回放功能。
    Filter 实质是一个 COM 组件,所以学习开发 Filter 前你应该对 COM 相关知识有点了解。COM 组件的实质是实现了纯虚指针接口的 C++ 对象。
    应用程序开发者只需要基本的 COM 组件知识:实例化COM组件、调用接口、管理接口的引用计数。Filter 开发者则需要更多。
    选择一个基类,声明自己的类。
    应该清楚这个 Filter 在整个 Filter Graph 的位置,这个 Filter 的输入是什么数据,输出是什么数据,有几个输入 Pin、几个输出 Pin 等,可以画出这个 Filter 的草图。
    Win7: DirectShow SDK 做为 Windows SDK(GRMSDK_EN_DVD.iso) 的一部分,不再有单独的 DirectX SDK 包。
    在 DirectShow 中,应用程序要实现功能就必须将这些 Filter 链接在一起,因而一个 Filter 的输出就变成了另一个 Filter 的输入。这一系列串在一起的 Filter 称为 Filter Graph。
     
    使用 VS2008 建立 Filter 开发工程的过程如下:
    (1) 新建 
    Visual C++/Win32 项目,工程名如:FilterSample。点击“确定”进入下一步;
    (2) 应用程序类型选择:DLL,一般不选择 MFC 和 ATL;
    工程的建立完成,编译后可以先将输入文件改名。方法如下:
    属性页/链接器/常规/输出文件,修改为:$(OutDir)/FilterSample.ax
     
    DirectShow 必须用到以下头文件的库文件:
     1 #include "streams.h"  
     2 #include "initguid.h"  
     3 strmbasd.lib  
     4 winmm.lib  
     5 uuid.lib  
     6 Quartz.lib   输出 AMGetErrorText 函数,如果不调用此函数,此库不是必需的。  
     7   
     8 FilterSample.def 文件的内容:  
     9 LIBRARY FilterSample.ax   
    10 EXPORTS  
    11 ; 需要定义的导出函数  
    12 DllMain PRIVATE  
    13 DllRegisterServer PRIVATE  
    14 DllUnregisterServer PRIVATE  
    15 ; 在基类中已经定义的导出函数  
    16 DllGetClassObject PRIVATE  
    17 DllCanUnloadNow PRIVATE  
    18   
    19 dllmain.cpp 的代码如下:  
    20 // dllmain.cpp : 定义 DLL 应用程序的入口点。  
    21 #include "stdafx.h"  
    22 #include "streams.h"  
    23   
    24 // BOOL APIENTRY DllMain( HMODULE hModule,  
    25 //                        DWORD  ul_reason_for_call,  
    26 //                        LPVOID lpReserved  
    27 //           )  
    28 // {  
    29 //  switch (ul_reason_for_call)  
    30 //  {  
    31 //  case DLL_PROCESS_ATTACH:  
    32 //  case DLL_THREAD_ATTACH:  
    33 //  case DLL_THREAD_DETACH:  
    34 //  case DLL_PROCESS_DETACH:  
    35 //    break;  
    36 //  }  
    37 //  return TRUE;  
    38 // }  
    39   
    40 STDAPI DllRegisterServer()  
    41 {  
    42   return AMovieDllRegisterServer2(TRUE);  
    43 }  
    44 STDAPI DllUnregisterServer()  
    45 {  
    46   return AMovieDllRegisterServer2(FALSE);  
    47 }  
    48   
    49 extern "C" BOOL WINAPI DllEntryPoint(HINSTANCE, ULONG, LPVOID);  
    50 BOOL APIENTRY DllMain(HANDLE hModule, DWORD  dwReason,   LPVOID lpReserved)  
    51 {  
    52   return DllEntryPoint((HINSTANCE)(hModule), dwReason, lpReserved);  
    53 }  
    编译时,可能会遇到如下问题:
    1>e:worksourcecode estcodefiltersampledllmain.cpp(23) : error C3861: “AMovieDllRegisterServer2”: 找不到标识符
    1>e:worksourcecode estcodefiltersampledllmain.cpp(27) : error C3861: “AMovieDllRegisterServer2”: 找不到标识符
    编译错误, 一般是头文件没有包含。所以,包含: #include "streams.h"
     
    1>dllmain.obj : error LNK2019: 无法解析的外部符号 _AMovieDllRegisterServer2@4,该符号在函数 _DllRegisterServer@0 中被引用
    1>dllmain.obj : error LNK2019: 无法解析的外部符号 _DllEntryPoint@12,该符号在函数 _DllMain@12 中被引用
    1>E:WorkSourceCodeTestCodeFilterSampleDebugFilterSample.dll : fatal error LNK1120: 2 个无法解析的外部命令
    链接错误, 一般是库文件没有包含。所以,库输入中包含: strmbasd.lib
     
    1>正在链接...
    1>strmbasd.lib(wxdebug.obj) : error LNK2019: 无法解析的外部符号 __imp__timeGetTime@0,该符号在函数 "void __stdcall DbgInitialise(struct HINSTANCE__ *)" (?DbgInitialise@@YGXPAUHINSTANCE__@@@Z) 中被引用
    1>strmbasd.lib(wxutil.obj) : error LNK2001: 无法解析的外部符号 __imp__timeGetTime@0
    1>strmbasd.lib(wxutil.obj) : error LNK2019: 无法解析的外部符号 __imp__timeSetEvent@20,该符号在函数 "unsigned int __cdecl CompatibleTimeSetEvent(unsigned int,unsigned int,void (__stdcall*)(unsigned int,unsigned int,unsigned long,unsigned long,unsigned long),unsigned long,unsigned int)" (?CompatibleTimeSetEvent@@YAIIIP6GXIIKKK@ZKI@Z) 中被引用
    1>E:WorkSourceCodeTestCodeFilterSampleDebugFilterSample.dll : fatal error LNK1120: 4 个无法解析的外部命令
    包含  winmm.lib, 可以解决 timeGetTime 链接错误的问题
     
    增加头文件 FilterSample.h,其内容如下:
    其中 GUID 的生成,需要用到下面的工具: Microsoft SDKsWindowsv7.1Binguidgen.exe
     1 #ifndef _FILTER_SAMPLE_H_  
     2 #define _FILTER_SAMPLE_H_  
     3   
     4 // {33B57142-BD07-4a77-AE91-A8F6C24A8F40}  
     5 DEFINE_GUID(CLSID_FilterSample,   
     6     0x33b57142, 0xbd07, 0x4a77, 0xae, 0x91, 0xa8, 0xf6, 0xc2, 0x4a, 0x8f, 0x40);  
     7   
     8 class CFilterSample: public CCritSec, public CBaseFilter  
     9 {  
    10 public:  
    11   CFilterSample(TCHAR *pName,LPUNKNOWN pUnk,HRESULT *hr);  
    12   virtual ~CFilterSample();   
    13   static CUnknown * WINAPI CreateInstance(LPUNKNOWN pUnk, HRESULT *phr);   
    14   CBasePin *GetPin(int n);  
    15   int GetPinCount();    
    16 };  
    17   
    18 #endif  

    FilterSample.cpp 的内容如下:

     1 // FilterSample.cpp : 定义 DLL 应用程序的导出函数。  
     2 //  
     3   
     4 #include "stdafx.h"  
     5 #include "streams.h"  
     6 #include "initguid.h"  
     7   
     8 #include "FilterSample.h"  
     9   
    10 // Using this pointer in constructor  
    11 #pragma warning(disable:4355 4127)  
    12   
    13 //////////////////////////////////////////////////////////////////////////  
    14 // AMOVIESETUP_FILTER 描述一个 Filter  
    15 // AMOVIESETUP_PIN 描述 pin  
    16 // AMOVIESETUP_MEDIATYPE 描述数据类型  
    17 const AMOVIESETUP_MEDIATYPE sudPinTypes =  
    18 {  
    19   &MEDIATYPE_NULL,         // Major CLSID  
    20   &MEDIASUBTYPE_NULL       // Minor type  
    21 };  
    22   
    23 const AMOVIESETUP_PIN psudPins[] =  
    24 {  
    25   {   
    26     L"Input",             // Pin's string name  
    27     FALSE,                // Is it rendered  
    28     FALSE,                // Is it an output  
    29     FALSE,                // Allowed none  
    30     FALSE,                // Allowed many  
    31     &CLSID_NULL,          // Connects to filter  
    32     L"Output",            // Connects to pin  
    33     1,                    // Number of types  
    34     &sudPinTypes          // Pin information  
    35   },  
    36   {  
    37     L"Output",            // Pin's string name  
    38     FALSE,                // Is it rendered  
    39     TRUE,                 // Is it an output  
    40     FALSE,                // Allowed none  
    41     FALSE,                // Allowed many  
    42     &CLSID_NULL,          // Connects to filter  
    43     L"Input",             // Connects to pin  
    44     1,                    // Number of types  
    45     &sudPinTypes          // Pin information  
    46   }  
    47 };  
    48   
    49 const AMOVIESETUP_FILTER sudInfTee =  
    50 {  
    51   &CLSID_FilterSample,           // CLSID of filter  
    52   L"Filter Sample Test Lib",     // Filter's name  
    53   MERIT_DO_NOT_USE,              // Filter merit  
    54   2,                             // Number of pins  
    55   psudPins                       // Pin information  
    56 };  
    57 //////////////////////////////////////////////////////////////////////////  
    58   
    59 CFactoryTemplate g_Templates[1] =   
    60 {  
    61   {  
    62     L"Filter Sample",                // Name  
    63     &CLSID_FilterSample,             // CLSID  
    64     CFilterSample::CreateInstance,   // Method to create an instance of MyComponent  
    65     NULL,                            // Initialization function  
    66     &sudInfTee                       // Set-up information (for filters)  
    67   }  
    68 };  
    69 int g_cTemplates = sizeof(g_Templates) / sizeof(g_Templates[0]);  
    70   
    71   
    72 CFilterSample::CFilterSample(TCHAR *pName,LPUNKNOWN pUnk,HRESULT *hr)  
    73   :CBaseFilter(NAME("Filter Sample"), pUnk, this, CLSID_FilterSample)  
    74 {  
    75 }  
    76   
    77 CFilterSample::~CFilterSample()  
    78 {  
    79 }   
    80   
    81 CBasePin * CFilterSample::GetPin(int n)  
    82 {  
    83   return NULL;  
    84 }  
    85 int CFilterSample::GetPinCount()  
    86 {  
    87   return 0;  
    88 }  
    89   
    90 CUnknown * WINAPI CFilterSample::CreateInstance(LPUNKNOWN pUnk, HRESULT *pHr)  
    91 {  
    92   CFilterSample *pFilter = new CFilterSample(NAME("Filter Sample"), pUnk, pHr);  
    93   if (pFilter== NULL)  
    94   {  
    95     *pHr = E_OUTOFMEMORY;  
    96   }  
    97   return pFilter;  
    98 }  
    编译时,可能遇到如下问题:
    1>FilterSample.obj : error LNK2019: 无法解析的外部符号 "public: __thiscall CBaseFilter::CBaseFilter(wchar_t const *,struct IUnknown *,class CCritSec *,struct _GUID const &)" (??0CBaseFilter@@QAE@PB_WPAUIUnknown@@PAVCCritSec@@ABU_GUID@@@Z),该符号在函数 "public: __thiscall CFilterSample::CFilterSample(wchar_t *,struct IUnknown *,long *)" (??0CFilterSample@@QAE@PA_WPAUIUnknown@@PAJ@Z) 中被引用
    1>E:WorkSourceCodeTestCodeFilterSampleDebugFilterSample.dll : fatal error LNK1120: 1 个无法解析的外部命令
    解决方法: 属性页 常规->字符集 修改为“使用多字节字符集”
     
    编译通过后,如何验证此 Filter 呢?
    regsvr32 FilterSample.ax
    regsvr32 提示错误:
    模块“FilterSample.ax”已加载,但找不到入口点 DllRegisterServer。
    请确保“FilterSample.ax”为有效的 DLL 或 OCX 文件,然后重试。
    出现此错误的原因,是 FilterSample.def 未链接到工程中。在工程属性页,“链接器”/“输入”/“模块定义文件” 中输入: FilterSample.def 后,重新编译。
    然后在命令行执行: regsvr32 FilterSample.ax,则提示成功。
     
    如何确认成功了呢?可通过 Microsoft SDKsWindowsv7.1Bingraphedt.exe 来查看。方法如下:
    点击 graphedt.exe 的 Graph 菜单,选择 Insert Filters...。在弹出的对话框: Which filters do you want to insert? 中,选择 Directshow Filters/Filter Sample Test Lib。
    这个名字看起来是不是很熟悉?看看上面的代码中是不是有这样的字符串,呵呵...。如果还不确认,请看 Filter Sample Test Lib 的 GUID 和 文件名分别是:
    @device:sw:{083863F1-70DE-11D0-BD40-00A0C911CE86}{33B57142-BD07-4A77-AE91-A8F6C24A8F40} 和 E:FiltersFilterSample.ax(具体的目录与执行 regsvr32 时 FilterSample.ax 所在的路径相关)。
  • 相关阅读:
    getContentResolver()内容解析者查询联系人、插入联系人
    ContentProvider备份短信,以xml文件存储
    ContentProvider详解
    bindService初步了解
    Service之来电监听(失败的案例)
    Android帧动画
    AlertDialog之常见对话框(单选对话框、多选对话框、进度条对话框)
    BroadcastReceiver之(手动代码注册广播)屏幕锁屏、解锁监听、开机自启
    BroadcastReceiver之有序广播
    [FJOI2015]火星商店问题
  • 原文地址:https://www.cnblogs.com/91program/p/5205020.html
Copyright © 2020-2023  润新知