madplay 源码工作原理分析.docx
- 文档编号:6916676
- 上传时间:2023-05-10
- 格式:DOCX
- 页数:17
- 大小:27.28KB
madplay 源码工作原理分析.docx
《madplay 源码工作原理分析.docx》由会员分享,可在线阅读,更多相关《madplay 源码工作原理分析.docx(17页珍藏版)》请在冰点文库上搜索。
madplay源码工作原理分析
madplay源码工作原理分析
madplay源码工作原理分析:
本人因项目工作需要,要在基于6410的开发板上移植madplay的代码,其中要修改相关代码以适应
项目需求,于是有了对madplay源码的分析,整理后发出以方便后来人移植改写madplay用
1.
目标:
弄清madplay的主要流程机理,结合工作目标重点摸清有关Play,Pause,Resume,Nextmp3,Prevmp3,Stop,
shuffle,loop,Voladjustment
的工作机理,为改写代码作准备
2.总体机理:
版本:
madplay-0.15.2b,libmad-0.15.1b,libid3tag-0.15.1b
入口点:
madplay.c:
main()
下面主要集中在所关心的骨架流程方面,各个小细节除非与工作目标相关,否则一律略去
********************************************
main()流程分析
********************************************
----------------------------
player{}用于全局记录有关变量
----------------------------
step1:
main():
player_init(&player)初始化player{}参数
----------------------------
step2:
main():
get_options(argc,argv,&player)对argv[]各类参数进行解析,记录在player->options,或player->output或
其它相关变量中:
看几个与工作目标有关的:
1)输出声音通道及Mono还是Stereo选择:
-1,-2,-m,-S:
用于设置player->output.select为:
PLAYER_CHANNEL_LEFTorPLAYER_CHANNEL_RIGHTorPLAYER_CHANNEL_MONO
orPLAYER_CHANNEL_STEREO
2)loop
-r:
player->repeat保存重复播放的次数,如无重复播放,则设为-1
3)volume方面
player->output.attamp_db减弱的分贝
player->output.voladj_db设定的分贝
----------------------------
step3:
main():
player_run()执行播放,这里实现对mp3(单个或多个)进行播放,是主要函数
----------------------------
step4:
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,(charconst**)&argv[optind])
argc:
为多少首播放歌,argv[]为mp3路径
见下面的调试记录
-------------------------------
~/test$ls
madplayshelltest2.mp3test3.wavtest5.mp3test7.mp3test9.mp3
madplay_testtest1.mp3test3.mp3test4.mp3test6.mp3test8.mp3
~/test$gdb--args./madplaytest1.mp3test2.mp3test3.mp3
GNUgdb6.8-debian
Copyright(C)2008FreeSoftwareFoundation,Inc.
LicenseGPLv3+:
GNUGPLversion3orlater //gnu.org/licenses/gpl.html> Thisisfreesoftware: youarefreetochangeandredistributeit. ThereisNOWARRANTY,totheextentpermittedbylaw.Type"showcopying" and"showwarranty"fordetails. ThisGDBwasconfiguredas"i486-linux-gnu"... (gdb)bplayer_run Breakpoint1at0x804f845: fileplayer.c,line2700. (gdb)r Startingprogram: /home/yuxu/test/madplaytest1.mp3test2.mp3test3.mp3 [Threaddebuggingusinglibthread_dbenabled] MPEGAudioDecoder0.15.2(beta)-Copyright(C)2000-2004RobertLeslieetal. [NewThread0xb7c446b0(LWP6724)] [SwitchingtoThread0xb7c446b0(LWP6724)] Breakpoint1,player_run(player=0xbf95631c,argc=3,argv=0xbf9565d8)atplayer.c: 2700 warning: Sourcefileismorerecentthanexecutable. 2700{ (gdb)pargv[0] $1=0xbf95760e"test1.mp3" (gdb)pargv[1] $2=0xbf957618"test2.mp3" (gdb)pargv[2] $3=0xbf957622"test3.mp3" (gdb) ------------------------------- 2.player_run(): player->playlist.entries,player->playlist.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,VolAdjustment NextMp3,PrevMp3 再就是一些其它操作: 如设置相应的TYTY属性及信号处理函数,略去不表 ------------------------------- 具体调试分析见下: ~/test$gdb--args./madplaytest1.mp3test2.mp3test3.mp3 GNUgdb6.8-debian Copyright(C)2008FreeSoftwareFoundation,Inc. LicenseGPLv3+: GNUGPLversion3orlater //gnu.org/licenses/gpl.html> Thisisfreesoftware: youarefreetochangeandredistributeit. ThereisNOWARRANTY,totheextentpermittedbylaw.Type"showcopying" and"showwarranty"fordetails. ThisGDBwasconfiguredas"i486-linux-gnu"... (gdb)bplayer_run Breakpoint1at0x804f845: fileplayer.c,line2700. (gdb)r Startingprogram: /home/yuxu/test/madplaytest1.mp3test2.mp3test3.mp3 [Threaddebuggingusinglibthread_dbenabled] MPEGAudioDecoder0.15.2(beta)-Copyright(C)2000-2004RobertLeslieetal. [NewThread0xb7bf66b0(LWP6832)] [SwitchingtoThread0xb7bf66b0(LWP6832)] Breakpoint1,player_run(player=0xbfe087dc,argc=3,argv=0xbfe08a98)atplayer.c: 2700 warning: Sourcefileismorerecentthanexecutable. 2700{ (gdb)s 2704player->playlist.entries=argv; (gdb) 2705player->playlist.length=argc; (gdb)s 2710if((player->options&PLAYER_OPTION_TTYCONTROL)&& (gdb)p/xplayer->options $1=0x40 (gdb)p/xPLAYER_OPTION_TTYCONTROL $2=0x40 (gdb)s 54return__open_alias(__path,__oflag,__va_arg_pack()); (gdb) 2538tty_fd=open(TTY_DEVICE,O_RDONLY); (gdb)bt #0player_run(player=0xbfe087dc,argc=3,argv=0xbfe08a98)atplayer.c: 2538 #10x0804b9fdinmain(argc=3,argv=0xbfe08a94)atmadplay.c: 816 (gdb)s 2539if(tty_fd==-1){ (gdb)bt #0player_run(player=0xbfe087dc,argc=3,argv=0xbfe08a98)atplayer.c: 2539 #10x0804b9fdinmain(argc=3,argv=0xbfe08a94)atmadplay.c: 816 (gdb)s 2546if(tcgetattr(tty_fd,&save_tty)==-1){ (gdb) ------------------------------- 强调一点: 这里主要意义就在于后面的播放过程中,要读取用户的键盘输入,就是用read(tty_fd,&key,1)来处理的 4.player_run(): setup_filters()==>addfilter(player,tty_filter,player) 将会执行代码段: #ifdefined(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(): 特别说明: tty_filter()==>readkey()==>swtich...case处理各类键盘输入的命令: voidfilter_init(structfilter*filter,filter_func_t*func,void*data,structfilter*chain) { filter->func=func; ... } intaddfilter(structplayer*player,filter_func_t*func,void*data) { structfilter*filter; filter=filter_new(func,data,player->output.filters); ... player->output.filters=filter; return0; } ========================================== 有关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)即,当Pause时,读键操作是阻塞的,即进入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查看有无键按下 就是这样的一个播放循环,后面还会讲到 2)代码框架: enummad_flowtty_filter(void*data,structmad_frame*frame) { command=rea dkey(0); if(command==-1) returnMAD_FLOW_BREAK; again: switch(command){ caseKEY_STOP: ... caseKEY_PAUSE: stop_audio(player,stopped); command=readkey (1); ... break; caseKEY_FORWARD: caseKEY_CTRL('n'): case'>': player->control=PLAYER_CONTROL_NEXT; gotostop; caseKEY_QUIT: caseKEY_CTRL('c'): case'Q': player->control=PLAYER_CONTROL_STOP; gotostop; caseKEY_GAINDECR: caseKEY_GAININCR: caseKEY_GAINZERO: caseKEY_GAININFO: { switch(command){ caseKEY_GAINDECR: db=set_gain(player,GAIN_ATTAMP|GAIN_RELATIVE,-0.5); break; caseKEY_GAININCR: db=set_gain(player,GAIN_ATTAMP|GAIN_RELATIVE,+0.5); break; caseKEY_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.voladj_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指向的filterlist中挂上了gain_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(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() ==> #definemad_f_mul(x,y)((x)*(y)) frame->sbsample[ch][s][sb]=mad_f_mul(frame->sbsample[ch][s][sb],gain); ==> mad_synth_frame()==>synth_full()==>dct32() 也就是: 调用gain_filter进行对mp3声音原始数据进行gain处理,也就是直接将gain融入mp3数据中,然后再离散余弦变换 解码mp3文件的编码,这样声音音量级别就提高了,也就是音量调节是纯软件的,直接对数据进行的处理变换 ============================================ 6.播放mp3的工作机理: 1)主架构流程: player_run()==>setup_tty()==>openTTY_DEVICE ==>setup_filters()==>gain_filter,tty_filter加入filterlist ==>audio_control_init(&control,AUDIO_COMMAND_INIT)+player->mand(&control)==>audio_alsa()=> init()==>snd_pcm_open() ==>play_all()===核心函数 ==>audio_control_init(&control,AUDIO_COMMAND_FINISH)+player->mand(&control)==>stop()==> snd_pcm_drop(),snd_pcm_prepare() play_all()核心函数: ==>处理随机播放: 见下代码,不多说,easy if(player->options&PLAYER_OPTION_SHUFFLE){ srand(time(0)); for(i=0;i j=rand()%count; tmp=playlist->entries[i]; playlist->entries[i]=playlist->entries[j]; playlist->entries[j]=tmp; } } ==>重要参数说明: count=playlist->length;播放mp3文件数量 playlist->current: 当前所播放的mp3的位置 playlist->entries[playlist->current]: 当前播放的mp3文件 ==>开始播放一首mp3: 若播放失败,则该
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- madplay 源码工作原理分析 源码 工作 原理 分析