windows mobile 使用 libmad 解码 mp3

鉴客 发布于 2011/10/23 09:25
阅读 981
收藏 0

libmad本来是个linux下的解码库,但是现在已经有人将之移植到windows mobile上,参见:http://www.oschina.net/question/54100_30177

利用libmad来播放mp3的思路很简单:开启两个线程,其中一个线程用来解码,一个线程用来播放,中间开一个数据队列用来连接这两个线程。解码线程将解码好的数据放进数据队列,播放线程从数据队列中取解码好的数据用来播放。其中播放的时候用到了双缓冲技术。

以下是我自己的程序在调用libmad库来解码时的大致代码:

解码的线程函数:

    DWORD WINAPI CMediaPlay::Decode(void * ptemp) 
    { 
          CMediaPlay *p = (CMediaPlay*)ptemp; 
          TCHAR *szMusicName = _T("\\My Documents\\My Music\\test.mp3"); 
          CFile file; 
          if (!file.Open(szMusicName,CFile::modeRead)) 
          { 
               TRACE(_T("Can't open the file !")); 
               return 0; 
          } 
          unsigned long iNumReturn = file.Read(p->szMusicBuf,MUSICBUF); 
    // 以下三个函数用来初始化跟libmad库,解码完成后需要调用相应的finish函数释放资源 
          mad_stream_init(p->pm_stream); 
          mad_frame_init(p->pm_frame); 
          mad_timer_reset(&(p->Timer)); 
          mad_synth_init(p->pm_synth); 
    //将读到的缓冲区跟libmad库中的mad_stream对象关联起来,由于我这是测试代码,mp3 
    //文件很小,所以我是一次性全部读进缓冲区,
    //需要多次读文件的可以去参看madlld这个基于//libmad代码。 
          mad_stream_buffer(p->pm_stream, p->szMusicBuf, iNumReturn); 
    //开始解码 
          for (;;) 
          { 
               while (mad_frame_decode(p->pm_frame, p->pm_stream)==-1) 
               { 
                     if (MAD_ERROR_BUFLEN == p->pm_stream->error) 
                     { 
                          bDecode = TRUE; 
                          goto decodeEnd; 
                     } 
               } 
    //同志们呀,第一帧要丢掉呀!原因不明,我每次解出来后播放效果总是不理想,总是有噪 
    //音,不明原因,直到昨天仔细的看了下tcpmp的代码后才发现tcpmp丢掉了第一帧数据。。 
    if (bFirstFrame) 
               { 
                     bFirstFrame--; 
                     continue; 
               } 
               mad_timer_add(&(p->Timer),p->pm_frame->header.duration); 
    // 解码输出 
               mad_synth_frame(p->pm_synth, p->pm_frame); 
               DWORD length = p->pm_synth->pcm.channels == 
    2?p->pm_synth->pcm.length*sizeof(signed short)*2: 
    p->pm_synth->pcm.length*sizeof(signed short); 
               if (!p->outBuf) 
               { 
                     p->outBuf = new unsigned char[length]; 
               } 
               unsigned char *OutputPtr = p->outBuf; 
               for(int i=0;i<p->pm_synth->pcm.length;i++) 
               { 
                     signed short Sample; 
          //下面的函数是为了把解码出来的32位数据转成16位数据,直接从madlld扒出来滴 
                 Sample=MadFixedToSshort(p->pm_synth->pcm.samples[0]); 
                     *(OutputPtr++)=Sample&0xff; 
                     *(OutputPtr++)=Sample>>8;  
                     if (p->pm_synth->pcm.channels == 2) 
                     { 
    Sample=MadFixedToSshort(p->pm_synth->pcm.samples[1]); 
    *(OutputPtr++)=Sample&0xff; 
    *(OutputPtr++)=Sample>>8; 
    } 
    } 
          //将解码完成的数据放进数据队列供播放线程读。 
               SaveData(p->outBuf,length); 
               ResumeThread(p->hThread2);    } 
          return 0; 
    } 

双缓冲播放PCM音频,这里讲得很详细,参看:http://www.oschina.net/question/54100_30178

加载中
返回顶部
顶部