linux下mplayer播放器应用程序总结

时间:2021-09-02 10:13:34

原文地址:http://blog.csdn.net/panda19881/article/details/6152581

一:mplayer简介

MPlayer是一款开源的多媒体播放器,以GNU通用公共许可证发布。此款软件可在各主流作业系统使用,例如Linux和其他类Unix作业系统、微软的视窗系统及苹果电脑的Mac OS X系统。MPlayer是建基于命令行界面,在各作业系统可选择安装不同的图形界面。

因为linux下都是命令行的操作方式,所以对mplayer的各种操作都是用命令来实现的,这次主要用的是它的slave工作方式

 

slave模式协议

 

1,简介:

      默认mplayer是从键盘上获得控制信息

  mplayer另外提供了一种更为灵活的控制方式,用来进行播放控制——slave模式

      在slave模式下,MPlayer为后台运行其他程序,不再截获键盘事件,

  MPlayer会从标准输入读一个换行符(/n)分隔开的命令。

 

2,操作:

 

#mplayer -input cmdlist

 // 会打印出一份当前mplayer所支持的所有slave模式的命令

 

方法一:从控制台输入控制命令(测试使用)

    运行mplayer -slave -quiet <movie>,并在控制台窗口输入slave命令。

//-slave 启动从模式  

//-quiet 不输出冗余的信息

 

 

 

常用到的 Mplayer指令:

loadfile   string   //参数string 为 歌曲名字。 

volume 100 1  //设置音量 中间的为音量的大小。

mute  1/0 //静音开关

pause  //暂停/取消暂停

get_time_length  //返回值是播放文件的长度,以秒为单位。

seek value   //向前查找到文件的位置播放 参数value为秒数。

get_percent_pos //返回文件的百分比(0--100

get_time_pos //打印出在文件的当前位置用秒表示,采用浮点数

volume <value> [abs] //增大/减小音量,或将其设置为<value>,如果[abs]不为零

 

get_file_name //打印出当前文件名

get_meta_album //打印出当前文件的'专辑'的元数据

get_meta_artist //打印出当前文件的'艺术家'的元数据

get_meta_comment //打印出当前文件的'评论'的元数据

get_meta_genre //打印出当前文件的'流派'的元数据

get_meta_title //打印出当前文件的'标题'的元数据

get_meta_year //打印出当前文件的'年份'的元数据

 

方法二:从有名管道(fifo)输入控制命令(应用编程中使用)

    #mkfifo </tmp/fifofile>

    #mplayer  -slave  -input  file=</tmp/fifofile> <movie>

    //用户可以通过往管道里写入slave命令来实现对应的功能

 

主进程创建一个无名管道和一个有名管道

 

1:开一个子进程

在子进程中:

启动Mplayer,参数规定通过命名管道进行通信;

把子进程的标准输出重定向无名管道的写端;

Mplayer从命名管道读到主进程发送的命令;

Mplayer发出的内容发送到无名管道中,父进程通过读管道就可以读到Mplayer发出的信息。

 

2:在父进程中:

启动两个线程

第一个线程,不断使用fgets从键盘获取一个字符串命令,并写入命名管道中

第二个线程,循环检测无名管道是否有信息可读,有信息将其打印输出在屏幕上

 

 

 

二,实现的功能:

1、 显示播放列表 

2、 当前播放的歌曲名字,字体为白色,背景为蓝色。 

3、 可以通过点击相应的歌曲名字,播放相应的歌曲 

4、 实现歌曲的播放,暂停,上一首,下一首。 

5、 实现快进功能。 

6、 在歌词秀窗口中显示歌词。 

 

三,实现的方案:

 第0步: 功能:初始化图形库和触摸屏,实现背景窗口的初始化。

 

要求:创建一个mplayer_init.c 在此文件中  写一个函数tft_init()初始化窗口

 

提示:用到的接口函数

     1:TFT_Init(); 图形库的初始化函数

     2:ts_cal_init();  触摸屏的初始化函数

     3:创建窗口

 

背景窗口:

WindowBack =  TFT_CreateWindowEx(0,0,320,240,COLOR_WHITE);

歌曲进度窗口:

Window_rate =  TFT_CreateWindowEx(5,102,180,5,COLOR_GREEN);

音量调节窗口:

Window_vol= TFT_CreateWindowEx(110,118,45,5,COLOR_GREEN);

歌词显示窗口:

Window_lrc=TFT_CreateWindowEx(4,151,180,86,COLOR_BLUE);

歌词列表窗口:

WindowList =  TFT_CreateWindowEx(194,30,123,200,COLOR_BLACK); 

歌曲实时信息窗口

Window_time =  TFT_CreateWindowEx(5,17,177,28,COLOR_BLACK); 

歌曲信息窗口

Window_msg =  TFT_CreateWindowEx(5,47,177,54,0xf81f); 

 

1步:功能:从文件夹中读取歌曲名字,保存在全局的指针数组中。在屏幕上实现歌词列表。

       要求:1:把某个目录下的歌曲文件名字,全部赋值给指针数组。(写一个函数get_song_list()实现)

     2:把所有的歌曲列在歌词列表窗口中,当前播放歌曲的名字在列表中应该用个矩形框反显一下,以示区别:通过清窗口,然后重新往窗口打印来实现)

 

mplayer_init.c 中写一个函数去实现功能。

 

   

       提示:获取某个目录下文件的名称所用函数

DIR* opendir(char* pathname);   打开歌曲文件夹

struct dirent * readdir(DIR* dir);  获取过来保存在指针数组中

int closedir(DIR *dir);           关闭该文件夹

 

opendir 返回一个DIR类型的指针。

readdir参数是opendir返回的指针。返回值是struct dirent类型的指针。

比如:readdir函数返回值为dpdp->d_name 即文件的名字。

循环把dp->d_name 全局的指针数组赋值即可,

赋值之前要判断一下dp->d_name[0]=='.' 如果相等则continue

还要判断后缀是否是.mp3;否则循环给指针数组赋值

注意每次赋值之前要malloc空间。

循环赋值的时候给一个变量++ 测出有多少首歌

 

 

2步:功能:播放/暂停,上一首、下一首,快进、快退,点播放列表中歌曲的名字实现切换歌曲。 // 用命名管道

       要求:切换歌曲的时候,播放列表中的相应歌曲名字要反显。

        提示:歌曲的切换通过改变指针数组中的参数实现,即按下相应切换键的时候改变指针数组的参数,再发送指令切换歌曲。

 

在歌词列表实现之后,创建子进程,在子进程中启动Mplayer

启动Mplayer的语句:

execl("./mplayer","mplayer","-ac","mad","-slave","-quiet","-input","file=/tmp/my_fifo",buf,NULL);

 

参数:"-ac" "mad"             用的mad解码器

      "-slave"   Mplayer运行在slave模式下,在关于slave模式,MPlayer为后台运行,不再截获键盘事件,MPlayer 从标准输入读取以新行 (/n) 分隔开的命令行

      "-quiet"   使得控制台消息少输出特别地阻止状态行 (即 A: 0.7 V: 0.6 A-V: 0.068 ...)的显示。

      "-intput" "file=/tmp/fifo"    Mplayer 通过命名管道获取命令。

      buf     是歌曲的路径字符串的首地址

      NULL      在参数的最后一个为NULLMplayer可以通过它来判断到底有多少个参数,这个是必须有的。

execl中规定MPlayer从命名管道中获取消息,主进程中就必须通过向命名管道写"命令字符串"来控制Mplayer

所以在主进程中必须创建子进程之前创建fifo,父子进程通过fifo通信。

 

 

主进程中创建touch_pthread线程。任务是:检测触摸屏,检测到相应的键后,干相应的事情。

 

3步:功能:屏幕上显示歌曲长度、当前播放到多少秒、当前歌曲的“专辑、歌手、标题、发行年份”,进度条

         

要求:

     1:在屏幕歌曲信息窗口中显示歌曲的总长度,当前播放时间.(切换歌曲活快进快退的时候刷新信息)

     2:在歌曲信息窗口中显示 歌曲的“专辑、歌手、标题、发行年份”.(切换歌曲的时候刷新信息).

     3:播放进度条随着时间推移。(切换歌曲、或快进快退的时候可以刷新)

 

提示: 1: 父子进程通过管道通信。即子进程通过管道把消息传给父进程

   子进程把Mplayer输出的信息重定向到管道中。

    主进程从管道中读,读出来后解析再做相应的处理。

2: 主进程几个创建子线程

1:pipe_read 循环读管道把读到的消息保存在字符数组中。

2:pipe_read_dispose 循环解析读到的消息,把有用的消息解析出来,做相应的处理

3:get_percent_pos 每隔一段时间发一条检测时间的命令,获取当前播放时间。

 

4步:功能:在歌词窗口显示歌词。

       要求:歌词循环打印,歌词与歌曲同步,切换歌曲的时候切换新的歌词。

       提示:可以用Mplayer返回回来的当前播放时间去查找歌词解析里的时间,这样快进歌词也可以跟着同步。

     如果用以前的虚拟时间,歌曲快进,歌词不能同步。

     歌词解析功能也是创建一个新的线程去完成

 

四,思路

1,初始化:

在编写任何一个项目程序之前,都有一些初始化工作要做,首先必须把该项目要用的硬件配置好,也就是静态的程序工作,上边的第零步和第一步都是初始化工作。还有一个初始化的就是触摸屏,因为之词用的是图片,所以要找到图片是对应功能键在触摸屏上的位置,包括xy坐标的范围和对应的功能键,这个以通过建立一个结果体数组,然后有键按下后判断其范围,并把对应的键值返回:

这在touchscreen.c文件里实现

2,从最基本的功能一步一步实现最终的功能,基本功能是实现最终功能的基础

3,写程序之前应该分析项目的整体实现方法,要有可行性,不要最后走到死胡同

4,做完之后要检测,看某些地方有没有再好的实现方法。

在分析项目的时候,看要不要用进程,用不上进程的地方就尽量不要用,进程一般用在、、、;用了进程之后,进程之间如何通信,有关联的进程数据传输一般用无名管道,无关联的用有名管道,

一些实时性要求比较高的地方要用到线程,比如等待触摸屏,独立的线程处理比较简单,但关联的线程处理起来就比较麻烦,信号,互斥锁,信号量,都不能用的时候就自己建立一个标志位,进行控制;

 

Mplayer的执行和控制部分:

1,简单的播放歌曲

在该项目中,mplayer可执行程序的运行要通过exec函数来实现,这种函数执行完之后就退出线程了,因此必须给他新建一个子线程,

if((pid=fork())==-1)

{

perror("fork");

exit(1);

}

else if(pid==0)//在子进程中播放歌曲

{

char song[SONG_CHNUM];

close(pipedes[0]);

dup2(pipedes[1],1);

sprintf(song,"%s%s","./song/",song_list[0]);//得到整个歌曲路径

execlp("./mplayer","","-ac","mad","-slave","-quiet","-input","file=fifo",song,NULL);}

通过程序控制mplayer要用有名管道传送命令,通过无名管道读取mplayer返回的信息,因为mplayer默认是把信息发送到标准输出上,所以要用dup2()中定向标准输出到无名管道的写端:dup2(pipedes[1],1);

创建有名管道和无名管道

 unlink(FIFO);//如果管道存在,先删除

if(mkfifo("fifo",IPC_CREAT|0x744)==-1)//创建有名管道

{

perror("mkfifo");

exit(1);

}

 

if(pipe(pipedes)==-1)//创建无名管道用于从mplayer读取歌曲信息

{

perror("pipe");

exit(1);

}

 

因为在该项目中要经常向mplayer发送命令,那么就建立一个函数通过写有名管道向mplayer发送命令:

写之前在主进程中打开:

if((fd=open(FIFO,O_RDWR))==-1)

{

perror("open");

exit(1);

}

 

void send_cmd(char *cmd)//通过有名管道向mplayer发送命令

{

if((write(fd,cmd,strlen(cmd)))!=strlen(cmd))

{

perror("write cmd");

}

}

这样一个简单的mplayer就建立成功了,运行这个框架下的程序,可以自己播放一首歌,一首歌播完后由于exec函数的性质,整个程序就执行完了。

 

2,触摸屏处理

要进行控制的话就要对触摸屏进行处理,初始化不必说了,因为触摸屏要实时监测,所以必须起一个新的线程,而该线程只检测触摸屏,没有跟其他县城竞争资源:

void *touch_pthread()

{

int key=0;

while(1)

{

usleep(100*MS);//延时处理触摸屏键值

if(ts_read(&ts)==-1)//读取按下的点

continue;

if((key=Touch_Trans(ts.x,ts.y))==-1)//将按下的点转化成设定的键值

continue;

key_dispose(key);//处理键值

}

return NULL;

}

该进程通过执行读取触摸屏函数ts_read(&ts)和合判断键值函数Touch_Trans(ts.x,ts.y)到按下点对应的键值key,送往键值处理函数key_dispose(key)去执行相应的按键动作。

在按键处理函数里:

有暂停,快进,快退,上一首,下一首等等,这些都是通过发送给mplayer命令来实现的,mplayer,有这样一个属性,在暂停之后,不管向它发送什么命令,他都会结束暂停,所以在发送暂停命令之后要关闭其它线程向mplayer发送命令,通过以下方法来实现:

case SONG_PAUSE://暂停

{

                i++;

                if(i%2==1) 

                    my_lock=0;/*mplayer发送命令暂停标志位*/

                else if(i%2==0)

                    my_lock=1;

send_cmd("pause/n");

break;

}

my_lock是个全局变量,但它为1时,其他线程才能给mplayer发送命令。与2取余是因为暂停和取消暂停时一个键(命令),

换歌是通过发送命令来实现的而不是改变歌名

每次换歌之后要执行一些操作,所以在换歌后设置一个标志位:new_song_flag=1;

换个的时候注意歌曲数目不要越界;

 

 

 

3,获取歌曲信息

获取歌曲信息也是通过向歌曲发送命令来执行的,然后读取mplayer返回来的信息,有两种类型的信息,

一种是在开始播放歌曲,即换歌后要发送的命令:获取歌曲信息命令

一个是在整个歌曲播放过程中一直发送的命令:获取歌曲时间和进度命令

这两种命令不能同时发送,否则有的时候收到的信息就是混杂的,不方便解析;

实时发送时间命令是一个线程,发送歌词信息命令在另一个线程暂时性的执行,这种互斥访问首先先到的是互斥锁,但在切歌后,获取歌词信息命令必须发送,而互斥锁有个线程抢占的过程,那么暂时性的执行就有可能得不到互斥锁,那么只能自己设定标志位了:

 

发送获取歌词函数:

void get_song_msg()

{

int i;

    my_lock=0;//设置标志位,让两一个进程停止向mplayer发送命令

    printf("my_lock=%d/n", my_lock );

char *song_msg_cmd[4]={"get_meta_title/n","get_meta_artist/n",

"get_meta_album/n","get_meta_year/n"};

for(i=0;i<4;i++)

{

send_cmd(song_msg_cmd[i]);

usleep(500*MS);

}

send_cmd("get_time_length/n");

    my_lock=1;

    printf("my_lock=%d/n", my_lock );

   

}

 

发送获取歌词播放时间命令线程:

void *get_pos_pthread()

{

while(1)

{

        if(my_lock==1 )

        {

     usleep(500*MS);

     send_cmd("get_percent_pos/n");

     usleep(500*MS);

     send_cmd("get_time_pos/n");

        } 

}

return NULL;

}

 

这里用的标志位跟暂停里用的一样,可以用不同的标志位。

 

 

 

 

读取命令和发送命令相对应,发送命令在一个线程里,那么接收命令也在另建立一个线程,因为mplayer播放歌曲开始要发送一些相关信息,所以对接收到的信息根据所需内容的特征进行判断,然后处理。

 

 

这里建立两个线程,感觉可以建立一个线程,但执行起来不好用,不知道为什么,没有仔细研究:

读信息线程

void *pipe_read_pthread()

{

int size;

char buf[REC_MSG_CHNUM];

while(1)

{

        memset(buf, 0 , REC_MSG_CHNUM) ;

if((size = read(pipedes[0],buf,sizeof(buf))) == -1)//读取mplayer发过来的歌曲信息

{

perror("read pipe");

exit(1);

}

        if( size == 0)//如果没有读到信息,则返回继续读取

            continue;

buf[size]='/0';//使信息变成字符串,便于处理

// printf("******************msg_buf=%s/n/n",buf);

        strcpy(msg_buf,buf);

       if(strncmp(buf,"ANS_META",8) ==0) //获取歌曲信息

{

buf[strlen(buf)-2]='/0';//多减一个去掉引号

msg_dispose(buf);

}

        sem_post(&cmd_sem) ;

}

return NULL;

}

处理信息线程:

void *pipe_read_dispose_pthread()

{

 char buf[REC_MSG_CHNUM];

 while(1)

 {

   sem_wait(&cmd_sem) ;

   strcpy(buf,msg_buf);

   if(strncmp(buf,"ANS_PERCENT_POSITION", 20)==0) //获取进度信息

   {

     percent_dispose(buf);

   }

   else if(strncmp(buf,"ANS_TIME_POSITION", 17) ==0) //获取歌曲当前播放时间

   {

    time_dispose(buf);

   }

   

   else if(strncmp(buf,"ANS_LENGTH",10) ==0) //获得歌的总长度

   {

     length_dispose(buf);

   }

 }

return NULL;

}

 

在这遇到一个问题,搞了好长时间,自动切歌的时候,不更新歌曲信息:

有两个原因:第一个是,发送获取歌词信息命令和获取时间命令同时发送时,接收到信号不规范:

******************msg_buf=POSITION=0.0

ANS_PERCENT_POSITION=0

ANS_META_TITLE='梦醒时分'

ANS_META_ARTIST='陈淑桦'

ANS_META_ALBU

 

******************msg_buf=M='情牵淑桦'

ANS_META_YEAR='1999'

ANS_LENGTH=246.00

ANS_TIME_POSITION=0.5

ANS_PERCENT_POSITION=0

就这种,一个buf,就收到好几条信息

用标志位隔开后,好了,可以接受单条信息,但就在接收歌词信息的时候,程序不执行信息解析线程,就只好把歌曲信息解析判断放在上边了;

信号量的作用是在有收到信息的情况下解析信息。

如果放在同一线程中,是不是每次解析之前延时一段时间,活用一个类似于信号功能的方法,让他不要一直解析。

 

解析了信息之后就进行相应的操作,

更新歌曲信息

更新时间,显示时间

实时更新进度条,但播放到了99%就自动换歌,跟执行手动换歌一样。

 

4,加上歌词

 

在歌曲播放开始获取歌词,解析到链表里,另建一个线程,在播放歌曲的同时通过比较歌曲播放时间来显示歌词,

滚屏用移位法,

TFT_ClearWindow(Window_lrc);

TFT_SetColor(Window_lrc,COLOR_WHITE);

for(i=0;i<4;i++)//把下一行拷到上一行,实现滚屏

{

  strcpy(lrc_buf[i],lrc_buf[i+1]);

  TFT_Print(Window_lrc,"%s/n",lrc_buf[i]);

 

}

strcpy(lrc_buf[i],temp->lrctent);

就是在每次显示之前,清屏,然后把显示缓冲区的字符串数组前一个歌词用后一个覆盖,新的歌词加到最后一个缓冲区

 

 

 

每次切歌之后,都要在歌词列表区对当前播放的歌进行高亮显示,获取歌曲信息,获取歌词,显示歌词,释放上次歌词解析是为链表molloc的空间。

void slice_song(void)

    high_song();//高亮当前歌曲名

    free_link();//释放链表空间

 get_lrc();   //得到歌词

    sleep(1);//延时让mplayer发送完刚开始的信息

    get_song_msg();//发送获得当前歌曲信息的命令

    sleep(1) ;

    msg_disply();//显示歌曲信息   

学到的知识:

指针:

指针必须指向一块地址之后才能对其操作

在二维指针中

Char *buf[10];

这只是定义了10个指针,这10个指针的地址在一块,但他们指向的空间还没有分配,用之前必须分配地址大小

 

对于指针而言,它是指向一个内存区域,你对它操作的时候,应该知道你操作的实际地址是什么,这个地址里的数据你在以后还会用吗,这次改变对后续操作有影响吗?一般来说用指针是方便读取数据,最好不要用指针对程序多出共享地址(全区地址)的内容进行修改

 

格式输入输出:sprintf(song_msg.length,"%02d:%02d",minu,sec);

数据宽度是2,不够的话在左边补0

 

 

对进程的使用和理解,线程,互斥锁,信号等等

 

文件包含:

每一个.c文件对应一个.h文件

.c文件定义全局变量,函数以及函数功能的实现

.h文件声明全局变量,声明函数,宏定义,结构体定义等等

然后总的定义一个.h文件,把所有的.h文件包含,每个.c文件包含这个总的.h文件

每个.h文件要有条件编译;

这是我写该项目的主文件,我贴上来主要是自己以后有时间了回头看看,还有自己刚开始学习linux,肯定有好多编程问题,希望好心人能指出。

主文件mplayer_main.c

[cpp]  view plain copy
  1. /* ************************************************************************ 
  2. //                                  Last Change:  2011-01-19 15:56:14 
  3.  *       Filename:  mplayer_main.c 
  4.  *    Description:  mplayer maintance file 
  5.  *        Version:  1.0 
  6.  *        Created:  2011-1-13 11:27:45 
  7.  *       Revision:  none 
  8.  *       Compiler:  gcc 
  9.  *         Author:  panda  
  10.  *        Company:  sunplusapp  
  11.  * ************************************************************************/  
  12. #include"mplayer_include.h"  
  13. #define FIFO    "fifo"  
  14. int fd;  
  15. int pipedes[2];  
  16. char msg_buf[REC_MSG_CHNUM ] ;/*接收到信息缓冲区*/  
  17. int my_lock=0;//发送命令标志位  
  18. /***************************************************************************** 
  19.  *       Function name: send_cmd 
  20.  *         Description: send commend to mplayer by fifo 
  21.  *    parameter  input: cmd 
  22.  *    parameter output: None 
  23.  *              return: None 
  24.  *****************************************************************************/  
  25. void send_cmd(char *cmd)//通过有名管道向mplayer发送命令  
  26. {  
  27.     if((write(fd,cmd,strlen(cmd)))!=strlen(cmd))  
  28.     {  
  29.         perror("write cmd");  
  30.     }  
  31. }  
  32. /***************************************************************************** 
  33.  *       Function name: touch_pthread 
  34.  *         Description: a pthread that checking toucher status all times  
  35.  *    parameter  input: None 
  36.  *    parameter output: None 
  37.  *              return: None 
  38.  *****************************************************************************/  
  39. void *touch_pthread()  
  40. {  
  41.     int key=0;  
  42.     while(1)  
  43.     {  
  44.         usleep(100*MS);//延时处理触摸屏键值  
  45.         if(ts_read(&ts)==-1)//读取按下的点  
  46.             continue;  
  47.         if((key=Touch_Trans(ts.x,ts.y))==-1)//将按下的点转化成设定的键值  
  48.             continue;  
  49.         key_dispose(key);//处理键值  
  50.     }  
  51.     return NULL;  
  52. }  
  53. /***************************************************************************** 
  54.  *       Function name: pipe_read_pthread 
  55.  *         Description: a pthread that ciculate reading msg from pipe data that reciver to mplayer 
  56.  *    parameter  input: None 
  57.  *    parameter output: None 
  58.  *              return: None 
  59.  *****************************************************************************/  
  60. void *pipe_read_pthread()  
  61. {  
  62.     int size;  
  63.     char buf[REC_MSG_CHNUM];  
  64.     while(1)  
  65.     {  
  66.         memset(buf, 0 , REC_MSG_CHNUM) ;  
  67.         if((size = read(pipedes[0],buf,sizeof(buf))) == -1)//读取mplayer发过来的歌曲信息  
  68.         {  
  69.             perror("read pipe");  
  70.             exit(1);  
  71.         }  
  72.         if( size == 0)//如果没有读到信息,则返回继续读取  
  73.             continue;  
  74.         buf[size]='/0';//使信息变成字符串,便于处理  
  75. //      printf("******************msg_buf=%s/n/n",buf);  
  76.         strcpy(msg_buf,buf);  
  77.        if(strncmp(buf,"ANS_META",8) ==0)                //获取歌曲信息  
  78.         {  
  79.             buf[strlen(buf)-2]='/0';//多减一个去掉引号  
  80.             msg_dispose(buf);  
  81.         }  
  82.         sem_post(&cmd_sem) ;  
  83.     }  
  84.     return NULL;  
  85. }  
  86. /***************************************************************************** 
  87.  *       Function name: pipe_read_dispose_pthread 
  88.  *         Description: a pthread that ciculate resolving msg 
  89.  *    parameter  input: None 
  90.  *    parameter output: None 
  91.  *              return: None 
  92.  *****************************************************************************/  
  93. void *pipe_read_dispose_pthread()  
  94. {  
  95.     char buf[REC_MSG_CHNUM];  
  96.     while(1)  
  97.     {  
  98.         sem_wait(&cmd_sem) ;  
  99.         strcpy(buf,msg_buf);  
  100.         if(strncmp(buf,"ANS_PERCENT_POSITION", 20)==0)      //获取进度信息  
  101.         {  
  102.             percent_dispose(buf);     
  103.         }  
  104.         else if(strncmp(buf,"ANS_TIME_POSITION", 17) ==0)   //获取歌曲当前播放时间  
  105.         {  
  106.             time_dispose(buf);  
  107.         }  
  108.   
  109.         else if(strncmp(buf,"ANS_LENGTH",10) ==0)           //获得歌的总长度  
  110.         {  
  111.             length_dispose(buf);  
  112.         }  
  113.     }  
  114.     return NULL;  
  115. }  
  116.   
  117. /***************************************************************************** 
  118.  *       Function name: get_percent_pos_pthread 
  119.  *         Description: a pthread that geting song time and percent of mplayer 
  120.  *    parameter  input: None 
  121.  *    parameter output: None 
  122.  *              return: None 
  123.  *****************************************************************************/  
  124. void *get_pos_pthread()  
  125. {  
  126.     while(1)  
  127.     {  
  128.         if(my_lock==1 )  
  129.         {  
  130.             usleep(500*MS);  
  131.             send_cmd("get_percent_pos/n");  
  132.             usleep(500*MS);  
  133.             send_cmd("get_time_pos/n");  
  134.         }   
  135.     }  
  136.     return NULL;  
  137. }  
  138. /***************************************************************************** 
  139.  *       Function name: display_lrc_pthread 
  140.  *         Description: a pthread that displaying lyric 
  141.  *    parameter  input: None 
  142.  *    parameter output: None 
  143.  *              return: None 
  144.  *****************************************************************************/  
  145. void *display_lrc_pthread()  
  146. {  
  147.     LRC *temp;  
  148.     char oldtime[10]="00:00";  
  149.     sleep(1);  
  150.     while(1)  
  151.     {  
  152.         if(strcmp(song_msg.cur_time,oldtime)!=0)//时间变化了进入相应的歌词显示  
  153.         {  
  154.             temp=head;  
  155.             while(temp!=NULL)  
  156.             {  
  157.                 if(display_lrc(temp)==1)//如果找到该时间的歌词,则跳出循环,等待下一次时间的到来  
  158.                 {  
  159.                     break;    
  160.                 }  
  161.                 temp=temp->next;  
  162.             }  
  163.             strcpy(oldtime, song_msg.cur_time);  
  164.         }  
  165.     }  
  166.     free_link(head);//释放链表空间  
  167.     return NULL;  
  168. }  
  169. /***************************************************************************** 
  170.  *       Function name: main 
  171.  *         Description: maintance function  
  172.  *    parameter  input: None 
  173.  *    parameter output: None 
  174.  *              return: None 
  175.  *****************************************************************************/  
  176. int main(int argc,char *argv[])  
  177. {  
  178.     pid_t pid;  
  179.       
  180.     unlink(FIFO);//如果管道存在,先删除  
  181.     tft_init();//初始化触摸屏  
  182.     get_song_list();//得到歌曲列表  
  183.   
  184.         unlink(FIFO);//如果管道存在,先删除  
  185.     if(mkfifo("fifo",IPC_CREAT|0x744)==-1)//创建有名管道  
  186.     {  
  187.         perror("mkfifo");  
  188.         exit(1);  
  189.     }  
  190.       
  191.     if(pipe(pipedes)==-1)//创建无名管道用于从mplayer读取歌曲信息  
  192.     {  
  193.         perror("pipe");  
  194.         exit(1);  
  195.     }  
  196.   
  197.     if((pid=fork())==-1)  
  198.     {  
  199.         perror("fork");  
  200.         exit(1);  
  201.     }  
  202.     else if(pid==0)//在子进程中播放歌曲  
  203.     {  
  204.         char song[SONG_CHNUM];    
  205.         close(pipedes[0]);  
  206.         dup2(pipedes[1],1);  
  207.         sprintf(song,"%s%s","./song/",song_list[0]);//得到整个歌曲路径  
  208.         execlp("./mplayer","","-ac","mad","-slave","-quiet","-input","file=fifo",song,NULL);  
  209.           
  210.     }  
  211.     else if(pid>0)  
  212.     {  
  213.         pthread_t tid_touch;  
  214.         pthread_t tid_pr;  
  215.         pthread_t tid_prd;  
  216.         pthread_t tid_gpp;  
  217.         pthread_t tid_plp;  
  218.   
  219.         usleep(500*MS);//等待让歌曲播放之后在获取信息  
  220.         if((fd=open(FIFO,O_RDWR))==-1)  
  221.         {  
  222.             perror("open");  
  223.             exit(1);  
  224.         }  
  225.   
  226.         pthread_create(&tid_touch,NULL,touch_pthread,NULL);//检测触摸屏  
  227.           
  228. /*循环读管道把读到的消息保存在字符数组中*/  
  229.         pthread_create(&tid_pr,NULL,pipe_read_pthread,NULL);  
  230.   
  231. /*解析读到的消息,把有用的消息解析出来,做相应的处理*/  
  232.         pthread_create(&tid_pr,NULL,pipe_read_dispose_pthread,NULL);  
  233.   
  234. /*每隔一段时间发一条检测时间的命令,获取当前播放时间*/  
  235.         pthread_create(&tid_gpp,NULL,get_pos_pthread,NULL);  
  236.         pthread_create(&tid_plp,NULL,display_lrc_pthread,NULL);//显示歌词  
  237.           
  238.         slice_song();     //切歌后要执行的函数  
  239.                   
  240.         pthread_join(tid_touch,NULL);  
  241.         pthread_join(tid_pr,NULL);  
  242.         pthread_join(tid_prd,NULL);  
  243.         pthread_join(tid_gpp,NULL);  
  244.         pthread_join(tid_plp,NULL);  
  245.     }  
  246.       
  247.     return 0;  
  248. }  

 

总的头文件mplayer_include.h

[c-sharp]  view plain copy
  1. #ifndef _MPLAYER_INCLUDE_  
  2. #define _MPLAYER_INCLUDE_  
  3.  
  4. #include<stdio.h>  
  5. #include<stdlib.h>  
  6. #include<unistd.h>  
  7. #include<string.h>  
  8. #include<dirent.h>  
  9. #include<sys/stat.h>  
  10. #include<sys/types.h>  
  11. #include<fcntl.h>  
  12. #include<pthread.h>  
  13. #include<sys/ipc.h>  
  14. #include<semaphore.h>//sem_init()  
  15.  
  16. #include"TFT_API.h"  
  17. #include"mplayer_init.h"  
  18. #include"touchscreen.h"  
  19. #include"readlrc.h"  
  20.  
  21. #define SONG_NUM        10/*歌曲数目*/  
  22. #define SONG_CHNUM      100/*歌曲名的字符串个数*/  
  23. #define MS              1000/*usleep()*/  
  24. #define REC_MSG_CHNUM   100/*接收到信息的字符个数*/  
  25. #endif