主页 > 其他  > 

Myplater项目

Myplater项目
一、项目要求

.基于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项目