madplay源代码导读

来源:互联网 发布:ps4网络nat3转nat2 编辑:程序博客网 时间:2024/06/01 10:30

1.      madplay基于libmad的基础上做了一个播放器,该播放器除了目前不支持网络播放以为,其余功能都支持。如快进播放,seek播放,暂停,恢复等

int main(int argc, char *argv[]) //后续如果做二次开发的话,可以将main函数改造成普通函数,普通函数形成传入agrv[].

{

 player_init(&player);

   初始化player成员变量。

   player.options |= PLAYER_OPTION_TTYCONTROL;  默认支持键盘按键操作

get_options(argc,argv, &player);//该函数只解析-或者—开头的选择,其他不能解析

将main函数的传入的参数,解析后并赋值给player结构体中的各个成员。

f(player.verbosity >= 0)

    ver_banner(stderr);

输入标题,信息(即文件头信息)默认player.verbosity ,所以输出Verbosity信息

设置播放绝对时间

设置默认输出模块(默认为osss驱动输出,如修改改成其他默认,改makefile或者configure传入或改代码

player_run();进入播放循环中  选项中,除-或—开头的选项坐标播放文件。

player_finish()播放完毕或出错,player_run()退出,完成播放回收

}

 

player_run(struct player *player, int argc,char const *argv[])

入口参数:player对象这个结构体

节目个数 argc

节目链表的第一个地址:即argv

{

  初始化tty     setup_tty()

  初始化附加数据路径  (没明白这个辅数据是什么)

setup_filters(player)  (这个filter是一个链表,建立各自filter指针链表,在解码时,每解一帧后输出到驱动前都要进行filter动作,完成播放控制,如音量调节,暂停,恢复,继续播放等等)

set_gain(player, 0, 0);  //设置增益参数,相当于调节音量

初始化音频 

播放所有的节目play_all(player); 里面是一个大循环,循环播放所有的节目或异常退出

反初始化音频

 

}

 

play_all(struct player *player)

{

   初始化节目单

   如果是随机模式,则初始化随机节目单

  play_one(player)  小循环,必需播完一个节目再退出来

  一个节目播放完,或者被滤波打断,小循环跳出播放下一首后上一首歌 等动作。

 

}

 

如何实现播放控制:

1.      run_sync 解码循环中,每解码一帧后输出前,都要进行filter动作(即decode_filter 函数的执行)。来完成是播放标志控制进而跳出循环或继续输出。

2.      filter动作是一个链表,里面可能是设置音量等参数,输出其他信息,这中filter不会打断循环,循环继续讲数据送入驱动;而播放下一首,上一首,进入Mad_FLOW_Stop状态却会从循环中跳出来,并返回result=-1,返回到playall()函数进行下一首的开始播放;如果是暂停的话,就一直在改循环中continue,不会往下送数据,知道resume后才送数据,进行正常解码。

3.      decode_filter 每解码一帧,完成filter动作。

4.      filter_run()中完成每个filter函数动作,如:mono_filter,gain_filter,mixer_filter,fadein_filter,tty_filter等动作

5.      setup_filters 就是建立一个链表,链表数据域为滤波函数指针。

6.      addfilter 就是创意一个链表节点,比插入到头节点后面

7.      filter_new 就是完成一一个链表节点的创建和插入动作。

8.      decode_output 输出配置filter动作完成一些非中断式的特技动作(如调节音量,停止,左右声道选择,停止还是播放,实际的硬件的控制)。

 

如何显示播放时间:

1.在每帧输出到底层驱动是显示或者键盘按I字母时显示

show_status(&player->stats, header,0, 0);

先将实际独到time_str

mad_timer_string(timer, time_str, "%02lu:%02u:%02u",

                   MAD_UNITS_HOURS, 0, 0);

再完成打印

message("%s %s", time_str, label? label : stats->label);

状态标签也是在main函数出入的。详见使用方法

 

 

 

 

如何关联某种驱动的输出。

 在main函数中默认为player.output.command = audio_output(0);除非通过main函数出入-o

layer->output.path = optarg;进行转码成wav等格式,否则默认送人底层驱动播放。

送入顶层驱动有有很多中,如OSS,alsa,win32等,

Config.h文件中设置默认为oss

#define AUDIO_DEFAULT audio_oss

可以根据实际情况就行更改。

如果我设备没有oss驱动,而是alsa驱动,就将宏定义改为

#define AUDIO_DEFAULT audio_alsa即可

player.output.command = audio_output(0) 返回输出模型

struct output *output =&player->output;

 if(output->command(&control) == -1)

就是调用相应的音频驱动操作函数。

如oss驱动映射到

audio_oss(union audio_control *control)

如alsa驱动就映射到

int audio_alsa(union audio_control*control)

 

 

 

 

 

如何实现seek效果.

Stream->skip这个值通过某个线程传入,或者在filter函数中传入,每解码一帧,有一个帧头检测过程,在帧头检测过程中有一个skip动作,可以帮助我们跳过某些帧,实现seek的效果。

 

Pause和resume实现原理:

接受的pasue按键,读按键是就阻塞,造成底层播放流程无法开展,下一帧解码也无法开展,整个流程就冻结了。按任意非定义的键取消阻塞即可(因为已经定义键,将会走定义流程)。

enum mad_flow flow = MAD_FLOW_CONTINUE; 确保继续该解码循环,恢复播放

Stop和resume实现原理

Stop后,也是进程阻塞,但按任意非定义键重新播放

player->control = PLAYER_CONTROL_REPLAY;

flow = MAD_FLOW_STOP;

确保跳出解码这个循环,并重启播放

1 0
原创粉丝点击