这是一个非常经典的外部程序控制(IPC - Inter-Process Communication)场景,核心思想是:你的C程序不直接处理音视频,而是像用户在终端里一样,通过命令行去“指挥”mplayer这个外部程序来完成播放、暂停、停止等操作。

实现这个目标主要有两种主流方法:
- 管道:这是最常用、最灵活的方法,你的C程序可以向
mplayer发送命令,并读取mplayer的输出(如播放进度、状态等)。 - 系统调用:通过
system()函数直接执行mplayer的命令,这种方法简单粗暴,但无法与mplayer进行实时交互。
下面我们重点讲解功能更强大的管道方法,并简要介绍系统调用。
使用管道进行实时控制(推荐)
这种方法的核心是使用 popen() 函数。popen() 会创建一个管道,允许你的C程序通过这个管道向一个新启动的进程(这里是mplayer)发送输入,或者从该进程读取输出。
工作流程
- 启动
mplayer:使用popen()以“写”模式启动mplayer。mplayer会进入“slave”模式(从属模式),等待接收来自标准输入的命令。 - 发送命令:你的C程序通过写入管道,向
mplayer发送命令,pause,seek,volume等。 - 读取反馈(可选):如果你想获取播放状态(如当前时间、总时长),可以重新以“读”模式打开
mplayer,或者启动一个专门的mplayer实例来输出信息。 - 关闭管道:当你完成所有操作后,关闭管道,
popen()会自动关闭并等待mplayer进程结束。
详细代码示例
下面是一个完整的C语言示例,它演示了如何启动mplayer,并实现播放、暂停、音量控制、进度跳转等功能。

准备工作
-
安装 MPlayer 在Linux上,通常使用包管理器安装:
# 对于 Debian/Ubuntu sudo apt-get update sudo apt-get install mplayer # 对于 CentOS/RHEL/Fedora sudo yum install mplayer # 或者 sudo dnf install mplayer
-
准备一个测试视频文件 在你的C程序同目录下放一个名为
test.mp4的视频文件。
C语言代码 (mplayer_controller.c)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h> // 用于 sleep 函数
// 定义向 mplayer 发送命令的函数
void send_command_to_mplayer(FILE *mplayer_pipe, const char *command) {
if (mplayer_pipe != NULL) {
// 将命令和换行符写入管道
fprintf(mplayer_pipe, "%s\n", command);
// 刷新缓冲区,确保命令立即发送
fflush(mplayer_pipe);
printf("已发送命令: %s\n", command);
} else {
perror("无法向 mplayer 发送命令");
}
}
int main() {
// 1. 启动 MPlayer
// "mplayer -slave -quiet -input file=/tmp/mplayer_pipe test.mp4"
// -slave: 启用从属模式,接受命令
// -quiet: 减少不必要的输出
// -input file=<path>: 指定命令输入文件,这是更稳定的方式,比管道更推荐
const char *video_file = "test.mp4";
char command_str[256];
snprintf(command_str, sizeof(command_str), "mplayer -slave -quiet -input file=/tmp/mplayer_fifo %s", video_file);
// 使用 popen 以 "w" (写) 模式启动 mplayer
// 注意:直接用管道有时不稳定,推荐使用 -input file 指定一个命名管道
// 这里为了演示,我们先用 popen,更健壮的方式是先创建命名管道 mkfifo /tmp/mplayer_fifo
FILE *mplayer_pipe = popen(command_str, "w");
if (mplayer_pipe == NULL) {
perror("popen 失败,请确保 mplayer 已安装");
return 1;
}
printf("MPlayer 已启动,正在播放: %s\n", video_file);
printf("程序将演示几个控制命令...\n");
// 等待几秒,让视频开始播放
sleep(3);
// 2. 发送控制命令
send_command_to_mplayer(mplayer_pipe, "pause"); // 暂停/继续
sleep(2);
send_command_to_mplayer(mplayer_pipe, "volume 50 1"); // 设置音量为 50 (0-100), 1表示绝对音量
sleep(2);
send_command_to_mplayer(mplayer_pipe, "seek 10 0"); // 快进 10 秒 (0 表示绝对时间)
sleep(2);
send_command_to_mplayer(mplayer_pipe, "seek -5 1"); // 后退 5 秒 (1 表示相对时间)
sleep(2);
send_command_to_mplayer(mplayer_pipe, "quit"); // 退出 mplayer
// 3. 关闭管道
pclose(mplayer_pipe);
printf("MPlayer 已关闭,程序结束,\n");
return 0;
}
如何编译和运行
-
创建命名管道(推荐做法,比
popen更稳定)mplayer的-input file选项需要一个已经存在的命名管道文件。mkfifo /tmp/mplayer_fifo
这个命令创建了一个名为
mplayer_fifo的特殊文件,你的C程序可以向它写入,而mplayer会从另一端读取。
(图片来源网络,侵删) -
修改代码(使用命名管道) 将上面代码中
popen的命令字符串修改为:// 注意:这里我们不再需要 popen 来管理 mplayer 的输入 // 而是直接启动 mplayer,让它自己从 /tmp/mplayer_fifo 读取命令 snprintf(command_str, sizeof(command_str), "mplayer -slave -quiet -input file=/tmp/mplayer_fifo %s &", video_file);
你的C程序需要用
fopen()来打开这个命名管道进行写入:FILE *mplayer_pipe = fopen("/tmp/mplayer_fifo", "w"); if (mplayer_pipe == NULL) { perror("无法打开命名管道"); return 1; } // ... 发送命令的代码不变 ... fclose(mplayer_pipe); // 关闭文件描述符这种方式下,
mplayer和你的C程序是两个独立运行的进程,通信更可靠。 -
编译
gcc mplayer_controller.c -o mplayer_controller
-
运行
# 确保你的 test.mp4 文件在当前目录 ./mplayer_controller
你将看到终端输出命令信息,同时视频窗口会弹出并执行相应的操作(播放、暂停、快进等)。
常用 MPlayer Slave 模式命令
通过管道,你可以发送以下命令来控制 mplayer:
| 命令 | 描述 | 示例 |
|---|---|---|
pause |
暂停/继续播放 | pause |
quit |
退出 mplayer |
quit |
get_time_length |
获取视频总时长(秒),输出到标准错误 | get_time_length |
get_time_pos |
获取当前播放位置(秒),输出到标准错误 | get_time_pos |
seek |
跳转时间 | seek 10 (跳到第10秒) seek 10 1 (从当前位置快进10秒) seek -5 1 (从当前位置后退5秒) |
speed_set |
设置播放速度 | speed_set 2.0 (2倍速) |
volume |
设置音量 | volume 80 (设置音量为80) volume 80 1 (绝对音量设置为80) |
get_volume |
获取当前音量,输出到标准错误 | get_volume |
fullscreen |
切换全屏 | fullscreen |
sub_select |
选择字幕 | sub_select 0 (选择第一个字幕) |
使用 system() 函数(简单但不灵活)
这种方法非常简单,就是直接调用命令行,但无法进行交互。
示例代码
#include <stdio.h>
#include <stdlib.h>
int main() {
printf("使用 system() 启动 MPlayer 播放视频...\n");
// 直接执行 mplayer 命令
// system() 会阻塞你的C程序,直到 mplayer 播放完毕或被用户关闭
int status = system("mplayer test.mp4");
if (status == -1) {
perror("system() 调用失败");
} else {
printf("MPlayer 已退出,退出码: %d\n", WEXITSTATUS(status));
}
return 0;
}
缺点
- 无法交互:你的C程序在
system()调用期间会“卡住”,无法在播放过程中发送新的命令(如暂停)。 - 效率低:每次调用
system()都会创建一个新的shell进程,开销较大。 - 获取信息困难:很难直接获取
mplayer的播放状态或输出。
| 方法 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 管道 | 功能强大,可实时交互,能获取播放状态,控制灵活。 | 实现相对复杂,需要理解进程间通信。 | 绝大多数需要控制播放器的应用,如GUI前端、自动化脚本等。 |
| 系统调用 | 实现极其简单,代码量少。 | 无法交互,功能单一,效率低。 | 只需简单启动播放,无需任何控制的场景。 |
对于在C语言中控制mplayer,强烈推荐使用管道(最好是命名管道)的方法,它为你提供了最大的灵活性和控制力。
