madplay 源码工作原理分析.docx

上传人:b****4 文档编号:6916676 上传时间:2023-05-10 格式:DOCX 页数:17 大小:27.28KB
下载 相关 举报
madplay 源码工作原理分析.docx_第1页
第1页 / 共17页
madplay 源码工作原理分析.docx_第2页
第2页 / 共17页
madplay 源码工作原理分析.docx_第3页
第3页 / 共17页
madplay 源码工作原理分析.docx_第4页
第4页 / 共17页
madplay 源码工作原理分析.docx_第5页
第5页 / 共17页
madplay 源码工作原理分析.docx_第6页
第6页 / 共17页
madplay 源码工作原理分析.docx_第7页
第7页 / 共17页
madplay 源码工作原理分析.docx_第8页
第8页 / 共17页
madplay 源码工作原理分析.docx_第9页
第9页 / 共17页
madplay 源码工作原理分析.docx_第10页
第10页 / 共17页
madplay 源码工作原理分析.docx_第11页
第11页 / 共17页
madplay 源码工作原理分析.docx_第12页
第12页 / 共17页
madplay 源码工作原理分析.docx_第13页
第13页 / 共17页
madplay 源码工作原理分析.docx_第14页
第14页 / 共17页
madplay 源码工作原理分析.docx_第15页
第15页 / 共17页
madplay 源码工作原理分析.docx_第16页
第16页 / 共17页
madplay 源码工作原理分析.docx_第17页
第17页 / 共17页
亲,该文档总共17页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

madplay 源码工作原理分析.docx

《madplay 源码工作原理分析.docx》由会员分享,可在线阅读,更多相关《madplay 源码工作原理分析.docx(17页珍藏版)》请在冰点文库上搜索。

madplay 源码工作原理分析.docx

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:

若播放失败,则该

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > IT计算机 > 电脑基础知识

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2