论文部分内容阅读
摘要:本文讨论了一种基于Linux的MP3播放器的设计。系统基于Linux操作系统,利用GNU开发工具进行软件开发,使用C99标准的C语言编写,利用开源的高质量MPEG音频解码器MAD对MP3文件进行解码生成PCM数据,用ALSA中的PCM接口处理PCM数据,最后将数字信号转化为模拟信号,实现MP3音频的播放。
关键词:MP3;MAD;ALSA
中图分类号:TP37文献标识码:A文章编号:1009-3044(2007)15-30849-03
A Design of MP3 Player Based on Linux
WANG Fu-pan1, FANG Long2
(College of Computer Science and Technology, Southwest University of Science and Technology, Mianyang 621010, China)
Abstract:This paper discussed a method for the design of Linux-based MP3 Players. The system is based on Linux and designed with C in GNU, high quality MPEG audio decode library MAD was used to decode the MP3 audio file into PCM data, and then the ALSA was adopted to deal with the PCM data. At last, PCM data was converted from digit signal to analog signal and be played.
Key words:MP3; MAD; ALSA
1 引言
多媒体信息资源在现代人的生活中起着重要的作用,以MP3为代表的许多优秀的多媒体格式受到了越来越多的用户和厂商的青睐,并且取得了极大的市场成功。目前基于Windows的多媒体播放系统已发展得非常成熟并被广泛使用。
Linux操作系统是现代除MS Windows外另一个流行的操作系统。由于其具有Windows所不具备的开放源代码、免费等特点,加之其出众的安全性能和稳定性,在各种服务器市场以及嵌入式市场占有大部分的份额。另外由于桌面环境KDE(K Desktop Environment)和GNOME(GNU Object Model Environment)的功能越来越稳定和强大,带来很好的用户体验,因而吸引了愈来愈多的用户,Linux平台下的应用软件得以迅速发展。本文就设计一种基于Linux的MP3播放器进行了讨论。
2 Linux开发环境的构造
建立Linux下开发环境是系统设计流程的第一步。设计中使用的工具包括使用CVS进行版本控制,使用Makefile进行工程管理,以及Vim、GDB、GCC等。灵活和熟练的使用这些高效的开发工具,将会加快开发进度,起到事半功倍的效果。下面将对这些工具做一简要介绍。[1]
2.1 GCC(GNU Compiler Collection)
GCC是GNU编译器的集合,可以对很多程序设计语言编写的程序进行编译,其中包括C/C++、Java、ADA等等。GCC有很复杂和高级的使用,但是最基本的方法是将源程序编译成obj文件,然后利用连接器ld连接相关的库文件生成可执行文件。表1说明了部分GCC参数。
表1 GCC部分参数
2.2 GDB(GNU Debugger)
调试器 GDB主要是帮助开发者查看一个正在运行的程序内部的执行情况。它可以指定一个程序的启动方式,可以指定程序的停止条件,可以改变程序的运行状态。通过GDB file core文件可以启动并且调试可执行文件。GDB的常用命令如表2所示。
2.3 Vim (Vi IMproved)
Vim[4] (Vi IMproved)主要是由Bram.moolenaar(bram@vim.org)开发和维护的一个源代码开发的慈善软件。Vim是当今优秀的编辑器之一(另一款是emacs),有很强大的文本处理能力,尤其在处理程序代码的时候更是游刃有余。Vim具有良好的可移植性和跨平台运行的特性,在运行在以下平台上UNIX/Linux、win32、Mac等平台下运行,为用户提供一致的编辑体验。
表2 GDB常用命令
2.4 CVS (Concurrent Version System)
CVS是版本控制系统是一种GNU工具,主要用于在多人开发环境下的源码的维护。CVS的命令格式是:
cvs [cvs_options] cvs_command [command_options] [command_args]
常用的CVS命令包括import、Commit、checkout和checkin等。
2.5 Make
Make 工具的目的是为了自动化决定一个大型项目中哪些模块需要被重新编且对之进行重新编译。
3 系统解决方案分析
MP3音频文件的处理过程是利用一个设计合理的解码库将MP3转化为PCM数据,然后利用底层的声频驱动程序将PCM转化为模拟信号。因此软件需要有MP3解码功能和PCM数据播放功能。
3.1 MP3解码器的解决方案
MP3解码器的作用在于将MP3文件转换为PCM数据。[2]目前有很多优秀的MP3解码器可以达到此目的。MAD是一款高质量的MPEG声音解码器。它在支持MPEG-1、MPEG-2以及MPEG2.5的所有的三层声音层layerI、layerII、layerIII都完全得到了实现。
MAD具有24-bit PCM输出,100%定点计算,完全基于ISO/IEC标准的新实现以及使用GPL(General Public License)发布的软件的特点。MAD提供了完全的24-bit PCM输出,使用MAD的应用程序可以产出更高质量音频输出,即使输出设备只支持16-bit的PCM输出,应用程序仍然可以通过其他的方法来增加可听声音的动态范围。由于MAD使用整数计算而不是浮点数计算,所以它适合没有浮点数单元的架构,其所有的计算都在32-bit的定点表达式下处理。目前有很多多媒体播放器采用MAD来对MP3文件进行解码操作,如xmms、mpg321等。本设计也选用MAD作为MP3的解码库。
3.2 PCM播放解决方案
很多Linux下的音频驱动可以将PCM数据转变为模拟信号输出,如OSS(Open Sound System)和ALSA。ALSA[1]是由一套内核驱动程序、应用程序编程接口库以及一些有用的声音处理工具组成。相对OSS而言,ALSA提供了更加简洁的API,对应用程序开发更方便。
4 MP3播放器的系统实现
4.1 系统结构
MP3播放器主要包括MP3解码、PCM播放、错误处理、播放列表等模块。其结构如图1所示。
图1 MP3播放器系统模块
解码的流程如图2所示。MP3文件通过MAD解码为PCM数据,随后PCM数据被ALSA处理转换为可听的声音。
图2 解码的流程
4.2 主要模块设计
4.2.1 MP3解码与PCM播放
MP3的解码库采用的是MAD这一个优秀的开源库。MAD提供了有效的编程接口使得MP3的解码过程得到了简化。MAD中主要的数据结构如下:
struct mad_stream
{ unsigned char const *buffer;/* 输入流缓冲区 */
unsigned char const *bufend;/* 缓冲区结束*/
unsigned long skiplen;/* 到下一帧的需要跳过的长度 */
int sync;/* 流同步标志 */
unsigned long freerate;/* free 位率 (fixed) */
unsigned char const *this_frame;/* 当前帧的开始位置 */
unsigned char const *next_frame;/* 下一帧的开始位置 */
struct mad_bitptr ptr;/* 正在处理的位的指针 */
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;/* 解码选项 (see below) */
enum mad_error error;/* 错误代码 (see above) */ }
如果缓冲区最后一个MPEG数据帧只有部分数据包括在缓冲区中,那么struct mad_stream 中的 next_frame 域指到不完整数据的开始地址。由于缓冲区的MPEG数据帧不一定完整,所以不完整的MPEG帧的数据必须拷贝到下一次解码操作的缓冲区中,进行再次解码。这里我们还看到 bufend 指向缓冲区数据的最后地址,也就是最后一字节的地址加1的位置。mad_stream.bufend-mad_stream.next_frame 就是剩余的未被解码的MPEG帧的数据的字节数量(假设此帧在缓冲区中不完整)。mad_stream 的 error 域用来记录操作 mad_stream 得到的错误代码。错误代码在mad.h文件中有详细的定义。
struct mad_header
{ enum mad_layer layer; /* audio layer (1, 2, or 3) */
enum mad_mode mode;/* 通道模式 (see above) */
int mode_extension;/* 附加的模式信息 */
enum mad_emphasis emphasis;/* de-emphasis to use (see above) */
unsigned long bitrate;/* 位率(bps) */
unsigned int samplerate;/* 采样频率 (Hz) */
unsigned short crc_check;/* frame crc accumulator */
unsigned short crc_target;/* final target crc checksum */
int flags;/* flags (see below) */
int private_bits;/* private bits (see below) */
mad_timer_t duration;/* audio playing time of frame */ }
struct mad_frame
{ struct mad_header header;/* mpeg 音频头 */
int 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_header中存储了媒体文件的一些基本信息,如采样率、位率、通道模式等。结构体mad_frame保存了struct mad_header 的信息。
struct mad_pcm {
unsigned int samplerate;/* 采样率*/
unsigned short channels;/* 通道数*/
unsigned short length;/* number of samples per channel */
MAD_fixed_t samples[2][1152]; /* PCM output samples [ch][sample] */ };
struct mad_pcm包含采样率、声道数以及PCM采样数据。这些参数可用来初始化音频设备。
struct mad_synth
{ mad_fixed_t filter[2][2][2][16][8];/* polyphase filterbank outputs */
unsigned int phase;/* current processing phase */
struct mad_pcm PCM;/* PCM output */ }
mad_synth结构体中的关键域PCM保存解码和合成后得到的PCM数据。
在结构体PCM_t中存储了PCM数据相关的内容。
typedef struct
{ /* pcm name*/
char* pcm_name;
/* sample rate (default = 44100)*/
unsigned int sample_rate;
/* number of channel*/
int channels;
/*number of frames*/
snd_pcm_uframes_t period_size;
/*number of period*/
int periods;
/*bytes default 4096*/
snd_pcm_format_t format;
} PCM_t;
要完成PCM设备的初始化操作,首先需要指定一个snd_pcm_t类型的PCM设备,然后通过snd_pcm_stream_t类型指定PCM流。这个流可以被用来播放或者采集声频信息,另外还要提供一些要用到的配置信息,比如缓冲区大小、采样率、PCM数据格式等。类型snd_pcm_hw_params_t包含了硬件信息。char* pcm_name指定PCM设备名。对PCM设备最重要的ALSA接口是“plughw”和“hw”接口。如果使用“plughw”接口,便可以不用关心声卡。如果声卡不支持指定的采样率或者采样格式,那么数据会被自动的转换。snd_pcm_hw_parmas_alloc用来在栈上分配snd_pcm_hw_params_t结构体。
4.2.2 错误处理模块
出错处理模块包括日志部分和出错处理。本模块的接口如表3所示。
表3 错误处理模块接口表
4.2.3 播放列表模块
播放列表功能是在文件playlist.c中实现的。这一个模块的主要的功能包括添加文件和递归的添加目录到播放列表中,对播放列表中的歌曲进行有序的和随机的播放。以下结构体定义了播放列表相关的数据结构。
typedef struct
{char* plistname;/*filename of the plist*/
int song_num;
char** songs;/*max number of songs*/
char* buff;/*buff*/
int buff_size; }
plist_t;
4.3 系统功能的测试
(1)带有播放列表的随机播放(测试效果图略);
(2)带有播放列表的依次播放测试(测试效果图略)。
5 总结
近年来,Linux已被广泛应用于各种领域,基于Linux平台的应用软件发展非常迅速。本文对一种基于Linux的MP3播放器的设计进行了讨论,系统采用GNU开发工具进行软件开发,使用C99标准的C语言编写,利用开源的高质量MPEG音频解码器MAD对MP3文件进行解码生成PCM数据,用ALSA中的PCM接口处理PCM数据,实现MP3音频的播放。测试证明该播放器能够实现对MP3文件的有效播放并稳定运行。
参考文献:
[1] 李善平, 施韦, 林欣. Linux教程[M]. 北京:清华大学出版社,2005.
[2] 王森林, 庄圣贤. 基于嵌入式Linux的MP3播放器设计[J]. 重庆工学院学报(自然科学版),2007,(3):65-68.
[3] 周文堂, 周群彪, 蔡妍. 基于Linux的多路话音采集压缩卡驱动程序研究[J]. 四川大学学报(自然科学版),2007,(1):1-3.
[4] Linda Lamb, Arnold Robbins. Learning the vi Editor, Sixth Edition[M]. 北京:机械工业出版社,2003.
[5] 唐永刚, 张宪民. Linux下的声卡编程及一种实用的音视频同步方法[J]. 计算机工程,2004(19):176-178.
注:本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文。
关键词:MP3;MAD;ALSA
中图分类号:TP37文献标识码:A文章编号:1009-3044(2007)15-30849-03
A Design of MP3 Player Based on Linux
WANG Fu-pan1, FANG Long2
(College of Computer Science and Technology, Southwest University of Science and Technology, Mianyang 621010, China)
Abstract:This paper discussed a method for the design of Linux-based MP3 Players. The system is based on Linux and designed with C in GNU, high quality MPEG audio decode library MAD was used to decode the MP3 audio file into PCM data, and then the ALSA was adopted to deal with the PCM data. At last, PCM data was converted from digit signal to analog signal and be played.
Key words:MP3; MAD; ALSA
1 引言
多媒体信息资源在现代人的生活中起着重要的作用,以MP3为代表的许多优秀的多媒体格式受到了越来越多的用户和厂商的青睐,并且取得了极大的市场成功。目前基于Windows的多媒体播放系统已发展得非常成熟并被广泛使用。
Linux操作系统是现代除MS Windows外另一个流行的操作系统。由于其具有Windows所不具备的开放源代码、免费等特点,加之其出众的安全性能和稳定性,在各种服务器市场以及嵌入式市场占有大部分的份额。另外由于桌面环境KDE(K Desktop Environment)和GNOME(GNU Object Model Environment)的功能越来越稳定和强大,带来很好的用户体验,因而吸引了愈来愈多的用户,Linux平台下的应用软件得以迅速发展。本文就设计一种基于Linux的MP3播放器进行了讨论。
2 Linux开发环境的构造
建立Linux下开发环境是系统设计流程的第一步。设计中使用的工具包括使用CVS进行版本控制,使用Makefile进行工程管理,以及Vim、GDB、GCC等。灵活和熟练的使用这些高效的开发工具,将会加快开发进度,起到事半功倍的效果。下面将对这些工具做一简要介绍。[1]
2.1 GCC(GNU Compiler Collection)
GCC是GNU编译器的集合,可以对很多程序设计语言编写的程序进行编译,其中包括C/C++、Java、ADA等等。GCC有很复杂和高级的使用,但是最基本的方法是将源程序编译成obj文件,然后利用连接器ld连接相关的库文件生成可执行文件。表1说明了部分GCC参数。
表1 GCC部分参数
2.2 GDB(GNU Debugger)
调试器 GDB主要是帮助开发者查看一个正在运行的程序内部的执行情况。它可以指定一个程序的启动方式,可以指定程序的停止条件,可以改变程序的运行状态。通过GDB file core文件可以启动并且调试可执行文件。GDB的常用命令如表2所示。
2.3 Vim (Vi IMproved)
Vim[4] (Vi IMproved)主要是由Bram.moolenaar(bram@vim.org)开发和维护的一个源代码开发的慈善软件。Vim是当今优秀的编辑器之一(另一款是emacs),有很强大的文本处理能力,尤其在处理程序代码的时候更是游刃有余。Vim具有良好的可移植性和跨平台运行的特性,在运行在以下平台上UNIX/Linux、win32、Mac等平台下运行,为用户提供一致的编辑体验。
表2 GDB常用命令
2.4 CVS (Concurrent Version System)
CVS是版本控制系统是一种GNU工具,主要用于在多人开发环境下的源码的维护。CVS的命令格式是:
cvs [cvs_options] cvs_command [command_options] [command_args]
常用的CVS命令包括import、Commit、checkout和checkin等。
2.5 Make
Make 工具的目的是为了自动化决定一个大型项目中哪些模块需要被重新编且对之进行重新编译。
3 系统解决方案分析
MP3音频文件的处理过程是利用一个设计合理的解码库将MP3转化为PCM数据,然后利用底层的声频驱动程序将PCM转化为模拟信号。因此软件需要有MP3解码功能和PCM数据播放功能。
3.1 MP3解码器的解决方案
MP3解码器的作用在于将MP3文件转换为PCM数据。[2]目前有很多优秀的MP3解码器可以达到此目的。MAD是一款高质量的MPEG声音解码器。它在支持MPEG-1、MPEG-2以及MPEG2.5的所有的三层声音层layerI、layerII、layerIII都完全得到了实现。
MAD具有24-bit PCM输出,100%定点计算,完全基于ISO/IEC标准的新实现以及使用GPL(General Public License)发布的软件的特点。MAD提供了完全的24-bit PCM输出,使用MAD的应用程序可以产出更高质量音频输出,即使输出设备只支持16-bit的PCM输出,应用程序仍然可以通过其他的方法来增加可听声音的动态范围。由于MAD使用整数计算而不是浮点数计算,所以它适合没有浮点数单元的架构,其所有的计算都在32-bit的定点表达式下处理。目前有很多多媒体播放器采用MAD来对MP3文件进行解码操作,如xmms、mpg321等。本设计也选用MAD作为MP3的解码库。
3.2 PCM播放解决方案
很多Linux下的音频驱动可以将PCM数据转变为模拟信号输出,如OSS(Open Sound System)和ALSA。ALSA[1]是由一套内核驱动程序、应用程序编程接口库以及一些有用的声音处理工具组成。相对OSS而言,ALSA提供了更加简洁的API,对应用程序开发更方便。
4 MP3播放器的系统实现
4.1 系统结构
MP3播放器主要包括MP3解码、PCM播放、错误处理、播放列表等模块。其结构如图1所示。
图1 MP3播放器系统模块
解码的流程如图2所示。MP3文件通过MAD解码为PCM数据,随后PCM数据被ALSA处理转换为可听的声音。
图2 解码的流程
4.2 主要模块设计
4.2.1 MP3解码与PCM播放
MP3的解码库采用的是MAD这一个优秀的开源库。MAD提供了有效的编程接口使得MP3的解码过程得到了简化。MAD中主要的数据结构如下:
struct mad_stream
{ unsigned char const *buffer;/* 输入流缓冲区 */
unsigned char const *bufend;/* 缓冲区结束*/
unsigned long skiplen;/* 到下一帧的需要跳过的长度 */
int sync;/* 流同步标志 */
unsigned long freerate;/* free 位率 (fixed) */
unsigned char const *this_frame;/* 当前帧的开始位置 */
unsigned char const *next_frame;/* 下一帧的开始位置 */
struct mad_bitptr ptr;/* 正在处理的位的指针 */
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;/* 解码选项 (see below) */
enum mad_error error;/* 错误代码 (see above) */ }
如果缓冲区最后一个MPEG数据帧只有部分数据包括在缓冲区中,那么struct mad_stream 中的 next_frame 域指到不完整数据的开始地址。由于缓冲区的MPEG数据帧不一定完整,所以不完整的MPEG帧的数据必须拷贝到下一次解码操作的缓冲区中,进行再次解码。这里我们还看到 bufend 指向缓冲区数据的最后地址,也就是最后一字节的地址加1的位置。mad_stream.bufend-mad_stream.next_frame 就是剩余的未被解码的MPEG帧的数据的字节数量(假设此帧在缓冲区中不完整)。mad_stream 的 error 域用来记录操作 mad_stream 得到的错误代码。错误代码在mad.h文件中有详细的定义。
struct mad_header
{ enum mad_layer layer; /* audio layer (1, 2, or 3) */
enum mad_mode mode;/* 通道模式 (see above) */
int mode_extension;/* 附加的模式信息 */
enum mad_emphasis emphasis;/* de-emphasis to use (see above) */
unsigned long bitrate;/* 位率(bps) */
unsigned int samplerate;/* 采样频率 (Hz) */
unsigned short crc_check;/* frame crc accumulator */
unsigned short crc_target;/* final target crc checksum */
int flags;/* flags (see below) */
int private_bits;/* private bits (see below) */
mad_timer_t duration;/* audio playing time of frame */ }
struct mad_frame
{ struct mad_header header;/* mpeg 音频头 */
int 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_header中存储了媒体文件的一些基本信息,如采样率、位率、通道模式等。结构体mad_frame保存了struct mad_header 的信息。
struct mad_pcm {
unsigned int samplerate;/* 采样率*/
unsigned short channels;/* 通道数*/
unsigned short length;/* number of samples per channel */
MAD_fixed_t samples[2][1152]; /* PCM output samples [ch][sample] */ };
struct mad_pcm包含采样率、声道数以及PCM采样数据。这些参数可用来初始化音频设备。
struct mad_synth
{ mad_fixed_t filter[2][2][2][16][8];/* polyphase filterbank outputs */
unsigned int phase;/* current processing phase */
struct mad_pcm PCM;/* PCM output */ }
mad_synth结构体中的关键域PCM保存解码和合成后得到的PCM数据。
在结构体PCM_t中存储了PCM数据相关的内容。
typedef struct
{ /* pcm name*/
char* pcm_name;
/* sample rate (default = 44100)*/
unsigned int sample_rate;
/* number of channel*/
int channels;
/*number of frames*/
snd_pcm_uframes_t period_size;
/*number of period*/
int periods;
/*bytes default 4096*/
snd_pcm_format_t format;
} PCM_t;
要完成PCM设备的初始化操作,首先需要指定一个snd_pcm_t类型的PCM设备,然后通过snd_pcm_stream_t类型指定PCM流。这个流可以被用来播放或者采集声频信息,另外还要提供一些要用到的配置信息,比如缓冲区大小、采样率、PCM数据格式等。类型snd_pcm_hw_params_t包含了硬件信息。char* pcm_name指定PCM设备名。对PCM设备最重要的ALSA接口是“plughw”和“hw”接口。如果使用“plughw”接口,便可以不用关心声卡。如果声卡不支持指定的采样率或者采样格式,那么数据会被自动的转换。snd_pcm_hw_parmas_alloc用来在栈上分配snd_pcm_hw_params_t结构体。
4.2.2 错误处理模块
出错处理模块包括日志部分和出错处理。本模块的接口如表3所示。
表3 错误处理模块接口表
4.2.3 播放列表模块
播放列表功能是在文件playlist.c中实现的。这一个模块的主要的功能包括添加文件和递归的添加目录到播放列表中,对播放列表中的歌曲进行有序的和随机的播放。以下结构体定义了播放列表相关的数据结构。
typedef struct
{char* plistname;/*filename of the plist*/
int song_num;
char** songs;/*max number of songs*/
char* buff;/*buff*/
int buff_size; }
plist_t;
4.3 系统功能的测试
(1)带有播放列表的随机播放(测试效果图略);
(2)带有播放列表的依次播放测试(测试效果图略)。
5 总结
近年来,Linux已被广泛应用于各种领域,基于Linux平台的应用软件发展非常迅速。本文对一种基于Linux的MP3播放器的设计进行了讨论,系统采用GNU开发工具进行软件开发,使用C99标准的C语言编写,利用开源的高质量MPEG音频解码器MAD对MP3文件进行解码生成PCM数据,用ALSA中的PCM接口处理PCM数据,实现MP3音频的播放。测试证明该播放器能够实现对MP3文件的有效播放并稳定运行。
参考文献:
[1] 李善平, 施韦, 林欣. Linux教程[M]. 北京:清华大学出版社,2005.
[2] 王森林, 庄圣贤. 基于嵌入式Linux的MP3播放器设计[J]. 重庆工学院学报(自然科学版),2007,(3):65-68.
[3] 周文堂, 周群彪, 蔡妍. 基于Linux的多路话音采集压缩卡驱动程序研究[J]. 四川大学学报(自然科学版),2007,(1):1-3.
[4] Linda Lamb, Arnold Robbins. Learning the vi Editor, Sixth Edition[M]. 北京:机械工业出版社,2003.
[5] 唐永刚, 张宪民. Linux下的声卡编程及一种实用的音视频同步方法[J]. 计算机工程,2004(19):176-178.
注:本文中所涉及到的图表、注解、公式等内容请以PDF格式阅读原文。