基于alsa和libmad嵌入式mp3播放器

news/2024/11/29 4:48:17/

可移植ok6410 的mp3播放器,基于alsa和libmad库,内含编译好的库和播放器以及源代码,解压后可直接运行,和以移植好的mplayer官方播放器(可快进 暂停 时间轴 音量控制等)

源码及移植库文件下载地址:
https://download.csdn.net/download/ywueoei/10898346

####################################################################

1 设计功能概述
基于ALSA通过Libmad解码对MP3格式音乐进行播放。
2 设计方案
2.1 设计说明
由于 Linux 具有开放源码,软件资源丰富,性能高效、稳定,支持多种体系结构,大小、功能都可定制,价格低廉等优点,本MP3 播放器系统基于嵌入式Linux操作系统来实现。
而对于 MP3 播放器一些底层功能的实现,可以基于一些开源音频解码库,只要开发者遵循开发协议即可,这样可以加快开发速度和减少开发成本。在本 MP3 播放器的设计和实现的过程中,主要采用 libmad 解码库。libmad是一个开源的高精度MPEG音频解码库,它提供 24-bit 的PCM输出。用 libmad 解码库对 MP3 文件进行解码播放的音质比较好,而且使用libmad提供的API,可以实现 MP3 数据解码和顺序播放
开发环境:Linux内核版本:Linux Ubuntu 3.1.0,开发环境Ubuntu16.4交叉编译器arm-linux-gcc,开发语言为C语言,开发工具:vim,在arm-linux平台上的实现:将代码使用arm-linux-gcc工具在PC端进行静态编译,编译完成之后,将生成的可执行文件放在主机目录下,使用主机的xshell连接arm-linux开发板,通过nfs工具将可执行文件上传至开发板。
2.2 设计过程
1.ALAS和Libmad两个库的移植
1)ALSA移植
① 下载必要的文件
下载页面:http://dl.ambiweb.de/mirrors/ftp.alsa-project.org/lib/
alsa-lib-1.0.24.1.tar.bz2
alsa-utils-1.0.24.2.tar.bz2
在/forlink/nfsroot/alsa_arm目录下存放它们
② 编译安装alsa-lib
解压alsa-lib,然后进入解压后的目录
在终端下输入配置命令:
./configure --host=arm-linux --target=arm-linux --prefix=/usr/local/arm/4.5.1/arm-none-linux-gnueabi/lib/arm-alsa --enable-static --enable-shared --disable-python --with-configdir=/usr/share --with-plugindir=/usr/lib/alsa_lib
配置完成后编译:
make
编译完成后安装;
make install
③ 编译安装alsa-utils
解压alsa-utils,然后进入解压后的目录
在终端下输入配置命令:
PKG_CONFIG_PATH="/usr/local/arm/4.5.1/arm-none-linux-gnueabi/lib/arm-alsa/lib/pkgconfig"
LDFLAGS="-L/usr/local/arm/4.5.1/arm-none-linux-gnueabi/lib -lpthread -lc -lgcc"
CFLAGS="-I/usr/local/arm/4.5.1/arm-none-linux-gnueabi/include"
./configure
–host=arm-linux
–target=arm-linux
–prefix=/forlink/nfsroot/alsa_arm/alsa_u
–disable-alsamixer
–disable-xmlto
–with-alsa-prefix=/usr/local/arm/4.5.1/arm-none-linux-gnueabi/lib/arm-alsa/lib/
–with-alsa-inc-prefix=/usr/local/arm/4.5.1/arm-none-linux-gnueabi/lib/arm-alsa/include/
配置完成后编译:
make
编译完成后安装:
make install
2)Libmad移植
① 下载 libmad-0.15.1b.tar.gz,解压,运行configure,生成makefile,修改 makefile。
./configure CC=arm-linux-gcc --host=arm-linux --disable-shared --disable-debugging --prefix=/usr/local/libmad/mad
gedit Makefile
Ctrl+F找到并删除-fforce-mem -> Save(删掉-fforce-mem)
② 编译&安装。
make -j4 && make install -j4
//-j4是4线程的意思,可以不加直接make。看电脑处理器决定。
3)将编译alsa-lib,alsa-utils所产生的4个目录复制到/usr/ks/
四个目录:
/usr/local/arm/4.5.1/arm-none-linux-gnueabi/lib/arm-alsa
/usr/share/alsa
/usr/lib/alsa_lib
/forlink/nfsroot/alsa_arm/alsa_u
目标板中挂载共享目录/forlinx/nfsroot/到/mnt/nfs目录
在超级终端下输入命令:mount -o nolock 192.168.137.2:/forlinx/nfsroot /mnt/nfs
将目标板挂载目录下的文件复制到正确的位置,在超级终端下进入/mnt/nfs目录。
首先移植alsa_u中的文件:
cd /tmp/alsa_u
cp -r bin/* /bin
然后移植arm-alsa中的文件
cd /tmp/arm-alsa
cp -r lib/* /lib
然后移植alsa中的文件
cd /tmp
cp -r alsa/* /usr/share
到此alsa移植完成,alsa_lib中的文件不移植也可以
测试:输入aplay ring.wav,可以听到铃声
2.编译代码。
·编写MP3播放程序Mp3player.c
·交叉编译:arm-linux-gcc -o Mp3player Mp3player.c -lmad -lasound
编译生成Mp3player便是可以在开发板上直接运行的文件,把文件夹和一首 歌放到U盘,板子插上U盘,监测U盘盘符并挂载。
把文件拷到板子上,运行,完美播放音乐。
cp /udisk/Mp3player /bin -rf
cp /udisk/pfzl.mp3 /bin
cd /bin/
运行:./Mp3player pfzl.mp3 50 (音量)

int main(int argc, char *argv[])
{struct stat stat; //定义相关文件状态信息结构体void *fdm;if (argc != 3){printf("Usage: minimad + mp3 file name + volume\n");return 1;}int fd;fd=open(argv[1],O_RDWR);if(fd<0){perror("open file failed:");return 1;} if (fstat(fd, &stat) == -1 ||stat.st_size == 0)  //获取文件状态{printf("fstat failed:\n");return 2;}fdm = mmap(0, stat.st_size, PROT_READ, MAP_SHARED, fd, 0);  //共享存储文件映射,可读if (fdm == MAP_FAILED)return 3;if(set_pcm()!=0) //设置pcm 参数{printf("set_pcm fialed:\n");return 1; }set_volume(atoi(argv[2]));     //设置混音器decode(fdm, stat.st_size);     //解码if (munmap(fdm, stat.st_size) == -1)return 4;snd_pcm_drain(handle);  //把所有挂起没有传输完的声音样本传输完全,最后关闭该音频流,释放之前动态分配的缓冲区,退出。snd_pcm_close(handle);  //关闭声卡return 0;
}
Alsa设置
int set_pcm()
{int rc; int dir=0;int rate = 44100;; /* 采样频率 44.1KHz*///int format = SND_PCM_FORMAT_S16_LE; /* 量化位数 16 */int channels = 2; /* 声道数 2 */rc=snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0); //打开默认的PCMif(rc<0){perror("\nopen PCM device failed:");exit(1);}snd_pcm_hw_params_alloca(&params); //分配params结构体rc=snd_pcm_hw_params_any(handle, params);//初始化paramsif(rc<0){perror("\nsnd_pcm_hw_params_any:");exit(1);}rc=snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED); //初始化访问权限if(rc<0){perror("\nsed_pcm_hw_set_access:");exit(1);}rc=snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE); //设置16位采样精度 if(rc<0){perror("snd_pcm_hw_params_set_format failed:");exit(1);} rc=snd_pcm_hw_params_set_channels(handle, params, channels); //设置声道,1表示单声>道,2表示立体声if(rc<0){perror("\nsnd_pcm_hw_params_set_channels:");exit(1);}rc=snd_pcm_hw_params_set_rate_near(handle, params, &rate, &dir); //设置>频率if(rc<0){perror("\nsnd_pcm_hw_params_set_rate_near:");exit(1);}   rc = snd_pcm_hw_params(handle, params); //安装从配置空间中选择的一个PCM硬件配置,然后snd_pcm_prepare。if(rc<0){perror("\nsnd_pcm_hw_params: ");exit(1);} return 0; 
}void set_volume(long volume)
{snd_mixer_t *mixerFd;snd_mixer_elem_t *elem;long minVolume = 0,maxVolume = 100;int result;// 打开混音器if ((result = snd_mixer_open( &mixerFd, 0)) < 0){printf("snd_mixer_open error!\n");mixerFd = NULL;}//将HCTL连接到打开的混音器if ((result = snd_mixer_attach( mixerFd, "default")) < 0){printf("snd_mixer_attach error!\n");snd_mixer_close(mixerFd);mixerFd = NULL;}// 注册混音器if ((result = snd_mixer_selem_register( mixerFd, NULL, NULL)) < 0){printf("snd_mixer_selem_register error!\n");snd_mixer_close(mixerFd);mixerFd = NULL;}// 加载混音器if ((result = snd_mixer_load( mixerFd)) < 0){printf("snd_mixer_load error!\n");snd_mixer_close(mixerFd);mixerFd = NULL;}// 遍历混音器元素for(elem=snd_mixer_first_elem(mixerFd); elem; elem=snd_mixer_elem_next(elem)){if (snd_mixer_elem_get_type(elem) == SND_MIXER_ELEM_SIMPLE &&snd_mixer_selem_is_active(elem)) // 找到可以用的, 激活的elem{snd_mixer_selem_get_playback_volume_range(elem, &minVolume, &maxVolume);snd_mixer_selem_set_playback_volume_all(elem, volume);}}
snd_mixer_close(mixerFd);Libmad设置
static enum mad_flow input(void *data, struct mad_stream *stream)
{struct buffer *buffer = data;if (!buffer->length)return MAD_FLOW_STOP;mad_stream_buffer(stream, buffer->start, buffer->length);buffer->length = 0;return MAD_FLOW_CONTINUE;
}
/*以下实用程序例程可对MAD的高分辨率采样进行简单的舍入,限幅和缩放,最低可达16位。*/
static inline
signed int scale(mad_fixed_t sample)
{/* round */sample += (1L << (MAD_F_FRACBITS - 16));/* clip */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);
}*这是输出回调函数。 在每帧MPEG音频数据被完全解码之后调用它。 此回调的目的是输出(或播放)已解码的PCM音频。
*/
static enum mad_flow output(void *data, struct mad_header const *header,struct mad_pcm *pcm)
{unsigned int nchannels, nsamples,n;mad_fixed_t const *left_ch, *right_ch;/*pcm-> samplerate包含采样频率*/nchannels = pcm->channels;n=nsamples = pcm->length;left_ch = pcm->samples[0];right_ch = pcm->samples[1];unsigned char Output[6912], *OutputPtr; int fmt, wrote, speed, exact_rate, err, dir; OutputPtr = Output; while (nsamples--) {signed int sample;/*以16位有符号的小端PCM *///输出样本sample = scale(*left_ch++);*(OutputPtr++) = sample >> 0; *(OutputPtr++) = sample >> 8; if (nchannels == 2) { sample = scale (*right_ch++); *(OutputPtr++) = sample >> 0; *(OutputPtr++) = sample >> 8; } }OutputPtr = Output; snd_pcm_writei (handle, OutputPtr, n); OutputPtr = Output; return MAD_FLOW_CONTINUE;
}//这是错误回调函数。
Static enum mad_flow error(void *data, struct mad_stream *stream, struct mad_frame *frame)
{struct buffer *buffer = data;printf("this is mad_flow error\n");fprintf(stderr, "decoding error 0x%04x (%s) at byte offset %u\n",stream->error, mad_stream_errorstr(stream),stream->this_frame - buffer->start);/ *在此返回MAD_FLOW_BREAK以停止解码(并传递错误)* /return MAD_FLOW_CONTINUE;
}//这是main()调用的函数,用于执行所有解码。
static
int decode(unsigned char const *start, unsigned long length)
{struct buffer buffer;struct mad_decoder decoder;int result;/*初始化我们的私有消息结构*/buffer.start = start;buffer.length = length;/*配置输入,输出和错误功能*/mad_decoder_init(&decoder, &buffer,input, 0 /* header */, 0 /* filter */, output,error, 0 /* message */);/* start decoding *//*开始解码 同步*/result = mad_decoder_run(&decoder, MAD_DECODER_MODE_SYNC);/* release the decoder 释放解码器*/ mad_decoder_finish(&decoder); return result;
}

源码及移植库文件下载地址:
https://download.csdn.net/download/ywueoei/10898346


http://www.ppmy.cn/news/245334.html

相关文章

MP3基本知识及构成

1、MP3是什么&#xff1f; MP3是一种有损数字音频压缩格式。全称是Mpeg-1 audio Layer 3&#xff0c;其中MPEG是Moving Picture Experts Group的缩写&#xff0c;意思是动态图象专家组。所谓“有损压缩音频格式”也就是对数字音频使用了对音质有损耗的压缩方式&#xff0c;以达…

【毕业设计】基于单片机的MP3设计与实现 - stm32

文章目录 1 简介2 主要器件3 实现效果4 设计原理核心算法&#xff1a;音频解码流程 5 部分实现代码6 最后 1 简介 Hi&#xff0c;大家好&#xff0c;这里是丹成学长&#xff0c;今天向大家介绍一个学长做的单片机项目 基于单片机的MP3设计与实现 大家可用于 课程设计 或 毕业…

小白必看:零基础入门网络安全

1、什么是网络安全&#xff1f; 官方的回答&#xff1a;指网络系统的硬件、软件及其系统中的数据受到保护&#xff0c;不因偶然的或者恶意的原因而遭受到破坏、更改、泄露&#xff0c;系统连续可靠正常地运行&#xff0c;网络服务不中断。 具有保密性、完整性、可用性、可控性…

【大唐杯学习超快速入门】5G智能网络优化

这里写目录标题 学习--实验背景上下行速率VOLTE掉话率优化时延优化 接入保持特性提升无线接通率切换成功率 附录 数据分析其他几种选项差不多 学习–实验背景 观看视频进行学习&#xff0c;理解该仿真的内涵 使用人工智能代替人工分析&#xff0c;对5G网络进行优化 上下行速率…

【Android开发基础】四大组件之一Service(服务)的应用场景及使用(以实时聊天为例)

文章目录 一、引言1、什么是服务&#xff1f;2、应用场景3、其他类同 二、生命周期三、基础使用1、创建服务2、注册服务3、启动服务 四、进阶使用&#xff08;实时聊天&#xff09;1、实现效果2、数据流图3、服务部分 一、引言 1、什么是服务&#xff1f; Service&#xff08;…

Elasticsearch 支持的字段类型及其查询方式

以下是 Elasticsearch 支持的字段类型及其查询方式的表格&#xff1a; 字段类型描述查询方式Text存储文本数据match、match_phrase、multi_match、common_terms、query_stringKeyword存储关键字数据term、terms、range、prefix、wildcard、regexp、fuzzy、existsNumeric存储数…

高薪软件测试工程师成长之路,你现在到哪个阶段?

目录 前言&#xff1a; 大厂喜欢什么样的人才 学历 技术 编程语言 总结&#xff1a; 岗位薪资大概标准 前言&#xff1a; 随着现代软件应用日益广泛&#xff0c;软件测试作为一项重要的技术手段和质量保证措施&#xff0c;越来越受到业界和用户的重视。作为软件开发领域中的…

vue实现预览PDF、Excel、Docx、Txt、PPT文件的功能

目录&#xff1a; 一、实现步骤 二、实现效果 代码真实可用&#xff01; 一、实现步骤&#xff1a; 1、使用的是vue和elementUI&#xff0c; 假设有这些变量&#xff1a;attachment是附件的意思 data() {return {previewDialog: false,attachmentSrc: ,attachmentList: [{…