




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、madplay 源码工作原理分析madplay 源码工作原理分析: 本人因项目工作需要,要在基于6410的开发板上移植madplay的代码,其中要修改相关代码以适应 项目需求,于是有了对madplay源码的分析,整理后发出以方便后来人移植改写madplay用 1. 目标:弄清madplay的主要流程机理,结合工作目标重点摸清有关Play,Pause,Resume,Next mp3,Prev mp3,Stop, shuffle, loop,Vol adjustment 的工作机理,为改写代码作准备 2.总体机理: 版本:madplay-0.15.2b,libmad-0.15.1b,libid3t
2、ag-0.15.1b 入口点:madplay.c: main() 下面主要集中在所关心的骨架流程方面,各个小细节除非与工作目标相关,否则一律略去 * main() 流程分析 * - player用于全局记录有关变量 - step 1: main():player_init(&player)初始化player参数 - step 2: main():get_options(argc, argv, &player)对argv各类参数进行解析,记录在player-options,或player-output或 其它相关变量中: 看几个与工作目标有关的: 1)输出声音通道及Mono还是Stereo选择:
3、 -1,-2,-m,-S:用于设置player-output.select为:PLAYER_CHANNEL_LEFT or PLAYER_CHANNEL_RIGHT or PLAYER_CHANNEL_MONO or PLAYER_CHANNEL_STEREO 2)loop -r:player-repeat保存重复播放的次数,如无重复播放,则设为-1 3)volume方面 player-output.attamp_db 减弱的分贝 player-output.voladj_db 设定的分贝 - step 3: main():player_run()执行播放,这里实现对mp3(单个或多个)进行播
4、放,是主要函数 - step 4: main():player_finish() 小结: madplay()主体流程简单: player_init()+get_options()=player_run()=player_finish() 也即初始化全局结构,及cmd命令选项解析=mp3播放=结束扫尾工作 * main() 分析Over * * player_run() 流程分析 - 核心 * 1.player_run()入口参数分析: player_run(&player, argc - optind, (char const *) &argvoptind) argc:为多少首播放歌,argv
5、为mp3路径 见下面的调试记录 - /test$ ls madplay shell test2.mp3 test3.wav test5.mp3 test7.mp3 test9.mp3 madplay_test test1.mp3 test3.mp3 test4.mp3 test6.mp3 test8.mp3 /test$ gdb -args ./madplay test1.mp3 test2.mp3 test3.mp3 GNU gdb 6.8-debian Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU
6、 GPL version 3 or later This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. Type show copying and show warranty for details. This GDB was configured as i486-linux-gnu. (gdb) b player_run Breakpoint 1 at 0x804f845: file player.c, li
7、ne 2700. (gdb) r Starting program: /home/yuxu/test/madplay test1.mp3 test2.mp3 test3.mp3 Thread debugging using libthread_db enabled MPEG Audio Decoder 0.15.2 (beta) - Copyright (C) 2000-2004 Robert Leslie et al. New Thread 0xb7c446b0 (LWP 6724) Switching to Thread 0xb7c446b0 (LWP 6724) Breakpoint 1
8、, player_run (player=0xbf95631c, argc=3, argv=0xbf9565d8) at player.c:2700 warning: Source file is more recent than executable. 2700 (gdb) p argv0 $1 = 0xbf95760e test1.mp3 (gdb) p argv1 $2 = 0xbf test2.mp3 (gdb) p argv2 $3 = 0xbf test3.mp3 (gdb) - 2.player_run():player-playlist.entries,player-playl
9、ist.length的意义: 有了上面的分析,这两个-playlist.entries,-playlist.length就清楚了,不多说 player-playlist.entries = argv; player-playlist.length = argc; 3.player_run()=setup_tty()=tty_fd = open(TTY_DEVICE, O_RDONLY); TTY_DEVICE:/dev/tty 这里打开终端,用于后面在播放过程中,对键盘进行读取工作,以判定用户发出什么指令如:Stop,Pause,Resume,Vol Adjustment ,Next Mp3,
10、Prev Mp3 再就是一些其它操作:如设置相应的TYTY属性及信号处理函数,略去不表 - 具体调试分析见下: /test$ gdb -args ./madplay test1.mp3 test2.mp3 test3.mp3 GNU gdb 6.8-debian Copyright (C) 2008 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later This is free software: you are free to change and redistribute it. There is
11、 NO WARRANTY, to the extent permitted by law. Type show copying and show warranty for details. This GDB was configured as i486-linux-gnu. (gdb) b player_run Breakpoint 1 at 0x804f845: file player.c, line 2700. (gdb) r Starting program: /home/yuxu/test/madplay test1.mp3 test2.mp3 test3.mp3 Thread deb
12、ugging using libthread_db enabled MPEG Audio Decoder 0.15.2 (beta) - Copyright (C) 2000-2004 Robert Leslie et al. New Thread 0xb7bf66b0 (LWP 6832) Switching to Thread 0xb7bf66b0 (LWP 6832) Breakpoint 1, player_run (player=0xbfe087dc, argc=3, argv=0xbfe08a98) at player.c:2700 warning: Source file is
13、more recent than executable. 2700 (gdb) s 2704 player-playlist.entries = argv; (gdb) 2705 player-playlist.length = argc; (gdb) s 2710 if (player-options & PLAYER_OPTION_TTYCONTROL) & (gdb) p /x player-options $1 = 0x40 (gdb) p /x PLAYER_OPTION_TTYCONTROL $2 = 0x40 (gdb) s 54 return _open_alias (_pat
14、h, _oflag, _va_arg_pack (); (gdb) 2538 tty_fd = open(TTY_DEVICE, O_RDONLY); (gdb) bt #0 player_run (player=0xbfe087dc, argc=3, argv=0xbfe08a98) at player.c:2538 #1 0x0804b9fd in main (argc=3, argv=0xbfe08a94) at madplay.c:816 (gdb) s 2539 if (tty_fd = -1) (gdb) bt #0 player_run (player=0xbfe087dc, a
15、rgc=3, argv=0xbfe08a98) at player.c:2539 #1 0x0804b9fd in main (argc=3, argv=0xbfe08a94) at madplay.c:816 (gdb) s 2546 if (tcgetattr(tty_fd, &save_tty) = -1) (gdb) - 强调一点:这里主要意义就在于后面的播放过程中,要读取用户的键盘输入,就是用read(tty_fd, &key, 1)来处理的 4.player_run():setup_filters()=addfilter(player, tty_filter, player) 将会
16、执行代码段: # if defined(USE_TTY) if (player-options & PLAYER_OPTION_TTYCONTROL) & addfilter(player, tty_filter, player) = -1) return -1; # endif 而在addfilter()中=filter_new()中malloc()一个新filter=filter_init()初始化:filter-func = tty_filter() player-output.filters将指向这个新分配的filter,而且这个新分配的filter-func为tty_filter()
17、: 特别说明: tty_filter()=readkey()=swtich.case处理各类键盘输入的命令: void filter_init(struct filter *filter,filter_func_t *func, void *data, struct filter *chain) filter-func = func; . int addfilter(struct player *player, filter_func_t *func, void *data) struct filter *filter; filter = filter_new(func, data, play
18、er-output.filters); . player-output.filters = filter; return 0; = 有关tty_filter函数调用链的说明: 1):流程: tty_filter()=command=readkey(blocking:阻塞否)=switch(command).case处理各种命令:如:KEY_STOP,KEY_PAUSE KEY_FORWARD,KEY_BACK,KEY_QUIT,KEY_GAINDECR,KEY_GAININCR,KEY_GAINZERO, 如下为清理过的流程示意图: 提醒一点:KEY_PAUSE:readkey(1)即,当Pa
19、use时,读键操作是阻塞的,即进入readkey()执行以下代码: do count = read(tty_fd, &key, 1); while (count = -1 & errno = EINTR); 当无键按下时,read()阻塞睡眠,用top查看果然没有占用cpu了 而总的流程是这样的: 先tty_filter()查看有无key按下,此时是readkey(0)不阻塞形式,无键按下即返回之,有键按下则执行命令,见下面的 代码框架,再去每次取40, 000Bmp3数据进行mp3解码,然后送往alsa驱动去pcm播放,再又回到tty_filter查看有无键按下 就是这样的一个播放循环,后面
20、还会讲到 2)代码框架: enum mad_flow tty_filter(void *data, struct mad_frame *frame) command = readkey(0); if (command = -1) return MAD_FLOW_BREAK; again: switch (command) case KEY_STOP: . case KEY_PAUSE: stop_audio(player, stopped); command = readkey(1); . break; case KEY_FORWARD: case KEY_CTRL(n): case : pl
21、ayer-control = PLAYER_CONTROL_NEXT; goto stop; case KEY_QUIT: case KEY_CTRL(c): case Q: player-control = PLAYER_CONTROL_STOP; goto stop; case KEY_GAINDECR: case KEY_GAININCR: case KEY_GAINZERO: case KEY_GAININFO: switch (command) case KEY_GAINDECR: db = set_gain(player, GAIN_ATTAMP | GAIN_RELATIVE,
22、-0.5); break; case KEY_GAININCR: db = set_gain(player, GAIN_ATTAMP | GAIN_RELATIVE, +0.5); break; case KEY_GAINZERO: db = set_gain(player, GAIN_ATTAMP, 0); break; default: db = set_gain(player, 0, 0); break; . stop: stop_audio(player, 1); = 5.音量Gain设定: set_gain(player, 0, 0);= db = player-output.vol
23、adj_db + player-output.attamp_db; player-output.gain = db ? mad_f_tofixed(pow(10, db / 20) : MAD_F_ONE; player-output.gain保存了最终的音量db设定值 那么音量Gain是如何执行的呢? 1.gain_filter的初始化设定: player_run()=setup_filters()= addfilter(player, gain_filter, &player-output.gain); =player-output.filters指向的filter list中挂上了gai
24、n_filter,同时,还有前面所说的tty_filter gain_filter用于调节音量,而tty_filter用于读取键盘输入确定用户的命令输入 补充参数初始值来源: main()=get_options()=依据选项-a 或 -A对参数进行player-output.attamp_db,player-output.voladj_db设定初 始值 case a: player-output.attamp_db = get_decibels(optarg); preamp = 1; break; case A: player-output.voladj_db = get_decibels
25、(optarg); 2.音量调节的方法: play_all()=play_one()=decode()=mad_decoder_run()=run_sync()=decoder-filter_func()= decoder-filter_func(decoder-cb_data, stream, frame)=gain_filter() = # define mad_f_mul(x, y) (x) * (y) frame-sbsamplechssb = mad_f_mul(frame-sbsamplechssb, gain); = mad_synth_frame()=synth_full()=
26、dct32() 也就是:调用gain_filter进行对mp3声音原始数据进行gain处理,也就是直接将gain融入mp3数据中,然后再离散余弦变换 解码mp3文件的编码,这样声音音量级别就提高了,也就是音量调节是纯软件的,直接对数据进行的处理变换 = 6.播放mp3的工作机理: 1)主架构流程: player_run()=setup_tty()=open TTY_DEVICE =setup_filters()=gain_filter,tty_filter加入filter list =audio_control_init(&control, AUDIO_COMMAND_INIT)+player
27、-mand(&control)=audio_alsa()= init()=snd_pcm_open() =play_all() = 核心函数 =audio_control_init(&control, AUDIO_COMMAND_FINISH)+mand(&control)=stop()= snd_pcm_drop(),snd_pcm_prepare() play_all()核心函数: =处理随机播放:见下代码,不多说,easy if (player-options & PLAYER_OPTION_SHUFFLE) srand(time(0
28、); for (i = 0; i entriesi; playlist-entriesi = playlist-entriesj; playlist-entriesj = tmp; =重要参数说明: count = playlist-length;播放mp3文件数量 playlist-current:当前所播放的mp3的位置 playlist-entriesplaylist-current:当前播放的mp3文件 =开始播放一首mp3:若播放失败,则该项清零,记数变量- if (play_one(player) = -1) playlist-entriesi = 0; -count; . =若该
29、首歌播放成功,则依据player-control进行如下处理: 这里主要关注取下一首歌,上一首歌及重复随机播放及Stop 具体细节见下面的代码框架,不难,不详说 while (playlist-current length) . switch (player-control) case PLAYER_CONTROL_DEFAULT: if (player-options & PLAYER_OPTION_SHUFFLE) & player-repeat & +i length) 处理随机重复播放的情况 case PLAYER_CONTROL_NEXT: +playlist-current; br
30、eak; case PLAYER_CONTROL_PREVIOUS: do if (playlist-current- = 0) playlist-current = playlist-length; while (playlist-current length & playlist-entriesplaylist-current = 0); break; case PLAYER_CONTROL_STOP: playlist-current = playlist-length; count = 0; break; 可见,对取上一首歌的处理流程总结如下: 1.主播放循环过程中不断的tty_fil
31、ter()+gain_filter, mp3解码, alsa PCM放声 2.tty_filter()=readkey()=switch(command)case KEY_FORWARD: .=player-control = PLAYER_CONTROL_NEXT =goto stop;=stop_audio()+return MAD_FLOW_STOP;= run_sync()播放mp3主循环检测到tty_filter()返回值为MAD_FLOW_STOP,立即终止mp3播放主循环 if (decoder-filter_func) switch (decoder-filter_func(d
32、ecoder-cb_data, stream, frame) case MAD_FLOW_STOP: goto done; . =mad_decoder_run()结束返回至decode() =decode()结束返回至play_one() =play_one()结束,返回至play_all()的播放循环中即上面的代码框架所说的对switch (player-control)的处理 3.小结:对取上一首歌,下一首歌的处理,均由tty_filter()检测到后,设定player-control为相应的值,返回MAD_FLOW_STOP 提前结束play_one()单首歌的播放过程,返回至play
33、_all()经switch. case.处理,对playlist-current进行相应处理后 取上|下一首歌继续play_one 4.对stop命令的处理,类取上一首,下一首歌的处理完全一样,自己看了 5.对Pause命令的处理,上面在tty_filter中已经说明了是阻塞式read()一直等待有键按下才继续前进,而且在阻塞过程中 没有占用cpu,top可查看之,比mplayer,每20ms查一次键盘输入要好 linux-2.6.13下madplay在S3C2440上移植的全过程详解一. 声卡(uda1341 philis) 驱动的移植: 在移植之前,自己看了不了这方面的文章,但是觉得大同小
34、异,有一些大侠还用了一些我看不懂的文件(.ko,我似乎没有见过这样的文件,知道的请相告一声_),后来就开始动手移植了。 1. 首先自己在网上下了一个uda1341的驱动文件s3c2410-uda1341.c(好像是从csdn中下的),稍作了修改(下面会提到怎么修改)后,把它放到linux2.6.14/sound/oss/目录下。 2. 修改oss目录下的kconfig文件,以便在我们下面配置内核的时候可以选中它,主要是在前面添加下面的几行: config S3C2410_SND_UDA1341 tristate S3C2410 UDA1341 driver (S3C2410) depends
35、on SOUND_PRIME!=n & SOUND & ARM & ARCH_SMDK2410 修改Makefile文件,在它的适当位置添加下面的一行,这样配置后,如果我们选中了它编译的时候我们就可以在该目录下生成一 个 s3c2410-uda1341.o文件。 Obj-$(CONFIG_S3C2410_SND_UDA1341) += s3c2410-uda1341.o 3. 修改增加内存映射,以使内核知道该虚拟地址可用,而且对应的物理地址是我们的声卡。修改/arch/arm/mach-s3c2410/smdk-s3c2410.如下: static struct map_desc smdk24
36、10_iodesc _initdata = /* nothing here yet */ 0xe, 0x, SZ_1M, MT_DEVICE, / 网卡内存映射 0xf0d00000, 0x, SZ_1M, MT_DEVICE, / 声卡内存映射 ; 上面一行是 我的网卡的地址映射,后面一行是声卡的地址映射。s3c2410 的 虚拟地址 0xf0d00000,物理地址 0x(这个可以在asm/arch/map.h文件中找到)。 4, 配置完毕后,在make menuconfig后,选择driver-sound-oss-uda1341 ,选择对声卡的支持。编译内核,把内核Image下载到板子上,
37、为了测试我们是否已经是成功地移植了声卡,可以进行如下的测试: A. 查看在/dev/sound/下是否有dsp以及mixer两个设备; B. 如果有,再执行如下的命令:cat 1.wav /dev/sound/dsp;就是将PCM数据放到dsp上,如果成功地进行了移植,那么耳机就会听到一些声音,当然还不是音乐。这里只能是用.wav文件来测试,因为它是PCM编码的,不能用mp3文件,否则会听不到发声。以下是内核在启动时在终端打印出来的消息: s3c2410iis_probe.success to get memory region resoucesuccess to ioremap() regi
38、oniis_clock = clk_get(dev, iis); donesuccess to find clock sourcelocal_irq_savelocal_irq_restore init_s3c2410_iis_bus. _raw_writel(0, iis_base + S3C2410_IISPSR);.done_raw_writel(0, iis_base + S3C2410_IISCON);.done_raw_writel(0, iis_base + S3C2410_IISMOD);.done_raw_writel(0, iis_base + S3C2410_IISFCO
39、N);.doneclk_disable(iis_clock) doneinit_s3c2410_iis_bus done init_uda1341. init_uda1341 done success to get DMA channels 1 success to get DMA channels 2 UDA1341 audio driver initialized 5. 在编译的时候,发现我下的文件中有一个错误,发生在init_s3c2410_iis_bus_tx()中,说什么 S3C2410_IISMOD_MASTER,自己看了一下asm/arch/reg-iis.h中将无有关主模式的定
40、义,只有从模式的定义,我想既然函数中已经是先将iismod初始化为0,就已经是主模式了,干脆将它注释掉了。 声卡驱动已经基本完成。接下来就是将madplay播放器移到ARM上。二. 播放器的移植 现在有很多的播放器可以移植到arm9上,你mplayer,madplay等。但发现移植mplayer时遇到了一个很致命的文件错误,怎么也解决不了,mplayer在2410上的移植.pdf中也没有相关的方法,我只好暂时耽下,换了另外一个播放器madplay. 1. 移植madplay前的准备。 madplay的移植需要以下的几个包:madplay-0.15.2b.tar.gz,libmad-0.15.1
41、b.tar.gz,libid3tag-0.15.1b.tar.gz 和 zlib-1.1.4.tar.gz。其中前面的三个包可以在/project/showfiles.php?group_id=12349下载,后一个包可以在/zlib/zlib-1.1.4.tar.gz中找到。 为了编译这个播放器,还需要一个交叉编译器,我用的是arm-linux-gcc 3.4.1版本,网上很多文章都说用arm-linux-gcc 2.95.3这个交叉编译器,但是我在用它配置(./configure)libid3tag的时候,它最后
42、老是说configure文件的某一行有错, check config.log for detail。没办法,只好用3.4.1版本的编译器。 2. 开始编译 2.1. 用交叉编译工具编译zlib,并且把库生成到交叉编译环境的库目录下,我把它放到了/usr/local9/arm/3.4.1/arm-linux目录下。./configure -prefix=/usr/local9/arm/3.4.1/arm-linux。 再修改(不能跟上面的步骤调转)makefile文件: CC=/usr/local9/arm/3.4.1/bin/arm-linux-gcc AR=/usr/local9/arm/3
43、.4.1/bin/arm-linux-ar rcs RANLIB=/usr/local9/arm/3.4.1/bin/arm-linux-ranlib make ,make install ,编译好之后就可以在上面prefix指定的目录下的lib目录下找到libz.a这个库。 2.2. 编译libid3tag ./configure CC=/usr/local9/arm/3.4.1/bin/arm-linux-gcc -prefix=/usr/local9/arm/3.4.1/arm-linux -host=arm-linux -disable-debugging -disable-share
44、d -enable-static CPPFLAGS=-I/usr/local9/arm/3.4.1/arm-linux/include LDFLAGS=-L/usr/local9/arm/3.4.1/arm-linux/lib 其中,-disable-shared -enable-static是指定为静态编译。不过我发现这样并不能够进行编译。至于如何进行表态编译,我将在下面中进行介绍。 make, make install 2.3. 编译libmad ./configure CC=/usr/local9/arm/3.4.1/bin/arm-linux-gcc -prefix=/usr/local9/arm/3.4.1/arm-linux -host=arm-linux -disable-debugging -disable-shared -enable-static CPPFLAGS=-I/usr/local9/arm/3.4.1/arm-linux/include LDFLAGS=-L/usr
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 隧道监控量测必测项目表
- 灯具安装方案
- 河北省承德市隆化县2023-2024学年四年级下学期数学期末数学试卷(含答案)
- IT创新创业教育基础 课件 第1-3讲-IT创新创业的基本概念-IT创新创业成功要素
- 新疆生产建设兵团第三师图木舒克市第一中学2022-2023学年高二下学期期末考试化学试题(含答案)
- 汽车传感器与检测技术电子教案:现代检测系统的构成
- 黑龙江省哈尔滨市2022-2023学年高二下学期期末考试化学试题(含答案)
- 从化团建活动策划方案
- 付费学员活动方案
- 代扣代缴业务活动方案
- 2025年全钒液流电池行业调研分析报告
- 2025年二级建造师考试《矿业工程管理与实物》真题及答案
- 2025年Python数据分析试题及答案
- 植物保护通论重点复习题
- 儿童抽动障碍共患焦虑抑郁障碍诊治2025
- 2024年山东省初中学业水平考试语文试题(文字版-含答案)
- 2024-2025教科版一年级下册科学期末考试卷附参考答案 (三套)
- 高血压药的类型
- 家规家训课件
- 《深圳音乐厅解析》课件
- 2025届河南省鹤壁市淇县第一中学高三下学期联合考试英语试题含解析
评论
0/150
提交评论