使用Mplayer实现MP3功能

核心功能

1. 界面设计

项目首先定义了一个clearscreen函数,用于清空屏幕,为用户界面的更新提供了便利。yemian函数负责显示主菜单界面,提供了包括查看播放列表、播放控制、播放模式选择等在内的9个选项。

2. 文件格式支持

is_supported_file函数用于检测文件扩展名,确保只有支持的视频和音频文件被播放器处理。目前支持的格式包括.mp4.avi等。

3. 文件列表展示

print_file_list函数遍历指定目录,列出所有支持的视频文件,并由allnum变量记录文件总数。

4. 播放控制

open_file函数根据用户选择打开相应的视频文件,并使用mplayer命令行工具进行播放。通过execvp系统调用,我们可以启动mplayer进程并传递必要的参数。

5. 命令发送

send_command_to_mplayer函数通过命名管道与mplayer进程通信,发送播放控制命令,如停止、暂停、快进等。

6. 播放模式

control_mplayer函数实现了一个循环,根据用户输入的选项,执行不同的播放控制逻辑。它还处理了播放模式的切换,包括列表循环、单曲循环和随机播放。

7. 多进程管理

项目使用了fork系统调用创建子进程来运行mplayer,并通过管道与主进程通信,实现了进程间的同步和数据传递。

项目代码

#include <stdio.h>
#include<time.h>
#include<string.h>
#include<stdlib.h>
#include <unistd.h>
#include <termios.h>
#include<dirent.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <errno.h>

void clearscreen() {
	printf("\033[2J");
}

void yemian() 
{

	clearscreen();
	printf("                  +-----------------------------------+\n");
	printf("                  |          视频播放器               |\n");
	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");
}

int is_supported_file(const char *filename) {
	const char *extensions[] = {".mp4", ".avi", ".flv", ".wma", ".rmvb", ".mp3", ".rm",NULL}; // 支持的文件扩展名
	const char **ext = extensions; 
	while (*ext != NULL) {
		if (strstr(filename, *ext) != NULL) {
			return 1;
		}
		ext++;
	}
	return 0;
}

int allnum;
int print_file_list(DIR *dir) {
	struct dirent *entry;
	int i=1;
	while ((entry = readdir(dir)) != NULL) {
		if (is_supported_file(entry->d_name)) {
			printf("                  |%d %s                    \n",i++, entry->d_name);
		}
	}
	return i-1;
}

void print_file_list2() {
	int i=1;
	printf("                  |%d list_cycle                   \n",i++);
	printf("                  |%d single_cycle                    \n",i++);
	printf("                  |%d random_cycle                    \n",i++);
}

int open_file(DIR *dir, const char *base_path, int n) {
	struct dirent *entry;
	int count = 0;
	rewinddir(dir);
	while ((entry = readdir(dir)) != NULL) {
		if (is_supported_file(entry->d_name)) {
			count++;
			if (count == n) {
				char full_path[1024];
				snprintf(full_path, sizeof(full_path), "%s%s%s", base_path,"/", entry->d_name);
				char *argv[] = {"mplayer", "-slave", "-quiet", "-input", "file=/tmp/fifofile", full_path, NULL};
				if(execvp("mplayer", argv) == -1) {
					perror("execvp failed");
				}
				break;
			}
		}
	}
	return count;
}

int page2(const char *dirname) {
	clearscreen();
	printf("                  +-----------------------------------+\n");
	printf("                  |       视频文件播放列表            |\n");
	printf("                  +-----------------------------------+\n");
	DIR *dir = opendir(dirname);
	if (dir == NULL) {
		perror("打开目录失败");
	}
	printf("                  |以下是可播放的视频文件列表:         |\n");
	int t= print_file_list(dir);
	closedir(dir);
	printf("                  +-----------------------------------+\n");
	return t;
}

int page3() {
	clearscreen();
	printf("                  +-----------------------------------+\n");
	printf("                  |  请选择你的播放模式               |\n");
	printf("                  +-----------------------------------+\n");
	print_file_list2();
	printf("                  |                                   |\n");
	printf("                  +-----------------------------------+\n");
}

int position;
char temp[1000];
void func1(const char*dirname,int n) {

	DIR *dir = opendir(dirname);
	if (dir == NULL) {
		perror("打开目录失败");
	}
	open_file(dir,dirname,n);
	closedir(dir);
}

#define FIFO_NAME "/tmp/fifofile"
void send_command_to_mplayer(const char *command) {
	int fd_fifo = open(FIFO_NAME, O_WRONLY);
	if (fd_fifo < 0) {
		perror("open FIFO for writing");
		return;
	}
	write(fd_fifo, command, strlen(command));
	close(fd_fifo);
}

int mode=1;
void control_mplayer() {
	int command;
	while (1) {
		yemian(); // 显示菜单
		printf("请输入操作选项:");
		scanf("%d", &command);
		switch (command) {
		case 1:
			send_command_to_mplayer("stop\n");
			system("./a.out");
			break;
		case 2:
			send_command_to_mplayer("pause\n");
			break;
		case 3:
			send_command_to_mplayer("stop\n");
			break;
		case 4:
			send_command_to_mplayer("stop\n");
			sleep(1); // 这里只是示例,具体时间需要根据您的程序调整
			if (mkfifo(FIFO_NAME, 0666) == -1 && errno != EEXIST) {
				perror("mkfifo");
				exit(EXIT_FAILURE);
			}
			int pipefd[2];
			if (pipe(pipefd) == -1) {
				perror("pipe");
				exit(EXIT_FAILURE);
			}
			pid_t mplayer_pid = fork();
			if (mplayer_pid == -1) {;
				perror("fork");
				exit(EXIT_FAILURE);
			}
			if (mplayer_pid == 0) {
				close(pipefd[0]);
				write(pipefd[1], &(mode), sizeof(mode));
				if(position>0&&position<(allnum+1))
				{
					if(mode==1&&position!=1)
					{
						position--;
					}
					if(mode==2)
					{
					}
					if(mode==3)
					{
						srand((unsigned int)time(NULL));
						position=1 + (rand() % 3);
					}
				}
				write(pipefd[1], &(position), sizeof(position));
				close(pipefd[1]);
				sleep(1);
				func1(temp,position);
			}
			close(pipefd[1]);
			read(pipefd[0], &mode, sizeof(mode));
			read(pipefd[0], &position, sizeof(position));
			close(pipefd[0]);
			sleep(2); // 等待时间可能需要调整
			control_mplayer();
			unlink(FIFO_NAME);
			waitpid(mplayer_pid, NULL, 0);
			break;
		case 5:
			send_command_to_mplayer("stop\n");
			sleep(1); // 这里只是示例,具体时间需要根据您的程序调整
			if (mkfifo(FIFO_NAME, 0666) == -1 && errno != EEXIST) {
				perror("mkfifo");
				exit(EXIT_FAILURE);
			}
			int pipefd1[2];
			if (pipe(pipefd1) == -1) {
				perror("pipe");
				exit(EXIT_FAILURE);
			}
			pid_t mplayer_pid1 = fork();
			if (mplayer_pid1 == -1) {;
				perror("fork");
				exit(EXIT_FAILURE);
			}
			if (mplayer_pid1 == 0) {
				close(pipefd1[0]);
				write(pipefd1[1], &(mode), sizeof(mode));
				if(position>0&&position<allnum+1)
				{	
					if(mode==1&&position!=allnum)
					{
						position++;
					}
					if(mode==2)
					{
					}
					if(mode==3)
					{
						srand((unsigned int)time(NULL));
						position=1 +(rand()%3);
					}
				}
				write(pipefd1[1], &(position), sizeof(position));
				close(pipefd1[1]);
				sleep(1);
				func1(temp,position);
			}
			close(pipefd1[1]);
			read(pipefd1[0], &mode, sizeof(mode));
			read(pipefd1[0], &position, sizeof(position));
			close(pipefd1[0]);
			sleep(2); // 等待时间可能需要调整
			control_mplayer();
			unlink(FIFO_NAME);
			waitpid(mplayer_pid1, NULL, 0);
			break;
		case 6:
			printf("请你输入你需要播放的倍速");
			float speed_rate;
			scanf("%f",&speed_rate);
			char speed_command[50];
			snprintf(speed_command, sizeof(speed_command), "speed_set %f\n", speed_rate);
			send_command_to_mplayer(speed_command);
			break;
		case 7:
			printf("请你输入你需要定到的位置");
			int num2;
			scanf("%d",&num2);
			char seek_command[50];
			snprintf(seek_command, sizeof(seek_command), "seek %d 1\n",num2);
			send_command_to_mplayer(seek_command);
			break;
		case 8:
			page3();
			printf("请输入您想要的播放模式(1-列表循环,2-单曲循环,3-随机播放):");
			scanf("%d",&mode);
			sleep(2);
			break;
		case 9:
			// 发送退出命令给 MPlayer,然后退出控制循环
			send_command_to_mplayer("quit\n");
			break;
		default:
			printf("未知的命令,请重新输入。\n");
			break;
		}
	}
}

int main() {
	if (mkfifo(FIFO_NAME, 0666) == -1 && errno != EEXIST) {
		perror("mkfifo");
		exit(EXIT_FAILURE);
	}
	int pipefd[2];
	if (pipe(pipefd) == -1) {
		perror("pipe");
		exit(EXIT_FAILURE);
	}
	pid_t mplayer_pid = fork();
	if (mplayer_pid == -1) {;
		perror("fork");
		exit(EXIT_FAILURE);
	}

	if (mplayer_pid == 0) {
		close(pipefd[0]);
		char dirname[1024];
		printf("请输入目录路径: ");
		fgets(dirname, sizeof(dirname), stdin);
		size_t len = strlen(dirname);
		if(len > 0 && dirname[len - 1] == '\n') {
			dirname[len - 1] = '\0';
		}
		strcpy(temp,dirname);
		allnum=page2(dirname);
		printf("please input the Video_no");
		int t;
		scanf("%d",&t);

		position=t;
		write(pipefd[1], &position, sizeof(position));
		write(pipefd[1], temp, sizeof(temp));
		write(pipefd[1], &allnum, sizeof(allnum));
		sleep(5);
		func1(dirname,t);
		close(pipefd[1]);
	}

	close(pipefd[1]);
	read(pipefd[0], &position, sizeof(position));
	read(pipefd[0], temp, sizeof(temp));
	read(pipefd[0], &allnum, sizeof(allnum));
	close(pipefd[0]);
	sleep(8); // 等待时间可能需要调整
	control_mplayer();
	unlink(FIFO_NAME);
	waitpid(mplayer_pid, NULL, 0);
	return 0;
}

项目流程图

项目挑战

在开发过程中,我遇到了不少挑战,比如如何优雅地处理用户输入、如何确保进程间通信的可靠性等。通过查阅资料和不断调试,我逐步克服了这些难题。

项目收获

通过这个项目,我不仅提升了自己的编程能力,也对操作系统的原理有了更深入的理解。此外,我还学会了如何设计用户友好的命令行界面,以及如何处理多进程编程中的同步问题。

结语

这个视频播放器项目是我学习旅程中的一个里程碑。我相信,随着技术的不断进步,我将能够开发出更加复杂和功能丰富的应用程序。感谢大家的阅读,希望我的分享能给大家带来一些启发。

相关推荐

  1. 用 reduce 实现 map功能

    2024-07-10 10:06:02       50 阅读
  2. GoLang学习-Redis实现MQ功能

    2024-07-10 10:06:02       31 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-10 10:06:02       99 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-10 10:06:02       107 阅读
  3. 在Django里面运行非项目文件

    2024-07-10 10:06:02       90 阅读
  4. Python语言-面向对象

    2024-07-10 10:06:02       98 阅读

热门阅读

  1. 大数据平台之Hive Metastore

    2024-07-10 10:06:02       27 阅读
  2. 《框架封装 · Redis 事件监听》

    2024-07-10 10:06:02       28 阅读
  3. Knife4j的原理及应用详解(四)

    2024-07-10 10:06:02       32 阅读
  4. Stable Diffusion 深入浅出,一看就会

    2024-07-10 10:06:02       29 阅读
  5. Oracle 动态编译数据库对象

    2024-07-10 10:06:02       29 阅读
  6. 从“技术驱动”向“应用驱动”

    2024-07-10 10:06:02       35 阅读
  7. HTML(30)——动画

    2024-07-10 10:06:02       28 阅读
  8. 贪心算法-以高校教材管理系统为例

    2024-07-10 10:06:02       26 阅读