利用libmad解碼mp3

mp3是流媒體,所以一個完整文件往往比較大而且不能一次裝入sound緩存,所以其buffer管理就成了最大難題,至於解碼部分其實還是很簡單的,下面是僅關於解碼部分的說明

 

首先應該在自己的工程中包含以下三個庫:

libid3tag-0.15.1b
libmad-0.15.1b
libz-1.1.4
必要的三個結構體及相關的初始化
  1. mad_stream stream;  
  2. mad_frame frame;  
  3. mad_synth synth;  
  4. mad_stream_init(&stream);  
  5. mad_frame_init(&frame);  
  6. mad_synth_init(&synth);  
將stream和buffer關聯起來
  1. mad_stream_buffer(&stream, buffer, buffer_size);  
對壓縮數據進行解碼,這裏將控制着一個雙層的循環邏輯
  1. mad_frame_decode(&frame, &stream);  
如果mad_frame_decode返回-1,這說明這裏存在錯誤這需要對特定的錯誤進行處理
當錯誤代碼爲!MAD_RECOVERABLE(stream.error),則需要從新更新流媒體buffer
當錯誤代碼爲MAD_ERROR_BADDATAPTR時需要再進行decode
當錯誤代碼爲MAD_ERROR_LOSTSYNC則需要進行id3tag跳幀,並再次decode
  1. id3_tag_query(stream.this_frame, stream.bufend - stream.this_frame);  
  2. if(tagsize > 0)  
  3. {  
  4.     mad_stream_skip(&stream, tagsize);  
  5. }  
將解碼數據轉換爲設備所能接受的pcm數據
  1. mad_synth_frame(&synth, &frame);  
但是即使是pcm數據依然不能直接播放,還需要更具設備的支持能力進行相應的線性插值,轉換成8位、16位、及32位…… 雙聲道的轉換方式
  1. for(int i = 0; i < (int)synth.pcm.length; i++)  
  2. {  
  3.     sample0 = audio_linear_dither(16, synth.pcm.samples[0][i], &left_dither, &stats);  
  4.     sample1 = audio_linear_dither(16, synth.pcm.samples[1][i], &right_dither, &stats);  
  5.     tempBuffer[0] = sample0 >> 0;  
  6.     tempBuffer[1] = sample0 >> 8;  
  7.     tempBuffer[2] = sample1 >> 0;  
  8.     tempBuffer[3] = sample1 >> 8;  
  9. }  
單聲道的轉換方式
  1. register int sample0;  
  2. for(int i = 0; i < (int)synth.pcm.length; i++)  
  3. {  
  4.     sample0 = audio_linear_dither(16, synth.pcm.samples[0][i], &left_dither, &stats);  
  5.     tempBuffer[0] = sample0 >> 0;  
  6.     tempBuffer[1] = sample0 >> 8;  
  7. }  
當這個轉換後的pcm數據積累到一定程度就可以拷貝到設備緩存區進行播放了這裏省略不同設備的創建及播放代碼,要注意的是創建設備時需要的音頻信息是從synth.pcm中獲得的,如channels,samplerate,……
最後不要忘記如何關閉相關資源
  1. mad_synth_finish(&synth);  
  2. mad_frame_finish(&frame);  
  3. mad_stream_finish(&stream);  
再舉例一個基於looping結構的direct sound buffer管理機制:
詳細代碼可以參考我寫的一個工程:
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章