当前位置:文档之家› 流媒体MP3播放器教程

流媒体MP3播放器教程

基于libmad 的简单MP3流媒体播放器的实现.介绍本文在Fedora 5 Linux 下实现了一个基于libmad 的mp3 流媒体播放器。

此流媒体播放器可以播放基于HTTP 1.1 协议传输的MP3 流媒体数据。

基本原理是:从HTTP 服务器获得MP3 媒体信息,然后通过网络传输把MP3 数据以数据流的形式接收到MP3 流媒体播放器客户端,由客户端通过libmad 解码MP3 数据流,得到PCM 音频数据,写入音频设备,播放音乐。

本文的流媒体播放器只是实现了必要的简单功能,没有考虑太多情况。

比如,没有考虑实时播放控制,这样的话就不能随意选取播放点进行播放。

本文的MP3 流媒体播放器创建两个线程,使用两个缓冲区保存MP3 数据,可以一边下载数据,一边播放音乐。

编译运行此MP3 流媒体播放器需要安装libmad(/prodUCts/mad/) 以及ALSA(Advanced Linux Sound Architecture)()相关的软件。

ALSA包括4部分,分别是sound driver, sound library , sound utilities 以及tools。

至少应该安装sound driver, sound library 。

编译程序时连接库的选项是:-lmad -lasound -lpthread。

本文的MP3 流媒体播放器使用双缓冲区,一个是数据接收缓冲区,另一个是数据解码缓冲区。

主程序结构如下图所示,图中的蓝色线表示数据流向。

图1:MP3 流媒体播放器主程序结构图2.libmad简介MAD (libmad)是一个开源的高精度MPEG 音频解码库,支持MPEG-1(Layer I, Layer II 和LayerIII(也就是MP3)。

LIBMAD 提供24-bit 的PCM 输出,完全是定点计算,非常适合没有浮点支持的平台上使用。

使用libmad 提供的一系列API,就可以非常简单地实现MP3 数据解码工作。

在libmad 的源代码文件目录下的mad.h 文件中,可以看到绝大部分该库的数据结构和API 等。

本文用到的libmad 中的主要数据结构有:struct mad_stream, struct mad_synth, struct mad_frame。

它们的定义如下:清单1:libmad 中的主要数据结构struct mad_stream {unsigned char const *buffer; /* input bitstream buffer */ unsigned char const *bufend; /* end of buffer */unsigned long skiplen; /* bytes to skip before next frame */int sync; /* stream sync found */unsigned long freerate; /* free bitrate (fixed) */ unsigned char const *this_frame; /* start of current frame */ unsigned char const *next_frame; /* start of next frame */ struct mad_bitptr ptr; /* current processing bit pointer */struct mad_bitptr anc_ptr; /* ancillary bits pointer */ unsigned int anc_bitlen; /* number of ancillary bits */ unsigned char (*main_data)[MAD_BUFFER_MDLEN];/* Layer III main_data() */unsigned int md_len; /* bytes in main_data */int options; /* decoding options (see below) */enum mad_error error; /* error code (see above) */ };更多内容请看流媒体播放器流媒体文件格式播放技巧专题,或如果缓冲区最后一个MPEG 数据帧只有部分数据包括在缓冲区中,那么structmad_stream中的next_frame域指到不完整数据的开始地址。

∙由于缓冲区的MPEG 数据帧不一定完整,所以不完整的MPEG 帧的数据必须拷贝到下一次解码操作的缓冲区中,进行再次解码。

这里我们还看到bufend指向缓冲区数据的最后地址,也就是最后一字节的地址加 1 的位置。

mad_stream.bufend –mad_stream.next_frame就是剩余的未被解码的MPEG 帧的数据的字节数量(假设此帧在缓冲区中不完整)。

mad_stream的error域用来记录操作mad_stream得到的错误代码。

错误代码在mad.h 中有很详细的定义。

∙清单2:错误代码在mad.h 中的详细定义∙struct mad_synth {∙ mad_fixed_t filter[2][2][2][16][8]; /* polyphase filterbank outputs */∙ /* [ch][eo][peo][s][v] */∙ unsigned int phase; /* current processing phase */∙ struct mad_pcm pcm; /* PCM output */∙};mad_synth中的关键域pcm保存解码和合成后得到的PCM 数据。

清单3:mad_synth 中的关键域struct mad_pcm {unsigned int samplerate; /* sampling frequency (Hz) */ unsigned short channels; /* number of channels */unsigned short length; /* number of samples per channel */mad_fixed_t samples[2][1152]; /* PCM output samples[ch][sample] */};struct mad_pcm定义了音频的采样率、每个声道个数以及最后的PCM 采样数据。

这些参数可用来初始化音频设备。

清单4:struct mad_pcmstruct mad_frame {struct mad_header header; /* MPEG audio header */ int options; /* decoding options (from stream) */mad_fixed_t sbsample[2][36][32]; /* synthesis subband filter samples */mad_fixed_t (*overlap)[2][32][18]; /* Layer III block overlap data */};mad_frame是记录MPEG 帧解码后的数据的数据结构,其中的mad_header尤其重要,其用来记录MPEG 帧的一些基本信息,比如MPEG 层数、声道模式、流比特率、采样比特率等等。

声道模式包括单声道、双声道、联合立体混音声以及一般立体声。

清单5:mad_frameenum mad_mode {MAD_MODE_SINGLE_CHANNEL = 0, /* single channel */ MAD_MODE_DUAL_CHANNEL = 1, /* dual channel */MAD_MODE_JOINT_STEREO = 2, /* joint (MS/intensity) stereo */MAD_MODE_STEREO = 3 /* normal LR stereo */ };struct mad_header {enum mad_layer layer; /* audio layer (1, 2, or 3) */ enum mad_mode mode; /* channel mode */int mode_extension; /* additional mode info */enum mad_emphasis emphasis; /* de-emphasis to use */unsigned long bitrate; /* stream bitrate (bps) */ unsigned int samplerate; /* sampling frequency (Hz) */ unsigned short crc_check; /* frame CRC accumulator */ unsigned short crc_target; /* final target CRC checksum */ int flags; /* flags */int private_bits; /* private bits */mad_timer_t duration; /* audio playing time of frame */};下面就本文使用的API 的功能做简单介绍。

在本文中用到的API 包括:void mad_stream_init(struct mad_stream *)void mad_synth_init(struct mad_synth *);void mad_frame_init(struct mad_frame *);以上3个API 初始化解码需要的数据结构。

void mad_stream_buffer(struct mad_stream *, unsigned char const *, unsigned long);此函数把原始的未解码的MPEG 数据和mad_stream数据结构关联,以便使用mad_frame_decode( )来解码MPEG 帧数据。

int mad_frame_decode(struct mad_frame *, struct mad_stream *);把mad_stream中的MPEG 帧数据解码。

void mad_synth_frame(struct mad_synth *, struct mad_frame const *);把解码后的音频数据合成PCM 采样。

void mad_stream_finish(struct mad_stream *);void mad_frame_finish(struct mad_frame *);mad_synth_finish(struct mad_synth);以上 3 个API 在解码完毕后使用,释放libmad 占用的资源等。

相关主题