用Direct Sound为MP3解码器libmad播放输出_第1页
用Direct Sound为MP3解码器libmad播放输出_第2页
用Direct Sound为MP3解码器libmad播放输出_第3页
用Direct Sound为MP3解码器libmad播放输出_第4页
用Direct Sound为MP3解码器libmad播放输出_第5页
已阅读5页,还剩5页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、用Direct Sound为MP3解码器libmad播放输出WIN32平台下madplay默认采用WaveOut播放输出,本文实现为其增加Direct Sound输出。在Windows XP,VC+ 6.0测试通过。 (一)优秀的MP3解码器libmad简介 libmad是跨平台的基于命令行的MP3播放解码器,使用定点解码,可用于没有浮点运算的嵌入式系统。 (二)下载及测试 1、从官方网站下载madplay-0.15.2b.tar.gz,libmad-0.15.1b.tar.gz,libid3tag-0.15.1b.tar.gz,还要从下载libz-1.

2、1.4.tar.gz,共四个文件。将四个压缩包保存在同一目录,例如d:madplay。 2、用WINRAR“解码压到当前目录”方法将四个压缩包解压,在d:madplay下将有四个文件夹:madplay-0.15.2b,libmad-0.15.1b,libid3tag-0.15.1b,libz-1.1.4。 3、用VC+ 6.0打开D:madplaymadplay-0.15.2bmsvc+下的madplay工程。修改VC+ 6.0的编译环境:Tools -> Options -> Directories标签 -> Directories框下增加如下两行: D

3、:MADPLAYLIBMAD-0.15.1BMSVC+ D:MADPLAYLIBID3TAG-0.15.1B 点击OK保存设置退出。再为编译连接后的可执行文件指定运行参数:Project -> settings -> 点中左侧madplay -> 右侧Program arguments框内填入你硬盘上保存的一个MP3文件,例如:D:MP3test.mp3,单击OK保存设置退出。 按Ctrl+F5编译连接运行,就可以听到播放你选择的MP3歌曲了。 (三)为madplay增加Direct Sound输出 madplay采用Wave

4、Out作为播放输出,用DS输出的优点不再我说了吧。 1、在audio.h中查找到“audio_ctlfunc_t audio_win32;”这一行,在下面增加一行: audio_ctlfunc_t audio_dsound; 2、在config.h中找到“#define AUDIO_DEFAULT audio_win32”这一行,将这一行注释掉,然后在下面增加一行: #define AUDIO_DEFAULT audio_dsound 3、在工作区中选择FileView标签,点击madplay files下的Source Files,添加文件a

5、duio_dsound.c 我写的aduio_dsound.c的内容如下,添加了比较详细的注释。   /* aduio_dsound.c功能: 用 Direct Sound 为MP3解码器libmad播放输出.兼容 VC+ 6.0 的directx 7.0接口函数: audio_dsound()email: (请注明主题 mp3 decoder)2008.08*/ /*libmad解码器头文件*/#include "audio.h" /*Direct Sound 的头文件和库*/#include<dsound

6、.h>#pragma comment( lib, "dsound.lib" ) /*高精定时器的头文件和库*/#include<mmsystem.h>#pragma comment( lib, "winmm.lib") /*DS_N: 缓冲区块数,设为8块.DS_ONEBUF: 一块的长度.设解码16帧的PCM数据长度,4608*16=73728(72KB).DS_BUFSIZE: Direct sound缓冲区长度,DS_N*DS_ONEBUF=589824(576KB).   

7、60;        最小4,最大0xfffffff,在dsound.h中由DSBSIZE_MIN和DSBSIZE_MAX定义.每一帧的时长26ms,一块的时间长度为26*16=416ms;缓冲区总时间长度8*416=3328ms.*/#define DS_N   8#define DS_ONEBUF  73728#define DS_BUFSIZE  589824 /*pcm_data - 暂存写入到时DSound Buffer的数据,该数据是由audio_pcm()解码M

8、P3帧得到的PCM数据,不同的解码器(如mpg123,libmad等)解码一帧的函数都采用向外部提供的接收缓冲区写入解码得到的PCM数据,将本模块略作改写可用于不同的MP3解码器播放输出.*/static unsigned char pcm_dataDS_ONEBUF+4608;static int pcm_length=0;static audio_pcmfunc_t *audio_pcm;static LPDIRECTSOUND   ds_lpDS=0;static LPDIRECTSOUNDBUFFER  ds_lpDSB=0;static HWND

9、0;  ds_hWndMain=0;static HANDLE  ds_hSemaphoreNotify=0;static DWORD  ds_dwWriteCursor=0;static DWORD  ds_dwPlayCursorOld=0;static MMRESULT  ds_timerID=0;static int   ds_iWriteTimes=0; /#define DBGOUTPUT #ifdef DBGOUTPUT  #include <stdio.h>#endi

10、f /*DirectSoundBuffer 通知机制引发的问题:若采用DirectSoundBuffer通知机制,发现运行其它使用相同通知机制的播放程序时,会造成本程序的通知事件误触发,如何识别是本程序还是其它程序引发的通知事件? 如何解决? 本程序采用定时器回调函数定时判断播放位置、发信号(设置通知事件).ds_dwWriteCursor: 写入光标,指向播放一块后释放的一个空闲块首址,跟随于播放光标后.ds_dwPlayCursor: 播放光标,取值(0.n)*DS_ONEBUF ds_dwPlayCursorOld: 暂存播放光标先前值,取值(0.n-1)*DS_ON

11、EBUF, 若使用写入光标,     由于本函数中“读”与audio_play()中“写”不同步而出错.*/ /*MyPlayPositionNotify()  - 定时器回调函数,播放完一块发一次信号.*/static void CALLBACKMyPlayPositionNotify(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) DWORD dwPlayCursor=0; ds_lpDSB->lpVtbl->GetCurr

12、entPosition(ds_lpDSB,&dwPlayCursor, NULL); if(dwPlayCursor>ds_dwPlayCursorOld+DS_ONEBUF |  (dwPlayCursor<DS_ONEBUF && ds_dwPlayCursorOld=DS_BUFSIZE-DS_ONEBUF) #ifdef DBGOUTPUT  printf("nWriteCursor = %6d, PlayCursor = %6d, PlayCursorOld = %6d",  &

13、#160; ds_dwWriteCursor, dwPlayCursor, ds_dwPlayCursorOld);#endif  dwPlayCursor /= DS_ONEBUF;  ds_dwPlayCursorOld = dwPlayCursor*DS_ONEBUF;   /* 发信号,使audio_play()内的等待函数返回. */  ReleaseSemaphore(ds_hSemaphoreNotify,1,NULL);  static int audio_open(int nChannels,long nS

14、amplesPerSec,unsigned int depth) DSBUFFERDESC dsbd; WAVEFORMATEX wvOut;  ds_dwWriteCursor=0; ds_dwPlayCursorOld=0; ds_iWriteTimes=0;  if(nSamplesPerSec = -1)  return -1;  /* Create DirectSound */ if ( DirectSoundCreate(NULL, &ds_lpDS, N

15、ULL) != DS_OK )   return -1;   if( ds_hWndMain = 0 )  ds_hWndMain=GetDesktopWindow();  /* Set Cooperative Level */ if ( ds_lpDS->lpVtbl->SetCooperativeLevel(ds_lpDS,ds_hWndMain, DSSCL_PRIORITY) != DS_OK )   return -1;   wvOut.wFormatT

16、ag      = WAVE_FORMAT_PCM; wvOut.wBitsPerSample  = depth; wvOut.nChannels       = nChannels; wvOut.nSamplesPerSec  = nSamplesPerSec; wvOut.nAvgBytesPerSec = wvOut.nSamplesPerSec * wvOut.nChannels * wvOut.wBitsPerSam

17、ple/8; wvOut.nBlockAlign     = wvOut.nChannels * wvOut.wBitsPerSample/8;  /* Create Secondary Sound Buffer */  ZeroMemory(&dsbd, sizeof(DSBUFFERDESC); dsbd.dwSize   = sizeof(DSBUFFERDESC); dsbd.dwFlags  = DSBCAPS_GLOBALFOCUS &

18、#160;     | DSBCAPS_CTRLVOLUME      | DSBCAPS_GETCURRENTPOSITION2; dsbd.dwBufferBytes = DS_BUFSIZE; dsbd.lpwfxFormat = &wvOut; if ( ds_lpDS->lpVtbl->CreateSoundBuffer(ds_lpDS,&dsbd, &ds_lpDSB, NULL) != DS_OK )   retur

19、n -1;   ds_hSemaphoreNotify = CreateSemaphore(NULL,DS_N,DS_N,NULL); if( ds_hSemaphoreNotify = NULL )  return -1;  return 0; /*audio_play() - 播放一块,每解码一帧被调用一次返回值: 写入到 SoundBuffer 的字节数,失败返回0*/static int audio_play(struct audio_play *play) LPVOID lpDSBuf;

20、0;DWORD dwDSLockSize; UINT len=0; HRESULT hr;  /* 1. 调用audio_pcm()解码一帧,得到的PCM写入到暂存区audio_pcm */  len = audio_pcm(pcm_data+pcm_length, play->nsamples,play->samples0,     play->samples1, play->mode, play->stats); pcm_length += len;&

21、#160;if (pcm_length < DS_ONEBUF)  return 0;  /* 2. 若audio_pcm已写满DS_ONEBUF字节,等待播放完一块后释放一个空闲块 */  WaitForSingleObject(ds_hSemaphoreNotify,INFINITE);  /* 3. 将audio_pcm写入到 SoundBuffer,使完成播放一块 */  hr = ds_lpDSB->lpVtbl->Lock(ds_lpDSB,ds_dwWriteCursor,

22、pcm_length,&lpDSBuf,&dwDSLockSize,NULL,0,0); if(hr = DSERR_BUFFERLOST)   ds_lpDSB->lpVtbl->Restore(ds_lpDSB);  ds_lpDSB->lpVtbl->Lock(ds_lpDSB,ds_dwWriteCursor,pcm_length,&lpDSBuf,&dwDSLockSize,NULL,0,0);  if(FAILED(hr)  return 0; CopyMe

23、mory(lpDSBuf,pcm_data,dwDSLockSize); ds_lpDSB->lpVtbl->Unlock(ds_lpDSB,lpDSBuf,dwDSLockSize,NULL,0);  /* 4. 更新相关变量! */  pcm_length=0; ds_dwWriteCursor += dwDSLockSize; if( ds_dwWriteCursor >= DS_BUFSIZE)  ds_dwWriteCursor -= DS_BUFSIZE;  /*

24、5. 首次写满Direct SoundBuffer后,启动定时器,开始播放 */  if(ds_iWriteTimes < DS_N)   ds_iWriteTimes+;  if(ds_iWriteTimes = DS_N)    UINT uRs = DS_ONEBUF / 4608 / 2 * 26;   ds_timerID = timeSetEvent( uRs/2, uRs, (LPTIMECALLBACK)MyPlayPositionNotify, 0,    &#

25、160;        TIME_PERIODIC | TIME_CALLBACK_FUNCTION );   ds_lpDSB->lpVtbl->SetCurrentPosition(ds_lpDSB,0);   ds_lpDSB->lpVtbl->Play(ds_lpDSB,0, 0, DSBPLAY_LOOPING);  #ifdef DBGOUTPUT  printf("nWriteTimes= %2d, WriteByte

26、s= %d",ds_iWriteTimes,dwDSLockSize);#endif   return dwDSLockSize; static int audio_init(struct audio_init *init)  SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);  SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST);   return 0; 

27、;static int audio_config(struct audio_config *config)  unsigned int bitdepth;   bitdepth = config->precision & 7;  if (bitdepth = 0)    bitdepth = 16;  else if (bitdepth > 32)    bitdepth = 32;   audio_close();   if

28、 (audio_open(config->channels,config->speed, bitdepth) = -1)   return -1;   switch (config->precision = bitdepth)   case 8:    audio_pcm = audio_pcm_u8;    break;   case 16:    audio_pcm = audio_pcm_s16le; 

29、   break;   case 24:    audio_pcm = audio_pcm_s24le;    break;   case 32:    audio_pcm = audio_pcm_s32le;    break;     return 0; static int audio_pause(int bPause) static int paused;&#

30、160;if(ds_lpDSB = 0)  return -1; if (bPause && !paused)   ds_lpDSB->lpVtbl->Stop(ds_lpDSB);  return 0;  else if (!bPause && paused)   ds_lpDSB->lpVtbl->Play(ds_lpDSB,0, 0, DSBPLAY_LOOPING);  return 0;   paused = bPaus

31、e; return 0; static int audio_stop() if(ds_lpDSB = 0)  return -1; ds_lpDSB->lpVtbl->Stop(ds_lpDSB); return 0; /*audio_flush() - 播放完Direct Sound缓冲区ds_lpDSB中的数据,DS_N-1块*/static void audio_flush() int i; for( i=1; i<DS_N; i+ )  WaitForSingleObj

32、ect(ds_hSemaphoreNotify,INFINITE); static int audio_close() SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_NORMAL); SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS);  if (ds_lpDSB != 0)   ds_lpDSB->lpVtbl->Stop(ds_lpDSB);  ds_lpDSB->lpVtbl->Release(ds_lpDSB);  ds_lpDSB = 0;  if (ds_timerID != 0)   timeKillEvent(ds_timerID);  ds_t

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论