DirectShow是微软公司提供的一套在Windows平台上进行流媒体处理的开发包,与DirectX开发包一起发布。DirectShow为多媒体的捕捉和回放提供了强有力的支持。运用DirectShow我们可以很方便地从支持WDM驱动模型的采集卡上捕获数据,并且进行相应的后期处理乃至存储到文件中。它广泛地支持各种媒体格式,包括Asf、Mpeg、Avi、Dv、Mp3、Wave等等,使得多媒体数据的回放变得轻而易举。另外,DirectShow还集成了DirectX其它部分(比如DirectDraw、DirectSound)的技术,直接支持DVD播放,视频的非线性编辑,以及与数据摄像机的交换。更值得一提的是,DirectShow提供的是一种开放式的开发环境,我们可以根据自己的需要定制自己的组件。
本文将对DirectShow的应用进行入门级的介绍。
入门
DirectShow使用一种叫做FilterGraph的模型来管理整个数据流的处理过程,参与数据流处理的各个功能模块称做Filter,各个Filter在FilterGraph中按一定的顺序连成一条流水线协调工作,完成一些相对独立的功能,如Filter可以完成如下的一些功能: 财软联盟.fs119.net
读文件
从视频设备中获取视频
对视频流进行解码
将数据送往声卡或显卡
每个Filter都有输入端和输出端,例如一个MPEG-1解码Filter它的输入是MPEG编码的流数据,它的输出端是一解码过的流数据。DirectShow正是通过将不同的Filter连接在一起完成特定的功能的,我们将这些Filter的连接叫做FilterGraph,如下图A给出是播放AVI的FilterGraph:
图A 播放AVI文件的GraphFilter图
上图中每个模块分别代表了不同的Filter,媒体文件Filter从硬盘读取AVI文件,AVI分离Filter将文件分离为音频流和视频流,AVI解码Filter对视频流进行解码并送往Video表现Filter,由后者将各帧在显示器上显示,默认的DirectSound设备用DirectSound将音频流输出。 财管家园 fs119.net
我们的应用并不需要对这当中的所以的数据流进行管理,在DirectShow提供一个称做FilterGraph管理器的高级组件。在我们的应用中只需要调用它的API即可,如Run、Stop等,如果你想对其中的数据流做更进一步的控制,你可以对这些Filter直接通过COM接口进行存取。
FilterGraph管理器同时也提供了另一个功能:应用程序可以通过管理器控制FilterGraph如何生成。 财软联盟,fs119.net
财 管家园 fs119.net
财管家 园 fs119.net
财软.联盟.fs119.net
DirectShow应用 财软联盟 fs119.net 财软 联盟 fs119.net
从广义上说,所有的DirectShow应用都必须完成三件事情,如下图B所示:
图B
1.生成FilterGraph管理器的一个实例。
2.利用FilterGrapth实例生成FilterGraph,具体应该由哪些Filter组成FilterGraph视我们的应用的需要而定。
3.通过对FilterGraph管理器的方法调用和来自FilterGraph的消息的响应FilterGraph和数据流进行控制。
DirectShow是基于COM的,FilterGraph管理器和Filter都是COM对象,在开始着手之前你应该对COM有个基本的认识。
下面让我们着手开始做一个简单的DirectShow应用,在这个应用中我们实现这样的功能:打开一个媒体文件,并对其进行播放。
设置环境
在利用DirectShow进行流媒体的处理之前,必须正确安装DirectX的SDK,DirectXSDK可以到微软的网站上下载,目前,DirectX最新版本为9.0。
在正确安装好DirectXSDK后,我们必须设置DirectXSDK的头文件和库文件,使其在VisualStudio的搜索路径内。对于VisualStudio.NET2003可如下进行设置:菜单→工具→选项→项目→VC目录,在包含文件中加入D:\DXSDK\Include,在库文件中加入D:\DXSDK\lib(我的SDK的安装路径是D:\DXSDK):
头文件
财软联.盟.fs119.net
库文件
文件名称
描述
Strmiids.lib
此库文件中导出类标识(CLSID)和接口标识(IID),所有的DirectShow应用都必须包含此文件。
Quartz.lib
此库文件中导出函数AMGetErrorText,如果你的程序中调用了此函数,则必须包含此库文件。
财管家.园.fs119.net
财.管家园.fs119.net
财管家园.fs119.net
财管家园 fs119.net 开始工程 财管.家园.fs119.net 财管家园,fs119.net
打开VisualStudio.NET2003,文件→新建→项目
1.生成基于MFC的应用程序,名称PlayWnd。
2.选择应用程序类型基于对话框,点击完成。
3.设置工程属性
项目→PlayWnd属性→配置属性→链接器→输入→附加依赖项,添加库文件Strmiids.lib和Quartz.lib。
由于Dshow.h头文件是在任何DirectShow工程中都要用到的,因此我们stdafx.h加入如下行:
#include<Dshow.h>
4.设计对话框,如下:
控件类型
StaticText
Caption
媒体文件名:
IDC_MEDIAFILE_EDIT
控件类型
EditControl
控件类型
Button
Caption
浏览
控件类型
PictureControl
Type
Rectangle
控件类型
Button
Caption
播放
控件类型
Button
Caption
暂停
控件类型
Button
Caption
关闭
5.COM的初始化和卸载,
修改PlayWnd.cpp添加初始化代码(加入的代码用粗黑体表示,下同)
BOOLCPlayWndApp::InitInstance()
{
//使用ComCtl32.dll版本6或更高版本来启用可视化方式,
//则需要InitCommonControls()。否则,将无法创建窗口。
InitCommonControls();
{
TRACE("ERROR-CouldnotinitializeCOMlibrary.\n");
returnFALSE;
}
CWinApp::InitInstance();
AfxEnableControlContainer();
修改PlayWnd.cpp添加卸载COM代码,注意需要对虚函数ExitInstance进行重载
财软联.盟.fs119.net
{
//关闭COM
CoUninitialize();
}
财软联盟.fs119.net
财管 家园 fs119.net
财管家园,fs119.net
6.定义媒体控制成员变量 财,软联盟,fs119.net
修改PlayWndDlg.h如下:
HICONm_hIcon;
virtual
afx_msg
afx_msg
afx_msgHCURSOROnQueryDragIcon();
DECLARE_MESSAGE_MAP()
IGraphBuilder*m_pGraph;
IMediaControl*m_pMediaControl;
IMediaEventEx*m_pEvent;
//FilterGraph管理器获取事件消息的方法
IMediaSeeking*m_pMediaSeeking;
CStringm_strMediaFile;
BOOLm_isPlaying;
};
在CPlayWndDlg的构造函数中添加初始化代码。
CPlayWndDlg::CPlayWndDlg(CWnd*pParent/*=NULL*/)
:CDialog(CPlayWndDlg::IDD,pParent)
{
m_hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_pGraph=NULL;
m_pMediaControl=NULL;
m_pEvent=NULL;
m_pMediaSeeking=NULL;
m_strMediaFile="";
m_isPlaying=FALSE;
}
由于一些和窗体控制有关的初始化代码不能放在构造函数中进行,我们将其放在CPlayWndDlg::OnInitDialog()中,我们必须在此必须对CPlayWndDlg添加WS_CLIPCHILDREN的Style,因为在我们的应用中把视频窗体作为CPlayWndDlg的一个子窗体来使用的,这是非常重要的,许多开发人员在刚开始使用DirectShow时,父窗体的Style没有设置正确,造成视频不能正确显示,代码如下:
//执行此操作
SetIcon(m_hIcon,TRUE);
SetIcon(m_hIcon,FALSE);
ModifyStyle(0,WS_CLIPCHILDREN);
((CEdit*)GetDlgItem(IDC_MEDIAFILE_EDIT))->SetReadOnly(TRUE);
}
添加相应的清除代码,重载CPlayWndDlg的DestoryWindow方法,如下:
{
m_pGraph->Release();
m_pMediaControl->Release();
m_pEvent->Release();
m_pMediaSeeking->Release();
m_pGraph=NULL;
m_pMediaControl=NULL;
m_pEvent=NULL;
m_pMediaSeeking=NULL;
}
财软 联盟 fs119.net
财管家.园.fs119.net
财软,联盟,fs119.net
财管家,园,fs119.net 7.修改CPlayWndDlg::OnPaint(),由于现在视频显示区域必须由我们自己进行重画: 财软联盟 fs119.net 财管家.园.fs119.net 财管家园.fs119.net
{
{
CPaintDCdc(
SendMessage(WM_ICONERASEBKGND,
CRectrect;
GetClientRect(&rect);
dc.DrawIcon(x,y,m_hIcon);
}
{
{
CClientDCdc(GetDlgItem(IDC_VW_FRAME));
dc.SetBkColor(RGB(0,0,0));
CRectrc;
GetDlgItem(IDC_VW_FRAME)->GetClientRect(rc);
dc.FillRect(rc,CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
GetDlgItem(IDC_VW_FRAME)->Invalidate();
}
CDialog::OnPaint();
}
}
添加浏览、播放、暂停、关闭四按钮的相应事件响应函数,同时在CPlayWndDlg中添加如下四个私有方法:
上述方法的实现如下:
{
IVideoWindow*pVideoWinow=NULL;
{
m_pGraph->QueryInterface(IID_IVideoWindow,(
CRectrc;
GetDlgItem(IDC_VW_FRAME)->GetWindowRect(rc);
ScreenToClient(rc);
pVideoWinow->SetWindowPosition(rc.left,rc.top,rc.Width(),rc.Height());
pVideoWinow->Release();
pVideoWinow=NULL;
}
}
{
IVideoWindow*pVidWin=NULL;
return;
m_pGraph->QueryInterface(IID_IVideoWindow,(
m_pEvent->WaitForCompletion(INFINITE,&levCode);
pVidWin->put_Visible(OAFALSE);
pVidWin->Release();
m_pMediaSeeking->Release();
m_pMediaControl->Release();
m_pEvent->Release();
m_pGraph->Release();
m_pMediaSeeking=NULL;
m_pMediaControl=NULL;
m_pEvent=NULL;
m_pGraph=NULL;
UpdateData(
CClientDCdc(GetDlgItem(IDC_VW_FRAME));
dc.SetBkColor(RGB(0,0,0));
CRectrc;
GetDlgItem(IDC_VW_FRAME)->GetClientRect(rc);
ClientToScreen(rc);
dc.FillRect(rc,CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH)));
Invalidate();
}
{
IVideoWindow*pVidWin=NULL;
HRESULThr;
if(m_pMediaControl) 财管 家园 fs119.net
{
LONGLONGpos=0;
hr=m_pMediaControl->Stop();
hr=m_pMediaSeeking->SetPositions(&pos,AM_SEEKING_AbsolutePositioning,&pos,AM_SEEKING_NoPositioning);
m_pGraph->QueryInterface(IID_IVideoWindow,(
pVidWin->put_Visible(OAFALSE);
m_isPlaying=FALSE;
GetDlgItem(IDC_PLAY_BUTTON)->EnableWindow(TRUE);
GetDlgItem(IDC_PAUSE_BUTTON)->EnableWindow(FALSE);
pVidWin->Release();
longlevCode;
m_pEvent->WaitForCompletion(INFINITE,&levCode);
m_pMediaControl->Release();
}
}
{
IVideoWindow*pVidWin=NULL;
{
m_pGraph->QueryInterface(IID_IVideoWindow,(
pVidWin->put_Visible(OATRUE);
m_pGraph->QueryInterface(IID_IMediaControl,(
m_pMediaControl->Run();
m_isPlaying=TRUE;
GetDlgItem(IDC_PLAY_BUTTON)->EnableWindow(FALSE);
GetDlgItem(IDC_PAUSE_BUTTON)->EnableWindow(TRUE);
}
}
财软联,盟,fs119.net
财软联 盟 fs119.net
浏览、播放、暂停、关闭四按钮的相应事件响应函数如下: 财管家园,fs119.net 财软.联盟.fs119.net
{
CFileDialogdlgFile(TRUE,NULL,NULL,
OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT,
"MovieFiles(*.avi;*.mpg;*.mpeg)|\
*.avi;*.mpg;*.mpeg|\
AudioFiles(*.wav;*mp3;*.mpa;*.mpu;*.au)|\
*.wav;*.mp3;*.mpa;*.mpu;*.au|\
MidiFiles(*.mid;*.midi;*.rmi)|\
*.mid;*.midi;*.rmi||",this);
{
m_strMediaFile=dlgFile.GetPathName();
GetDlgItem(IDC_MEDIAFILE_EDIT)->SetWindowText(m_strMediaFile);
}
else
CoCreateInstance(CLSID_FilterGraph,NULL,CLSCTX_INPROC,IID_IGraphBuilder,(void**)&m_pGraph);
HRESULThr=m_pGraph->RenderFile(CA2W(m_strMediaFile),NULL);
{
charszMsg[200];
AMGetErrorText(hr,szMsg,sizeof(szMsg));
AfxMessageBox(szMsg);
}
IVideoWindow*pVidWin=NULL;
m_pGraph->QueryInterface(IID_IVideoWindow,(void**)&pVidWin);
pVidWin->put_Owner((OAHWND)m_hWnd);
pVidWin->put_WindowStyle(WS_CHILD|WS_CLIPSIBLINGS|WS_CLIPCHILDREN);
CRectrc;
GetDlgItem(IDC_VW_FRAME)->GetWindowRect(rc);
ScreenToClient(rc);
pVidWin->SetWindowPosition(rc.left,rc.top,rc.Width(),rc.Height());
m_pGraph->QueryInterface(IID_IMediaEventEx,(
m_pEvent->SetNotifyWindow((OAHWND)m_hWnd,WM_GRAPHNOTIFY,0);
m_pGraph->QueryInterface(IID_IMediaSeeking,(void**)&m_pMediaSeeking);
}
{
Play();
}
{
m_pMediaControl->Pause();
m_isPlaying=TRUE;
GetDlgItem(IDC_PLAY_BUTTON)->EnableWindow(TRUE);
GetDlgItem(IDC_PAUSE_BUTTON)->EnableWindow(FALSE);
}
{
CleanUp();
OnCancel();
}
8.添加对WM_GRAPHNOTIFY消息,及其响应函数
在PlayWndDlg添加消息ID定义:
在PlayWndDlg.h中,代码如下:
HICONm_hIcon;
virtualBOOLOnInitDialog();
afx_msg
afx_msg
afx_msgHCURSOROnQueryDragIcon();
DECLARE_MESSAGE_MAP()
afx_msgHRESULTOnGraphNotify(WPARAMwParam,LPARAMlParam);
IGraphBuilder*m_pGraph;
IMediaControl*m_pMediaControl;
IMediaEventEx*m_pEvent;
PlayWndDlg.cpp,如下:
ON_BN_CLICKED(IDC_BROWSE_BUTTON,OnBnClickedBrowseButton)
ON_BN_CLICKED(IDC_PLAY_BUTTON,OnBnClickedPlayButton)
ON_BN_CLICKED(IDC_PAUSE_BUTTON,OnBnClickedPauseButton)
ON_BN_CLICKED(IDCANCEL,OnBnClickedCancel)
ON_MESSAGE(WM_GRAPHNOTIFY,OnGraphNotify)
END_MESSAGE_MAP()
实现如下:
HRESULTCPlayWndDlg::OnGraphNotify(WPARAMwParam,LPARAMlParam)
{
HRESULThr;
{
hr=m_pEvent->FreeEventParams(levCode,lparam1,lparam2);
{
TRACE("Endofthemediafile!!.\n");
Stop();
//CleanUp();
break;
}
}
}
财管家园.fs119.net
财,软联盟,fs119.net
Google.cn搜索相关文章:
谷歌中搜索全球网 VisualC.NETDirectShow编程
百度中搜索 VisualC.NETDirectShow编程
谷歌中搜索www.fs119.net VisualC.NETDirectShow编程
下一篇:VC.NET开发环境整合技巧