Myplater项目
- 其他
- 2025-08-30 21:48:02

一、项目要求
.基于Mplayer的视频播放器 1.需求分析: 1.该程序能够加载指定路径下所有的音视频文件 (.mp3 .mp4 .avi .rm .rmvb .flv .wma) 2.能够通过界面操作视频播放器 支持: 上键 下键 回车 ESC 支持: 焦点定位 1.一级页面功能如下: +-------------------+ | 视频播放器 | |-------------------| |1.查看播放列表 | |2.开始/暂停 | |3.停止 | |4.上一个 | |5.下一个 | |6.快进 | |7.定位 | |8.播放方式 | |9.退出 | +-------------------+
查看播放列表二级页面如下: +-------------------+ | 视频播放器 | |-------------------| |1.张三的歌.mp4 | |2.李四的曲.avi | |... | +-------------------+
定位的二级页面 +-------------------+ | 视频播放器 | +-------------------+ 定位:XX:XX:XX 3.在一级页面启动播放列表功能,进入二级页面, 焦点定位到对应歌曲按下enter播放歌曲,按下 ESC按键能够返回一级页面 4.在一级页面启动下一个功能,能够播放下一个音 视频文件,如果到达最末尾则提示:最后一首歌曲 5.在一级页面启动上一个功能,能够播放上一个音 视频文件,如果到达最前面则提示:第一首歌曲
6.在一级页面启动快进功能,能够按倍速播放, 第一次选择启动2倍速播放 第二次选择启动4倍速播放 第三次选择返回1倍速播放(默认) 周而复始 7.在一级页面启动开始功能, 如果音视频正在播放,则暂停播放 如果音视频正在暂停,则继续播放 如果音视频文件没有播放,则按照 播放方式(1.顺序循环 2.单曲循环 3.随机播放) 播放歌曲 8.在一级页面启动停止功能: 如果音视频文件没有播放,则提示:未播放音视频文件 如果音视频正在播放,则停止当前播放内容 9.在一级页面启动定位功能: 如果定位在音视频文件播放时间内,则跳到对应位置播放 如果定位位置超过文件播放时间,则提示:定位错误 10.播放方式 在一级页面启动播放方式功能: 第一次选择启动单曲循环 第二次选择启动随机播放 第三次选择返回顺序循环(默认)
11.在一级页面启动退出功能: 则程序退出
二、思考内容: 1.如何使用颜色打印?printf颜色打印
printf("\033[0m \033[属性代码1;属性代码2;属性代码3...m字符串,\033[0m"); printf("\033[0m \033[格式命令如:闪烁;背景颜色;字体颜色m我是中国人 \033[0m\n"); printf("\033[0m \033[5;46;31m我是中国人! \033[0m\n"); //每一步骤的意义 printf("\033[0m");//清空设置 printf("\033[5;35;43m");//填写颜色设置 printf("我是中国人!\n");//要打印的内容 printf("\033[0m");//清空设置在使用完属性代码进行输出后,一定要用\033[0m重置一下,否则会影响到后续的输出。
需要注意的是用vscode进行闪烁属性的时候,无法正常闪烁,用虚拟机里面的终端就可以正常使用。
2.如何操作焦点位置?刚开始打印的位置就是start 到end之间的内容
然后focus进行向下移动,移动到end的位置
当走到end的之后 start ,end 和focus一起向下移动。
功能示例代码如下:
void MenuChoose(void) { char ch = 0; int medialen = 20; ch = getchar(); if ('w' == ch) { if (focus > pos_start) { focus--; } else if (focus == pos_start && pos_start == 0) { return; } else if (focus == pos_start) { pos_start--; pos_end--; focus--; } } else if ('s' == ch) { if (focus < pos_end) { focus++; } else if (focus == pos_end && pos_end == medialen) { return; } else if (focus == pos_end) { pos_start++; pos_end++; focus++; } } return; } 3.如何从终端接收上键?下键?回车?ESC按键?怎么接收上 下 键?上下不是一个字符。
ESC是 ^[ 看作是 : ESC + \n 对应的ascii码是27 和 10;
DOWN是^[ [B 看作是:ESC + [ + B 对应的ascii码是27 91 66
UP是^[ [B 看作是:ESC + [ + A 对应的ascii码是27 91 65
判断按键代码示例如下:
#include <stdio.h> #include <string.h> int main(int argc, const char *argv[]) { char str[32] = {0}; while (1) { memset(str, 0, sizeof(str)); fgets(str, sizeof(str), stdin); if (27 == str[0] && 10 == str[1]) { printf("ESC键!\n"); return; } else if (10 == str[0]) { printf("回车键!\n"); } else if (27 == str[0] && 91 == str[1]) { if (65 == str[2]) { printf("UP键!\n"); } else if (66 == str[2]) { printf("DOWN键!\n"); } } } return 0; } 4.如何加载音视频文件?调用mplyer通过音视频文件所在的路径来加载文件。
5.如何打印界面? #include <stdio.h> typedef struct media { int id; char medianame[512]; }MEDIA_CFG_S; typedef struct menuinfo { int id; int pos_start; int pos_end; int focus; }MENU_CFG_S; MEDIA_CFG_S medialist[32] = { {1, "张三的歌"}, {2, "张三的歌"}, {3, "张三的歌"}, {4, "张三的歌"}, {5, "张三的歌"}, {6, "张三的歌"}, {7, "张三的歌"}, {8, "张三的歌"}, {9, "张三的歌"}, {10, "张三的歌"}, {11, "张三的歌"}, {12, "张三的歌"}, {13, "张三的歌"}, {14, "张三的歌"}, {15, "张三的歌"}, {16, "张三的歌"}, {17, "张三的歌"}, {18, "张三的歌"}, {19, "张三的歌"}, {20, "张三的歌"}, {21, "张三的歌"}, }; int pos_start; //界面起始位置 int pos_end = 10; //界面结束位置 int focus; //界面焦点位置 int menulevel = 2; //一级界面 void MenuShow(void) { int i = 0; if (menulevel == 2) { printf("+-----------------------------+\n"); printf("| 音视频播放器 |\n"); printf("|-----------------------------|\n"); for (i = pos_start; i <= pos_end; i++) { if (i == focus) { printf("|\033[30;43m%2d.%-30s\033[0m|\n", medialist[i].id, medialist[i].medianame); } else { printf("|%2d.%-30s|\n", medialist[i].id, medialist[i].medianame); } } printf("+-----------------------------+\n"); } else { } return; } void MenuChoose(void) { char ch = 0; int medialen = 20; ch = getchar(); if ('w' == ch) { if (focus > pos_start) { focus--; } else if (focus == pos_start && pos_start == 0) { return; } else if (focus == pos_start) { pos_start--; pos_end--; focus--; } } else if ('s' == ch) { if (focus < pos_end) { focus++; } else if (focus == pos_end && pos_end == medialen) { return; } else if (focus == pos_end) { pos_start++; pos_end++; focus++; } } return; } int main(int argc, const char *argv[]) { while (1) { system("clear"); MenuShow(); MenuChoose(); } return 0; }这里就是打印界面,每按一次上下键都会打印一次完整的显示,所以调用system("clear");将之前打印的清除掉,然后在进行打印,这样就只保存了最后一次的打印。
6.如何存储所有的音视频文件?用一个二维的数组,每一行都存储一个音视频文件的路径
7.如何控制mplayer播放器?fork + exec来进行播放,也就是创建子进程来播放mplayer。
示例代码如下:
#include <stdio.h> #include <unistd.h> #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> #include <string.h> #include <stdlib.h> int main(int argc, const char *argv[]) { pid_t pid; int fd = 0; char tmpbuff[1024] = {0}; pid = fork(); if (-1 == pid) { perror("fail to fork"); return -1; } if (0 == pid) { execlp("mplayer", "mplayer", "-slave", "-input", "file=/tmp/myfifo", "../1.flv", "-quiet", NULL); } else if (pid > 0) { fd = open("/tmp/myfifo", O_RDWR); if (-1 == fd) { perror("fail to open"); return -1; } while (1) { fgets(tmpbuff, sizeof(tmpbuff), stdin); //pause\n write(fd, tmpbuff, strlen(tmpbuff)); } close(fd); } return 0; }那怎么控制mplayer?
在mplayer工作的时候,可以指定一个从属模式设置一个管道,打开这个管道然后写命令。
三、软件编写1.查看播放列表:在指定目录下遍历文件,找到以媒体文件结尾的文件名,将其路径存储在变量中
2.开始/暂停: fork + exec(mplayer)
3.停止:向管道中写入命令
4.上一首:
5.下一首:
6.快进:向管道中写入命令
7.定位:向管道中写入命令
8.播放方式:SIGCHLD证明有子进程结束了
9.退出:进程任务结束,如果mplayer正在播放,将mplayer结束
1.head.h #ifndef __HEAD_H__ #define __HEAD_H__ extern int LoadMediaFile(char *pDirName); extern void ShowMediaList(void); extern int StopMedia(void); extern int PlayMedia(int MediaIndex); extern int ExecUserChoose(int No); extern int GetUserChoose(void); extern void ShowMenu(void); extern int PauseMedia(void); extern int SetMediaSpeed(void); extern int SetMediaPosition(void); extern void SwitchMediaMode(void); extern void sigchild_handler(int signo); extern char MediaList[100][256]; //存放媒体文件列表 extern int CurMediaLen; //当前加载的媒体文件个数 //是否为播放上一首 extern int IsPlayPre; //是否为播放下一首 extern int IsPlayNext; #endif 2.main.c /*************************************************** * * 主函数 * **************************************************/ #include <stdio.h> #include "head.h" int main(void) { int No = 0; while (1) { CurMediaLen = LoadMediaFile("/home/linux/Music"); ShowMenu(); No = GetUserChoose(); if (9 == No) { break; } ExecUserChoose(No); } return 0; } 3.menu.c /*************************************************** * * 界面相关代码 * **************************************************/ #include "head.h" #include <stdio.h> #include <signal.h> #include <sys/types.h> #include <sys/wait.h> /*************************************************** *函数名:ShowMenu *功 能: * 显示界面 *参数: * void *返回值: * void ***************************************************/ void ShowMenu(void) { printf("===========================================\n"); printf("1.查看播放列表\n"); printf("2.开始/暂停\n"); printf("3.停止\n"); printf("4.上一首\n"); printf("5.下一首\n"); printf("6.快进\n"); printf("7.定位\n"); printf("8.播放方式\n"); printf("9.退出\n"); printf("===========================================\n"); return; } /*************************************************** *函数名:GetUserChoose *功 能: * 获得用户的选择 *参数: * void *返回值: * 用户选择的选项编号 ***************************************************/ int GetUserChoose(void) { int No = 0; printf("请选择:\n"); scanf("%d", &No); return No; } /*************************************************** *函数名:PlayNext *功 能: * 播放下一首 *参数: * void *返回值: * void ***************************************************/ void PlayNext(void) { StopMedia(); IsPlayNext = 1; return; } /*************************************************** *函数名:PlayPre *功 能: * 播放下一首 *参数: * void *返回值: * void ***************************************************/ void PlayPre(void) { StopMedia(); IsPlayPre = 1; return; } /*************************************************** *函数名:ExecUserChoose *功 能: * 执行用户选择 *参数: * No: 用户选择的选项编号 *返回值: * 成功返回0 * 失败返回-1 ***************************************************/ int ExecUserChoose(int No) { if (1 == No) { ShowMediaList(); } else if (2 == No) { PauseMedia(); } else if (3 == No) { signal(SIGCHLD, SIG_DFL); StopMedia(); wait(NULL); signal(SIGCHLD, sigchild_handler); } else if (4 == No) { PlayPre(); } else if (5 == No) { PlayNext(); } else if (6 == No) { SetMediaSpeed(); } else if (7 == No) { SetMediaPosition(); } else if (8 == No) { SwitchMediaMode(); } else if (9 == No) { signal(SIGCHLD, SIG_DFL); StopMedia(); } return 0; } 4.mplayer.c /*************************************************** * * 媒体相关代码 * **************************************************/ #include <dirent.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <sys/wait.h> #include <time.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <signal.h> #include "head.h" //存放媒体文件列表 char MediaList[100][256] = {0}; //当前加载的媒体文件个数 int CurMediaLen = 0; //当前播放的媒体的编号 int CurMediaIndex = 0; //Mplayer播放方式 typedef enum MediaMode { MPLAYER_MODE_NEXT = 1, MPLAYER_MODE_SINGLE = 2, MPLAYER_MODE_RANDOM = 3, }MPLAYER_MODE_EN; //当前播放模式 MPLAYER_MODE_EN CurMediaMode = MPLAYER_MODE_NEXT; //Mplayer播放速度 typedef enum MediaSpeed { MPLAYER_SPEED_ONE = 1, MPLAYER_SPEED_TWO = 2, MPLAYER_SPEED_FOUR = 4, }MPLAYER_SPEED_EN; //当前播放速度 MPLAYER_SPEED_EN CurMediaSpeed = MPLAYER_SPEED_ONE; //Mplayer播放状态 typedef enum MediaStat { MPLAYER_STAT_FREE, //空闲状态 MPLAYER_STAT_PLAY, //播放状态 MPLAYER_STAT_PAUSE, //暂停状态 }MPLAYER_STAT_EN; //当前播放状态 MPLAYER_STAT_EN CurMediaStat = MPLAYER_STAT_FREE; //是否为播放上一首 int IsPlayPre = 0; //是否为播放下一首 int IsPlayNext = 0; /*************************************************** *函数名:IsMediaFile *功 能: * 判断是否为媒体文件 *参数: * pfilename: 文件名 *返回值: * 成功返回 1 * 失败返回 0 ***************************************************/ int IsMediaFile(char *pfilename) { char *ptmp = NULL; //helloworld.mp4 ptmp = pfilename + strlen(pfilename); while (ptmp >= pfilename && *ptmp != '.') { ptmp--; } if (!strcmp(ptmp, ".mp3") || !strcmp(ptmp, ".mp4") || !strcmp(ptmp, ".flv")) { return 1; } return 0; } /*************************************************** *函数名:LoadMediaFile *功 能: * 加载指定目录下所有的媒体(.mp3、.mp4、.avi、.flv)文件 *参数: * pDirName: 存放媒体文件的目录 *返回值: * 成功返回实际加载媒体文件个数 * 失败返回 -1 ***************************************************/ int LoadMediaFile(char *pDirName) { //1.遍历目录文件下的所有文件名 DIR *dp = NULL; struct dirent *pp = NULL; int cnt = 0; dp = opendir(pDirName); if (NULL == dp) { return -1; } while (1) { pp = readdir(dp); if (NULL == pp) { break; } if ('.' == *pp->d_name) { continue; } if (IsMediaFile(pp->d_name)) { sprintf(MediaList[CurMediaLen], "%s/%s", pDirName, pp->d_name); CurMediaLen++; cnt++; } } closedir(dp); return cnt; } /*************************************************** *函数名:sigchild_handler *功 能: * 播放完毕处理函数 *参数: * signo:信号的编号 *返回值: * void ***************************************************/ void sigchild_handler(int signo) { wait(NULL); if (IsPlayNext) { if (CurMediaIndex == CurMediaLen) { printf("已经到最末尾了!\n"); return; } else { PlayMedia(CurMediaIndex+1); } IsPlayNext = 0; return; } if (IsPlayPre) { if (CurMediaIndex == 0) { printf("已经到最开头了!\n"); return; } else { PlayMedia(CurMediaIndex-1); } IsPlayPre = 0; return; } if (CurMediaMode == MPLAYER_MODE_NEXT) { if (CurMediaIndex == CurMediaLen) { printf("已经到最末尾了!\n"); return; } else { PlayMedia(CurMediaIndex+1); } } else if (CurMediaMode == MPLAYER_MODE_SINGLE) { PlayMedia(CurMediaIndex); } else if (CurMediaMode == MPLAYER_MODE_RANDOM) { srand(time(NULL)); PlayMedia(rand() % CurMediaLen); } return; } /*************************************************** *函数名:PlayMedia *功 能: * 播放媒体文件 *参数: * MediaIndex:媒体文件的编号 *返回值: * 成功返回 0 * 失败返回 -1 ***************************************************/ int PlayMedia(int MediaIndex) { pid_t pid; signal(SIGCHLD, sigchild_handler); pid = fork(); if (-1 == pid) { return -1; } if (0 == pid) { mkfifo("/tmp/myfifo", 0664); close(1); close(2); execlp("mplayer", "mplayer", "-slave", "-input", "file=/tmp/myfifo", MediaList[MediaIndex], NULL); } CurMediaIndex = MediaIndex; CurMediaStat = MPLAYER_STAT_PLAY; CurMediaSpeed = MPLAYER_SPEED_ONE; return 0; } /*************************************************** *函数名:ShowMediaList *功 能: * 打印媒体列表 *参数: * void *返回值: * void ***************************************************/ void ShowMediaList(void) { int i = 0; int No = -1; for (i = 0; i < CurMediaLen; i++) { printf("%d.%s\n", i+1, MediaList[i]); } while (1) { printf("请选择播放的歌曲编号(输入0返回上一级)\n"); scanf("%d", &No); if (0 == No) { break; } PlayMedia(No-1); } return; } /*************************************************** *函数名:StopMedia *功 能: * 停止播放媒体文件 *参数: * void *返回值: * 成功返回 0 * 失败返回 -1 ***************************************************/ int StopMedia(void) { int fd = 0; fd = open("/tmp/myfifo", O_RDWR); if (-1 == fd) { return -1; } write(fd, "stop\n", 5); CurMediaStat = MPLAYER_STAT_FREE; close(fd); return 0; } /*************************************************** *函数名:PauseMedia *功 能: * 暂停媒体文件 *参数: * void *返回值: * 成功返回 0 * 失败返回 -1 ***************************************************/ int PauseMedia(void) { int fd = 0; fd = open("/tmp/myfifo", O_RDWR); if (-1 == fd) { return -1; } write(fd, "pause\n", 6); close(fd); if (MPLAYER_STAT_PLAY == CurMediaStat) { CurMediaStat = MPLAYER_STAT_PAUSE; } else if (MPLAYER_STAT_PAUSE == CurMediaStat) { CurMediaStat = MPLAYER_STAT_PLAY; } return 0; } /*************************************************** *函数名:SetMediaSpeed *功 能: * 设置媒体播放速度 *参数: * void *返回值: * 成功返回 0 * 失败返回 -1 ***************************************************/ int SetMediaSpeed(void) { int fd = 0; fd = open("/tmp/myfifo", O_RDWR); if (-1 == fd) { return -1; } if (MPLAYER_SPEED_ONE == CurMediaSpeed) { write(fd, "speed_set 2\n", 12); CurMediaSpeed = MPLAYER_SPEED_TWO; } else if (MPLAYER_SPEED_TWO == CurMediaSpeed) { write(fd, "speed_set 4\n", 12); CurMediaSpeed = MPLAYER_SPEED_FOUR; } else if (MPLAYER_SPEED_FOUR == CurMediaSpeed) { write(fd, "speed_set 1\n", 12); CurMediaSpeed = MPLAYER_SPEED_ONE; } close(fd); return 0; } /*************************************************** *函数名:SetMediaPosition *功 能: * 设置媒体播放位置 *参数: * void *返回值: * 成功返回 0 * 失败返回 -1 ***************************************************/ int SetMediaPosition(void) { int fd = 0; int n = 0; char cmdbuf[1024] = {0}; fd = open("/tmp/myfifo", O_RDWR); if (-1 == fd) { return -1; } printf("请输入秒数:\n"); scanf("%d", &n); sprintf(cmdbuf, "seek %d 2\n", n); write(fd, cmdbuf, strlen(cmdbuf)); close(fd); return 0; } /*************************************************** *函数名:SwitchMediaMode *功 能: * 切换媒体播放模式 *参数: * void *返回值: * 成功返回 0 * 失败返回 -1 ***************************************************/ void SwitchMediaMode(void) { if (CurMediaMode == MPLAYER_MODE_NEXT) { printf("切换为:单曲循环\n"); CurMediaMode = MPLAYER_MODE_SINGLE; } else if (CurMediaMode == MPLAYER_MODE_SINGLE) { printf("切换为:随机播放\n"); CurMediaMode = MPLAYER_MODE_RANDOM; } else if (CurMediaMode == MPLAYER_MODE_RANDOM) { printf("切换为:顺序播放\n"); CurMediaMode = MPLAYER_MODE_NEXT; } return; } 5.makefile a.out:main.c menu.c mplayer.c gcc $^ -o $@ 四、工作方式Myplater项目由讯客互联其他栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“Myplater项目”