资讯动态

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

发布时间:2026/9/6 20:03:59 来源:尧图企业网站定制
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 协议来控制播放器客户端连接到一个 socketUnix 域 socket 或命名管道向播放器发送命令、接收回复与事件。启用方式有两个选项--input-ipc-serverpath在指定路径Unix socket 或命名管道上监听供任意多个客户端连接--input-ipc-clientfd://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 / Unixsocat假设 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。为避免冲突代码点 U0020 及以上的全部字符都应直接以 UTF-8 编码。极端情况下 mpv 可能输出损坏的 UTF-8见第 6 节。每条命令、回复、事件之间以换行符\n分隔每条消息必须以\n结尾且消息内部不能出现\n——实际效果是消息在发送前应压缩为单行minifiedJSON。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}三个要点按设计不会收到命令已启动的确认。长耗时命令在发出后直到执行完毕才会有回复一些本质同步执行的命令若被标记async会表现为立即完成的异步命令异步命令的取消能力在 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-NN 为整数{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 的一个伪脚本后端启动外部进程实现在 mpv 脚本目录即配置目录下的 scripts 目录详见 mpv man 的FILES章节放入带.run扩展名的文件或通过其他方式加载见Script location。这些脚本通过操作系统原生机制直接执行就像在 shell 中运行一样必须有正确的 shebang 并设置可执行位执行时IPC 连接所用的 socket 通过文件描述符继承传给子进程并以特殊命令行参数--mpv-ipc-fdN指明 FD 编号N 为数字之后的行为与普通的--input-ipc-serverIPC 连接完全一致。mpv 不尝试观察或与启动的脚本进程做其他交互Windows 上目前不可用。源码印证该后端注册在 player/scripting.c 中——mp_scripting_run结构体.name ipc、.file_ext runload_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-fdN指定的 FD 作为 stdin/stdout 通道与 mpv 双向通信无需管理任何 socket 路径或权限。9. 速查小结启动mpv file.mkv --input-ipc-server/tmp/mpvsocketUnix或--input-ipc-server\\.\\pipe\\mpvsocketWindows缺\\.\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.cUnix 侧 socket 实现 input/ipc-unix.cWindows 命名管道实现 input/ipc-win.cJSON 扩展解析 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),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价