mpv | libmpv 中文文档

文档地址:https://github.com/mpv-player/mpv/blob/master/libmpv/client.h

本文会持续更新跟进mpv的开发进度。目前状态: 未完成.

译者声明

本翻译由Reverier-Xu根据原文档人工翻译而成,尽力保证了准确性与易读性,如有问题还请参照原文档。

本文档可以引用转载,但必须注明原作者并附上本文链接。如有对原文进行的更改,请务必标识出来。

API提供的机制

这份API提供了对mpv播放的控制机制。本API并不直接提供给你关于播放器的单个组件或者单个元素,只提供对播放器的总体控制。这在某种程度上可以当成MPlayer的从属机制(slave mode),你可以通过本API对播放器发送命令,从播放器检索或者设置播放的状态或属性,以及接收播放器传来的事件。

这份API可以用于两个用途:

  • mpv命令行播放器添加其他的功能,mpvLua扩展脚本系统就是这么做的。(目前没有插件API可以在外部用户代码中获得客户端的API句柄,他必须是播放器的固定部分。)
  • 使用mpv_create()函数,将mpv当作一个程序库来使用。这里提供了将mpv嵌入其他应用程序时所要用到的最基本的函数。

关于文档

libmpvC API文档就写在这个头文件里面(译者注:现在被翻译成文档放在这个博客里了)。请注意,与播放器的大部分交互是通过选项(options)/命令(commands)/属性(properties)来完成的,可以通过此API来进行。从本质上来讲,一切事件都是由它们完成的,包括加载文件,检索文件进度等等。

在其他的地方也有一些文档:

你可以在这里查看一些示例:

事件循环

一般情况下,使用此API的开发者应当在后台运行一个事件循环来持续接收本播放器发出的事件。这个事件循环的名称应当叫做mpv_wait_event(),一旦有新的mpv客户端API可用,它将返回这个API。你也可以通过mpv_set_wakeup_callback()函数将这个事件循环集成到其他的现有事件循环里(例如GUI程序的事件循环),然后通过调用mpv_wait_event()来轮询事件,轮询事件的间隔(timeout)应当设置为0

请注意,播放器和事件循环实际上是分离的。不调用mpv_call_event()并不会让播放器停止播放。但是这最终会阻塞你的API事件处理队列。

同步与异步调用

API同时支持同步和异步的调用方法。同步调用需要等待播放器核心的响应,而等待的事件很可能是不确定的(例如较差的网络加载速度)。而异步调用仅将调用的操作当成请求放入处理队列中,然后将操作的结果当成事件,在处理结束后返回。

异步调用

此客户端API包含了异步调用所需要的函数。这些函数允许你将操作请求立即发送给播放器,然后在播放器处理完成之后得到事件回复。这些请求所使用的函数都用_async作为后缀名。这些函数处理完成的结果都会当成事件,通过mpv_wait_event()进行发送(与正常的事件流交叉)。

libmpv使用一个64位的userdata值将你的请求和处理完成后的结果事件相关联,这个值是通过reply_userdata参数传送给请求函数的。而请求得到的回复将包含一个mpv_event->reply_userdata成员,这个成员的值与你传入的相应请求中userdata的值是相同的,你可以通过这个将请求和回复对应起来。

这个userdata是由开发者自行设置的。本API仅把这个值当成一个事件标签,所以可以任意设置。但请注意,将userdata设置成0属于合法操作,但是如果事件不是一个答复(例如视频播放完成事件),则开发者必须要小心,不能错误的将mpv_event->reply_userdata当成一个答复,因为0mpv事件中userdata的默认值。(译者注:言外之意就是不要使用0作为userdata,不便于区分。)

调用队列并不保证按照请求的先后顺序去执行。如果你不希望事件的执行顺序被打乱,请在异步调用完成并收到回复事件后再进行下一个请求。

多线程

API在一般情况下是完全线程安全的,除非有特别注明。

不过同时使用多个线程去操控播放器是没有必要的,因为所用请求都会被播放器放入队列当中挨个执行。

基础环境要求

接下来的要求都是在C语言环境基础之上的。这个对于将mpv作为程序库嵌入其他应用程序的开发者来说尤其重要。

  • LC_NUMERIC环境变量必须设置为"C"。如果你的应用程序使用了setlocale(),请当心,不要设置LC_ALL环境变量。如果你这么做了,请将LC_NUMERIC变量设置回默认值:setlocale(LC_NUMERIC, "C")
  • 如果使用基于X11V0,那么mpv会设置xlib error handler。这个错误处理程序是进程范围的,而且没有适当的方法在同一进程内与其他的xlib用户共享。这可能在一些GUI框架中会遇到困扰。
  • mpv使用了一些可能并不安全的库,例如Fribidi(通过libass使用),ALSAFFmpeg,除了这些之外可能还有更多。
  • FPU的精度至少得设置到双精度
  • Windows上,mpv会自动调用timeBeginPeriod(1)
  • 内存即将耗尽时,mpv会自动终止进程。
  • 在某些情况下,mpv可能会启动子进程,例如ytdl包装器脚本。
  • 打开UNIX IPC(默认是关闭的)时会将SIGPIPE的信号处理器覆盖掉,设置到SIG_IGN。对于一些子进程的调用命令也会这么做。
  • mpv会在使用到随机数时通过srand()函数为传统的C语言随机数生成器设置新种子。
  • 由于mpv在某些情况下会启动子进程,开发者应当避免覆盖SIGCHLD或者等待父进程中或其他库中的所有PID(例如调用wait())。libmpv仅等待它的子进程。
  • 如果进程中的任何地方注册了信号处理程序,则它们必须设置SA_RESTART标志。 否则,你可能会接收到随机的信号错误。

文件名编码

mpv在任何地方都使用UTF-8编码。

在某些平台上(例如Linux),文件名可能不必要一定是UTF-8编码,由于这个原因,libmpv也支持使用非UTF-8的字符串。libmpv会使用Linux Kernel同款编码,并且不会重新编码文件名称。至少在Linux平台上,将一个字符串传递给libmpv和将一个字符串传递给fopen()函数是一样的。

Windows平台上,文件名一直都是UTF-8。在调用WIN32 API时,libmpv会自动在UTF-8UTF-16之间相互转换。libmpv不使用也不接受本地的8位字符串编码。在这个平台上libmpv不再使用fopen()函数,而是使用_wfopen()函数来处理文件。

OS X 平台上,libmpv获取或返回的文件名和其他的字符串的unicode规范可能不一致,但你得往好处想。

请参考MPV_FORMAT_STRING处的标注。

集成视频播放窗口

建议使用渲染API(在render_cb.h中)。此API需要你创建和维护OpenGL上下文,你可以通过调用API来渲染视频。 此API不直接包含键盘或鼠标输入的处理。

除此之外你还有一个比较老的办法来做到这一点,那就是获取到原始的窗口句柄,然后将他设置为"wid"选项。这个办法只能在X11win32OS X上使用。这个用起来比渲染API要简单的多得多,但是也有各种奇怪的问题。

请参考客户端API调用示例和mpvmanpage。这里还有一个扩展的讨论页面:

兼容性

mpv的开发工作并不是停滞不前的,而对mpv的内部以及接口的更改可能会导致与开发者使用的API的兼容性问题。

mpvAPI是通过版本来控制的(参考MPV_CLIENT_API_VERSION),对API的更改会放在DOCS/client-api-changes.rst。不过本文档所描述的C语言API很有可能会在很长一段时间里保持稳定,但是这些API对应的功能可能会更快的改变。比如说给选项改一个新名字或者改变有效值的取值范围。

应当使用防御性编程来处理控制libmpv的模块,以应对可能存在的选项,命令,属性消失,更改,取值范围更新或者基础类型改变。使用MPV_FORMAT_STRING来代替其他类型可能是个好主意,以使你的代码与可能存在的mpv更改脱钩。

参考:DOCS/compatibility.rst

未来发展

以下计划中的更改,很可能会在libmpv的下一个重大变更中完成:

  • 移除所有被标记为deprecated(已过时)的符号和包含文件。
  • 重新分配枚举数值来消除无用的类型。
  • 移除mpv_opengl_init_params.extra_exts域。
  • 更改mpv_event_end_file.reason的类型。
  • 默认关闭所有事件。

定义与宏

MPV_MAKE_VERSION

版本信息会在每次API更改之后递增。此定义的低16个字节表示小版本编号,高16个字节表示主要版本编号。如果API与上一个版本不再兼容,那么主要版本编号会更改。这个只会影响到C语言部分,并且没有属性和选项可供设置。

每个API的更改都可以在仓库里的DOCS/client-api-changes.rst找到。

你可以使用MPV_MAKE_VERSION()并将此宏返回的数值和整数比较。

1
2
#define MPV_MAKE_VERSION(major, minor) (((major) << 16) | (minor) | 0UL)
#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(1, 109)

MPV_ENABLE_DEPRECATED

开发者可以在引用libmpv之前定义"#define MPV_ENABLE_DEPRECATED 0",这个标记允许开发者使用已经过时的API

当然,已经过时的API,包括属性,命令和其他的函数是可以正常工作的。

1
2
3
#ifndef MPV_ENABLE_DEPRECATED
#define MPV_ENABLE_DEPRECATED 1
#endif

结构定义

struct mpv_handle

客户端API所使用的客户端上下文。每个客户端都有自己私有的句柄。

枚举定义

enum mpv_error

API函数会返回的错误代码枚举类型。0和正整数通常意味着成功,负数意味着执行失败,有错误发生。

枚举定义 含义
MPV_ERROR_SUCCESS 0 没有错误发生(通常表示操作成功完成)。请注意许多API函数会返回正数的错误代码,这通常意味着操作成功执行了。你可以使用>= 0来判断操作是否成功。
MPV_ERROR_EVENT_QUEUE_FULL -1 事件环缓冲区满了。这意味着客户端卡住了,而且不能接收任何事件。这个会在有很多异步请求出现但是还没有应答时发生。不过这个错误应该永远不会产生,除非mpv由于一些原因卡住了,而且客户端在源源不断的发送异步请求。
MPV_ERROR_NOMEM -2 无法分配内存。
MPV_ERROR_UNINITIALIZED -3 mpv核心没有初始化也没有进行配置。请查看mpv_create()函数的记录。
MPV_ERROR_INVALID_PARAMETER -4 当参数设置成非法或者不支持的值是所产生的通用错误。对于播放器产生的错误,在没有更好的描述方法时才会使用本信号。
MPV_ERROR_OPTION_NOT_FOUND -5 试图设置一个不存在的选项。
MPV_ERROR_OPTION_FORMAT -6 试图为选项设置一个不支持的MPV_FORMAT
MPV_ERROR_OPTION_ERROR -7 设置选项失败了。通常来说这个错误会在提供的选项值无法被解析时发生。
MPV_ERROR_PROPERTY_NOT_FOUND -8 访问的属性不存在。
MPV_ERROR_PROPERTY_FORMAT -9 尝试使用不支持的MPV_FORMAT来设置或获取一个属性。
MPV_ERROR_PROPERTY_UNAVAILABLE -10 这个属性存在但是不可用。这个通常发生在相关的子系统没有被激活时,比如在音频关闭时查询音频的参数。
MPV_ERROR_PROPERTY_ERROR -11 设置或者获取某个属性的时候失败了。
MPV_ERROR_COMMAND -12 运行mpv_command()或相似函数时引发的通用错误。
MPV_ERROR_LOADING_FAILED -13 加载过程中引发的通用错误。(通常与mpv_event_end_file.error一起使用)
MPV_ERROR_AO_INIT_FAILED -14 初始化音频输出失败。
MPV_ERROR_VO_INIT_FAILED -15 初始化视频输出失败。
MPV_ERROR_NOTHING_TO_PLAY -16 没有音视频数据可以播放。这通常在一个已经识别的媒体文件里没能找到能够播放的音视频流或者没有音视频流被选择播放。
MPV_ERROR_UNKNOWN_FORMAT -17 在加载文件时发现文件格式未识别,或者文件已损坏。
MPV_ERROR_UNSUPPORTED -18 表示某些系统要求未得到满足的一般错误。
MPV_ERROR_NOT_IMPLEMENTED -19 被调用的函数只是一个空函数,还没有被实现。
MPV_ERROR_GENERIC -20 未知的错误。

enum mpv_format

选项和属性的数据格式。 获取/设置属性和选项的API函数支持多种格式,此枚举类型对这些数据格式进行了描述。

枚举定义 含义
MPV_FORMAT_NONE 0 无效的格式,有时用于空值。这个值将始终定义为0, 因此可以保证mpv_formatmpv_node初始化时的值始终为MPV_FORMAT_NONE。(这有些时候会让事情好起来。)
MPV_FORMAT_STRING 1 基础类型为char*。此格式表示一个纯字符串的属性,例如在input.conf里使用${=property}(参照input.rst
NULL是不合法的。
警告:虽然编码通常情况下都是UTF-8,但并不是一直都这样。文件标签通常会将字符串存在一些遗留代码页中,并且文件名也不一定必须是UTF-8(至少在Linux上是这样)。如果你给代码传入的字符串需要是有效的UTF-8编码,你得自己想办法解决这个问题。
Windows上文件名倒一直是UTF-8编码的,libmpv在调用Win32 API时会自动在UTF-8UTF-16之间进行转换。参考Encoding of filenames节。

示例:
char *result=NULL;
if(mpv_get_property(ctx, "property", MPV_FORMAT_STRING, &result) < 0)
goto error;
printf("%s\n", result);
mpv_free(result);

或者使用mpv_get_property_string()
char *value = "the new value";
mpv_set_property(ctx, "property", MPV_FORMAT_STRING, &value);

或者仅仅使用mpv_set_property_string()
MPV_FORMAT_OSD_STRING 2 此类型的基本类型为char*。此类型返回一个表示OSD属性的字符串,例如在input.conf中的${property}(参考input.rst)。在很多情况下,这个和原始字符串类型是相同的,但是在另一些情况下它具有OSD的文本格式。它旨在让人类可读。不要尝试解析这些字符串。
MPV_FORMAT_FLAG 3 基础类型为int。他只接受0(no)和1(yes)作为有效值。
读取示例:
int result;
if (mpv_get_property(ctx, "property", MPV_FORMAT_FLAG, &result) < 0)
goto error;
printf("%s\n", result ? "true" : "false");

写入示例:
评论

:D 一言句子获取中...