news 2026/9/6 20:03:54

mpv JSON IPC 协议完全解析:通过 Unix Socket 与命名管道远程控制播放器

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
mpv JSON IPC 协议完全解析:通过 Unix Socket 与命名管道远程控制播放器

mpv JSON IPC 协议完全解析:通过 Unix Socket 与命名管道远程控制播放器

【免费下载链接】mpv🎥 Command line media player项目地址: https://gitcode.com/GitHub_Trending/mp/mpv

本文以 mpv 官方 IPC 文档(DOCS/man/ipc.rst)为主体,系统讲解 mpv 的 JSON IPC 控制协议:如何用--input-ipc-server/--input-ipc-client建立连接、消息格式与request_id机制、异步命令、属性观察、UTF-8 边界问题与 JSON 扩展语法,并结合 input/ipc.c、input/ipc-unix.c、input/ipc-win.c 等源码实现,帮助读者既能快速上手 shell 控制,又能深入理解协议在 mpv 内部的落地方式。

1. IPC 是什么、不是什么

mpv 支持外部程序通过基于 JSON 的 IPC 协议来控制播放器:客户端连接到一个 socket(Unix 域 socket 或命名管道),向播放器发送命令、接收回复与事件。启用方式有两个选项:

  • --input-ipc-server=<path>:在指定路径(Unix socket 或命名管道)上监听,供任意多个客户端连接;
  • --input-ipc-client=fd://<N>:不创建 socket,而是把继承的某个文件描述符当作一条已经accept()到的连接使用(Windows 下还支持handle://<N>)。

安全边界必须牢记:官方文档明确警告,IPC 不是一个安全的网络协议——没有认证、没有加密,且暴露了诸如run这类可执行任意系统命令的危险命令。它的设计用途就是本地控制播放器,地位等同于 MPlayer 时代的 slave 协议。因此任何跨网络或跨用户的暴露都不可接受。

两个选项的注册定义在 options/options.c(第 917–918 行)中:

{"input-ipc-server", OPT_STRING(ipc_path), .flags = M_OPT_FILE}, {"input-ipc-client", OPT_STRING(ipc_client)},

注意input-ipc-server带有M_OPT_FILE标志,路径会经过mp_get_user_path()展开(见 input/ipc-unix.c 中mp_init_ipc()),因此支持~$等展开规则。完整的选项说明(含 Linux 抽象命名空间@前缀、Windows 下\\.\pipe\前缀自动补全等行为)见 DOCS/man/options.rst 中--input-ipc-server/--input-ipc-client条目。

从 input/ipc-unix.c 的mp_init_ipc()可以印证文档中的行为细节:--input-ipc-client的取值必须以fd://开头并跟一个整数 FD,否则打印Invalid IPC client argument并放弃该特性。

2. 命令行实战:socat 与 Windows 命令提示符

2.1 Linux / Unix:socat

假设 mpv 以如下方式启动:

mpv file.mkv --input-ipc-server=/tmp/mpvsocket

即可用 socat 发送 JSON 命令并读取回复(socat 在 stdin/stdout 与 mpv socket 连接之间搬运数据):

> echo '{ "command": ["get_property", "playback-time"] }' | socat - /tmp/mpvsocket {"data":190.482000,"error":"success"}

也可以发送 input.conf 风格的纯文本命令:

> echo 'show-text ${playback-time}' | socat - /tmp/mpvsocket

文本命令不会在 socket 上返回回复(该示例命令只是把播放时间显示到 OSD 上)。

想让 mpv 启动后不立即退出、可以持续被控制,可配合--idle选项启动(不加载文件)。

2.2 Windows:命名管道

Windows 上测试更困难:Cygwin/MSYS2 的 socat 端口不理解命名管道;echo只能发命令、收不到回复。假设:

mpv file.mkv --input-ipc-server=\\.\\pipe\\mpvsocket

在命令提示符中发送命令:

echo show-text ${playback-time} >\\.\pipe\mpvsocket

要像 Linux 那样同时双向读写,必须编写使用 overlapped file I/O 的外部程序(或 .NET 的NamedPipeClientStream之类的封装)。另外文档提到一个实用技巧:可以用 PuTTY 把该管道当作“串口”设备打开,无需写代码即可交互式测试。

从实现侧看,input/ipc-win.c 的ipc_thread()CreateNamedPipeW创建管道,状态为PIPE_TYPE_MESSAGE | PIPE_READMODE_BYTE | PIPE_WAIT | PIPE_REJECT_REMOTE_CLIENTS——即兼容消息模式与字节模式客户端。同时源码中create_restricted_sd()构造了 SDDL 安全描述符,只允许当前用户在当前(或更高)完整性级别的进程读写管道,这是对"无认证协议"在本地层面的最小兜底。

3. 协议规范:消息格式、回复与事件

3.1 编码与分帧

协议使用 RFC-8259 定义的 UTF-8 JSON,但有一个例外:不允许用\u转义序列构造代理对(surrogate pairs)。为避免冲突,代码点 U+0020 及以上的全部字符都应直接以 UTF-8 编码。极端情况下 mpv 可能输出损坏的 UTF-8(见第 6 节)。

  • 每条命令、回复、事件之间以换行符\n分隔;
  • 每条消息必须以\n结尾,且消息内部不能出现\n——实际效果是:消息在发送前应压缩为单行(minified)JSON。

3.2 发送命令

客户端发送形如:

{ "command": ["command_name", "param1", "param2", ...] }

其中command_name是命令名,参数必须是原生 JSON 值(整数、字符串、布尔值等)。

mpv 会回复命令是否执行成功,并附一个可能为null的命令返回数据字段:

{ "error": "success", "data": null }

3.3 事件推送

mpv 也会主动向客户端推送事件:

{ "event": "event_name" }

event_name是事件名,还可能携带事件专属的附加字段。

3.4 request_id:把回复和命令配对起来

由于事件可能在任意时刻发生,有时很难判断哪条回复对应哪条命令。命令可携带可选的request_id,它会原样拷贝进回复;mpv 不解释其含义,仅供请求方使用。要求是:request_id必须是整数(无小数、范围-2^63..2^63-1的数);其他类型目前会给出警告,未来版本将直接报错。

示例请求与回复:

{ "command": ["get_property", "time-pos"], "request_id": 100 }
{ "error": "success", "data": 1.468135, "request_id": 100 }

未指定request_id时,回复中会被置为 0。

源码印证:input/ipc.c 的json_execute_command()中,reqid_node存在时直接mpv_node_map_add(..., "request_id", reqid_node)原样回填,否则写入 int64 的 0;对非整数的request_id会打印"'request_id' must be an integer. Using other types is deprecated and will trigger an error in the future!",与文档描述逐字对应。

3.5 非 JSON 文本命令与注释

如果一行(跳过空白后)的首字符不是{,mpv 会把整行当作input.conf 风格的非 JSON 文本命令处理(等价于客户端 API 中的mpv_command_string())。以#开头的行和空行被忽略。

嵌入的 0 字节当前会终止当前行,但文档提醒:不要依赖这个行为。

对应源码在 input/ipc.c 的mp_ipc_consume_next_command():先json_skip_whitespace,然后line0[0] == '\0' || '#'跳过、'{'json_execute_command()、其余走text_execute_command()(内部调用mpv_command_string(),且不产生回复)。

3.6 数据流时序

文档给出的时序约束在实现中可以直接验证(input/ipc-unix.c 的client_thread()):

  • mpv 侧在执行命令、写回复期间不再服务该 socket:例如命令执行期间发生的事件,不会抢在回复之前写入 socket。这一点未来可能改变,唯一保证是"对 IPC 消息的回复按序发出";
  • 由于 socket I/O 天然异步,你可能在收到上一条命令回复之前先读到不相关的事件消息——这些事件是 mpv 在读到你这条命令之前就已排队好的;
  • 如果未来 mpv 侧改为非阻塞写/非阻塞执行,事件可能在任意时刻被发送;
  • 还可以使用异步命令(见第 4 节),它们以任意顺序返回,且执行期间完全不阻塞 IPC 交互。

从源码结构看,client_thread()poll()同时监听"播放器唤醒管"与客户端 socket:唤醒时批量mpv_wait_event取出事件并用mp_json_encode_event()编码写出;读入数据则累积到缓冲区,遇到\n才调用mp_ipc_consume_next_command()取出一整行命令处理。这解释了"回复按序、事件可能穿插"的行为来源。

4. 异步命令

任何命令都可以异步执行:行为与同步执行完全一致,只是不阻塞——执行期间可以继续发送其他命令,完成顺序任意。

控制字段是async:存在时必须是布尔值,缺省视为false。示例:发起

{ "command": ["screenshot"], "request_id": 123, "async": true }

完成后收到:

{"request_id":123,"error":"success","data":null}

三个要点:

  1. 按设计,不会收到"命令已启动"的确认。长耗时命令在发出后直到执行完毕才会有回复;
  2. 一些本质同步执行的命令若被标记async,会表现为"立即完成的异步命令";
  3. 异步命令的取消能力在 libmpv API 中可用,但 IPC 协议尚未实现。

源码中,input/ipc.c 的json_execute_command()async字段的处理是:存在且非布尔则报MPV_ERROR_INVALID_PARAMETER;为真时调用mpv_command_node_async(client, reqid, cmd_node)并置send_reply = false(即本次不立即写回复,等事件线程把COMMAND_REPLY事件编码写出)——这正是"没有启动确认、回复任意到达"机制的实现来源。

5. 命名参数命令与 IPC 专属命令

5.1 命名参数

command字段是 JSON对象而非数组,则按命名参数解析(对应 C APImpv_command_node()文档中MPV_FORMAT_NODE_MAP的情形)。部分命令用命名参数可读性更好,少数生僻命令基本必须使用命名参数。目前只有"正规命令"(见List of Input Commands,即 DOCS/man/commands.rst 中列出的命令)支持命名参数。

5.2 IPC 协议额外的命令

List of Input Commands中所有命令外,IPC 还支持以下命令(实现见 input/ipc.c):

命令说明示例
client_name返回客户端名字符串,形如ipc-N(N 为整数){"command": ["client_name"]}
get_time_us返回 mpv 内部时间(微秒,系统时间加任意偏移)
get_property读取属性,值放入回复的data字段{"command": ["get_property", "volume"]}{"data": 50.0, "error": "success"}
get_property_string同上,但data恒为字符串{"command": ["get_property_string", "volume"]}{"data": "50.000000", "error": "success"}
set_property设置属性{"command": ["set_property", "pause", true]}{"error": "success"}
set_property_stringset_property的别名,两者都接受原生值与字符串
observe_property观察属性变化,变化时产生property-change事件见下
observe_property_string同上,但data恒为字符串
unobserve_property撤销观察,参数为观察时使用的数字 id{"command": ["unobserve_property", 1]}
request_log_messages开启 mpv 日志输出(以事件形式接收),参数为日志级别(同 C APImpv_request_log_messages
enable_event/disable_event启用/禁用指定事件,等价于 C APImpv_request_event();传字符串all表示全部事件
get_version返回该 mpv 实例客户端 API 的版本号

observe_property的完整交互示例:

{ "command": ["observe_property", 1, "volume"] } { "error": "success" } { "event": "property-change", "id": 1, "data": 52.0, "name": "volume" }

警告(原文档原样强调):连接一旦断开,IPC 客户端在 mpv 内部被销毁,被观察的属性会随之注销。比如用分次调用 socat 发命令时就会这样,看起来就像"属性观察不生效"。必须保持 IPC 连接常开,观察才有效。

request_log_messages还附有一条重要告诫:日志输出是给人看的(主要用于调试),试图解析日志获取信息只会导致未来版本一升级就坏——需要信息时应该提 feature request,要求提供正规的返回该信息的事件。

关于enable_event/disable_event:默认大多数事件本来就是启用的,因此该命令实际使用价值有限。

6. UTF-8 边界问题

正常情况下所有字符串都是 UTF-8,但有时字符串会处于某种损坏编码(常见于文件标签;许多 Unix 系统上的文件名也不保证是 UTF-8)。这意味着 mpv 偶尔会发出非法 JSON。如果客户端解析器因此出问题,应当在送入 JSON 解析器之前,先对原始数据中的非法 UTF-8 序列做过滤替换。

mpv 承诺不会通过损坏的\u转义序列(包括代理对)去构造非法 UTF-8。

7. JSON 扩展语法

mpv 的 JSON 解析器支持以下非标准扩展(与 misc/json.c 头部注释一致):

  • 数组或对象元素可以有尾随逗号
  • 对象语法除了:之外还接受=
  • 对象 key 可以不带引号,前提是首字符属于A-Za-z_、其余字符只含A-Za-z0-9_
  • 允许\xAB形式的字节转义(AB 为两位十六进制数)。

示例:

{ objkey = "value\x0A" }

等价于:

{ "objkey": "value\n" }

这对手写命令时省却引号、以及表达控制字符非常便利,但注意这是单向便利:mpv 发出的消息始终是标准 JSON。

8. 不创建 server 的客户端连接方式:.run脚本

除了--input-ipc-server,还有一种匿名 IPC 连接方式,通过 mpv 的一个"伪脚本后端"启动外部进程实现:

  1. 在 mpv 脚本目录(即配置目录下的 scripts 目录,详见 mpv man 的FILES章节)放入带.run扩展名的文件,或通过其他方式加载(见Script location)。这些脚本通过操作系统原生机制直接执行(就像在 shell 中运行一样),必须有正确的 shebang 并设置可执行位;
  2. 执行时,IPC 连接所用的 socket 通过文件描述符继承传给子进程,并以特殊命令行参数--mpv-ipc-fd=N指明 FD 编号(N 为数字);
  3. 之后的行为与普通的--input-ipc-serverIPC 连接完全一致。mpv 不尝试观察或与启动的脚本进程做其他交互;
  4. Windows 上目前不可用

源码印证:该后端注册在 player/scripting.c 中——mp_scripting_run结构体.name = "ipc".file_ext = "run"load_run()调用mp_ipc_start_anon_client()生成一对socketpair()(见 input/ipc-unix.c 对应函数),拼出--mpv-ipc-fd=%d参数后经mp_subprocess()以 detach 方式拉起子进程。而 input/ipc-win.c 中的mp_ipc_start_anon_client()直接返回false,与"Windows 上暂不可用"的文档表述一致。

这种模式的典型用法是:写一个带 shebang 的 Python/Shell 脚本放入 scripts 目录,脚本内以--mpv-ipc-fd=N指定的 FD 作为 stdin/stdout 通道与 mpv 双向通信,无需管理任何 socket 路径或权限。

9. 速查小结

  • 启动mpv file.mkv --input-ipc-server=/tmp/mpvsocket(Unix)或--input-ipc-server=\\.\\pipe\\mpvsocket(Windows,缺\\.\pipe\前缀会自动补);--idle可让 mpv 常驻等待控制。
  • 最小请求{"command": ["get_property", "playback-time"]}+ 换行;回复{"data":190.482000,"error":"success"}
  • 配对回复:始终带上整数request_id,回复会原样带回。
  • 长任务:加"async": true,接受"无启动确认、回复乱序、不可取消"三件事。
  • 属性订阅observe_property前记住"连接必须保持",否则观察随连接销毁而注销。
  • 文本命令:不以{开头的行按 input.conf 语法执行、无回复;#与空行忽略。
  • 安全:仅限本机信任环境使用;run命令暴露意味着任何能连上 socket 的本机进程都能执行任意命令。

参考路径汇总:协议文档 DOCS/man/ipc.rst;命令解析与回复构造 input/ipc.c;Unix 侧 socket 实现 input/ipc-unix.c;Windows 命名管道实现 input/ipc-win.c;JSON 扩展解析 misc/json.c;选项定义 options/options.c 与 DOCS/man/options.rst;.run脚本后端 player/scripting.c;命令清单 DOCS/man/commands.rst。

【免费下载链接】mpv🎥 Command line media player项目地址: https://gitcode.com/GitHub_Trending/mp/mpv

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/6 20:01:29

通达信缠论笔线段自动画线:基于DLL插件的完整实现方案

简介&#xff1a;这是一份通达信缠论笔线段画线公式源码的主图文档&#xff0c;专为使用通达信软件进行缠论技术分析的投资者和指标开发者准备。文档详细讲解了基于分型与笔划分的画线公式实现方法&#xff0c;包含DINGFEN、DIFEN、ZHUANGZHE等核心变量和函数定义&#xff0c;并…

作者头像 李华
网站建设 2026/9/6 19:53:21

IOPaint AI去水印完整指南:免费开源上手

IOPaint AI去水印完整指南&#xff1a;免费开源上手 【免费下载链接】IOPaint Image inpainting tool powered by SOTA AI Model. Remove any unwanted object, defect, people from your pictures or erase and replace(powered by stable diffusion) any thing on your pictu…

作者头像 李华
网站建设 2026/9/6 19:53:18

Stewart平台六自由度主动隔振仿真复现:建模、控制与优化

简介&#xff1a;一份聚焦六自由度隔振平台优化与控制技术研究的论文复现资料&#xff0c;面向机械工程与控制工程背景的研究人员和工程师&#xff0c;解决控制力矩陀螺引发的卫星微振动问题&#xff0c;基于Stewart机构开展主被动联合隔振方案设计与仿真。内容完整覆盖主被动隔…

作者头像 李华
网站建设 2026/9/6 19:53:09

基于STM32的智能家居护眼台灯设计与实现

简介&#xff1a;这是一份基于STM32的智能家居护眼台灯设计与实现的电子信息专业论文写作模板&#xff0c;内含完整论文结构&#xff0c;涵盖摘要、绪论、系统分析、硬件选型、算法设计等章节&#xff0c;适合具备单片机基础的电子信息类学生、嵌入式初学者及智能硬件爱好者用于…

作者头像 李华