一个基本的媒体播放器






4.45/5 (36投票s)
使用 MCIWnd 包装类编写一个简单的媒体播放器。

介绍 MCIWnd 窗口类
MCIWnd 是一个用于控制多媒体设备的窗口类。与 MCIWnd 相关的函数、消息和宏的库提供了一种简单的方法来将多媒体播放或录制功能添加到您的应用程序中。  
MCIWnd 窗口类非常易于使用。通过识别一个简单的 HWND 成员变量,并使用一个函数将其分配给 MCI 窗口,您可以创建一个控件来播放使用媒体控制接口 (MCI) 的任何设备,并获得对机器上安装的任何编解码器的支持。这些设备包括音频 CD、WAV 音频、MIDI 和具有任何受支持编解码器的视频设备。
自动化播放也非常快速和简单。仅使用一个函数和两个宏,应用程序可以创建一个具有适当媒体设备的 MCIWnd 窗口,播放该设备,并在内容播放完毕后关闭设备和窗口。
请注意,术语设备指的是从存储的文件到任何可播放介质的任何可播放媒体。
注意:要在您的应用程序中使用 MCIWnd 类,您必须将 vfw32.lib 库添加到项目设置的链接部分(可以通过 Ctrl+F7 访问)或只需添加以下行到您的头文件
#pragma comment(lib, "vfw32.lib")
它做的是同样的事情。
考虑到我们要编写一个基于对话框的播放器,在添加库后,将一个 HWND 成员变量添加到您的对话框类(如上所述),例如
HWND m_Player;
然后,将以下代码添加到您想要打开媒体进行播放的任何部分
m_Player = MCIWndCreate(GetSafeHwnd(),AfxGetInstanceHandle(),
    WS_CHILD | WS_VISIBLE, m_sFileName);
其中 m_sFileName 是一个保存媒体名称的成员变量。之后,您可以使用单行宏来控制媒体播放。例如,MCIWndPlay(m_Player) 开始媒体播放,或 MCIWndStop(m_Player) 停止媒体播放。
您完成了,您现在有一个媒体播放器了!
MCIWnd 的包装类:CEasyPlayer
我为此 API 编写了一个非常简单的包装类。这个包装类是我工作的一部分。某个程序需要简单地播放 wav 和 mp3 媒体,有时需要连续播放(循环)。因此,我只是在实现该类时封装了非常少的宏和消息。该类的接口如下
class CEasyPlayer : public CWnd
{
public:
CEasyPlayer();
CEasyPlayer(HWND hwParent);
public:
HWND hwndParent;
public:
long lPos;
void Rwd();
void Fwd();
void DecreaseVolume();
void IncreaseVolume();
long GetVolume();
long lVolume;
void SetVolume(long lVol);
long GetLength();
long GetPosition();
void SetPosition(long lPos);
HWND GetWindowHandle();
void Resume();
void Kill();
void Break();
void Loop();
void Close();
HWND Initialize();
void Play();
void Stop();
void Pause();
long GetMode();
CString GetPath();
void SetPath(CString sPath);
void SetParent(HWND hParent);
HWND GetParent();
virtual ~CEasyPlayer();
protected:
HWND c_Player;
CEvent m_Event;
CString m_sPath;
//{{AFX_MSG(CEasyPlayer)
afx_msg void OnDestroy();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
c_Player 就是所谓的 HWND 成员变量。我使用 c_ 前缀来区分控件变量和其他成员变量(值)。Initialize() 创建 MCIWnd 控件并将其分配给 c_Player。其他函数通过它们的名称来标识自己,这些名称显示了函数的确切职责。有必要提到 GetMode() 用于确定播放状态,并返回以下值之一
| 运行模式 | MCI 常量 | 
|---|---|
| 未准备好 | MCI_MODE_NOT_READY | 
| 打开 | MCI_MODE_OPEN | 
| 暂停 | MCI_MODE_PAUSE | 
| 播放中 | MCI_MODE_PLAY | 
| 录制中 | MCI_MODE_RECORD | 
| 搜寻中 | MCI_MODE_SEEK | 
| 已停止 | MCI_MODE_STOP | 
类代码很清晰,它只是封装了一些宏,将值传递给它们并从中获取结果。代码中唯一可能需要描述的部分是 Loop() 函数。使用 Loop() 将导致启动一个对 LoopThread() 的线程调用,其实现如下
UINT LoopThread(LPVOID pParam)
{
    CParams* pParameters;
    pParameters=(CParams*)pParam;
    CEasyPlayer* pWnd=(CEasyPlayer*)pParameters->pWnd;
    CEvent* pEvent=(CEvent*)pParameters->pEvent;
    HWND c_Player=(HWND)pParameters->hWnd;
    while(WaitForSingleObject(pEvent->m_hObject,5)==WAIT_TIMEOUT)
    {
        if (pWnd->GetMode()==MCI_MODE_STOP)
            ::PostMessage(c_Player, MCI_PLAY, 0, 0);
    }
    return 0;
}
一个条件循环,检查类的 m_Event 成员变量是否已设置,如果未设置,则检查媒体播放是否已停止。如果是,则通过向 HWND 控件发送 MCI_PLAY 消息来重播媒体。非常简单!
媒体播放器
在完成该项目后,我决定尝试编写一个媒体播放器,就是这样。利用 CStatic 控件作为 CWnd 派生类的潜力,我为我的包装类制作了一个 GUI。我使用一个 CStatic 控件来保持视频媒体播放(如果存在)。这个 CStatic 控件作为 CEasyPlayer 实例的父级运行。
改变方法,此应用程序没有使用 Loop() 成员函数进行连续媒体播放。而是使用定时器定期检查媒体是否停止。 
致谢
我必须提到我使用了 Nishant S 的方法来处理此应用程序中的键盘消息和菜单加速器。非常感谢 Nishant S.
我从 MSDN (^) 中提取了本文的简介部分。这篇文章最初写于 2003 年。


