摘 要:本文主要介绍了ActiveMovie控件一些特有的属性、方法和事件,并用一个实例阐述了它在多媒体开发中的使用方法。 关键词:ActiveMovie控件 多媒体 ActiveMovie控件是微软公司推出的用于多媒体程序设计的控件,它提供了非常完善的音频和视频媒体文件的回放功能,能支持多种文件格式,从最常见的WAV文件和AVI文件到使用MPEG压缩格式的VCD视频文件,都可以正常的进行播放。控件能根据文件后缀进行自动判别设备类型,并完成相应的控制。因此,若正在编写的应用程序需要提供多媒体支持,那么使用ActiveMovie控件是一个很好的主意。事实上,很多优秀的多媒体应用程序,其内部的多媒体回放就是利用ActiveMovie控件来实现。只要精心地设计应用程序的用户界面,我们一样可以开发出功能齐全、外观漂亮、具有相当水准的多媒体播放器。而且,在Windows 95/98和Windows NT的最新版本中,ActiveMovie控件已作为操作系统的一部分来提供,即使用户系统中没有安装ActiveMovie控件,Microsoft的许可协议也允许在你的应用程序的发行包中发布ActiveMovie的运行时文件。 本文将首先介绍ActiveMovie控件一些特有的属性、方法和事件,然后使用该控件开发一个具有一定功能的多媒体播放器,最后结合本例谈一谈使用ActiveMovie控件进行多媒体开发时需要注意的几个问题。 一、ActiveMovie控件特有的属性、方法和事件 ActiveMovie控件的特有属性及相关描述见表1。其它各控件常有的属性如BorderStyle、 DisplayForeColor、hWnd等,该控件也支持。 ActiveMovie控件特有的属性表 表1
属性 |
说明 |
CurrentState |
指示控件的状态:stopped、paused、running |
DisplayMode |
显示模式,即以时间方式还是帧方式 |
FileName |
指定该控件要操作的源文件完整名字 |
Rate |
指示媒体流的回放率 |
ReadyState |
指示控件状态,是否已经装入源文件 |
SelectionEnd |
指示播放媒体流的结束位置 |
SelectionStart |
指示播放媒体流的开始位置 |
CurrentPosition |
指示播放媒体流的当前位置 |
Volume |
设置音量 |
ActiveMovie控件常用方法有RUN、STOP、PAUSE三个,分别控制媒体流的播放、停止和暂停。使用时直接调用它们即可。其它通用方法如Drag 、Move、SetFocus等,该控件也支持。 ActiveMovie控件的特有事件及相关描述见表2。 ActiveMovie控件特有的事件表 表2
事件 |
说明 |
DisplayModeChange |
当DisplayMode属性值发生变化时触发 |
OpenComplete |
当源文件完全载入时触发 |
PositionChange |
当媒体流的当前位置改变时触发 |
ReadyStateChange |
当控件的ReadyState属性值改变时触发 |
StateChange |
当播放器的状态改变时触发 |
Error |
处理控件的出错事件 |
二、ActiveMovie的多媒体播放器设计 使用ActiveMovie控件开发多媒体应用程序可以大大提高多媒体开发效率,只要设置控件的FileName属性,确定该控件要打开的媒体文件名称,然后执行RUN方法就可以对该媒体文件进行播放;通过设置SelectionEnd 和SelectionStart的值,可以实现播放某一段媒体流;还能用鼠标Click相应的按钮完成播放、停止、暂停、快进、快退等功能。但对一个面向用户的多媒体应用程序来说,这还远远不够。下面,笔者利用ActiveMovie控件提供的一些方法和事件,在VC++6.0环境下设计一个多媒体播放器,该播放器能完成用户的一些必要操作,如任意打开和关闭一个媒体文件、调节媒体文件播放时的音频和视频效果等。为了便于读者更好地了解ActiveMovie控件的使用方法,笔者将编程的具体步骤和相应的源代码一一列出。 ①使用AppWizard创建一个基于对话框的MFC工程,将之命名为Videoplayer。所有步骤均使用AppWizard给出的默认设置,这样,应用程序自动提供了对ActiveX控件的支持。接着删除应用程序主对话框中的所有控件,包括“确定”和“取消”按钮。 ②在Project菜单的Add To Project子菜单下选择Components and Controls命令,打开一个“Components and Controls Gallery”对话框,在该对话框中双击Registered ActiveX Controls,并从中选择ActiveMovieControl Object ,单击Insert 按钮,这时在Controls工具箱中将会多一个按钮,单击该按钮,即可像添加一般的标准控件那样向主对话框添加ActiveMovie控件。为新添加的ActiveMovie控件(将其ID设置为IDC_AMOVIE)映射类型为CActiveMovie的成员变量m_amovie。 ③按表3创建应用程序的菜单资源IDR_MENU,接着使用属性对话框将应用程序主对话框的菜单资源设置为IDR_MENU。 应用程序使用的菜单资源表 表3
顶层菜单项 |
文件 |
播放 |
视频 |
音频 |
帮助 |
子菜单项 (资源ID) |
打开 (ID_FILEOPEN) 关闭 (ID_FILECLOSE) |
开始 (ID_PLAYSTART) 暂停 (ID_PLAYPAUSE) 停止 (ID_PLAYSTOP) |
原始大小 (ID_VIDEO1X) 原始大小的2倍 (ID_VIDEO2X) 全屏显示 (ID_VIDEOFULL) |
调节音量 (ID_VOLUME) 调节左右声道平衡 (ID_BALANCE) |
关于视频播放器 (ID_HELPABOUT) |
④设计用于音量调节的对话框,删除“Cancel”按钮,添加一个滑块控件。利用 ClassWizard为该对话框创建新的类CVolumeDlg,并为滑块控件映射类型为CSliderCtrl的成员变量m_sld。为类CVolumeDlg编写代码,给它提供一个外部编程接口SetVolume,该公有成员函数使用一个指向CActiveMovie对象的指针作为其参数,所进行的音量调节作用于该控件。这里需要注意的是,拖动或点击滑块时,向父窗口发送的消息是WM_HSCROLL,该消息的处理函数OnHScroll,传递给该处理函数的第二个参数的类型为CScrollBar*, 需要使用强调类型转换将其转换为CSliderCtrl*,以便能正确调用CSliderCtrl对象所提供的各种成员函数。以下是类CVolumeDlg的代码清单,由于篇幅有限,在这里省掉了由AppWizard生成的代码和注释。 //VolumeDlg.h 头文件 #include "ActiveMovie.h" class CVolumeDlg : public CDialog { public: void SetVolume(CActiveMovie* pAmovie); protected: CActiveMovie* m_pAmovie; ...... }; // VolumeDlg.cpp 实现文件 BOOL CVolumeDlg::OnInitDialog() { CDialog::OnInitDialog(); //设置音量滑块的最小值、标度和当前位置等 m_sld.SetRange(-10000,0); m_sld.SetTicFreq(1000); m_sld.SetLineSize(200); m_sld.SetPageSize(1000); //以ActiveMovie控件的当前音量作为滑块的当前位置 m_sld.SetPos(m_pAmovie->GetVolume()); return TRUE; } void CVolumeDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) {//在用户拖动或点击滑快控件时,将所作用的改变立即作用于ActiveMovie控件 CSliderCtrl *pSlider=(CSliderCtrl*)pScrollBar; int nVolume=pSlider->GetPos(); m_pAmovie->SetVolume(nVolume); CDialog::OnHScroll(nSBCode, nPos, pScrollBar); } void CVolumeDlg::SetVolume(CActiveMovie* pAmovie) {//提供给类外部的使用者的编程接口方法 m_pAmovie=pAmovie; //如果未加载任何媒体文件,则音量调节对话框不可用 //ActiveMovie控件的CurrentState属性返回控件的当前值,-1表示未加载任何//媒体文件,此时弹出出错信息 if(m_pAmovie->GetCurrentState()!=-1) { DoModal(); } else { MessageBox("音频设备尚未加载,请先打开一个媒体文件"); } } ⑤设计用于调节左右声道平衡的对话框,形式和音量调节对话框一致。用ClassWizard为其创建新的类CBalanceDlg,同样在类CBalanceDlg中定义公有成员函数SetBalance以供类外部的使用者调用,该函数也使用一个指向CActiveMovie对象的指针作为其参数。以下是类CBalanceDlg的代码清单: //BalanceDlg.h 头文件 #include "ActiveMovie.h" class CBalanceDlg : public CDialog { public: void SetBalance(CActiveMovie* pAmovie); protected: CActiveMovie* m_pAmovie; ...... }; // BalanceDlg. cpp 实现文件 BOOL CBalanceDlg::OnInitDialog() { CDialog::OnInitDialog(); //设置音量滑块的最小值、标度和当前位置等 m_sld.SetRange(-10000,10000); m_sld.SetTicFreq(2000); m_sld.SetLineSize(500); m_sld.SetPageSize(2000); m_sld.SetPos(m_pAmovie->GetBalance()); return TRUE; } void CBalanceDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) {//在用户拖动或点击滑快控件时,将所作用的改变立即作用于ActiveMovie控件 CSliderCtrl *pSlider=(CSliderCtrl*)pScrollBar; int nVolume=pSlider->GetPos(); //设置当前的声道平衡位置 m_pAmovie->SetBalance(nVolume); CDialog::OnHScroll(nSBCode, nPos, pScrollBar); } void CBalanceDlg::SetBalance(CActiveMovie* pAmovie) {//提供给类外部的使用者的编程接口方法 m_pAmovie=pAmovie; //如果未加载任何媒体文件,则音量调节对话框不可用 //ActiveMovie控件的CurrentState属性返回控件的当前值,-1表示未加载任何//媒体文件,此时弹出出错信息 if(m_pAmovie->GetCurrentState()!=-1) { DoModal(); } else { MessageBox("音频设备尚未加载,请先打开一个媒体文件"); } } ⑥在VideoplayerDlg.h前头添加两行代码:#include "VolumeDlg.h" #include "BalanceDlg.h" 利用ClassWizard为主对话框CVideoplayerDlg的菜单项添加消息映射,同时按照菜单功能完成各消息函数中的代码: void CVideoplayerDlg::OnFileOpen() {//打开一个媒体文件 CFileDialog dlg(TRUE,NULL,NULL,0,"所有文件|*.*",NULL); if(dlg.DoModal()==IDOK) { m_amovie.SetFileName(dlg.GetPathName()); } } void CVideoplayerDlg::OnFileClose() {//关闭文件,即简单将ActiveMovie控件的FileName属性设置为空 m_amovie.SetFileName(""); } void CVideoplayerDlg::OnFileExit() { //关闭应用程序 OnCancel(); } void CVideoplayerDlg::OnPlayStart() { //开始播放文件 m_amovie.Run(); } void CVideoplayerDlg::OnPlayPause() {//暂停媒体播放器 m_amovie.Pause(); } void CVideoplayerDlg::OnPlayStop() {//停止媒体播放器 m_amovie.Stop(); } void CVideoplayerDlg::OnVideo1x() {//首先暂停媒体播放器,然后再设置视频大小 m_amovie.Pause(); m_amovie.SetMovieWindowSize(0); m_amovie.Run(); } void CVideoplayerDlg::OnVideo2x() {//首先暂停媒体播放器,然后再设置视频大小 m_amovie.Pause(); m_amovie.SetMovieWindowSize(1); m_amovie.Run(); } void CVideoplayerDlg::OnVideofull() { m_amovie.Pause(); m_amovie.SetFullScreenMode(TRUE); m_amovie.Run(); } void CVideoplayerDlg::OnAudeovolume() {//调节音量大小 CVolumeDlg dlgVolume; dlgVolume.SetVolume(&m_amovie); } void CVideoplayerDlg::OnAudeobalance() {//调节左右声道平衡 CBalanceDlg dlgBalance; dlgBalance.SetBalance(&m_amovie); } void CVideoplayerDlg::OnHelpabout() {//弹出“关于媒体播放器”对话框 CAboutDlg dlgAbout; dlgAbout.DoModal(); } ⑦为了防止在ActiveMovie控件的状态改变时对整个程序用户界面外观的影响,此时很有必要改变对话框的大小以适应ActiveMovie控件的大小。为此,笔者专门在CVideoplayerDlg中定义了一个void型函数MoveMovieWindow( ),其中的代码如下: void CVideoplayerDlg::MoveMovieWindow() {//改变窗口大小以适应控件大小 CRect rc1,rc2,rc3; //得到ActiveMovie控件大小 m_amovie.GetWindowRect(rc1); //保证对话框客户区的宽不小于300象素,高不小于225象素 if(rc1.Width()<300||rc1.Height()<255) { rc1.right=rc1.left+300; rc1.bottom=rc1.top+225; } //获得对话框的大小 GetWindowRect(rc2); //获得对话框客户区大小 GetClientRect(rc3); //改变对话框大小以适应ActiveMovie控件大小 MoveWindow(rc2.left,rc2.top,rc2.Width()-rc3.Width()+rc1.Width(), rc2.Height()-rc3.Height()+rc1.Height()); //获得控件ActiveMovie的大小 m_amovie.GetWindowRect(rc1); GetClientRect(rc3); //使ActiveMovie控件在对话框的客户区居中 m_amovie.MoveWindow((rc3.Width()-rc1.Width())/2, (rc3.Height()-rc1.Height())/2,rc1.Width(),rc1.Height()); } ⑧利用ClassWizard为ActiveMovie控件IDC_AMOVIE添加一些必要的消息映射,并完成其中的代码: void CVideoplayerDlg::OnStateChangeAmovie(long oldState, long newState) {//当ActiveMovie控件状态发生改变时,主对话框的大小也将发生改变 MoveMovieWindow(); } void CVideoplayerDlg::OnReadyStateChangeAmovie(long ReadyState) {//当ActiveMovie控件准备状态发生改变时,主对话框的大小也将发生改变 MoveMovieWindow(); } void CVideoplayerDlg::OnDisplayModeChangeAmovie() {//当ActiveMovie控件显示模式改变时,主对话框的大小也将发生改变 MoveMovieWindow(); } void CVideoplayerDlg::OnErrorAmovie(short SCode, LPCTSTR Description, LPCTSTR Source, BOOL FAR* CancelDisplay) {//处理ActiveMovie的出错事件,弹出一个消息以告诉用户出错的代码和描述 CString str; str.Format("出现错误[%d]:/n/n%s",SCode,Description); MessageBox(str); *CancelDisplay=TRUE; } void CVideoplayerDlg::OnOpenCompleteAmovie() {//当ActiveMovie控件完成媒体文件的加载时自动播放该文件 m_amovie.Run(); } ⑨至此,已完成所有的编程工作,现在可以编译和生成多媒体播放器应用程序了。用它来播放各种格式的媒体文件,看看它的运行效果,你会惊喜地发现你开发的多媒体播放器和市场上的一些商业性多媒体软件一样,也能出色地完成任务。 三、总结 用ActiveMovie控件开发多媒体应用程序,关键是要熟悉该控件提供的各个接口属性和方法。笔者在Videoplayer应用程序中使用了ActiveMovie控件的一些接口函数,读者可以举一反三掌握其它接口函数的使用方法。除此之外,还应注意下面几点: (1)在执行RUN方法之前,最好先判断是否已经加载了媒体流文件,否则系统报错。这可以通过读取控件的CurrentState属性值来实现判断,然后进行相应的处理。当CurrentState属性值为-1时,表示未加载任何文件。 (2)如果想连续播放媒体文件某两个片段,则需要先设置控件的显示模式(Displaymode)属性以确定片段是以帧为单位还是以时间(毫秒)为单位。在执行完第一个片段的RUN方法后,必须通过读取控件的CurrentState属性值来判断控件的当前状态,以决定下一步动作。 (3)当用户执行了更改ActiveMovie控件状态的操作时,可能会破坏整个用户界面的一致性和完美性。在这种情况下,很有必要对用户界面对话框的大小做相应的调整。为此,笔者编写了MoveMovieWindow函数,专门用来调整用户对话框的尺寸大小,并保证ActiveMovie控件在对话框的客户区居中显示。实践证明,这个函数大大改善了用户界面的外观。 参考文献 1.David J.Kruglingski著,王国印译. Visual C++4.0技术内幕[M]. 北京:清华大学出版社,1998. 2. Robert D.Thompson著. MFC开发人员参考手册[M]. 北京:机械工业出版社,1998.8. 3.Peter Aitken等著,李鹤文,张文新译 . Visual C++多媒体开发指南 .北京:科学出版社 , 1996 |