这个音频播放器是别人写的,我看到代码结构比较清晰,代码量比较精简,所以就拿来作为一个例子给大家讲解一下。这个播放器的界面是用Win32开发的,界面很简单,上面是菜单栏,下面是一个播放进度条,界面截图如下:
这个播放器使用FFmpeg来解析音频文件格式和解码音频,播放音频用到了DirectSound。这里要说一下播放音频的方法,在Windows平台,播放音频的方法有很多,比较常用的是:DirectSound,WaveOut API,MCI函数,SDL,其中WaveOut API和MCI函数的用法可参考下面两篇博文:
https://www.cnblogs.com/margin1988/archive/2012/05/10/2493937.html
http://blog.csdn.net/dancewyr/article/details/7183572
下面我说一下这个代码的调用流程。
首先,程序创建窗口的时候会建立一个线程:
case WM_CREATE:
{
// start main play loop thread
HANDLE hThreadReadyEvent = CreateEvent(NULL, TRUE, FALSE, _T("ThreadReadyEvent"));
StartParameter startParam = {hWnd, hThreadReadyEvent};
dwMainLoopThreadId = 0;
hMainLoopThread = CreateThread(NULL, 0, MainLoopThreadProc, &startParam,
CREATE_SUSPENDED, &dwMainLoopThreadId);
ResumeThread(hMainLoopThread);
WaitForSingleObject(hThreadReadyEvent, INFINITE);
CloseHandle(hThreadReadyEvent);
hThreadReadyEvent = NULL;
}
break;
线程函数:MainLoopThreadProc用来从文件中读取和解析音频,MainLoopThreadProc函数实现如下:
DWORD WINAPI MainLoopThreadProc(VOID* pParam)
{
StartParameter* pStartParam = (StartParameter*)pParam;
BOOL bTerminateThread = FALSE;
// register all codecs.
av_register_all();
SetEvent(pStartParam->hThreadReadyEvent);
AudioState state = {0};
int buffer_size = (AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2;
memset(&state, 0, sizeof(AudioState));
int err = 0;
char filepath[MAX_PATH] = {0};
__int64 duration = 0;
int totalSeconds = 0;
int minute = 0;
int second = 0;
int totalMinute = 0;
int totalSecond = 0;
int channels = 0;
int samplerate = 0;
int bitpersample = 16;
DS_Info* info = NULL;
int frameSize = 0;
long bufferSize = 0;
int bytesPerSec = 0;
long waitTime = 0;
int deviceCount = 0;
DWORD readBytes = 0;
char input_buffer[BLOCK_SIZE] = {0};
TCHAR szTime[20] = {0};
TCHAR szPosition[10] = {0};
do
{
MSG msg = {0};
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
switch(msg.message)
{
case TM_PLAY:
{
#ifdef _UNICODE
WideCharToMultiByte(CP_ACP, 0, szFileName, -1, filepath, sizeof(filepath) / sizeof(char), NULL, NULL);
#else
memcpy(filepath, szFileName, sizeof(filepath) / sizeof(char));
#endif
err = avformat_open_input(&state.pFmtCtx, filepath, NULL, NULL);
if(err < 0)
{
TCHAR buffer[2*MAX_PATH];
_stprintf_s(buffer, sizeof(TCHAR) * (2 * MAX_PATH), _T("can not open file %s."), filepath);
MessageBox(hMainWindow, buffer, _T("Error