【视频处理工程】3、DirectShow基本开发过程(一)

来源:互联网 发布:我的体育老师 知乎 编辑:程序博客网 时间:2024/04/30 07:16

DiectShow工程的开发需要提前编译相关的两个静态库,具体方法在前文【视频处理工程】1、DirectShow基本概念中已有叙述。这里假设我们的开发环境是Windows 7+Visual Studio 2010 Ultimate,来看如何利用DirectShow开发视频处理的应用程序。


新建工程:

作为demo,我们新建一个简单的控制台工程,命名为MyDirectShowProject1.sln。随后,我们需要对工程进行一些设置,将directShow等相关的头文件目录加入到包含目录中。

1、包含头文件:

除了工程默认的库目录之外,还需要找到directShow所在的sdk目录,将DirectShow的头文件目录添加到工程目录中。具体方法是在Project Properties->Configuration Properties->VC++ Directories->Include Directories中添加DirectShow的common和baseclasses目录。我的电脑上的目录位置是在:C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshow\baseclasses和C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshow\common。

2、添加库目录:

分别对Debug和Release模式在Project Properties->Configuration Properties->VC++ Directories->Library Directories中加入DirectShow的lib文件的目录。如C:\Program Files\Microsoft SDKs\Windows\v7.1\Samples\multimedia\directshow\baseclasses\Release。

3、在工程中链接lib库文件

Project Properties->Configuration Properties->Linker->Input->Additional Dependencies中加入strmbase.lib(Release模式)或者strmbasd.lib(Debug模式)。


开发过程:

1、首先包含directshow头文件:

#include <DShow.h>

2、创建Filter Graph Manager对象

Filter Graph Manager也是一类典型的COM对象,因此创建FGM也需要首先初始化COM库,然后调用CoCreateInstance()根据CLSID建立对象。

IGraphBuilder *pGraph = NULL;//FGM的接口之一,IGraphBuilder继承自IFilterGraph。IFilterGraph提供了将filter加入graph,连接/断开filters,删除filter等其他基本操作。//IGraphBuilder则可以依据部分信息建立整个Filter GraphIMediaControl *pControl = NULL;//FGM的接口之一。IMediaControl控制Filter Graph中的数据流,包含Run,Stop,Paused方法。IMediaEvent   *pEvent = NULL;//FGM的接口之一。包含检索事件通知的方法,和重写FGM的默认事件处理函数。DWORDdwGraphRegister;// Initialize the COM library.HRESULT hr = CoInitialize(NULL);//在当前线程中初始化COM库。if (FAILED(hr)){printf("ERROR - Could not initialize COM library");return;}// Create the filter graph manager and query for interfaces.// 建立一个未经初始化的类实例,与某一CLSID相联系// 建立Filter Graph Manager对象,对象指针为pGraph。hr = CoCreateInstance(CLSID_FilterGraph,//class identifier is CLSID_FilterGraphNULL,//object is not being created as part of an aggregateCLSCTX_INPROC_SERVER,//The Filter Graph Manager is provided by an in-process DLL, so the execution context is CLSCTX_INPROC_SERVER. IID_IGraphBuilder,//interface ID,类名的识别码——A reference to the identifier of the interface .(void **)&pGraph);//输出指针,指向由上一个参数规定的对象。if (FAILED(hr)){printf("ERROR - Could not create the Filter Graph Manager.");return;}
为了使我们建立的filter graph manager可以在GraphEdt中显示出来,我们需要将这个对象加入活动对象表ROT中,而在程序结束该对象被析构之前需要将其从ROT中移除。实现这个功能需要分别调用下面两个函数。

HRESULT AddToRot(IUnknown *pUnkGraph, DWORD *pdwRegister) {    IMoniker * pMoniker = NULL;    IRunningObjectTable *pROT = NULL;    if (FAILED(GetRunningObjectTable(0, &pROT)))     {        return E_FAIL;    }        const size_t STRING_LENGTH = 256;    WCHAR wsz[STRING_LENGTH];    StringCchPrintfW(        wsz, STRING_LENGTH,         L"FilterGraph %08x pid %08x",         (DWORD_PTR)pUnkGraph,         GetCurrentProcessId()        );        HRESULT hr = CreateItemMoniker(L"!", wsz, &pMoniker);    if (SUCCEEDED(hr))     {        hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, pUnkGraph,            pMoniker, pdwRegister);        pMoniker->Release();    }    pROT->Release();        return hr;}void RemoveFromRot(DWORD pdwRegister){    IRunningObjectTable *pROT;    if (SUCCEEDED(GetRunningObjectTable(0, &pROT))) {        pROT->Revoke(pdwRegister);        pROT->Release();    }}


3、在Filter Graph Manager中添加Filter

给定了Filter的CLSID之后,将该filter添加到Filter Graph Manager中可以通过CoCreateInstance创建后通过IGraphBuilder::AddFilter添加。以下函数AddFilterByCLSID封装了这两个函数实现了该功能:

HRESULT AddFilterByCLSID( IGraphBuilder *pGraph, const GUID& clsid, LPCWCHAR wszName, IBaseFilter **ppF ){if (!pGraph || !ppF)return E_POINTER;*ppF = 0;IBaseFilter *pF = 0;HRESULT hr = CoCreateInstance(clsid, 0, CLSCTX_INPROC_SERVER, IID_IBaseFilter, reinterpret_cast<void**>(&pF));if (SUCCEEDED(hr)){hr = pGraph->AddFilter(pF, wszName);if (SUCCEEDED(hr))*ppF = pF;elsepF->Release();}return hr;}

通常,每一个filter的文件都已一个后缀名为ax的动态链接库实现。而且在调用之前需要将这个filter在注册表中注册,注册方式为regsvr32.exe filter.ax。注册之后在graphedt中便可以查看这个filter的CLSID等信息。但是包括我自己在内的很多人都遇到一个问题,就是在graphedt中试图添加一个DirectShow Filter是会出现程序崩溃的情况,因此在这里https://code.google.com/p/graph-studio-next/source/checkout下载了另一工具graphstudionext替代,界面如下图所示。在软件冲选择graph->Insert Filter,并在DirectShow Filter中选择了lav splitter source这个filter所显示的信息如下。



从该工具中,我们可以得到这个filter的CLSID并用上文实现的方法将一个LAV Splitter Source filter加入到filter graph manager中。


现在,我们可以尝试着将一个lav splitter source用上述方法添加到filter graph中。代码如下:

#include "stdafx.h"#include "DirectShowAPI.h"#include "global.h"int _tmain(int argc, _TCHAR* argv[]){IGraphBuilder *pGraph = NULL;//FGM的接口之一,IGraphBuilder继承自IFilterGraph。IFilterGraph提供了将filter加入graph,连接/断开filters,删除filter等其他基本操作。//IGraphBuilder则可以依据部分信息建立整个Filter GraphIMediaControl *pControl = NULL;//FGM的接口之一。IMediaControl控制Filter Graph中的数据流,包含Run,Stop,Paused方法。IMediaEvent   *pEvent = NULL;//FGM的接口之一。包含检索事件通知的方法,和重写FGM的默认事件处理函数。DWORD dwGraphRegister;// Initialize the COM library.HRESULT hr = CoInitialize(NULL);//在当前线程中初始化COM库。if (FAILED(hr)){printf("ERROR - Could not initialize COM library");return 0;}// Create the filter graph manager and query for interfaces.// 建立一个未经初始化的类实例,与某一CLSID相联系// 建立Filter Graph Manager对象,对象指针为pGraph。hr = CoCreateInstance(CLSID_FilterGraph,//class identifier is CLSID_FilterGraphNULL,//object is not being created as part of an aggregateCLSCTX_INPROC_SERVER,//The Filter Graph Manager is provided by an in-process DLL, so the execution context is CLSCTX_INPROC_SERVER. IID_IGraphBuilder,//interface ID,类名的识别码——A reference to the identifier of the interface .(void **)&pGraph);//输出指针,指向由上一个参数规定的对象。hr = AddToRot(pGraph,&dwGraphRegister);// //向Filter Graph中添加filter IBaseFilter *pLavSplitterSource, *pFileSourceFilter;  hr = AddFilterByCLSID(pGraph,CLSID_LavSplitter_Source,L"Lav Splitter Source",&pLavSplitterSource);while (1){}RemoveFromRot(dwGraphRegister);pGraph->Release();return 1;}

上述代码中存在一个死循环导致进程不会退出。在运行之后打开GraphStudioNext,并选择connect to remote graph并选择其中的选项后,界面上显示了filter graph中存在一个lav splitter source,如下图所示。


从图中可以看出,这个filter没有任何pin。这是因为没有加载任何文件。在这个filter上右键,选择choose source file,并选择一个视频文件加载后,filter上就出现了相应的输出pin,如下图所示:


此时filter上出现了三个输出pin,分别用于处理视频、音频和字幕数据。由此可以看出,lav splitter source属于那种必须加载文件然后才能枚举pin的那类,可以参考一下这里http://bbs.csdn.net/topics/290018228。




0 0
原创粉丝点击