本篇是创建游戏内核(21)的续篇,有关DirectAudio和DirectShow的基础知识请参阅用DirectX
Audio和DirectShow播放声音和音乐。
在MP3类中,可以初始化并关闭DirectShow,渲染媒体文件以及控制歌曲的回放(开始播放、停止播放以及暂停播放)。
来看看MP3类的定义:
//======================================================================================
// This class encapsulates mp3 playing.
//======================================================================================
typedef class MP3
{
public:
MP3();
~MP3();
BOOL init();
void shutdown();
BOOL render(const char* filename);
BOOL play();
BOOL stop();
BOOL pause();
BOOL is_playing();
private:
IGraphBuilder* _graph_builder;
IMediaControl* _media_control;
IMediaEvent* _media_event;
} *MP3_PTR;
实现:
//------------------------------------------------------------------------------
// Constructor, zero member data.
//------------------------------------------------------------------------------
MP3::MP3()
{
memset(this, 0, sizeof(*this));
}
//------------------------------------------------------------------------------
// Destructor, release resource.
//------------------------------------------------------------------------------
MP3::~MP3()
{
shutdown();
}
//------------------------------------------------------------------------------
// Release all resource which used to play mp3.
//------------------------------------------------------------------------------
void MP3::shutdown()
{
release_com(_media_event);
release_com(_media_control);
release_com(_graph_builder);
CoUninitialize();
}
//------------------------------------------------------------------------------
// Create graph builder, query interface for medial control and medial event.
//------------------------------------------------------------------------------
BOOL MP3::init()
{
// shutdown prior initialized system
shutdown();
// initialize com
CoInitialize(NULL);
// create graph builder object and media controls
if(FAILED(CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER, IID_IGraphBuilder,
(void**)&_graph_builder)))
{
return FALSE;
}
_graph_builder->QueryInterface(IID_IMediaControl, (void**) &_media_control);
_graph_builder->QueryInterface(IID_IMediaEvent, (void**) &_media_event);
return TRUE;
}
//------------------------------------------------------------------------------
// Builds a filter graph that renders the specified file.
//------------------------------------------------------------------------------
BOOL MP3::render(const char* filename)
{
// error checking
if(_graph_builder == NULL || _media_control == NULL)
return FALSE;
// stop the current song
_media_control->Stop();
// convert filename to wide-character string
WCHAR w_filename[MAX_PATH];
mbstowcs(w_filename, filename, MAX_PATH);
// builds a filter graph that renders the specified file
if(FAILED(_graph_builder->RenderFile(w_filename, NULL)))
return FALSE;
return TRUE;
}
//------------------------------------------------------------------------------
// Play mp3.
//------------------------------------------------------------------------------
BOOL MP3::play()
{
// error checking
if(_media_control == NULL)
return FALSE;
// Runs all the filters in the filter graph.
// While the graph is running, data moves through the graph and is rendered.
if(FAILED(_media_control->Run()))
return FALSE;
return TRUE;
}
//------------------------------------------------------------------------------
// Stop playing mp3.
//------------------------------------------------------------------------------
BOOL MP3::stop()
{
// error checking
if(_media_control == NULL)
return FALSE;
// stops all the filters in the graph
if(FAILED(_media_control->Stop()))
return FALSE;
return TRUE;
}
//------------------------------------------------------------------------------
// Pause playing mp3.
//------------------------------------------------------------------------------
BOOL MP3::pause()
{
// error checking
if(_media_control == NULL)
return FALSE;
// pause all the filters in the filter graph
if(FAILED(_media_control->Pause()))
return FALSE;
return TRUE;
}
//------------------------------------------------------------------------------
// Ascertain whether mp3 has completed playing.
//------------------------------------------------------------------------------
BOOL MP3::is_playing()
{
// error checking
if(_media_event == NULL)
return FALSE;
// get event and handle it
long event, param1, param2;
// retrieves the next event notification from the event queue
_media_event->GetEvent(&event, ¶m1, ¶m2, 1);
if(event == EC_COMPLETE)
{
// free resources associated with the paramters of an event
_media_event->FreeEventParams(event, param1, param2);
return TRUE;
}
_media_event->FreeEventParams(event, param1, param2);
return FALSE;
}
测试代码:
/*****************************************************************************
PURPOSE:
Test for class MP3.
*****************************************************************************/
#include "Core_Global.h"
class APP : public APPLICATION
{
public:
BOOL init()
{
_mp3.init();
if(_mp3.render("song.mp3"))
_mp3.play();
while(_mp3.is_playing())
;
return TRUE;
}
BOOL frame()
{
return TRUE;
}
BOOL shutdown()
{
return TRUE;
}
private:
MP3 _mp3;
};
int PASCAL WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
{
APP app;
return app.run();
}