linux下c语言用mplayer实现简单的音乐播放器

您所在的位置:网站首页 linux的播放器 linux下c语言用mplayer实现简单的音乐播放器

linux下c语言用mplayer实现简单的音乐播放器

2023-10-27 08:24| 来源: 网络整理| 查看: 265

主要功能及实现:

1,播放,暂停及继续,上一页下一页,上一首下一首和退出

2,以简单的并发来实现顺序播放等功能

3,可根据不同格式导入歌曲

4,ANSI控制码实现简单的界面制作

缺点:

1,未处理歌名太长覆盖界面的问题

2,上一页,下一页只经过简单处理,不是很方便

以下只对几个关键代码单独展示,完整源代码见文章末尾:

一、带路径的歌曲名导入链表

利用glob函数解析目录下的音乐名字并导入链表

/* 歌曲路径和名字导入链表 */ static LList_st *loading() { int i, ret; musicNode name; LList_st *head = NULL; head = llist_create(sizeof(name)); if (head == NULL) { fprintf(stderr,"llist_create() faild\n"); exit(1); } glob(PATTERN,0,NULL,&buff); for (i = 0; i < buff.gl_pathc; i++) { strncpy(name.musicName,buff.gl_pathv[i],NAMESIZE); ret = llist_insert(head,&name,BEHIND); if (ret < 0) { fprintf(stderr,"llist_insert() fail\n"); exit(1); } } return head; }

二、创建子进程

fork一个子进程,用子进程实现音乐播放,父进程每秒给alrm_handler发送一个信号,alrm_handler函数使用waitpid函数以非阻塞的方式来给子进程收尸,当子进程正常结束时,播放下一首。

/* 信号函数,接到信号时判断子进程是否正常结束,如果正常结束就播放下一首 */ static void alrm_handler(int s) { int status; int ret; ret = waitpid(pid,&status,WNOHANG); if (ret != 0) { if (WIFEXITED(status)) { cur = cur->next; if (cur == &head->head) cur = cur->next; strncpy(musicBuff,getNameFromLink(cur->data),MUSICSIZE); showList(cur,3); fflush(NULL); pid = fork(); createProgress(pid,musicBuff); } } } /* 创建子进程播放歌曲并将3个标准流置null,每秒向函数发送一个信号 */ void createProgress(pid_t pid,char *musicBuff) { int fd; if (pid < 0) { perror("fork()"); exit(1); } if (pid == 0) { fd = open("/dev/null",O_RDWR); if (fd < 0) { perror("open()"); exit(1); } dup2(fd,0); dup2(fd,1); dup2(fd,2); if (fd > 2) close(fd); execlp("mplayer","mplayer",musicBuff,NULL); perror("execlp()"); exit(1); } else { signal(SIGALRM,alrm_handler); struct itimerval new = {{1,0},{1,0}}; setitimer(ITIMER_REAL,&new,NULL); } }

三、主要运行函数

/* 运行函数 * 关闭系统回显和getchar()以\n结尾的设置 * * flag播放状态 0:未播放 1:正在播放 2:暂停 * tmp检测第一次是否创建了子进程,防止意外杀死主进程 0:未创建子进程 1:已创建子进程 * */ void operationFunction() { struct termios new,old; int flag = 0; int tmp = 0; char ch; tcgetattr(0,&old); tcgetattr(0,&new); new.c_lflag = new.c_lflag & ~(ICANON | ECHO); new.c_cc[VMIN] = 1; new.c_cc[VTIME] = 0; tcsetattr(0,TCSANOW,&new); printf("\033[?25l"); //隐藏光标 interface(); head = loading(); cur = head->head.next; showList(cur,0); fflush(NULL); while(1) { ch = getchar(); switch (ch) { /* 播放 */ case 'b': if (tmp == 0) { flag = 1; if (cur == NULL) cur = cur->next; strncpy(musicBuff,getNameFromLink(cur->data),MUSICSIZE); showList(cur,0); fflush(NULL); pid = fork(); tmp = 1; createProgress(pid,musicBuff); } break; /* 上一页 */ case 'w': interface(); showList(cur,2); fflush(NULL); break; /* 下一页 */ case 's': interface(); showList(cur,1); fflush(NULL); break; /* 上一首 */ case 'a': if (tmp == 1) { kill(pid,9); wait(NULL); } cur = cur->prev; if (cur == &head->head) cur = cur->prev; strncpy(musicBuff,getNameFromLink(cur->data),MUSICSIZE); showList(cur,3); fflush(NULL); if (tmp == 1) { pid = fork(); createProgress(pid,musicBuff); } break; /* 下一首 */ case 'd': if (tmp == 1) { kill(pid,9); wait(NULL); } cur = cur->next; if (cur == &head->head) cur = cur->next; strncpy(musicBuff,getNameFromLink(cur->data),MUSICSIZE); showList(cur,3); fflush(NULL); if (tmp == 1) { pid = fork(); createProgress(pid,musicBuff); } break; /* 暂停 | 恢复播放 */ case 'p': if (flag == 1) { kill(pid,19); flag = 2; } else if (flag == 2) { kill(pid,18); flag = 1; } break; default: break; } /* 退出 */ if (ch == 'q') { if (tmp) { kill(pid,9); wait(NULL); break; } else break; } } tcsetattr(0,TCSANOW,&old); //还原终端原始设置 printf("\033[?25h\033[2J");

源代码:

#include #include #include #include #include #include #include #include #include #include #include #include #include "mplayer.h" #include "double_link.h" #define PATTERN "/home/ll/Music/*.mp3" #define MUSICSIZE 256 #define ROW 15 #define LINE 10 /* 音乐名字数组*/ char musicBuff[MUSICSIZE] = {0}; /* 链表头结点 */ LList_st *head = NULL; /* 链表当前位置 */ llist *cur = NULL; /* 进程号 */ pid_t pid; glob_t buff; /* 歌曲位置 */ int songPosition = 0; /* 主界面 */ void interface() { int i, j, k; printf("\033[2J\033[5;25H\033[44m--====================--------------------\033[0m\n"); printf("%c[6;25H",'\033'); for (i = 0; i < ROW; i++) { printf("\033[44m||\033[0m"); for (j = 0; j < LINE; j++) { printf(" "); } printf("\033[44m||\t\t||\033[0m\n\033[24C"); } printf("\033[6;35H%s\n","歌单"); printf("\033[6;53H%s\n","按键说明"); printf("\033[8;52H%s\n","播放 'b'"); printf("\033[9;52H%s\n","暂停 'p'"); printf("\033[10;52H%s\n","退出 'q'"); printf("\033[12;52H%s\n","上一首 'a'"); printf("\033[13;52H%s\n","下一首 'd'"); printf("\033[15;52H%s\n","上一页 'w'"); printf("\033[16;52H%s\n","下一页 's'"); printf("\033[21;25H\033[44m--====================--------------------\033[0m\n"); } /* 歌曲路径和名字导入链表 */ static LList_st *loading() { int i, ret; musicNode name; LList_st *head = NULL; head = llist_create(sizeof(name)); if (head == NULL) { fprintf(stderr,"llist_create() faild\n"); exit(1); } glob(PATTERN,0,NULL,&buff); for (i = 0; i < buff.gl_pathc; i++) { strncpy(name.musicName,buff.gl_pathv[i],NAMESIZE); ret = llist_insert(head,&name,BEHIND); if (ret < 0) { fprintf(stderr,"llist_insert() fail\n"); exit(1); } } return head; } /* 从链表中获取歌曲名字 */ static char *getNameFromLink(void *record) { musicNode *dest = record; return dest->musicName; } /* 获取不包含路径的名字 */ static char *getRealName(char *name) { char *pos = NULL; pos = strrchr(name,'/'); if (pos == NULL) return name; return pos+1; } /* 歌单展示 *tmp为1时,下一页 *tmp为2时,上一页 *当当前链表歌曲和播放歌曲一样时,以红色背景色显示 * */ void showList(llist *cur,int tmp) { int i, k; printf("\033[8;31H"); if (tmp == 1) { songPosition += ROW-3; } if (tmp == 2) { songPosition -= ROW-3; } for (i = songPosition, k = 0; i < buff.gl_pathc && i data)) == 0) printf("\033[41m%s\033[0m\n\033[30C",getRealName(buff.gl_pathv[i])); else printf("%s\n\033[30C",getRealName(buff.gl_pathv[i])); } } } /* 信号函数,接到信号时判断子进程是否正常结束,如果正常结束就播放下一首 */ static void alrm_handler(int s) { int status; int ret; ret = waitpid(pid,&status,WNOHANG); if (ret != 0) { if (WIFEXITED(status)) { cur = cur->next; if (cur == &head->head) cur = cur->next; strncpy(musicBuff,getNameFromLink(cur->data),MUSICSIZE); showList(cur,3); fflush(NULL); pid = fork(); createProgress(pid,musicBuff); } } } /* 创建子进程播放歌曲并将3个标准流置null,每秒向函数发送一个信号 */ void createProgress(pid_t pid,char *musicBuff) { int fd; if (pid < 0) { perror("fork()"); exit(1); } if (pid == 0) { fd = open("/dev/null",O_RDWR); if (fd < 0) { perror("open()"); exit(1); } dup2(fd,0); dup2(fd,1); dup2(fd,2); if (fd > 2) close(fd); execlp("mplayer","mplayer",musicBuff,NULL); perror("execlp()"); exit(1); } else { signal(SIGALRM,alrm_handler); struct itimerval new = {{1,0},{1,0}}; setitimer(ITIMER_REAL,&new,NULL); } } /* 运行函数 * 关闭系统回显和getchar()以\n结尾的设置 * * flag播放状态 0:未播放 1:正在播放 2:暂停 * tmp检测第一次是否创建了子进程,防止意外杀死主进程 0:未创建子进程 1:已创建子进程 * */ void operationFunction() { struct termios new,old; int flag = 0; int tmp = 0; char ch; tcgetattr(0,&old); tcgetattr(0,&new); new.c_lflag = new.c_lflag & ~(ICANON | ECHO); new.c_cc[VMIN] = 1; new.c_cc[VTIME] = 0; tcsetattr(0,TCSANOW,&new); printf("\033[?25l"); //隐藏光标 interface(); head = loading(); cur = head->head.next; showList(cur,0); fflush(NULL); while(1) { ch = getchar(); switch (ch) { /* 播放 */ case 'b': if (tmp == 0) { flag = 1; if (cur == NULL) cur = cur->next; strncpy(musicBuff,getNameFromLink(cur->data),MUSICSIZE); showList(cur,0); fflush(NULL); pid = fork(); tmp = 1; createProgress(pid,musicBuff); } break; /* 上一页 */ case 'w': interface(); showList(cur,2); fflush(NULL); break; /* 下一页 */ case 's': interface(); showList(cur,1); fflush(NULL); break; /* 上一首 */ case 'a': if (tmp == 1) { kill(pid,9); wait(NULL); } cur = cur->prev; if (cur == &head->head) cur = cur->prev; strncpy(musicBuff,getNameFromLink(cur->data),MUSICSIZE); showList(cur,3); fflush(NULL); if (tmp == 1) { pid = fork(); createProgress(pid,musicBuff); } break; /* 下一首 */ case 'd': if (tmp == 1) { kill(pid,9); wait(NULL); } cur = cur->next; if (cur == &head->head) cur = cur->next; strncpy(musicBuff,getNameFromLink(cur->data),MUSICSIZE); showList(cur,3); fflush(NULL); if (tmp == 1) { pid = fork(); createProgress(pid,musicBuff); } break; /* 暂停 | 恢复播放 */ case 'p': if (flag == 1) { kill(pid,19); flag = 2; } else if (flag == 2) { kill(pid,18); flag = 1; } break; default: break; } /* 退出 */ if (ch == 'q') { if (tmp) { kill(pid,9); wait(NULL); break; } else break; } } tcsetattr(0,TCSANOW,&old); //还原终端原始设置 printf("\033[?25h\033[2J"); }



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3