DirectShow组件开发入门级二
该节主要针对DirectShow开发环境的配置问题,当然网上现有这方面的资源比较多,小菜只是稍微坐下整理,以供有需要的人参考学习
一、 设置DirectShow开发的编译环境:
1、资源筹集工作:
描述了如何来编译DirectShow应用。可以使用命令行形式来编译一个工程,也可以在Microsoft Visual Studio集成环境下(包含VC++)实现。
头文件:
所有的DirectShow应用都需要Dshow.h这个头文件,某些DirectShow接口需要附加的头文件,参考接口的说明视具体情况定。
库文件:
DirectShow使用以下库文件:
Strmiids.lib 输出类标识(CLSID)和接口标识(IID),所有DirectShow应用均需此库。
Quartz.lib 输出AMGetErrorText函数,如果不调用此函数,此库不是必需的。
有了以上这些头文件和库文件,你已经可以编写DirectShow应用了,但是微软建议使用DirectShow基类库来编写filter,这样可以大大减少程序编写的工作量。要使用DirectShow基类库,需要先编译它,由于该基类库是基于VS环境下的,因此应当通过Visual studio工具来进行编译才能生成相应Debug和Release版本的lib库,基类库位于SDK的Samples\Multimedia\DirectShow\BaseClasses文件夹下,包含两个版本的库:发布版(retail version)Strmbase.lib和调试版(debug version)Strmbasd.lib。
在编译生成该库时,会存在这样子的问题,由于工程内的编码风格参照了VC环境下的,因此变量的命名方式或者代码的数据处理风格和VS不一致,因此要进行两个地方的设置才能通过编译:
打开project->BaseClassesproperties->configuration->C/C++->Language->Force Comformance inFor Loop Scrope设置为No
打开project->BaseClasses properties->configuration->C/C++->Command Line,增加/wd4430选项
通过以上两个地方的设置,便可以生成相应版本的lib库文件
2、配置操作环境
当得到相应的资源后,我们需要对VS进行配置编译环境:
D:\DIRECTSHOWX9.0\Include
D:\DIRECTSHOWX9.0\Samples\C++\DirectShow\BaseClasses
如图,再添加库文件的引用。
D:\directShowX9.0\Samples\C++\DirectShow\BaseClasses\Debug
D:\directShowX9.0\Lib
D:\directShowX 9.0\Samples\C++\DirectShow\BaseClasses\Release
3、配置环境路径
建一个DLL工程,在建成后点击项目->属性->连接器->命令行,在附加选项中输入strmbasd.lib
在工程的CPP文件中添加#include <dshow.h>、#include <streams.h>
一般使用_stdcall函数调用协议,即在VS的菜单中选择Project|Setting|C/C++,在弹出的对话框中的Category中选择Code generation,然后在Calling convention中选择_stdcall;
使用多线程的C语言运行库时库,在VS下的菜单中选择Project|Setting|C/C++,在弹出的对话框中的Category中选择Code generation,然后在Use run-time library中,Debug版选择Debug Multithreaded,Release版选择Multithreaded;
然后将配置必要的链接库文件,在VS的菜单中选择Project|Setting|Link,在弹出的对话框中的Category中选择General,然后在Object/library modules 中输入如下代码:
Debug版本 Strmbasd.lib, Msvcrtd.lib, Winmm.lib
Release版本 Strmbase.lib, Msvcrt.lib, Winmm.lib
并且选中Ignore all default Libraries。
定义一个.def文件用于到处dll函数,假设filter的文件名为TransInplace.ax,.def文件的格式一般如下:
LIBRARY TransInplace.ax
EXPORTS
DllMain PRIVATE
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
同时定义DLL入口函数,代码如下:
//
// DllEntryPoint
extern "C"BOOL WINAPI DllEntryPoint(HINSTANCE,ULONG,LPVOID);
BOOL APIENTRY DllMain(HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved )
{
return DllEntryPoint((HINSTANCE)(hModule),ul_reason_for_call,lpReserved);
}
二、 简单对于DirectShow应用下的工程代码显示学习:
配置完以上步骤之后,就可以形成一个DirectShow的开发环境,可以实现一个简单的应用端代码的开发.
// Convert filename to wide character string
wcsncpy(wFile,T2W(szFile),NUMELMS(wFile)-1); //获取要进行播放的媒体文件路径
wFile[MAX_PATH-1]= 0;
// Get the interface for DirectShow'sGraphBuilder
JIF(CoCreateInstance(CLSID_FilterGraph, NULL,CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void**)&pGB));
//ZZS:---------------------------------------------------------------------
IBaseFilter *pIF_video= NULL;
ITransInplace *pITinplaceA = NULL;
//创建一个GUID为CLSID_TransInplaceFilter的Filter对象,存放于pIF_video中
JIF(CoCreateInstance(CLSID_TransInplaceFilter,NULL,CLSCTX_INPROC_SERVER,
IID_IBaseFilter,reinterpret_cast<void**>(&pIF_video)));
//查询可以获得相应该Filter的接口
JIF(pIF_video->QueryInterface(IID_ITransInplace,(void **)&pITinplaceA));
if (pITinplaceA !=NULL)
{
//对该接口进行判空
}
JIF(pGB->AddFilter(pIF_video,L"In-place-Video")); //将该Filter插入到FilterGraph中
// Get the media event interface beforebuilding the graph
JIF(pGB->QueryInterface(IID_IMediaEventEx,(void **)&pME));
// Have the graph builder construct theappropriate graph automatically
JIF(pGB->RenderFile(wFile,NULL));
/*对该FilterGraph进行枚举,获取到添加到filter链路中的所有Filter,并将其打印出来
if (pGB != NULL)
{
IEnumFilters *pEnum= NULL;
hr = pGB->EnumFilters(&pEnum); //获得Filter的枚举器
if (SUCCEEDED(hr))
{
ULONG cFetched;
char szName[256] ={0};
IBaseFilter *pFilter= NULL ;
IEnumPins *ppEnum= NULL;
while(S_OK == pEnum->Next(1,&pFilter,&cFetched)) //枚举每一个Filter获取相应的资源
{
FILTER_INFO info= {0};
pFilter->QueryFilterInfo(&info);
WideCharToMultiByte(CP_ACP,0,info.achName,256,szName,256,0,0);
OutputDebugStringA(szName);
info.pGraph->Release();
pFilter->Release();
}
pEnum->Release();
}
}
if( SUCCEEDED(hr ) )
{
// QueryInterface for DirectShow interfaces
JIF(pGB->QueryInterface(IID_IMediaControl,(void **)&pMC));
JIF(pGB->QueryInterface(IID_IMediaSeeking,(void **)&pMS));
// Query for video interfaces, which may notbe relevant for audio files
JIF(pGB->QueryInterface(IID_IVideoWindow,(void **)&pVW));
JIF(pGB->QueryInterface(IID_IBasicVideo, (void **)&pBV));
// Query for audio interfaces, which may notbe relevant for video-only files
JIF(pGB->QueryInterface(IID_IBasicAudio,(void **)&pBA));
// Have the graph signal event via windowcallbacks for performance
JIF(pME->SetNotifyWindow((OAHWND)ghApp, WM_GRAPHNOTIFY,0));
// Is this an audio-only file (no videocomponent)?
CheckVisibility();
if (!g_bAudioOnly)
{
// Setupthe video window
JIF(pVW->put_Owner((OAHWND)ghApp));
JIF(pVW->put_WindowStyle(WS_CHILD | WS_CLIPSIBLINGS| WS_CLIPCHILDREN));
JIF(InitVideoWindow(1, 1));
}
else
{
//Initialize the default player window and enable playback menu items
// thatdon't involve manipulating video size
JIF(InitPlayerWindow());
EnablePlaybackMenu(TRUE, AUDIO);
}
// Complete window initialization
CheckSizeMenu(ID_FILE_SIZE_NORMAL);
ShowWindow(ghApp,SW_SHOWNORMAL);
UpdateWindow(ghApp);
SetForegroundWindow(ghApp);
UpdateMainTitle();
g_bFullscreen = FALSE;
// Run the graph to play the media file
JIF(pMC->Run());
g_psCurrent = Running;
SetFocus(ghApp);
}