linux下mplayer播放器应用程序总结
一:
因为
slave模式协议
1,简介:
默认
mplayer另外提供了一种更为灵活的控制方式,用来进行播放控制——
在
MPlayer会从标准输入读一个换行符(
2,操作:
#mplayer -input cmdlist
// 会打印出一份当前
方法一:从控制台输入控制命令
运行
//-slave 启动从模式
//-quiet 不输出冗余的信息
常用到的
loadfile string //参数
volume 100 1 //设置音量 中间的为音量的大小。
mute 1/0 //静音开关
pause //暂停
get_time_length //返回值是播放文件的长度,以秒为单位。
seek value //向前查找到文件的位置播放 参数
get_percent_pos //返回文件的百分比(
get_time_pos //打印出在文件的当前位置用秒表示,采用浮点数
volume
get_file_name //打印出当前文件名
get_meta_album //打印出当前文件的
get_meta_artist //打印出当前文件的
get_meta_comment //打印出当前文件的
get_meta_genre //打印出当前文件的
get_meta_title //打印出当前文件的
get_meta_year //打印出当前文件的
方法二:从有名管道
#mkfifo
#mplayer -slave -input file=
//用户可以通过往管道里写入
主进程创建一个无名管道和一个有名管道
1:开一个子进程
在子进程中:
启动
把子进程的标准输出重定向无名管道的写端;
Mplayer从命名管道读到主进程发送的命令
Mplayer发出的内容发送到无名管道中,父进程通过读管道就可以读到
2:在父进程中:
启动两个线程
第一个线程,不断使用
第二个线程,循环检测无名管道是否有信息可读,有信息将其打印输出在屏幕上
二,实现的功能:
1、 显示播放列表
2、 当前播放的歌曲名字,字体为白色,背景为蓝色。
3、 可以通过点击相应的歌曲名字,播放相应的歌曲
4、 实现歌曲的播放,暂停,上一首,下一首。
5、 实现快进功能。
6、 在歌词秀窗口中显示歌词。
三,实现的方案:
第
要求:创建一个
提示:用到的接口函数
1:
2:
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);
第
要求:
2:把所有的歌曲列在歌词列表窗口中,当前播放歌曲的名字在列表中应该用个矩形框反显一下,以示区别:通过清窗口,然后重新往窗口打印来实现)
在
提示:获取某个目录下文件的名称所用函数
DIR* opendir(char* pathname); 打开歌曲文件夹
struct dirent * readdir(DIR* dir); 获取过来保存在指针数组中
int closedir(DIR *dir); 关闭该文件夹
opendir 返回一个
readdir参数是
比如:
循环把
赋值之前要判断一下
还要判断后缀是否是
注意每次赋值之前要
循环赋值的时候给一个变量
第
要求:切换歌曲的时候,播放列表中的相应歌曲名字要反显。
提示:歌曲的切换通过改变指针数组中的参数实现,即按下相应切换键的时候改变指针数组的参数,再发送指令切换歌曲。
在歌词列表实现之后,创建子进程,在子进程中启动
启动
execl("./mplayer","mplayer","-ac","mad","-slave","-quiet","-input","file=/tmp/my_fifo",buf,NULL);
参数:
"-slave" Mplayer运行在
"-quiet" 使得控制台消息少输出
"-intput" "file=/tmp/fifo" Mplayer 通过命名管道获取命令。
buf 是歌曲的路径字符串的首地址
NULL 在参数的最后一个为
在
所以在主进程中必须创建子进程之前创建
主进程中创建
第
要求:
1:在屏幕歌曲信息窗口中显示歌曲的总长度,当前播放时间
2:在歌曲信息窗口中显示 歌曲的“专辑、歌手、标题、发行年份”
3:播放进度条随着时间推移。
提示: 1: 父子进程通过管道通信。即子进程通过管道把消息传给父进程
子进程把
主进程从管道中读,读出来后解析再做相应的处理。
2: 主进程几个创建子线程
1:
2:
3:
第
要求:歌词循环打印,歌词与歌曲同步,切换歌曲的时候切换新的歌词。
提示:可以用
如果用以前的虚拟时间,歌曲快进,歌词不能同步。
歌词解析功能也是创建一个新的线程去完成
四,思路
1,初始化:
在编写任何一个项目程序之前,都有一些初始化工作要做,首先必须把该项目要用的硬件配置好,也就是静态的程序工作,上边的第零步和第一步都是初始化工作。还有一个初始化的就是触摸屏,因为之词用的是图片,所以要找到图片是对应功能键在触摸屏上的位置,包括
这在
2,从最基本的功能一步一步实现最终的功能,基本功能是实现最终功能的基础
3,写程序之前应该分析项目的整体实现方法,要有可行性,不要最后走到死胡同
4,做完之后要检测,看某些地方有没有再好的实现方法。
在分析项目的时候,看要不要用进程,用不上进程的地方就尽量不要用,进程一般用在、、、;用了进程之后,进程之间如何通信,有关联的进程数据传输一般用无名管道,无关联的用有名管道,
一些实时性要求比较高的地方要用到线程,比如等待触摸屏,独立的线程处理比较简单,但关联的线程处理起来就比较麻烦,信号,互斥锁,信号量,都不能用的时候就自己建立一个标志位,进行控制;
Mplayer的执行和控制部分:
1,简单的播放歌曲
在该项目中,
i
通过程序控制
创建有名管道和无名管道
因为在该项目中要经常向
写之前在主进程中打开:
这样一个简单的
2,触摸屏处理
要进行控制的话就要对触摸屏进行处理,初始化不必说了,因为触摸屏要实时监测,所以必须起一个新的线程,而该线程只检测触摸屏,没有跟其他县城竞争资源:
该进程通过执行读取触摸屏函数
在按键处理函数里:
有暂停,快进,快退,上一首,下一首等等,这些都是通过发送给
my_lock是个全局变量,但它为
换歌是通过发送命令来实现的而不是改变歌名
每次换歌之后要执行一些操作,所以在换歌后设置一个标志位:
换个的时候注意歌曲数目不要越界;
3,获取歌曲信息
获取歌曲信息也是通过向歌曲发送命令来执行的,然后读取
一种是在开始播放歌曲,即换歌后要发送的命令:获取歌曲信息命令
一个是在整个歌曲播放过程中一直发送的命令:获取歌曲时间和进度命令
这两种命令不能同时发送,否则有的时候收到的信息就是混杂的,不方便解析;
实时发送时间命令是一个线程,发送歌词信息命令在另一个线程暂时性的执行,这种互斥访问首先先到的是互斥锁,但在切歌后,获取歌词信息命令必须发送,而互斥锁有个线程抢占的过程,那么暂时性的执行就有可能得不到互斥锁,那么只能自己设定标志位了:
发送获取歌词函数:
发送获取歌词播放时间命令线程:
这里用的标志位跟暂停里用的一样,可以用不同的标志位。
读取命令和发送命令相对应,发送命令在一个线程里,那么接收命令也在另建立一个线程,因为
这里建立两个线程,感觉可以建立一个线程,但执行起来不好用,不知道为什么,没有仔细研究:
读信息线程
处理信息线程:
在这遇到一个问题,搞了好长时间,自动切歌的时候,不更新歌曲信息:
有两个原因:第一个是,发送获取歌词信息命令和获取时间命令同时发送时,接收到信号不规范:
就这种,一个
用标志位隔开后,好了,可以接受单条信息,但就在接收歌词信息的时候,程序不执行信息解析线程,就只好把歌曲信息解析判断放在上边了;
信号量的作用是在有收到信息的情况下解析信息。
如果放在同一线程中,是不是每次解析之前延时一段时间,活用一个类似于信号功能的方法,让他不要一直解析。
解析了信息之后就进行相应的操作,
更新歌曲信息
更新时间,显示时间
实时更新进度条,但播放到了
4,加上歌词
在歌曲播放开始获取歌词,解析到链表里,另建一个线程,在播放歌曲的同时通过比较歌曲播放时间来显示歌词,
滚屏用移位法,
就是在每次显示之前,清屏,然后把显示缓冲区的字符串数组前一个歌词用后一个覆盖,新的歌词加到最后一个缓冲区
每次切歌之后,都要在歌词列表区对当前播放的歌进行高亮显示,获取歌曲信息,获取歌词,显示歌词,释放上次歌词解析是为链表
学到的知识:
指针:
指针必须指向一块地址之后才能对其操作
在二维指针中
Char *buf[10];
这只是定义了
对于指针而言,它是指向一个内存区域,你对它操作的时候,应该知道你操作的实际地址是什么,这个地址里的数据你在以后还会用吗,这次改变对后续操作有影响吗?一般来说用指针是方便读取数据,最好不要用指针对程序多出共享地址(全区地址)的内容进行修改
格式输入输出:
数据宽度是
对进程的使用和理解,线程,互斥锁,信号等等
文件包含:
每一个.c文件对应一个.h文件
.c文件定义全局变量,函数以及函数功能的实现
.h文件声明全局变量,声明函数,宏定义,结构体定义等等
然后总的定义一个.h文件,把所有的.h文件包含,每个.c文件包含这个总的.h文件
每个.h文件要有条件编译;
这是我写该项目的主文件,我贴上来主要是自己以后有时间了回头看看,还有自己刚开始学习linux,肯定有好多编程问题,希望好心人能指出。
主文件mplayer_main.c
[cpp] view plain copy
- /* ************************************************************************
- // Last Change: 2011-01-19 15:56:14
- * Filename: mplayer_main.c
- * Description: mplayer maintance file
- * Version: 1.0
- * Created: 2011-1-13 11:27:45
- * Revision: none
- * Compiler: gcc
- * Author: panda
- * Company: sunplusapp
- * ************************************************************************/
- #include"mplayer_include.h"
- #define FIFO "fifo"
- int fd;
- int pipedes[2];
- char msg_buf[REC_MSG_CHNUM ] ;/*接收到信息缓冲区*/
- int my_lock=0;//发送命令标志位
- /*****************************************************************************
- * Function name: send_cmd
- * Description: send commend to mplayer by fifo
- * parameter input: cmd
- * parameter output: None
- * return: None
- *****************************************************************************/
- void send_cmd(char *cmd)//通过有名管道向mplayer发送命令
- {
- if((write(fd,cmd,strlen(cmd)))!=strlen(cmd))
- {
- perror("write cmd");
- }
- }
- /*****************************************************************************
- * Function name: touch_pthread
- * Description: a pthread that checking toucher status all times
- * parameter input: None
- * parameter output: None
- * return: None
- *****************************************************************************/
- 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;
- }
- /*****************************************************************************
- * Function name: pipe_read_pthread
- * Description: a pthread that ciculate reading msg from pipe data that reciver to mplayer
- * parameter input: None
- * parameter output: None
- * return: None
- *****************************************************************************/
- 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;
- }
- /*****************************************************************************
- * Function name: pipe_read_dispose_pthread
- * Description: a pthread that ciculate resolving msg
- * parameter input: None
- * parameter output: None
- * return: None
- *****************************************************************************/
- 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;
- }
- /*****************************************************************************
- * Function name: get_percent_pos_pthread
- * Description: a pthread that geting song time and percent of mplayer
- * parameter input: None
- * parameter output: None
- * return: None
- *****************************************************************************/
- 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;
- }
- /*****************************************************************************
- * Function name: display_lrc_pthread
- * Description: a pthread that displaying lyric
- * parameter input: None
- * parameter output: None
- * return: None
- *****************************************************************************/
- void *display_lrc_pthread()
- {
- LRC *temp;
- char oldtime[10]="00:00";
- sleep(1);
- while(1)
- {
- if(strcmp(song_msg.cur_time,oldtime)!=0)//时间变化了进入相应的歌词显示
- {
- temp=head;
- while(temp!=NULL)
- {
- if(display_lrc(temp)==1)//如果找到该时间的歌词,则跳出循环,等待下一次时间的到来
- {
- break;
- }
- temp=temp->next;
- }
- strcpy(oldtime, song_msg.cur_time);
- }
- }
- free_link(head);//释放链表空间
- return NULL;
- }
- /*****************************************************************************
- * Function name: main
- * Description: maintance function
- * parameter input: None
- * parameter output: None
- * return: None
- *****************************************************************************/
- int main(int argc,char *argv[])
- {
- pid_t pid;
- unlink(FIFO);//如果管道存在,先删除
- tft_init();//初始化触摸屏
- get_song_list();//得到歌曲列表
- unlink(FIFO);//如果管道存在,先删除
- if(mkfifo("fifo",IPC_CREAT|0x744)==-1)//创建有名管道
- {
- perror("mkfifo");
- exit(1);
- }
- if(pipe(pipedes)==-1)//创建无名管道用于从mplayer读取歌曲信息
- {
- perror("pipe");
- exit(1);
- }
- 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);
- }
- else if(pid>0)
- {
- pthread_t tid_touch;
- pthread_t tid_pr;
- pthread_t tid_prd;
- pthread_t tid_gpp;
- pthread_t tid_plp;
- usleep(500*MS);//等待让歌曲播放之后在获取信息
- if((fd=open(FIFO,O_RDWR))==-1)
- {
- perror("open");
- exit(1);
- }
- pthread_create(&tid_touch,NULL,touch_pthread,NULL);//检测触摸屏
- /*循环读管道把读到的消息保存在字符数组中*/
- pthread_create(&tid_pr,NULL,pipe_read_pthread,NULL);
- /*解析读到的消息,把有用的消息解析出来,做相应的处理*/
- pthread_create(&tid_pr,NULL,pipe_read_dispose_pthread,NULL);
- /*每隔一段时间发一条检测时间的命令,获取当前播放时间*/
- pthread_create(&tid_gpp,NULL,get_pos_pthread,NULL);
- pthread_create(&tid_plp,NULL,display_lrc_pthread,NULL);//显示歌词
- slice_song(); //切歌后要执行的函数
- pthread_join(tid_touch,NULL);
- pthread_join(tid_pr,NULL);
- pthread_join(tid_prd,NULL);
- pthread_join(tid_gpp,NULL);
- pthread_join(tid_plp,NULL);
- }
- return 0;
- }
总的头文件mplayer_include.h
[c-sharp] view plain copy
- #ifndef _MPLAYER_INCLUDE_
- #define _MPLAYER_INCLUDE_
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
- #include
//sem_init() - #include"TFT_API.h"
- #include"mplayer_init.h"
- #include"touchscreen.h"
- #include"readlrc.h"
- #define SONG_NUM 10/*歌曲数目*/
- #define SONG_CHNUM 100/*歌曲名的字符串个数*/
- #define MS 1000/*usleep()*/
- #define REC_MSG_CHNUM 100/*接收到信息的字符个数*/
- #endif
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
