| 結構體 | 用途 |
|---|---|
mad_stream | 儲存待解碼的位元流資料 |
mad_frame | MPEG 幀解碼後資訊 (含 mad_header:層級、聲道模式、位元率、取樣率) |
mad_synth | 合成濾波後的 PCM 輸出 |
mad_pcm | PCM 參數:取樣率、聲道數、取樣資料指標 |
libmad 採回呼函式機制,三大回呼:
input:提供輸入位元流output:處理解碼後的 PCM 資料 (播放/存檔)error:錯誤處理回呼回傳 mad_flow 控制流程:MAD_FLOW_CONTINUE/STOP/BREAK。
static int sfd;
if ((sfd = open("/dev/dsp", O_WRONLY)) < 0) { perror("open dsp"); return 1; }
// 立體聲、16-bit Little Endian、速率 = 取樣率 * 2 (雙聲道交錯)
int fmt = AFMT_S16_LE;
int speed = pcm->samplerate * 2;
ioctl(sfd, SNDCTL_DSP_SETFMT, &fmt);
ioctl(sfd, SNDCTL_DSP_CHANNELS, &channels);
ioctl(sfd, SNDCTL_DSP_SPEED, &speed);
static enum mad_flow output(void *data, struct mad_header const *header, struct mad_pcm *pcm) {
unsigned int nchannels = pcm->channels;
unsigned int nsamples = pcm->length;
mad_fixed_t const *left_ch = pcm->samples[0];
mad_fixed_t const *right_ch = pcm->samples[1];
unsigned char Output[6912], *OutputPtr = Output;
while (nsamples--) {
signed int sample = scale(*left_ch++);
*OutputPtr++ = sample >> 0;
*OutputPtr++ = sample >> 8;
if (nchannels == 2) {
sample = scale(*right_ch++);
*OutputPtr++ = sample >> 0;
*OutputPtr++ = sample >> 8;
}
}
int n = pcm->length * 4; // bytes = samples * channels * 2(bytes/sample)
OutputPtr = Output;
while (n > 0) {
int wrote = write(sfd, OutputPtr, n);
if (wrote < 0) { perror("write"); return MAD_FLOW_STOP; }
OutputPtr += wrote;
n -= wrote;
}
return MAD_FLOW_CONTINUE;
}
static inline signed int scale(mad_fixed_t sample) {
// 四捨五入 + 飽和限幅
sample += (1L << (MAD_F_FRACBITS - 16));
if (sample >= MAD_F_ONE) sample = MAD_F_ONE - 1;
else if (sample < -MAD_F_ONE) sample = -MAD_F_ONE;
return sample >> (MAD_F_FRACBITS + 1 - 16);
}
static enum mad_flow input(void *data, struct mad_stream *stream) {
struct buffer *buf = (struct buffer *)data;
if (!buf->length) return MAD_FLOW_STOP;
mad_stream_buffer(stream, buf->start, buf->length);
buf->length = 0;
return MAD_FLOW_CONTINUE;
}
int main(int argc, char *argv[]) {
int fd = open(argv[1], O_RDONLY);
struct stat st; fstat(fd, &st);
void *fdm = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
struct buffer buf = { (unsigned char*)fdm, st.st_size };
struct mad_decoder decoder;
mad_decoder_init(&decoder, &buf, input, 0, 0, output, error, 0);
mad_decoder_options(&decoder, 0);
mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);
mad_decoder_finish(&decoder);
munmap(fdm, st.st_size);
close(sfd);
return 0;
}
關鍵點:使用 mmap 將 MP3 檔案映射記憶體,input 回呼一次性餵入完整流,libmad 內部處理幀同步與解碼,output 即時播放。