第 10章媒体控制接口
10.1 MCI设备类型
10.2 MCI编程步骤
10.3使用 MCIWnd窗口类
10.1 MCI设备类型媒体控制接口允许控制两类设备:第一类为简单设备,是指那些不需要文件的设备,如 CD音频播放设备;第二类为复合设备,是那些需要文件的设备,
如数字视频及波形音频设备等。表列出了目前已定义的设备的标识符。
10.2 MCI编程步骤
打开设备
MCI为不同的多媒体设备打开提供相应的数据结构类型。若不想使用设备中特定的参数数据,则可使用统一的 MCI_OPEN_PARMS结构,原型:
typedef struct
{ DWORD dwCallback; // 低字节用于 MCI_NOTIFY的窗口句柄
MCIDEVICEID wDeviceID; // 返回的设备标识符
LPCSTR lpstrDeviceType; // MCI设备的类型
LPCSTR lpstrElementName; // 设备元素
LPCSTR lpstrAlias; // 可选的设备别名
} MCI_OPEN_PARMS;
打开多媒体设备的过程:定义一个 MCI_OPEN_PARMS结构类型变量,给结构变量中的相应参数赋值,调用 mciSendCommand向设备发送 MCI_OPEN命令消息,成功调用时,可获得相应的设备标识符。例如,下面的代码是打开波形音频设备:
WORD wDeviceID; // MCI设备 ID
CString fileName; // 波形文件名
...
MCI_OPEN_PARMS openParms; // MCI设备打开参数
openParms.lpstrDeviceType = "waveaudio"; // 波形音频设备
openParms.lpstrElementName = fileName;
if (mciSendCommand (NULL,MCI_OPEN,
MCI_OPEN_ELEMENT | MCI_OPEN_TYPE,
(DWORD)(LPVOID) &openParms)) return FALSE;
wDeviceID = openParms.wDeviceID;
...
10.2 MCI编程步骤
设置或获取设备信息使用 MCI_SET和 MCI_STATUS命令可以用来设置和获取设备信息,在用函数
mciSendCommand发送命令时,使用相应的 MCI_SET_PARMS和
MCI_STATUS_PARMS结构。原型:
typedef struct
{ DWORD dwCallback; // 低字节用于 MCI_NOTIFY的窗口句柄
DWORD dwTimeFormat; // 时间格式
DWORD dwAudio; // 输出声道
} MCI_SET_PARMS;
typedef struct
{ DWORD dwCallback; // 低字节用于 MCI_NOTIFY的窗口句柄
DWORD dwReturn; // 要获取的设备信息
DWORD dwItem; // 需要获取的信息项
DWORD dwTrack; // 曲目的长度或曲目号
} MCI_STATUS_PARMS;
例如,下面的代码是将波形音频设备的时间格式设成毫秒:
MCI_SET_PARMS setParms;
setParms.dwTimeFormat=MCI_FORMAT_MILLISECONDS;
if (mciSendCommand(wDeviceID,MCI_SET,MCI_SET_TIME_FORMAT,
(DWORD)(LPVOID) &setParms))
return FALSE;
10.2 MCI编程步骤
播放设备使用 MCI_PLAY命令可以使设备播放多媒体文件,并在用函数
mciSendCommand发送命令时,使用相应的 MCI_PLAY_PARMS结构,其原型如下:
typedef struct
{ DWORD dwCallback; // 低字节用于 MCI_NOTIFY的窗口句柄
DWORD dwFrom; // 播放的起点位置
DWORD dwTo; // 播放的终点位置
} MCI_PLAY_PARMS;
例如,下面的代码是播放波形音频设备:
MCI_PLAY_PARMS playParms;
// 定位到开始位置
mciSendCommand (wDeviceID,MCI_SEEK,MCI_SEEK_TO_START,NULL);
// 播放设备
if (mciSendCommand (wDeviceID,MCI_PLAY,NULL,
(DWORD)(LPVOID) &playParms))
return FALSE;
else
return TRUE;
10.2 MCI编程步骤例如,若接收 MM_MCINOTIFY消息的窗口是一个对话框 CMyDlg,则添加消息处理的过程如下:
(1)切换到项目工作区窗口的 ClassView页面,右击 CMyDlg类,选择快捷菜单中的
,Add Member Function...”命令。为 CMyDlg类添加保护型的成员函数,原型:
protected:
LRESULT OnMCINotify(WPARAM wParam,LPARAM lParam);
(2)在类 CMyDlg的消息入口处,添加下列消息宏指令:
BEGIN_MESSAGE_MAP(CMyDlg,CDialog)
//{{AFX_MSG_MAP(CMyDlg)
...
//}}AFX_MSG_MAP
ON_MESSAGE(MM_MCINOTIFY,OnMCINotify)
END_MESSAGE_MAP()
(3)编写 CMyDlg::OnMCINotify函数代码:
LRESULT CMyDlg::OnMCINotify(WPARAM wParam,LPARAM lParam)
{,..
return FALSE;
}
(4)关闭设备使用 MCI_STOP和 MCI_CLOSE命令可以分别用来停止播放和关闭设备。不需要设置或返回附加的信息,因此 不必考虑相应的 MCI_GENERIC_PARMS结构。
10.3使用 MCIWnd窗口类
MCIWnd是一个控制多媒体设备的窗口类。若在应用程序中使用 MCIWnd窗口类,必须在调用 MCIWnd函数所在的源文件的前面添加 vfw.h的头文件,以及编译时加入 vfw32.lib库或在程序中加入下列语句:
#pragma comment (lib,"vfw32.lib")
在 MCIWnd窗口类中,虽然它所提供的函数并不多,但是它所提供的宏却非常多,并且基本上与 MCI的底层功能相对应。
在应用程序中使用 MCIWnd窗口类的一般步骤是:
(1)在程序中调用 MCIWndRegisterClass函数注册 MCI窗口类,以便以后用
CreateWindow或 CreateWindowEx函数创建窗口,或者直接调用函数
MCIWndCreate创建窗口。
(2)获得相应的窗口句柄后,就可调用 MCIWndOpen宏来打开设备。
(3)由于 MCIWnd窗口提供了相应的媒体控制按钮,因而不需要用户编写额外的代码。
(4)但作为技巧,用户还应该跟踪 MCIWnd窗口的一些消息 (如 MCIWNDM_
NOTIFYSIZE)来调整 MCIWnd窗口。
10.3使用 MCIWnd窗口类
[例 Ex_MCI] 利用 MCIWnd窗口类在多文档应用程序中添加一个多媒体播放器。
(1)用 MFC AppWizard(exe)创建一个多文档项目 Ex_MCI,单击 [Finish]。
(2)在 StdAfx.h中放入包含文件使得应用程序能使用所有的多媒体代码。由于项目中的每一个文件已经包含了 StdAfx.h,所以在其他地方就不必再包含这些多媒体文件。
...
#endif // _AFX_NO_AFXCMN_SUPPORT
#include <vfw.h>
#pragma comment (lib,"vfw32.lib")
...
(3)在 CEx_MCIApp::InitInstance函数,使用 MCIWndRegisterClass函数注册 MCI窗口类。
虽然,后面的创建窗口是直接调用函数 MCIWndCreate来进行的,但还应该保证应用程序的运行系统拥有并支持 MCIWnd窗口类。
BOOL CEx_MCIApp::InitInstance()
{ if (!MCIWndRegisterClass()) return FALSE;
AfxEnableControlContainer();
...
}
(4)在 Ex_MCIView类中添加一个公共成员变量用来标识嵌入的 MCIWnd窗口句柄。
public:
CEx_MCIDoc* GetDocument();
HWND m_hMyMCIWnd;
...
10.3使用 MCIWnd窗口类
(5)用 ClassWizard为 Ex_MCIView类中添加 OnInitialUpdate消息处理函数,增加代码:
void CEx_MCIView::OnInitialUpdate()
{ CView::OnInitialUpdate();
m_hMyMCIWnd=MCIWndCreate(m_hWnd,AfxGetInstanceHandle(),
MCIWNDF_NOTIFYSIZE |MCIWNDF_NOERRORDLG |
WS_CHILD|WS_VISIBLE,NULL);
if (m_hMyMCIWnd==NULL) return;
const CString &filename=GetDocument()->GetPathName();
if (filename.GetLength()>0)
MCIWndOpen(m_hMyMCIWnd,(LPCSTR)filename,0);
}
(6)在 CEx_MCIView构造函数中将成员变量 m_hMyMCIWnd初始化为 NULL。
CEx_MCIView::CEx_MCIView()
{ m_hMyMCIWnd=NULL;
}
10.3使用 MCIWnd窗口类
(7) 要添加处理该消息的代码来调整窗口的大小以便能及时更新显示。需要手动进行。
在 Ex_MCIView.h文件中的消息声明处添加下列代码:
// Generated message map functions
protected:
//{{AFX_MSG(CEx_MCIView)
...
//}}AFX_MSG
afx_msg LONG OnNotifySize(UINT wParam,LONG lParam);
DECLARE_MESSAGE_MAP()
(8)在 Ex_MCIView.cpp的消息入口处添加下列代码:
BEGIN_MESSAGE_MAP(CEx_MCIView,CView)
//{{AFX_MSG_MAP(CEx_MCIView)
...
ON_MESSAGE(MCIWNDM_NOTIFYSIZE,OnNotifySize)
//}}AFX_MSG_MAP
// Standard printing commands
ON_COMMAND(ID_FILE_PRINT,CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT,CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW,CView::OnFilePrintPreview)
END_MESSAGE_MAP()
10.3使用 MCIWnd窗口类
(9)为 CEx_MCIView类添加该消息的处理函数 OnNotifySize,代码:
LONG CEx_MCIView::OnNotifySize(UINT wParam,LONG lParam)
{ CRect rc;
CFrameWnd* pParent=GetParentFrame();
if (m_hMyMCIWnd)
{,:GetWindowRect(m_hMyMCIWnd,rc);
pParent->CalcWindowRect(rc,CWnd::adjustBorder);
CSize size(rc.Width(),rc.Height());
if (GetExStyle()&WS_EX_CLIENTEDGE)
{ size.cx+=4;
size.cy+=4;
}
pParent->SetWindowPos(NULL,0,0,size.cx,size.cy,
SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE);
}
else
{ pParent->SetWindowPos(NULL,0,0,200,160,
SWP_NOZORDER|SWP_NOACTIVATE|SWP_NOMOVE);
}
return 1;
}
10.3使用 MCIWnd窗口类
(10)编译并运行。载入一个 AVI文件 (或其他媒体文件 )并单击 [播放 ](?)按钮,
如图。
图 10.1 Ex_MCI运行结果