为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

最新DirectShow视频采集开发指南

2013-10-11 41页 pdf 851KB 93阅读

用户头像

is_997467

暂无简介

举报
最新DirectShow视频采集开发指南 DirectShow 最新视频采集开发指南 2011.11 2.3 DirectShow视频采集方案 流媒体处理技术以其复杂性和技术性一直受到人们的关注。随着网络技术的不断发展,流媒体在网络 上得到了广泛地应用。如何能 够简单、有效地进行流媒体处理,已成为一个焦点问题。为此,Microsoft 推出了 DirectShow,DirectShow是 Microsoft推 出的基于 Windows平台的流媒体处理开发包,它与 DirectX一起发布。DirectShow对流媒体的捕捉...
最新DirectShow视频采集开发指南
DirectShow 最新视频采集开发指南 2011.11 2.3 DirectShow视频采集 流媒体处理技术以其复杂性和技术性一直受到人们的关注。随着网络技术的不断发展,流媒体在网络 上得到了广泛地应用。如何能 够简单、有效地进行流媒体处理,已成为一个焦点问。为此,Microsoft 推出了 DirectShow,DirectShow是 Microsoft推 出的基于 Windows平台的流媒体处理开发包,它与 DirectX一起发布。DirectShow对流媒体的捕捉、回放提供了强大的支持,使用它还可以 在基于 WDM 驱动的采集卡上进行数据捕捉。本节将介绍有关 DirectShow的相关知识。 2.3.1 DirectShow系统结构分析 DirectShow主要由过滤器(Filter Graph)图表构成。过滤图表中包含了各种 Filter,这些 Filter 能够按一定顺序连接在一起,构成一条流水线。从功能的角度划分,Filter 大体可以分为 3类,Source Filters、Transform Filters和 Rendering Filters。Source Filters主要负责获取数据,可以是 一个文件、一个采集卡、声卡或数码相机等。Transform Filters负责数据的转换、传输。例如各种 编码器、解码器等。Rendering Filters负责数据的最终去向,例如将数据传送到声卡、显卡或存储 为文件。 在开发 DirectShow应用程序时,通常需要一个过滤图表(Filter Graph),向过滤图表中添加 相应的过滤器,最后连接过滤器的引脚就完成了功能的设计。例如,实现一个简单的视频预览功能, 需要向过滤图表中添加一个视 频捕捉源过滤器和一个 Video Renderer过滤 器,将视频捕捉源过滤 器的输出引脚与 Video Renderer过滤器的输入引脚相连就可以了。而在程序中只需要按照设计过滤 图表的捕捉添加过滤器并连接过滤器引脚就可以了。在连接过滤器引脚时需要注 意:只能是输出过 滤器引脚与输入过滤器引脚相连,两个输出过滤器或两个输入过滤器引脚是不能相连的。 为了在程序中使用 DirectShow,需要单独安装 DirectX,当前 DirectX的最新版本为 9.0,即 DirectX9.0,用户可以从 Microsoft的官方网站上免费下载。在安装 DirectX之后,程序中需要引用 “dshow.h”头文件,并导入 “Strmiids.lib”库文件和“quartz.lib”库文件才可以使用 DirectShow。代码如下: #pragma comment (lib,"Strmiids") #pragma comment (lib,"quartz") #include 2.3.2 Filter图表设计 为了方便用户设计过滤图表,DirectX提供了一个 Graph Edit工具。用户可以单击“开始”菜单下 的“Microsoft DirectX 9 SDK\DirectX Utilities\Graph Edit”菜单项打开 Graph Edit工具,如 图 2.10所示。 图 2.10 Graph Edit工具 下面笔者介绍如何使用 Graph Edit工具设计过滤图表,过滤图表的功能是实现视频的预览功能。具 体步骤如下: (1)在图 2.4中单击“Graph/Insert Filters”菜单项打开“添加过滤器”窗口,如图 2.11所示。 图 2.11 添加过滤器窗口 (2)在“Video Capture Sources”节点下选择一个视频捕捉源过滤器,单击“Insert Filter”按 钮将其添加到过滤图表中,如图 2.12所示 图 2.12 添加视频捕捉源过滤器窗口 提示:如果系统中没有安装摄像头及其驱动程序,该节点下将不会有视频捕捉源过滤器。 (3)在“DirectShow Filters”节点下选择“Video Renderer”过滤器,将其添加到图表中,如图 2.13所示。 图 2.13 添加“Video Renderer”过滤器窗口 (4)利用鼠标将视频捕捉源过滤器的“Capture”引脚与“Video Renderer”过滤器的“VMR Input0”引脚相连,如图 2.14所示。 图 2.14 连接过滤器引脚窗口 (5)单击工具栏中的“ ”按钮运行过滤图表,将显示一个视频预览窗口,如图 2.15所示。 图 2.15 视频预览窗口 2.3.3 枚举系统设备 使用 Graph Edit工具,用户可以非常方便地获得与某一系统设备相关的过滤器。但是,在程序中该 如何获得这些过滤器呢? 用户可以采用枚举的方式列举系统中安装的设备。以列举系统中的视频捕捉设备为例,首先定义一个 设备列举接口 ICreateDevEnum的一个指针,调用 CoCreateInstance创建 ICreateDevEnum实例, 然后定义一个列举监视器 IEnumMoniker的一个指针,调用 ICreateDevEnum实例的 CreateClassEnumerator方法创建 IEnumMoniker实例,最后以循环的方式调用 IEnumMoniker实例的 Next方法遍历系统设备,调用 IEnumMoniker实例的 BindToObject方法将系统设备绑定到过滤器上。 在上面的描述中,ICreateDevEnum实例的 CreateClassEnumerator方法的第一个参数确定枚 举的系 统设备。例如,第一个参数为 CLSID_VideoInputDeviceCategory,表示将要枚举系统中的视频捕捉 卡,为 CLSID_VideoCompressorCategory,表示枚举系统中的视频压缩器。下面的代码演示了如何枚 举系统中的视频捕捉卡。 //枚举视频设备 ICreateDevEnum *pDevEnum = NULL; CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void **)&pDevEnum); IEnumMoniker *pClassEnum = NULL; pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0); ULONG cFetched; while (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK) { pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pSrc); pMoniker->Release(); break; } pClassEnum->Release(); 而下面的代码则用于判断系统中是否安装了指定的视频压缩器。 ICreateDevEnum *pDevEnum = NULL; CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void **)&pDevEnum); IEnumMoniker *pClassEnum = NULL; //列举视频压缩设备 pDevEnum->CreateClassEnumerator(CLSID_VideoCompressorCategory, &pClassEnum, 0); while (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK) { IPropertyBag* pProp= NULL; pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pProp); VARIANT varName; varName.vt = VT_BSTR; pProp->Read(L"FriendlyName", &varName,0); CString str = varName.bstrVal; if (str.Find("Microsoft Video 1",0)!= -1) { pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pCompress); pMoniker->Release(); break; } VariantClear(&varName); } pClassEnum->Release(); 2.3.4 查找 Filter Pin 每一个过滤器(Filter)至少应有一个引脚(Pin),或者是输入引脚或者是输出引脚。有些过滤器 还拥有多个引脚,即 又输入引脚又有输出引脚。但是过滤器的输入、输出引脚并不是对应的,有些 过滤器可以有多个输入引脚,而只有一个输出引脚或者没有输出引脚。在程序中为了连 接过滤器间 的引脚,通常需要获得过滤器的各个引脚。用户可以使用 IEnumPins接口来枚举某一个过滤器的输入、 输出引脚。过滤器 IBaseFilter提供了一个 EnumPins方法用于生成一个 IEnumPins接口实例,这样, 通过调用 IEnumPins的 Next方法便可以 访问各个引脚了。下面的代码定义了一个 FindPin函数,用 于获得某个过滤器的输入或输出引脚。 //查找引脚 IPin* CKinescopeDlg::FindPin(IBaseFilter *pFilter, PIN_DIRECTION dir) { IEnumPins* pEnumPins; IPin* pOutpin; PIN_DIRECTION pDir; pFilter->EnumPins(&pEnumPins); while (pEnumPins->Next(1,&pOutpin,NULL)==S_OK) { pOutpin->QueryDirection(&pDir); if (pDir==dir) { return pOutpin; } } return 0; } 用户可以按下面的方式获得某个过滤器的输入、输出引脚。 IPin * pComOut,*pComIn ; pComIn = FindPin(pCompress,PINDIR_INPUT); pComOut = FindPin(pCompress,PINDIR_OUTPUT); 2.3.5 连接 Filter Pin 使用 Graph Edit工具,用户可以利用鼠标非常方便地连接两个过滤器间的引脚。但是在程序中却没 这么简单了。首先需要按照 2.3.4节介绍的方法获得两个过滤器的输 入、输出引脚,然后将第一个 过滤器的输出引脚连接到第二个过滤器的输入引脚,其中,连接两个引脚需要调用 IGraphBuilder 接口的 ConnectDirect方法。下面的代码演示了如何连接两个过滤器的引脚。 IPin * pComOut,*pComIn ; pComIn = FindPin(pCompress,PINDIR_INPUT); pComOut = FindPin(pCompress,PINDIR_OUTPUT); IPin* pOutpin = FindPin(pSrc,PINDIR_OUTPUT); //pSrc的输出引脚 HRESULT result ; result = pGraph->ConnectDirect(pOutpin,pComIn,NULL); 2.3.6 视频预览设计方案 在开发视频应用程序时,一个最基本的功能是视频预览。本节将介绍如何应用 DirectShow实现视频 预览,效果如图 2.16所示。 图 2.16 视频预览设计方案 在使用 DirectShow开发应用程序时,通常需要先设计过滤图表,然后根据图表来设计应用程序。在 设计视频预览过滤图 表时,只需要两个步骤,第一个步骤是添加视频捕捉的源过滤器,第二个步骤 是添加 Video Render过滤器,并连接两个过滤器引脚。过滤图表具体设计步骤如下: (1)启动 Graph Edit工具, 在 Graph Edit工具中单击“Graph \Insert Filters”菜单项打开“添 加过滤器窗口”,在“Video Capture Sources”节点下选择一个视频捕捉源过滤器,单击“Insert Filter”按钮将其添加到过滤图表中,如图 2.11所示。 (2)在“DirectShow Filters”节点下将“Video Render”过滤器添加到图表中,如图 2.17所示。 图 2.17 过滤图表设计 1 (3)连接过滤器引脚,如图 2.18所示。 图 2.18 过滤图表设计 2 至此,完成视频预览过滤图表的设计。单击“Play”按钮运行过滤图表,将弹出一个视频预览窗口, 如图 2.19所示。 图 2.19 DerictShow预览窗口 程序具体步骤如下: 实例位置:光盘\mr\2\2.3\2.3.6\01 (1)创建一个基于对话框的工程,在对话框类的头文件中引用“dshow.h”头文件。 #pragma comment (lib,"Strmiids") #pragma comment (lib,"quartz") #include (2)在对话框类中定义如下成员变量。 IMediaControl *pMediaControl ; //媒体控制 IGraphBuilder *pGraph; //过滤图表 IBaseFilter *pSrc,*pPreview; //过滤器 IMoniker *pMoniker; //监视器 (3)向对话框类中添加 FindPin方法,查找过滤器的引脚。 //查找引脚 IPin* CPreviewDlg::FindPin(IBaseFilter *pFilter, PIN_DIRECTION dir) { IEnumPins* pEnumPins; IPin* pOutpin; PIN_DIRECTION pDir; pFilter->EnumPins(&pEnumPins); while (pEnumPins->Next(1,&pOutpin,NULL)==S_OK) { pOutpin->QueryDirection(&pDir); if (pDir==dir) { return pOutpin; } } return 0; } (4)在应用程序类的 InitInstance方法中初始化 Com接口。 //初始化 Com CoInitialize(NULL); (5)在对话框初始化时枚举视频捕捉设备,设计过滤图表。 ICaptureGraphBuilder2 * pBuilder = NULL; pGraph = NULL; pMediaControl = NULL; //枚举视频设备 ICreateDevEnum *pDevEnum = NULL; CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC, IID_ICreateDevEnum, (void **)&pDevEnum); IEnumMoniker *pClassEnum = NULL; pDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pClassEnum, 0); ULONG cFetched; if (pClassEnum->Next(1, &pMoniker, &cFetched) == S_OK) { pMoniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&pSrc); pMoniker->Release(); } pClassEnum->Release(); CoCreateInstance(CLSID_CaptureGraphBuilder2,0, CLSCTX_INPROC_SERVER,IID_ICaptureGraphBuilder2,(void**)&pBuilder); CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph); pBuilder->SetFiltergraph(pGraph); pGraph->QueryInterface(IID_IMediaControl,(void**)&pMediaControl); pGraph->AddFilter(pSrc,L"avi"); pPreview = NULL; CoCreateInstance(CLSID_VideoRenderer,0,CLSCTX_ALL, IID_IBaseFilter,(void**)&pPreview); if (pPreview != NULL) { pGraph->AddFilter(pPreview,L"preview"); //连接引脚 IPin * pSourceOut; pSourceOut = FindPin(pSrc,PINDIR_OUTPUT); IPin* pPreIn = FindPin(pPreview,PINDIR_INPUT); pGraph->ConnectDirect(pSourceOut,pPreIn,NULL); //获取预览窗口 IVideoWindow * pViewWnd= NULL; pPreview->QueryInterface(IID_IVideoWindow,(void**)&pViewWnd); if (pViewWnd) { //设置预览窗口的拥有者 pViewWnd->put_Owner((long)m_hWnd); pViewWnd->put_Left(1); pViewWnd->put_Top(1); //获取预览窗口风格 long style; pViewWnd->get_WindowStyle(&style); style = style & ~WS_CAPTION; style = style & ~WS_DLGFRAME; style = style & WS_CHILD; pViewWnd->put_WindowStyle(style); //设置预览窗口宽度和高度 CRect rc; GetClientRect(rc); pViewWnd->put_Height(rc.Height()-60); pViewWnd->put_Width(rc.Width()-2); } pMediaControl->Run(); } 2.3.7 事件通知设计方案 在使用 DirectShow开发应用程序时,通常需要 DirectShow与应用程序之间进行交互。例如,在使用 DirectShow播放影视文件时,在文件播放完毕后,应用程序需要得到通知,并通知用户文件播放完 毕。DirectShow采用了事件通知的机制与用 户应用程序进行交互。当过滤器的状态改变时,或者重 画视频窗口时,都将产生相应的事件,由 DirectShow处理并转发给应用程序,应用程序能够接收到 该 事件,并根据事件的不同类型作出相应的处理。DirectShow提供了 3个有关事件通知的接口,分别 为“IMediaEventSink”、 “IMediaEvent”和“IMediaEventEx”。其中,IMediaEventEx接口是 IMediaEvent接口的扩展,在应用程序中 经常使用该接口类处理事件。IMediaEventEx接口的主要方 法如下: 1.GetNotifyFlags方法 该方法用于获取事件通知是否被激活。语法如下: HRESULT GetNotifyFlags( long *lplNoNotifyFlags); 参数说明: lplNoNotifyFlags:确定事件通知是否被激活。如果为零,表示事件通知被激活,为 AM_MEDIAEVENT_NONOTIFY,表示事件通知不可用。 2.SetNotifyFlags方法 该方法用于设置事件通知是否被激活。语法如下: HRESULT SetNotifyFlags( long lNoNotifyFlags); lplNoNotifyFlags:如果为零,表示激活事件通知,为 AM_MEDIAEVENT_NONOTIFY,表示 禁止事件通 知。 3.SetNotifyWindow方法 该方法用于注册一个窗口来处理事件通知。语法如下: HRESULT SetNotifyWindow( OAHWND hwnd, long lMsg, long lInstanceData); 参数说明: hwnd:表示处理事件通知的窗口句柄。 lMsg:表示与事件通知关联的窗口消息。 lInstanceData:作为 lMsg消息处理函数的 lParam参数被传递。 4.GetEventHandle方法 该方法用于获取人工重置事件对象的句柄。语法如下: HRESULT GetEventHandle(OAEVENT *hEvent); 参数说明: hEvent:表示返回的人工重置事件对象的句柄。 5.GetEvent方法 该方法用于从消息队列中返回下一个事件通知。语法如下: HRESULT ( long *lEventCode, long *lParam1, long *lParam2, long msTimeout); 参数说明: lEventCode:表示接收的事件通知代码。 lParam1:表示第一个事件参数。 lParam2:表示第 2个事件参数。 msTimeout:表示超时时间,如果为 NFINITE,将一直等待,直到有事件通知为止。 6.FreeEventParams方法 该函数用于释放事件参数。语法如下: HRESULT FreeEventParams( long lEventCode, long lParam1, long lParam2); 参数说明: lEventCode:表示接收的事件通知代码。 lParam1:表示第一个事件参数。 lParam2:表示第 2个事件参数。 7.CancelDefaultHandling方法 该方法用于取消 DirectShow对事件进行的默认处理。语法如下: HRESULT CancelDefaultHandling( long lEvCode); 参数说明: lEvCode:表示事件通知代码。 8.RestoreDefaultHandling方法 该方法用于恢复 DirectShow对默认消息的处理。语法如下: HRESULT RestoreDefaultHandling( long lEvCode); 参数说明: lEvCode:表示事件通知代码。 在应用程序中可以有两种方式来接收和处理 DirectShow中的事件。第一种方式是让 DirectShow向应 用程序的 窗口中发送消息。第 2种方式是通过事件对象(这里的对象是指 Windows内核对象)。向 对而言,第一种方式比较简单,也比较常用,而第 2种方式多用于控 制台应用程序或多线程应用程 序。下面笔者将分别以这两种方式来实现事件通知消息。为了演示应用程序获得了 DirectShow发送 的事件通知,下面的两个 例子均以播放一个 AVI文件为例,在 DirectShow播放完 AVI文件,将向应 用程序发出通知,应用程序获得通知后,将弹出对话框提供用户,如图 2.20、图 2.21所示。 图 2.20 事件通知方式 1效果图 图 2.21 事件通知方式 2效果图 l 基于窗口消息的事件通知 实例位置:光盘\mr\2\2.3\2.3.7\01 (1)创建一个基于对话框的工程,在对话框中添加按钮、图像控件,如图 2.22所示。 图 2.22 事件通知方式 1对话框设计 (2)在类向导的“Member Variables”选项卡中为图像控件命名,如图 2.23所示。 图 2.23 类向导窗口 (3)在对话框类的头文件中引用“dshow.h”头文件,并导入相应的库文件。 #pragma comment (lib,"Strmiids") #pragma comment (lib,"quartz") #include (4)在应用程序的 InitInstance方法中初始化 Com库。 BOOL CNotifyEventApp::InitInstance() { AfxEnableControlContainer(); #ifdef _AFXDLL Enable3dControls(); #else Enable3dControlsStatic() #endif CoInitialize(NULL); CNotifyEventDlg dlg; m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); if (nResponse == IDOK) { } else if (nResponse == IDCANCEL) { } return FALSE; } (5)改写应用程序的 ExitInstance方法,在应用程序退出时卸载 Com库。 int CNotifyEventApp::ExitInstance() { CoUninitialize(); return CWinApp::ExitInstance(); } (6)在对话框类中添加如下成员变量。 IMediaControl *pMediaControl ; //媒体控制 IGraphBuilder *pGraph; //过滤图表 IBaseFilter *pSrc; //过滤器 IMoniker *pMoniker; //监视器 BOOL m_Previewed; //是否进行预览 IMediaEventEx *pEvent; //事件 IVideoWindow * pViewWnd; //预览窗口句柄 (7)自定义一个消息,用于在完成文件播放时向窗口中发送通知。 #define CM_NOTIFY WM_USER+1 (8)向对话框类中添加自定义消息处理函数 OnGraphNotify。 void CNotifyEventDlg::OnGraphNotify(WPARAM wParam, LPARAM lParam) { if (pEvent) { LONG eventcode = 0,param1 =0,param2 = 0; while (SUCCEEDED(pEvent->GetEvent(&eventcode,¶m1,¶m2,0))) { pEvent->FreeEventParams(eventcode,param1,param2); switch (eventcode) { case EC_COMPLETE: { m_Previewed = FALSE; pMediaControl->Stop(); pMediaControl->Release(); pGraph->Release(); pViewWnd->put_Visible(FALSE); MessageBox("预览完成","提示"); m_Panel.ShowWindow(SW_HIDE); m_Panel.ShowWindow(SW_SHOW); break; } } } } } (9)在对话框的消息映射部分添加消息映射宏,将消息与消息处理函数关联起来。 BEGIN_MESSAGE_MAP(CNotifyEventDlg, CDialog) //{{AFX_MSG_MAP(CNotifyEventDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_ChOOSE, OnChooSE) ON_MESSAGE(CM_NOTIFY,OnGraphNotify) //}}AFX_MSG_MAP END_MESSAGE_MAP() (10)处理“设置文件”按钮的单击事件,开始播放 AVI文件。 void CNotifyEventDlg::OnChooSE() { CFileDialog fDlg(TRUE,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,"avi文 件|*.avi"); if (fDlg.DoModal()==IDOK) { CString strFile= fDlg.GetPathName(); ICaptureGraphBuilder2 * pBuilder = NULL; pGraph = NULL; pMediaControl = NULL; CoCreateInstance(CLSID_CaptureGraphBuilder2,0,CLSCTX_INPROC_SERVER, IID_ICaptureGraphBuilder2,(void**)&pBuilder); CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph); pBuilder->SetFiltergraph(pGraph); pGraph->QueryInterface(IID_IMediaControl,(void**)&pMediaControl); pGraph->RenderFile(strFile.AllocSysString(),NULL); //获取预览窗口 pViewWnd= NULL; pGraph->QueryInterface(IID_IVideoWindow,(void**)&pViewWnd); if (pViewWnd) { //设置预览窗口的拥有者 pViewWnd->put_Owner((long)m_Panel. m_hWnd); pViewWnd->put_Left(1); pViewWnd->put_Top(1); //获取预览窗口风格 long style; pViewWnd->get_WindowStyle(&style); style = style & ~WS_CAPTION; style = style & ~WS_DLGFRAME; style = style & WS_CHILD; pViewWnd->put_WindowStyle(style); //设置预览窗口宽度和高度 CRect rc; m_Panel.GetClientRect(rc); pViewWnd->put_Height(rc.Height()); pViewWnd->put_Width(rc.Width()); } pGraph->QueryInterface(IID_IMediaEventEx, (void **)&pEvent); pEvent->SetNotifyWindow((OAHWND)m_hWnd,CM_NOTIFY,0); pMediaControl->Run(); m_Previewed = TRUE; } } l 基于事件对象的通知 实例位置:光盘\mr\2\2.3\2.3.7\02 (1)创建一个基于对话框的工程,在对话框中添加按钮、图像控件,如图 2.24所示。 图 2.24 事件通知方式 2话框设计 (2)在类向导的“Member Variables”选项卡中为图像控件命名。 (3)在对话框类的头文件中引用“dshow.h”头文件,并导入相应的库文件。 #pragma comment (lib,"Strmiids") #pragma comment (lib,"quartz") #include (4)在应用程序的 InitInstance方法中初始化 Com库。 BOOL CDirectShowEventApp::InitInstance() { AfxEnableControlContainer(); #ifdef _AFXDLL Enable3dControls(); #else Enable3dControlsStatic(); #endif CoInitialize(NULL); CDirectShowEventDlg dlg; m_pMainWnd = &dlg; int nResponse = dlg.DoModal(); if (nResponse == IDOK) { } else if (nResponse == IDCANCEL) { } return FALSE; } (5)改写应用程序的 ExitInstance方法,在应用程序退出时卸载 Com库。 int CDirectShowEventApp::ExitInstance() { CoUninitialize(); return CWinApp::ExitInstance(); } (6)在对话框类中添加如下成员变量。 IMediaControl *pMediaControl ; //媒体控制 IGraphBuilder *pGraph; //过滤图表 IBaseFilter *pSrc; //过滤器 IMoniker *pMoniker; //监视器 BOOL m_Previewed; //是否进行预览 IMediaEventEx *pEvent; //事件 IVideoWindow * pViewWnd; //视频预览窗口 BOOL m_Completed; //预览是否完成 HANDLE m_hThread; //线程句柄 (7)在对话框初始化时初始化成员变量。 BOOL CDirectShowEventDlg::OnInitDialog() { CDialog::OnInitDialog(); ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX); ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE); if (pSysMenu != NULL) { CString strAboutMenu; strAboutMenu.LoadString(IDS_ABOUTBOX); if (!strAboutMenu.IsEmpty()) { pSysMenu->AppendMenu(MF_SEPARATOR); pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu); } } SetIcon(m_hIcon, TRUE); SetIcon(m_hIcon, FALSE); m_Completed = FALSE; m_Previewed = FALSE; m_hThread = NULL; return TRUE; } (8)自定义一个消息 CM_COMPLETE,在线程函数中如果到 DirectShow完成了文件的播放,将发 送该消 息。 #define CM_COMPLETE WM_USER+1 (9)向对话框类中添加自定义消息 CM_COMPLETE的消息处理函数。 void CDirectShowEventDlg::Done(WPARAM wParam, LPARAM lParam) { if (m_hThread) { TerminateThread(m_hThread,0); m_hThread = NULL; } m_Previewed = FALSE; pMediaControl->Stop(); pMediaControl->Release(); pGraph->Release(); pViewWnd->put_Visible(FALSE); m_Panel.ShowWindow(SW_HIDE); m_Panel.ShowWindow(SW_SHOW); MessageBox("预览完成!","提示"); } (10)向对话框类中添加消息映射宏,将 CM_COMPLETE消息关联到消息处理函数 Done上。 BEGIN_MESSAGE_MAP(CDirectShowEventDlg, CDialog) //{{AFX_MSG_MAP(CDirectShowEventDlg) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_SETFILE, OnSetFile) ON_MESSAGE(CM_COMPLETE,Done) //}}AFX_MSG_MAP END_MESSAGE_MAP() (11)添加一个全局的线程函数,在线程函数中接收并处理 DirectShow中的事件。 DWORD WINAPI ThreadProc(LPVOID lpParameter ) { CDirectShowEventDlg* pWnd = (CDirectShowEventDlg*)lpParameter; HANDLE hEvent; pWnd->pEvent->GetEventHandle( (OAEVENT*) &hEvent); long code,p1,p2; BOOL done = FALSE; while (!done) { if (WaitForSingleObject(hEvent,80)==WAIT_OBJECT_0) { while (SUCCEEDED( pWnd->pEvent->GetEvent(&code,&p1,&p2,0))) { pWnd->pEvent->FreeEventParams(code,p1,p2); if (code==EC_COMPLETE) { pWnd->m_Completed = TRUE; pWnd->SendMessage(CM_COMPLETE); done=true; } } } } return 0 ; } (12)处理“设置文件”按钮的单击事件,开始播放 Avi文件,在文件播放完毕弹出对话框。 void CDirectShowEventDlg::OnSetFile() { if (! m_Previewed) { CFileDialog fDlg(TRUE,NULL,NULL,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,"avi文件|*.avi"); if (fDlg.DoModal()==IDOK) { CString strFile= fDlg.GetPathName(); ICaptureGraphBuilder2 * pBuilder = NULL; pGraph = NULL; pMediaControl = NULL; CoCreateInstance(CLSID_CaptureGraphBuilder2,0, CLSCTX_INPROC_
/
本文档为【最新DirectShow视频采集开发指南】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索